Compare commits

...
10 Commits
Author SHA1 Message Date
dennisthiessenandClaude Opus 5 2fadfdb8eb feat(scout): probe four unverified boards — add CERN, NCIA to manual check
Probed CERN, Swiss Post, NATO NCIA and SIX Group. Two actionable results:

- CERN: SmartRecruiters board "CERN", 66 live Geneva postings with real
  engineering (Deep Learning Developer, ML Engineer NGT, Full-stack SWE, Data
  Storage R&D Engineer). Added — the adapter already existed. Two standing
  caveats recorded in the entry: Geneva is ~1h50 from Bern so a 2-3 day hybrid
  is not viable without relocation, and CERN grades sit below the 180k bar.
- NATO NCIA: nato.int is Cloudflare-blocked to headless browsers. Moved to
  MANUAL_CHECK beside Oracle, with a note that NCIA is a separate pipeline from
  the JWC Stavanger reqs the `nato` adapter returns.

Not added, documented instead:
- Swiss Post: real board is job.post.ch (SuccessFactors CSB), scrapable via
  a[href*='/job/']. The only tech role on page 1 was served from the PostFinance
  sub-board, which is already covered. Paginated, so this is page-1 evidence
  only, not a whole-board verdict.
- SIX Group: SAPUI5 SPA backed by a legacy DWR RPC endpoint
  (careerJobSearchControllerProxy.getInitialJobSearchData.dwr). Scrapable in
  principle, brittle in practice; job rows did not render into readable text.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 18:28:45 +02:00
dennisthiessenandClaude Opus 5 cbb713ba7d chore(aws-fde): NO-GO at Phase 0 gate — 69/100 below the fit bar
User declined at the gate: 69 is not a strong enough fit to spend a package on.
Consistent with revealed behaviour — every application actually submitted scored
77.5-89; nothing below 75 has ever been sent.

No cohort slot consumed (Adjacent stays 1/2). No bullets written, no resume, no
cover letter. Phase 0 analysis retained in the session file in case a
better-fitting AWS req appears.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 13:02:54 +02:00
dennisthiessenandClaude Opus 5 cc109524f8 feat(aws-fde): Phase 0 for AWS Senior Forward Deployed Engineer, Zurich
Verbatim JD (amazon.jobs 10504263, posted 2026-08-17) retrieved via Playwright
and stored with the session.

Evidence Fit 69/100, Adjacent. All four Basic Qualifications are Direct, so the
minimum-qualification gate passes. Disclosed rather than buried: forward
deployment is the title-defining capability and is a Gap - SW-4, VZ-1 and
global_forbidden_output_patterns all forbid "customer-embedded delivery", and
application_strategy lists strategic-account FDE as a Stretch target. Scored
Adjacent because AWS's published minimum bar is pure software engineering and
the org is seven weeks old, hiring builders at volume.

Assets: AWS is the evidenced cloud (claims.json forbids GCP output), and Kiro -
named in the JD - is in the verified GenAI toolchain.

CL decision YES. Would consume the last Adjacent cohort slot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 12:58:39 +02:00
dennisthiessenandClaude Opus 5 e09437dc27 chore(pipeline): close SDU + Google FDE III, triage 5 JDs, drop Louis Dreyfus
Pipeline:
- SDU PhD: closed, not proceeding. Prof. Jørgensen never replied to the
  2026-08-02 enquiry; user dismissed it two days before the 2026-08-20 deadline.
- Google FDE III GTM: closed, not proceeding after two Google rejections. The
  bar for a third attempt is now a very strong fit; this was Adjacent with an
  agent-orchestration gap. Frees the Adjacent cohort slot (back to 1/2).

JD triage — 5 pulled and read, 1 survives:
- SHORTLIST AWS Senior FDE Zurich: all four basic quals pass and AI/agentic is
  preferred-only, unlike the Google Senior Staff FDE where vector DB + RAG were
  minimum quals. AWS is the evidenced cloud; JD names Kiro, which he uses.
- SKIP AWS ProServe Bern (clinical pharma domain gate), AWS Principal Delivery
  Consultant (8+ yrs architecture leadership + VP+ exec comms), GitLab FDE EMEA
  (Ruby/Go hard gate), MS 200044133 (title says FDE Data Scientist, quals are
  BGP/MPLS/SD-WAN network engineering — mislabelled req).

Roster:
- Dropped Louis Dreyfus: 300 roles, all Brazil/India/Bulgaria ops, zero Swiss.
- Kept MET Group: its "0 eligible" was a filter artifact; exclusion mode reveals
  real Baar/Zug commodity-trading roles.
- Kept Equinor/Telenor/NATO. Memory corrected: the Norway lane is selective, not
  closed — the user still wants very good Norwegian roles.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 12:16:45 +02:00
dennisthiessenandClaude Opus 5 3bb6baa1b3 chore(scout): remove temp probe output files
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 11:17:40 +02:00
dennisthiessenandClaude Opus 5 aad69745e7 chore(scout): remove temp probe scripts committed by mistake
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 11:17:34 +02:00
dennisthiessenandClaude Opus 5 284407cd23 fix(scout): repair Roche/Apple, add Amazon+Axpo, make title filtering fail-open
Scraper fixes:
- Roche: new fetch_phenom adapter (Phenom refineSearch). The old playwright scrape
  of ?locationsearch=Switzerland harvested recommendation-widget cards (Shanghai,
  Kyiv, Bogota) while the page reported no-results. 0 -> 88 CH-eligible roles.
- Apple: dropped default_location "Switzerland", which relabelled US "Various
  Locations" postings as Swiss (84 phantom CH rows over 4 runs). Now honestly 0.
- Meta: NOT broken — metacareers reports "1 Items" for Zurich. Comment added so it
  is not "fixed" again.

New boards:
- Amazon/AWS (fetch_amazon): 32 CH roles incl. a Zurich AWS FDE req and a Bern
  ProServe Cloud Architect. AWS is the evidenced cloud; claims.json forbids GCP.
- Axpo (teamtailor via base_url + pagination): 461 roles, opens the energy lane.
  Locations read from schema.org jobLocation with ISO alpha-2 expanded, so
  Madrid/Milan/Warsaw roles are not marked Swiss. Telenor benefits too.

Title filtering now has two explicit modes. Inclusion allowlists fail closed and
hide unanticipated good-fit roles, so they are now used only where volume forces
it (>~200 roles). Everything else uses the shared, board-agnostic
NOISE_TITLE_EXCLUDE, which fails open and leaves the final call to the scorer and
the reviewer. Palantir stays unfiltered per its existing documented rationale.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 11:17:24 +02:00
dennisthiessenandClaude Opus 5 082a1d250c docs(scout): roster review — broken scrapers, dead lanes, verified adds
Analysis of the 34-company roster against 4 recent runs and 253 decisions.
No COMPANIES changes.

Findings: Roche/Meta/Apple silently scrape garbage (non-CH rows, 1 intern,
internships-only) — same silent-failure class as the dbt Labs 404; seven boards
have no _title_filter; MET+LDC yielded 0 eligible across 1,464 scrapes.

Verified adds: Amazon/AWS (32 CH roles incl. a Zurich AWS FDE req, and AWS is
the evidenced cloud where GCP is forbidden) and Axpo (Teamtailor custom domain,
400 roles incl. Forward Deployed AI Engineer, opens the named energy lane).

Verified negative: Coinbase proper has 2 EMEA-remote non-eng roles; the
remote-EU data-infra tier is geo-banded below the comp bar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 10:46:23 +02:00
dennisthiessenandClaude Opus 5 c206563b59 chore(scout): drop Coinbase Ventures getro board
The board never carried Coinbase's own roles — only Getro portfolio companies.
Across ~3 months it surfaced 3 distinct CH-eligible roles, all from Ashby
(recruiting software, ruled out 2026-07-28) and all decided "skip". Since the
Ashby exclusion it has returned 0 jobs on every run, surfacing a false error
line in each report.

Entry replaced with a "Dropped:" note per the file's convention. fetch_getro is
retained (no caller) since it generalises to any Getro collection id.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 10:34:58 +02:00
dennisthiessenandClaude Opus 5 7b45d41ed8 fix(scout): repoint dead dbt Labs board at Fivetran after merger
The "dbtlabsinc" Greenhouse board started returning 404, silently dropping
a target company from every scan. getdbt.com/careers now redirects to a page
serving Fivetran's Greenhouse listings (gh_jid links) — the two companies
merged, so the roles live on board "fivetran" (239 jobs, 10 title matches).

Renamed the entry id dbtlabs -> fivetran and cleared the stale seen-state key.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 10:30:35 +02:00
6 changed files with 766 additions and 67 deletions
+3 -2
View File
@@ -157,8 +157,9 @@ _Update this section when starting/finishing a JD._
| Session | Status | Next Command |
|---------|--------|-------------|
| Google — Forward Deployed Engineer III, Google Cloud GTM (French, German), Zürich (req 78350205438567110) | **PHASE 0 DONE 2026-08-11** — Adjacent, **Evidence Fit 67/100**, hard gate PASS (all 5 minimum quals hold; German alone satisfies the "French **or** German" requirement), Channel Weak. Level badge is **Mid**; user explicitly overrode level/comp 2026-08-11 (*"ignore fit, i would gladly accept a mid FAANG offer"*) — do NOT re-raise level. **Caveat:** responsibility #1 (lead developer, production agentic workflows / multi-agent / MCP) is a **Gap** — SW-8 forbids agent-orchestration claims; ADK/LangGraph/CrewAI are `never-used`. GCP also unevidenced (AWS-primary). Consumes the **last Adjacent cohort slot (2/2)**. Sibling req *FDE III, Generative AI* confirmed CLOSED. CL decision YES — its job is pre-empting the overqualification screen that killed Business Home in ~24h | Phase 1 — bullet plan (awaiting user confirmation of role type, format, framing) |
| SDU Center for Energy Informatics, Odense DK — PhD, Theme 2 Predictive Maintenance & Asset Management of Smart Energy Networks (job 4159) | **EXPLORATORY 2026-08-02** (deadline 2026-08-20). Real JD scraped via Playwright. Strong genuine fit: thesis = vibration condition monitoring, RBR+ANN hybrid, throughput-vs-sensor-rate finding; Bosch fab sensor data; Swisscom data products as AI foundation. **Hard constraint: DKK 37,075/mo ≈ CHF 56k — far below the 180k bar; user accepts this knowingly as a PhD.** Real blocker is 2 letters of recommendation (13 yrs out of academia). Top-30% doc does NOT apply (numeric grading) — do NOT submit the ECTS-B/top-35% certificate against it. No publications. **Enquiry email to Prof. Bo Nørregaard Jørgensen SENT 2026-08-02** (draft in `output/sdu_phd_energy_informatics/enquiry_email_joergensen.md`); asked two questions — industry-candidate viability, and whether non-academic letters of recommendation are acceptable. | Await reply. Critical path is the 2 LORs, not the documents — chase referees regardless of reply. Build an **academic-style CV** (education-first, not the 2pp industry resume) when the user gives the go-ahead |
| AWS (AWS EMEA SARL, Switzerland Branch) — Senior Forward Deployed Engineer, Zürich (job 10504263) | **CLOSED — NO-GO 2026-08-18** at the Phase 0 gate. Evidence Fit **69/100** (Adjacent). Minimum-qual gate passed (all 4 Basic Quals Direct) but the *title-defining* capability — customer embedding — is a Gap that `claims.json` globally forbids claiming, and R2 multi-agent/retrieval is a second Gap. User declined: **69 is below the fit bar worth spending a package on.** Consistent with revealed behaviour — every application actually submitted scored **77.589**; nothing below 75 has ever been sent. **No cohort slot consumed (Adjacent stays 1/2).** Phase 0 analysis retained in the session file for reuse if a better-fitting AWS req appears. | Done — no package built |
| Google — Forward Deployed Engineer III, Google Cloud GTM (French, German), Zürich (req 78350205438567110) | **CLOSED — NOT PROCEEDING 2026-08-18.** Phase 0 was done (Evidence Fit 67/100, hard gate PASS) but user declined to proceed after **two Google rejections** (Merchant Data Science, Business Home): the bar is now that a Google req must fit *very* well to be worth a third attempt, and this one was Adjacent with an agent-orchestration Gap. **Frees the Adjacent cohort slot (back to 1/2).** Phase 1 never started. | Done — do not reopen without a materially stronger Google req |
| SDU Center for Energy Informatics, Odense DK — PhD, Theme 2 Predictive Maintenance & Asset Management of Smart Energy Networks (job 4159) | **CLOSED — NOT PROCEEDING 2026-08-18.** Enquiry email to Prof. Bo Nørregaard Jørgensen (sent 2026-08-02) went unanswered for 16 days; user dismissed the idea. Genuine thesis fit (vibration condition monitoring, RBR+ANN hybrid) but the blockers were never the documents — 2 letters of recommendation 13 years out of academia, and DKK 37,075/mo ≈ CHF 56k against a 180k bar. Deadline was 2026-08-20. | Done — no further action |
| Aker BP ASA — Data Product Architect, AI-ready Data Products (FINN 469067315) | **SUBMITTED 2026-07-30** (ahead of the 2026-08-02 deadline; Adjacent, **Evidence Fit 79/100**, Document Quality 93/100, hard gate PASS, Channel Weak; Stavanger/Oslo/Trondheim, English working language, no Norwegian and no clearance required, EEA work rights). 2pp resume + 1pp CL, both validator PASS. Honest practitioner framing: builds governed data products *inside* Swisscom's Data Mesh; role *authors* an enterprise framework — real level stretch, never fabricate authorship. **Atlassian Compass closed the catalogue-tool gap** (74→79). Remaining gaps: framework authorship, no energy domain, AWS vs their Microsoft/Cognite stack, **zero verified metrics**. | Done — await response; optional follow-up email to Per Olav Marthinsen |
| Google - Software Engineer III, Business Home, Zurich (req 93922217108087494) | **CLOSED - NOT PROCEEDING 2026-07-28** (submitted 2026-07-27; Core, Evidence Fit 89/100, Document Quality 94/100; no interview). Rapid early-screen disposition; known risks were Mid-level versus current Staff scope, data/platform versus product-SWE positioning, preferred algorithms/accessibility gaps, and a cold channel. | Done - cohort rejection recorded; do not treat this outcome alone as a document-quality failure |
| Microsoft — Principal Forward Deployed Engineer, SWE (German Speaking), Zürich (req 200043897) | **SUBMITTED 2026-07-27** (84.2/100 Pass 2; finalized 2-page resume + 1-page cover letter). Strong native-German, Staff progression, production ownership and enterprise-data-readiness case; honest gaps remain in end-to-end LLM delivery, Azure AI and strategic-account FDE experience. | Done — await response |
+205
View File
@@ -0,0 +1,205 @@
# Scout roster review — 2026-08-18
> **Status: implemented 2026-08-18.** Sections 1, 2 and 5 have been acted on; see
> "What was actually done" at the bottom, which also records two findings in this
> document that turned out to be **wrong** once the fixes were attempted.
Originally analysis only. Every claim below was verified by probing the
live endpoint; unverified candidates are listed separately as *probe-worthy*, not as recommendations.
Method: aggregated the scan-stats tables from the four most recent full runs (2026-07-14, 07-27,
08-07, 08-18), cross-referenced `state/decisions.json` (253 decisions), and live-probed candidate
ATS endpoints.
---
## 1. Three scrapers are silently broken
Same failure class as the dbt Labs 404 fixed earlier today, but worse: these return HTTP 200 and
plausible-looking rows, so the report shows "0 matches" and nothing looks wrong. **A company that
scrapes garbage is indistinguishable from a company with no openings.**
| Company | What it actually returns | Verified |
|---|---|---|
| **Roche** | Shanghai, Kyiv, Petaling Jaya, Bogota, Berlin, Mannheim, Penzberg. **Zero Swiss roles** despite Basel HQ — the `locationsearch=Switzerland` URL param is being ignored and an unfiltered default page is scraped. | live scrape, 10/10 rows non-CH |
| **Meta** | **1 row**: "Research Scientist Intern, AI/ML, Core Ads Growth (PhD)". Meta Zurich is a real engineering office. The `offices[0]=Zurich` filter or the lazy-load scroll is failing. | live scrape, 4 jobs across 4 runs |
| **Apple** | 21 rows, **all** internships, "Where we're hiring", and "US - Specialist: Seasonal, Part-time". Zero actual engineering reqs. | live scrape, all 21 rows |
**This invalidates a conclusion in the yield data.** Apple shows 21 decisions, all `skip`, 0 signal —
that reads as "Apple is a bad fit" but it is really "the scraper only ever saw the internships page."
Don't drop Apple on that evidence; fix the scrape first, then judge.
## 2. Seven boards have no title filter at all
`_title_filter` is absent on **BKW, SBB, BFH, PostFinance, Swissgrid, Novartis, Palantir**. This is
why reports drown in *Mitarbeiter/in Hausdienst*, *Financial Accountant*, *Studiengangsleiter Master
Physiotherapie*, *SAP Consultant Treasury*.
| Company | Eligible → match ≥2 (4 runs) | Reading |
|---|---|---|
| BKW | 61 / 75 scraped | 81% of the entire board "matches" |
| SBB | 27 / 27 | 100% — filter is doing nothing |
| BFH | 29 / 48 | 60% |
| Novartis | 105 eligible → 21 match | 23 skips vs 3 shortlists |
**These need a title filter, not removal.** BKW/SBB/BFH/PostFinance/Swissgrid are the Bern/Thun
WLB-exception tier where below-bar comp is deliberately accepted — the lane is intentional, the
noise is not. RUAG already carries a 29-term filter and behaves (13 eligible → 7 match); it is the
model to copy.
## 3. The yield metric in the decisions log is confounded
Raw decision counts reward boards with *no* title filter — more rows surfaced means more `skip`
rows recorded. Normalising to signal (`shortlist`+`applied`+`maybe`) per eligible role inverts the
ranking: **Snowflake** (5 decisions → 1 applied, 1 shortlist, 1 maybe off 14 eligible) is a far
better board than **Novartis** (31 decisions → 3 shortlists off 105 eligible). Worth keeping in
mind before reading the decisions log as a quality signal.
## 4. Dead lanes
- **MET Group + Louis Dreyfus: 1,464 roles scraped across 4 runs → 0 eligible, 0 matches. Ever.**
Both are title-filtered correctly; they simply have no CH/remote-CH engineering roles. LDC is
Geneva/Rotterdam-anchored (French). The commodity-trading lane is configured and producing nothing.
- **Norway (Telenor, Equinor, NATO JWC Stavanger)** — three of 34 companies on a lane your own notes
call mostly closed: comp below the 180k bar, Norwegian at A2, no clearance. Equinor just came back
rejected at 79 days. Consolidation candidate, though NATO JWC has an open application pending.
---
## 5. Verified adds — both confirmed live
### Amazon / AWS — the single biggest gap
`https://www.amazon.jobs/en/search.json?normalized_country_code[]=CHE` → clean public JSON, **32 CH roles**.
Among them, live right now:
- **Senior Forward Deployed Engineer, AWS Forward Deployed Engineering — Zurich**
- Sr. Delivery Consultant AI/ML, Professional Services — Zurich
- Sr Specialist SA GenAI, Specialists Team Germany/Switzerland — Zurich
- Senior Security Assurance Solutions Architect, AWS Security Assurance — Zurich
Why this matters more than any other candidate: **AWS is the primary cloud in the evidence base**
(SW-1 migration, the Swisscom data products). `claims.json:274` marks GCP `evidence: unverified,
output: forbidden` — which is exactly what hard-gated the two Google GenAI FDE reqs this morning.
An AWS-native FDE req in Zurich is the same lane without the cloud gap. Clears the comp bar.
No adapter work needed beyond a thin JSON fetcher.
### Axpo — the energy-trading lane, finally live
`https://careers.axpo.com/jobs.json` — Teamtailor on a custom domain. **400 roles, 98 tech-ish.**
Note the feed is JSON Feed format keyed `items`, not `jobs`, so the existing `fetch_teamtailor`
needs a small tweak (and the demo-board fingerprint guard still applies).
Live right now: **"Forward Deployed AI Engineer (f/m/d)"**, plus Senior Application Manager/Solution
Architect, Quantitative Modeller, Junior/Financial Data Analyst, Leiter/in IT Division Hydroenergie.
Memory (`user_role_targeting_energy_trading`) names Axpo and Alpiq explicitly as targets — data/
platform engineering *inside* a trading shop, not ETRM or quant. Only MET was ever configured, and
MET has produced nothing. Axpo is German-speaking (Baden/Zurich), which fits the DE/EN profile that
rules out the Geneva traders.
## 6. Verified negative — do not add
- **Coinbase proper.** Greenhouse board `coinbase` is live (169 jobs) but has exactly **2 EMEA-remote
roles, both non-engineering** (Business Controller, Threat Assessment Manager). The Ventures board
removed earlier was portfolio-only, so Coinbase was never really covered — but covering it properly
gains nothing. Crypto lane stays Kraken + Bitcoin Suisse.
- **Alpiq, Glencore, Swiss Re, Sunrise** — no SmartRecruiters, Greenhouse, Ashby or Lever board found.
Careers sites are bespoke/JS-rendered with no discoverable JSON API in a network trace. Not worth
Playwright maintenance on spec.
- **The remote-EU data-infra tier as a category** (ClickHouse, MongoDB, Redis, Temporal, Airbyte,
Starburst…). Skipping this deliberately: Grafana is already on the roster and memory flags it as
**below-bar geo-fenced comp**. These firms band EU-remote salaries the same way, so the whole tier
fails the 180k bar regardless of role fit. Elastic/Confluent/Grafana already cover the archetype.
## 7. Probe-worthy — not yet verified, do not add on my word
- **CERN** (`careers.cern/jobs`) — has dedicated "Data Science, AI & Analytics" and "Information
Technologies" fields of work. English-working international organisation in CH, i.e. the same lane
as the BIS Basel application. Needs a scrape-mechanics check. Best remaining unverified candidate.
- **Swiss Post** (`career.post.ch`) — Bern-headquartered, has an "Informatik und Digital Services"
category, fits the Bern WLB tier alongside PostFinance (already scraped, and a Swiss Post company).
My probe timed out on `networkidle`; needs a retry with a laxer wait.
- **NATO NCIA** (`ncia.nato.int/careers.html`) — the current `nato` adapter returns 4 reqs, all JWC
Stavanger. NCIA is NATO's actual technology arm (Brussels/The Hague/Mons) and is a separate
pipeline. Worth checking whether it is separately scrapable — it would be the one way to keep a
NATO lane without the Norway constraints.
- **SIX Group** — fingerprinted as SuccessFactors (`career_company=sixgroupse`). Zurich financial-
market infrastructure. Endpoint pattern is known; content unverified.
---
## Suggested order of work
1. **Fix Roche / Meta / Apple** — restores three companies that currently contribute nothing while
appearing healthy. Highest value per unit effort, and it's a correctness bug, not a preference.
2. **Add Amazon/AWS** — trivial adapter, an on-profile Zurich FDE req live today.
3. **Add Axpo** — small `fetch_teamtailor` tweak for the `items` key; opens the energy lane.
4. **Add title filters** to BKW, SBB, BFH, PostFinance, Swissgrid, Novartis, Palantir.
5. **Decide on MET/LDC and the Norway three** — a judgment call, not a bug.
6. Probe CERN, Swiss Post, NATO NCIA, SIX.
---
# What was actually done (2026-08-18)
Implementing the recommendations disproved two of them. Both corrections are recorded here
rather than quietly edited above, because the original claims were used to justify the work.
## Correction 1 — Meta is NOT broken
Section 1 listed Meta as returning garbage. It does not. `metacareers.com` itself reports
**"1 Items"** for the Zurich office filter — the board is genuinely near-empty and the scraper
reports it accurately. No change made beyond a comment recording the verification, so it is
not "fixed" again later. Roche and Apple were real bugs; Meta was not.
## Correction 2 — inclusion filters were the wrong instrument
Section 2 recommended adding `_title_filter` allowlists to seven boards. That was implemented
and then **reversed**, on the objection that an allowlist *fails closed*: a strong-fit role
with a title nobody anticipated is dropped at fetch time, never scored, and appears in no
report and no JSON dump. The final call should sit with the scorer and the reviewer, not a
keyword gate.
Filtering is now two explicit modes:
| Mode | Behaviour | Where |
|---|---|---|
| `_title_exclude` (**default**) | Fails **open** — drops only unambiguous non-tech titles (`hausdienst`, `physiotherapie`, `violine`, `lehrstelle`, `legal counsel`…). Everything else is scored. | 14 boards |
| `_title_filter` | Fails **closed** — allowlist, used only where volume makes full scoring impractical (>~200 roles) | Databricks, Snowflake, Datadog, Elastic, Fivetran, Louis Dreyfus |
`NOISE_TITLE_EXCLUDE` is one shared, board-agnostic list. Terms that could plausibly attach to
a technical role (analyst, manager, specialist, consultant, architect, lead) are deliberately
excluded from it.
Also corrected: BKW's 61/75 match rate was blamed on the missing filter. The real cause is
`_score_floor: 2`, set deliberately because the English keyword scorer cannot read German
titles. The floor was left in place.
## Fixes shipped
- **Roche** — new `fetch_phenom` adapter (Phenom `refineSearch`). Was 40 scraped / 0 Swiss;
now **133 scraped, 88 CH-eligible, 25 matches**.
- **Apple** — removed `default_location: "Switzerland"`, which was relabelling US "Various
Locations" postings as Swiss. Now honestly reports **0 CH-eligible**.
- **Amazon / AWS** — new `fetch_amazon` adapter. **32 CH roles, 29 eligible, 13 matches**,
including the Zurich AWS FDE req and a Senior ProServe Cloud Architect in **Bern**.
- **Axpo** — `fetch_teamtailor` extended for custom domains and pagination. 461 roles.
Locations now come from the feed's schema.org `jobLocation`, with ISO alpha-2 expanded to
full country names — without that, `"Burgdorf, CH"` failed the CH keyword match, and a
forced `default_location` would have marked ~380 Madrid/Milan/Warsaw roles as Swiss (the
Apple bug again). Telenor gained real locations from the same change.
- **Filter modes** as described above, plus `artificial intelligence`, `data scientist`,
`data-driven`, `ai engineer`, `ai platform`, `ai architect`, `ai-systems`, `data science`
added to the shared allowlist. Bare `"ai"` deliberately omitted — it substring-matches
*Maintenance*, *Training*, *Chair*.
- **Palantir left unfiltered** — its entry already documents why (its target titles, e.g.
"Deployment Strategist", are not in the allowlist). The original recommendation to filter it
would have hidden exactly the roles worth seeing.
## Still open (deliberately not done)
- **Section 4 judgment calls**: MET Group + Louis Dreyfus, and the three Norway companies.
These are preference decisions, not bugs.
- **Section 7 probes**: CERN, Swiss Post, NATO NCIA, SIX Group.
+314 -62
View File
@@ -138,6 +138,9 @@ NEGATIVE_KEYWORDS = {
# post mostly non-tech roles). Only keep titles containing one of these specific role
# phrases — kept tight so "Sales Engineer"/"Staff Accountant"/"Data Privacy Counsel"
# don't leak in. Matched as case-insensitive substrings against the title only.
# Inclusion allowlist. Applied ONLY to boards too large to score in full (>~200 roles:
# Databricks, Snowflake, Datadog, Elastic, Fivetran, Louis Dreyfus, Palantir). Everywhere else
# use NOISE_TITLE_EXCLUDE — see the design note there for why fail-open is the default.
ENG_TITLE_FILTER = [
"data engineer", "data engineering", "data platform", "platform engineer",
"data infrastructure", "data architect", "analytics engineer",
@@ -149,8 +152,52 @@ ENG_TITLE_FILTER = [
# "resident" alone catches Resident Solutions Architect/Engineer without opening the gate to
# all pre-sales SAs (the overscoring trap); "customer engineer" is Google's field-eng term.
"forward deployed", "forward-deployed", "field engineer", "resident", "customer engineer",
# Added 2026-08-18 after the CH boards were title-filtered: without these, real near-misses
# were dropped (BFH "Wissenschaftliche Mitarbeit Data-Driven Government", Novartis "Director
# & Group Head (AI-Systems & Scale)"). Deliberately NOT adding bare "ai" — it substring-matches
# Maintenance/Training/Chair and floods every board.
"artificial intelligence", "ai-systems", "ai platform", "ai engineer", "ai architect",
"data scientist", "data-driven", "data science",
]
# Generic non-tech title exclusions, shared by every board that uses exclusion-mode filtering.
#
# DESIGN NOTE (2026-08-18). Boards are filtered one of two ways:
# * inclusion (`_title_filter`) — an allowlist, used ONLY on boards too large to score in
# full (Databricks ~800, OpenAI ~730, Palantir ~300). It fails CLOSED: a great-fit role
# with a title nobody anticipated is dropped at fetch time and never reaches the scorer,
# so it appears in no report and in no JSON dump. That is an acceptable trade only where
# volume forces it.
# * exclusion (`_title_exclude`) — this list. It fails OPEN: everything survives unless it
# is *clearly* not an engineering role, and the score + the weak/noise bucket decide what
# surfaces. Prefer this. The final call belongs to the reviewer, not to a keyword gate.
#
# Keep these terms unambiguous. Anything that could plausibly attach to a technical role
# (analyst, manager, specialist, consultant, architect, lead) must NOT go in here.
NOISE_TITLE_EXCLUDE = [
# Facilities / retail / hospitality / admin
"hausdienst", "reinigung", "empfang", "hauswart", "chef de partie", "koch", "küche",
"restaurant", "catering", "fahrer", "logistik mitarbeiter", "lagerist", "verkauf",
"verkäufer", "retail", "barista", "security guard", "sicherheitsdienst",
# Care / health / teaching-of-non-tech
"physiotherapie", "pflege", "pflegefach", "hebamme", "ergotherapie", "psychologie",
"medical representative", "nurse", "arzt", "ärztin", "dentist",
# Arts / music / sport
"violine", "klavier", "musik", "dozierende*r violine", "sport",
# Back-office
"fundraising", "buchhaltung", "accountant", "accounting", "payroll", "steuer",
"recruiter", "talent acquisition", "human resources", "personalwesen",
"legal counsel", "rechtsanwalt", "rechtsreferendar", "notar", "jurist",
"kommunikation", "public relations", "übersetzer", "translator",
# Early-career / non-role listings
"lehrstelle", "praktikum", "praktikant", "internship", "intern ", "trainee",
"apprenti", "ausbildung", "schnupper", "where we're hiring", "talent community",
# Non-software engineering trades
"elektroplaner", "elektroinstallat", "sanitär", "heizung", "maler", "schreiner",
"hochspannung", "wasserbau", "strassenbau", "holzbau", "bauingenieur", "bauleiter",
]
# id, display, adapter, adapter_args
COMPANIES = [
("nvidia", "NVIDIA", "workday", {
@@ -167,6 +214,7 @@ COMPANIES = [
"tenant": "novartis",
"site": "Novartis_Careers",
"search_text": "Switzerland",
"_title_exclude": NOISE_TITLE_EXCLUDE,
}),
# PCSX (Eightfold) — Microsoft has a public position search endpoint
("microsoft", "Microsoft", "pcsx", {
@@ -177,22 +225,56 @@ COMPANIES = [
# Dropped: ClickHouse (Glassdoor 3.3, 36% recommend, toxic-culture flag — 2026-05).
# Dropped: HashiCorp — acquired by IBM (closed 2025); greenhouse/ashby/lever boards all 404,
# roles folded into IBM's careers (no clean public ATS API). 2026-06-06.
("confluent", "Confluent", "ashby", {"slug": "confluent", "_title_filter": ENG_TITLE_FILTER}),
("gitlab", "GitLab", "greenhouse", {"board": "gitlab", "_title_filter": ENG_TITLE_FILTER}),
("grafana", "Grafana Labs","greenhouse",{"board": "grafanalabs", "_title_filter": ENG_TITLE_FILTER}),
("confluent", "Confluent", "ashby", {"slug": "confluent", "_title_exclude": NOISE_TITLE_EXCLUDE}),
("gitlab", "GitLab", "greenhouse", {"board": "gitlab", "_title_exclude": NOISE_TITLE_EXCLUDE}),
("grafana", "Grafana Labs","greenhouse",{"board": "grafanalabs", "_title_exclude": NOISE_TITLE_EXCLUDE}),
# Added 2026-06-06 (Tier A/B data-infra). Databricks/Snowflake/Datadog have Zürich offices
# (Swiss-scale comp, clears bar); Elastic/dbt Labs are remote-EU (verify CH-equiv comp —
# (Swiss-scale comp, clears bar); Elastic/Fivetran are remote-EU (verify CH-equiv comp —
# may be geo-banded below 180k, like Grafana). All title-filtered (boards are 160-760 roles).
("databricks","Databricks","greenhouse", {"board": "databricks", "_title_filter": ENG_TITLE_FILTER}), # Zürich SWE + remote-EU; DK via default location policy
("snowflake", "Snowflake", "ashby", {"slug": "snowflake", "_title_filter": ENG_TITLE_FILTER}), # Zürich "Observe" observability SWE roles
("datadog", "Datadog", "greenhouse", {"board": "datadog", "_title_filter": ENG_TITLE_FILTER}), # Zürich branch + remote-EU
("elastic", "Elastic", "greenhouse", {"board": "elastic", "_title_filter": ENG_TITLE_FILTER}), # remote-first; ELK = his stack
("dbtlabs", "dbt Labs", "greenhouse", {"board": "dbtlabsinc", "_title_filter": ENG_TITLE_FILTER}), # remote-EU; analytics-eng
# dbt Labs -> Fivetran: the "dbtlabsinc" board 404'd from 2026-08-18. getdbt.com/careers now
# redirects to a page serving Fivetran's Greenhouse listings (gh_jid links) — the two merged, so
# the dbt roles live on board "fivetran". EMEA presence is Dublin/London/Serbia, no CH office, so
# most roles fall out on the location policy; kept for remote-EU analytics-eng reqs. 2026-08-18.
("fivetran", "Fivetran (ex-dbt Labs)", "greenhouse", {"board": "fivetran", "_title_filter": ENG_TITLE_FILTER}),
# --- Energy / commodity trading (SmartRecruiters; title-filtered to tech roles) ---
# Dropped: Vitol (Glassdoor 3.5, 55% recommend, grueling-hours/toxic flag — 2026-05).
# Dropped: Sygnum (Glassdoor 3.4, 51% recommend, comp 2.3/5 — below 180k bar — 2026-05).
("metgroup", "MET Group", "smartrecruiters", {"company": "METGroup", "_title_filter": ENG_TITLE_FILTER}),
("ldc", "Louis Dreyfus","smartrecruiters",{"company": "LouisDreyfusCompany", "_title_filter": ENG_TITLE_FILTER}),
# Axpo (Baden/Zurich) — Teamtailor on a custom domain; no <slug>.teamtailor.com host
# resolves, so this uses base_url. Added 2026-08-18: memory names Axpo/Alpiq as the
# energy-trading targets but only MET was ever configured, and MET+LDC have produced
# 0 CH-eligible roles across 1,464 scrapes. ~400 roles, German-speaking region (which is
# what rules out the Geneva traders), incl. a "Forward Deployed AI Engineer" at add time.
("axpo", "Axpo", "teamtailor", {
"base_url": "https://careers.axpo.com",
"default_location": "Switzerland",
"_title_exclude": NOISE_TITLE_EXCLUDE,
}),
# CERN (Geneva) — probed 2026-08-18: SmartRecruiters board "CERN", 66 live postings, all
# Geneva. Real engineering exists (Deep Learning Developer, ML Engineer for Next Generation
# Triggers, Full-stack SWE, Data Storage R&D Engineer, Software Engineer) and it is an
# English-working international organisation in CH — the BIS Basel lane.
# TWO STANDING CAVEATS, do not forget them when scoring a CERN role:
# 1. Geneva is ~1h50 each way from Bern — not viable for a 2-3 day hybrid without
# relocation, which the user has ruled out. Practical constraints will score low.
# 2. CERN pay grades sit below the CHF 180k bar.
# Added anyway because the adapter is free (already implemented) and a fully-remote or
# exceptional CERN req would otherwise never surface.
("cern", "CERN (Geneva)", "smartrecruiters", {
"company": "CERN",
"_title_exclude": NOISE_TITLE_EXCLUDE,
}),
("metgroup", "MET Group", "smartrecruiters", {"company": "METGroup", "_title_exclude": NOISE_TITLE_EXCLUDE}),
# Dropped: Louis Dreyfus — 2026-08-18. 300 roles, every one Brazil/India/Bulgaria/Asia
# operations (its Data Modeler reqs are in Bangalore). Geneva HQ but zero Swiss
# postings in any run. MET Group is retained by contrast: once exclusion-mode
# filtering replaced the allowlist, MET showed real Baar/Zug roles (Wholesale
# Specialist, Lead Trade Process Analyst, LNG Financial Trader) — its earlier
# "0 eligible across 1,464 scrapes" was a filter artifact, not an empty board.
# No data/platform eng reqs there yet, but it is the live CH commodity-trading lane.
# Equinor (Workday) — Norway energy major; lived/worked in NO before. Outlier location
# policy: Norway only (not CH / Europe-remote). Small board (~15); no title filter.
("equinor", "Equinor", "workday", {
@@ -240,19 +322,12 @@ COMPANIES = [
"url": "https://www.bis.org/doclist/vacancies.rss",
"default_location": "Basel, Switzerland",
}),
# Coinbase Ventures web3 talent network (Getro collection 1625). Aggregates roles
# across portfolio companies (Notion, Ashby, VALR, World, ...), NOT Coinbase itself —
# see fetch_getro. CH-filtered + eng title-filtered to stay relevant.
("coinbase_ventures", "Coinbase Ventures (web3)", "getro", {
"collection": 1625,
"locations": ["Switzerland"],
"job_functions": ["Software Engineering", "IT", "Data Science"],
# User preference 2026-07-28: recruiting-software domain is not a target.
# Exclude the underlying employer here without hiding unrelated companies
# carried by the Coinbase Ventures portfolio board.
"_exclude_orgs": ["Ashby"],
"_title_filter": ENG_TITLE_FILTER,
}),
# Dropped: Coinbase Ventures web3 talent network (Getro collection 1625) — 2026-08-18.
# Never carried Coinbase's own roles, only portfolio companies. Across ~3 months
# it surfaced 3 distinct CH-eligible roles, ALL from Ashby (recruiting software,
# ruled out 2026-07-28) and all decided "skip". With Ashby excluded the board has
# returned 0 jobs on every run since, reported as a false error each time.
# fetch_getro is retained for a future VC talent network worth tracking.
# Bitcoin Suisse (Zug) uses the onlyfy.jobs ATS. No title filter — small crypto
# firm, only a handful of CH roles; let scoring rank them (CH filter does the rest).
("bitcoin_suisse", "Bitcoin Suisse", "onlyfy", {"slug": "bitcoin-suisse"}),
@@ -280,6 +355,20 @@ COMPANIES = [
"page_param_start": 2,
"max_pages": 6,
}),
# Amazon + AWS share one board. Added 2026-08-18: AWS is the cloud the evidence base
# actually supports (Swisscom migration + data products), whereas claims.json marks GCP
# output-forbidden — so an AWS-native Zurich FDE req is the Google FDE lane without the
# cloud gap. 32 CH roles at time of adding, incl. "Senior Forward Deployed Engineer, AWS
# Forward Deployed Engineering" (Zurich).
# AWS names its delivery/field org differently from every other board, so the shared
# filter caught only 1 of 32 CH roles. These four terms are added narrowly and ONLY here:
# "solutions architect" is the classic overscoring trap (see job_scout_overscoring_findings),
# but on the AWS board it is the delivery-side title attached to migration/data work, which
# is exactly SW-1. Read the JD before trusting the score on any of these.
("amazon", "Amazon / AWS", "amazon", {
"countries": ["CHE"],
"_title_exclude": NOISE_TITLE_EXCLUDE,
}),
("apple", "Apple", "playwright", {
"url": "https://jobs.apple.com/en-us/search?location=switzerland-CHE",
"wait_for": "a[href*='/en-us/details/']",
@@ -287,9 +376,19 @@ COMPANIES = [
"title_attr": "text",
"link_attr": "href",
"url_prefix": "https://jobs.apple.com",
"default_location": "Switzerland",
# NO default_location. Apple's own postLocation-CHE filter leaks global reqs whose
# postLocationId is postLocation-USA ("Various Locations within United States"), and
# a forced "Switzerland" default relabelled every one of them as CH-eligible — 84
# phantom CH rows over 4 runs, all internships/retail, which then read as "Apple is a
# bad fit" in the decision log. Read the real location off the card instead; when
# Apple has no Swiss reqs the honest answer is 0. Verified 2026-08-18.
"use_inner_text_as_blob": True,
"scroll_count": 5,
}),
# Meta job links are /profile/job_details/<id>; title + location are in the link text.
# NOT broken despite returning ~1 role: verified 2026-08-18 that metacareers itself
# reports "1 Items" for the Zurich office filter. The board is genuinely near-empty;
# don't "fix" this scraper without first checking the live item count on the page.
("meta", "Meta", "playwright", {
"url": "https://www.metacareers.com/jobs?offices[0]=Zurich%2C%20Switzerland",
"wait_for": "a[href*='/profile/job_details/']",
@@ -301,22 +400,18 @@ COMPANIES = [
"scroll_count": 5,
"use_inner_text_as_blob": True,
}),
# PhenomPeople pattern (Roche) uses li.jobs-list-item.
# Card inner text is structured like: "<title> | Location | <city, country> | Category | ..."
# We extract title from first line, full text becomes the "description" so our location
# filter still sees Switzerland mentions.
("roche", "Roche", "playwright", {
"url": "https://careers.roche.com/global/en/search-results?keywords=&locationsearch=Switzerland",
"wait_for": "li.jobs-list-item, a.au-target",
"card": "li.jobs-list-item:not(:has-text('Saved jobs'))",
"title_attr": "text",
"link_sel": "a[href]",
"link_attr": "href",
"url_prefix": "https://careers.roche.com",
"default_location": "",
"cookie_accept": ["#onetrust-accept-btn-handler", "button:has-text('Accept All Cookies')"],
"scroll_count": 6,
"use_inner_text_as_blob": True,
# Roche: was a playwright scrape of the search-results page until 2026-08-18. That page's
# ?locationsearch=Switzerland filter silently fails — the page state reports "no-results"
# and the scrape harvested *recommendation-widget* cards instead, returning Shanghai,
# Kyiv, Bogota and Mannheim and zero Swiss roles for months while looking healthy. The
# underlying Phenom refineSearch endpoint filters correctly (134 CH roles), so hit it
# directly. Title-filtered: Roche CH is overwhelmingly lab/pharma/apprenticeship reqs.
("roche", "Roche", "phenom", {
"url": "https://careers.roche.com/widgets",
"ref_num": "ROCHGLOBAL",
"page_id": "page11-ds",
"country_facet": "Switzerland",
"_title_exclude": NOISE_TITLE_EXCLUDE,
}),
# Cisco (PhenomPeople, new careers.cisco.com domain). Keyword search surfaces CH roles.
("cisco", "Cisco", "playwright", {
@@ -356,6 +451,7 @@ COMPANIES = [
"field_url": "descriptionUrl", "field_date": "onlineSince",
"loc_suffix": " Switzerland",
"desc_keys": ["department", "typeOfEmployment", "entryLevel"],
"_title_exclude": NOISE_TITLE_EXCLUDE,
}),
# RUAG (Thun/Bern/Emmen). Jobs render on the portal as anchors to jobs.ruag.ch; the first
# line of each anchor is the title. All sites are Swiss, so default_location=Switzerland
@@ -373,7 +469,7 @@ COMPANIES = [
"scroll_count": 1,
"page_param": "page",
"max_pages": 10,
"_title_filter": ENG_TITLE_FILTER,
"_title_exclude": NOISE_TITLE_EXCLUDE,
}),
# SBB (company.sbb.ch — the correct host; company-jobs.sbb.ch was wrong). AEM job filter
# served as a flat JSON list; the fetch_sbb adapter replicates the user's IT + Bern-region
@@ -383,12 +479,14 @@ COMPANIES = [
"topic": "IT / Telekommunikation",
"region": "Bern Mittelland",
"_score_floor": 2,
"_title_exclude": NOISE_TITLE_EXCLUDE,
}),
# BKW Group (jobs.bkw.com — the real ATS host). PMS structured-data API; ~600 roles
# group-wide, so fetch_bkw keeps only Berufsfeld categories Informatik/Trading/Finanzen
# (IT/data + energy-trading, incl. the flagged Energiehandel roles). German/generic
# titles, so _score_floor keeps the pre-filtered set visible.
("bkw", "BKW (Bern)", "bkw", {"_score_floor": 2}),
("bkw", "BKW (Bern)", "bkw", {"_score_floor": 2,
"_title_exclude": NOISE_TITLE_EXCLUDE}),
# PostFinance (Bern). The careers site renders a small, client-side paginated board;
# scrape all pages through its stable next-page control. No title filter: the board is
# low-volume, and the scorer keeps unrelated banking/customer-service roles out of the
@@ -403,6 +501,7 @@ COMPANIES = [
"use_inner_text_as_blob": True,
"next_button": "#pfch-pagination-next",
"max_pages": 10,
"_title_exclude": NOISE_TITLE_EXCLUDE,
}),
# BFH (Bern University of Applied Sciences). Re-added 2026-07-14: the jobs.bfh.ch domain
# itself is a broken/stub SPA shell (renders "Career Center project template", nothing
@@ -422,6 +521,7 @@ COMPANIES = [
"link_sel": "a",
"default_location": "Switzerland",
"_score_floor": 2,
"_title_exclude": NOISE_TITLE_EXCLUDE,
}),
]
@@ -439,6 +539,12 @@ MANUAL_CHECK = [
# (then client-filter requisitionList[].PrimaryLocation for Switzerland/Zürich)
("Oracle", "ORC SPA resists scraping; REST endpoint known but needs CH geographyId (see code comment). Check Switzerland tech roles manually.",
"https://careers.oracle.com/en/sites/jobsearch/jobs?location=Switzerland"),
# NATO NCIA (Brussels/The Hague/Mons) — probed 2026-08-18. NCIA is NATO's technology arm and
# a SEPARATE pipeline from the `nato` adapter above, which only returns JWC Stavanger reqs
# (Taleo). nato.int sits behind Cloudflare and returns "Sorry, you have been blocked" to a
# headless browser, so there is no automated path. Manual only.
("NATO NCIA", "Cloudflare-blocked to headless browsers. NCIA is the tech arm and is separate from the JWC Stavanger reqs the `nato` adapter returns — check it manually for AI/data roles.",
"https://www.ncia.nato.int/careers.html"),
]
@@ -647,34 +753,80 @@ def fetch_rss(args):
return jobs
# schema.org JobPosting addresses carry ISO alpha-2 country codes; the location policy
# keyword lists are full names. Only the countries the policies actually test for.
_ISO2_COUNTRY = {
"CH": "Switzerland", "NO": "Norway", "DK": "Denmark", "DE": "Germany",
"AT": "Austria", "FR": "France", "IT": "Italy", "ES": "Spain", "PL": "Poland",
"NL": "Netherlands", "BE": "Belgium", "SE": "Sweden", "FI": "Finland",
"GB": "United Kingdom", "UK": "United Kingdom", "IE": "Ireland", "US": "United States",
"PT": "Portugal", "CZ": "Czechia", "RO": "Romania", "RS": "Serbia", "TR": "Turkey",
}
def fetch_teamtailor(args):
"""Teamtailor public JSON Feed (`https://<slug>.teamtailor.com/jobs.json`).
Used by Telenor. The public /jobs HTML page paginates and under-reports; the feed
returns the full board in one call, so prefer it. The feed carries no location
field, so default_location is required (Teamtailor boards are per-country anyway).
Used by Telenor (`slug`) and Axpo (`base_url`, a Teamtailor board on a custom domain —
careers.axpo.com — which no <slug>.teamtailor.com host resolves to). The public /jobs
HTML page paginates and under-reports; the feed is authoritative. The feed carries no
location field, so default_location is required (Teamtailor boards are per-country).
Descriptions are frequently Norwegian — see the _score_floor note on the company.
The feed caps at 100 items and links the next page via `next_url`; follow it, or large
boards silently truncate (Axpo is ~400 roles, i.e. 4 pages).
TRAP: an unclaimed slug returns Teamtailor's *demo* board (HTTP 200, plausible JSON)
instead of 404. Verified 2026-07-29: `ksat` and `akerbp` both served the seed set
below though neither company uses Teamtailor. Filtered here so phantom roles never
reach a report — if a real board is ever dropped by this, widen the fingerprint."""
DEMO_TITLES = {"sales development manager", "team lead - csm", "social media manager",
"customer success manager", "key account manager", "ux designer"}
url = f"https://{args['slug']}.teamtailor.com/jobs.json"
req = urllib.request.Request(url, headers={"User-Agent": USER_AGENT, "Accept": "application/json"})
with urllib.request.urlopen(req, timeout=30, context=_ssl_context()) as resp:
data = json.loads(resp.read().decode("utf-8", "replace"))
if args.get("base_url"):
url = args["base_url"].rstrip("/") + "/jobs.json"
else:
url = f"https://{args['slug']}.teamtailor.com/jobs.json"
jobs = []
for it in data.get("items", []):
jobs.append({
"id": it.get("id") or it.get("url", ""),
"title": it.get("title", ""),
"location": args.get("default_location", ""),
"url": it.get("url", ""),
"posted": it.get("date_published", ""),
"description": re.sub(r"<[^>]+>", " ", it.get("content_html", ""))[:2500],
})
for _ in range(args.get("max_pages", 10)):
req = urllib.request.Request(
url, headers={"User-Agent": USER_AGENT, "Accept": "application/json"})
with urllib.request.urlopen(req, timeout=30, context=_ssl_context()) as resp:
data = json.loads(resp.read().decode("utf-8", "replace"))
items = data.get("items", []) or []
for it in items:
# Prefer the schema.org JobPosting payload's real address over default_location.
# Axpo is a pan-European trader (Madrid, Milan, Warsaw, Germany, France as well as
# Baden/Zurich), so defaulting every role to the board's home country would mark
# ~380 non-Swiss roles CH-eligible — the same class of bug as Apple's forced
# "Switzerland" default. Telenor's feed has no _jobposting and falls back cleanly.
location = args.get("default_location", "")
places = ((it.get("_jobposting") or {}).get("jobLocation") or [])
if isinstance(places, dict):
places = [places]
parts = []
for place in places:
addr = (place or {}).get("address") or {}
# schema.org gives ISO alpha-2 ("CH", "NO"); the location policy matches on
# full country names, so expand or the role reads as location-unknown.
country = _ISO2_COUNTRY.get((addr.get("addressCountry") or "").upper(),
addr.get("addressCountry"))
bit = ", ".join(x for x in (addr.get("addressLocality"), country) if x)
if bit and bit not in parts:
parts.append(bit)
if parts:
location = " | ".join(parts)
jobs.append({
"id": it.get("id") or it.get("url", ""),
"title": it.get("title", ""),
"location": location,
"url": it.get("url", ""),
"posted": it.get("date_published", ""),
"description": re.sub(r"<[^>]+>", " ", it.get("content_html", ""))[:2500],
})
nxt = data.get("next_url")
if not items or not nxt or nxt == url:
break
url = nxt
titles = {j["title"].strip().lower() for j in jobs}
if jobs and len(titles & DEMO_TITLES) >= 4:
raise RuntimeError(
@@ -685,9 +837,10 @@ def fetch_teamtailor(args):
def fetch_getro(args):
"""Getro network job-board search API (POST JSON). Powers VC portfolio talent
networks — here the Coinbase Ventures web3 network (collection 1625). Returns roles
across ALL portfolio companies (Notion, Ashby, VALR, World, ...), NOT Coinbase itself;
Coinbase doesn't list its own openings on its Ventures board. Server-side filters:
networks. NO company in COMPANIES currently uses this adapter — the Coinbase Ventures
network was dropped 2026-08-18 (see the note there). Kept because it generalises to any
Getro collection id. Note such boards list PORTFOLIO companies' roles, never the VC's
own openings, so an org filter is usually needed. Server-side filters:
searchable_locations and job_functions. Org name is folded into the title since this
is a multi-company board."""
collection = args["collection"]
@@ -731,6 +884,94 @@ def fetch_getro(args):
return jobs
def fetch_amazon(args):
"""amazon.jobs public search JSON. Covers Amazon + AWS, which share one board.
`normalized_country_code[]` is the filter that actually works; the plain `country[]`
and `loc_query` params are ignored and silently return the global (US-heavy) set —
verified 2026-08-18, where `country[]=CHE` returned 6,837 mostly-Seattle hits against
32 for the normalized form."""
base = "https://www.amazon.jobs/en/search.json"
headers = {"User-Agent": ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")}
jobs, offset, page_size = [], 0, 100
while True:
qs = urllib.parse.urlencode({
"radius": "100mi", "offset": offset, "result_limit": page_size,
"sort": "recent", "base_query": args.get("base_query", ""),
})
countries = "".join(f"&normalized_country_code[]={urllib.parse.quote(c)}"
for c in args.get("countries", ["CHE"]))
data = http_get_json(f"{base}?{qs}{countries}", headers=headers)
batch = data.get("jobs", []) or []
for j in batch:
jobs.append({
"id": str(j.get("id_icims") or j.get("id") or ""),
"title": j.get("title", ""),
"location": j.get("normalized_location") or j.get("location") or "",
"url": "https://www.amazon.jobs" + (j.get("job_path") or ""),
"posted": j.get("posted_date", ""),
"description": (j.get("description_short") or j.get("description") or "")[:2000],
})
total = data.get("hits", 0)
offset += page_size
if not batch or offset >= total or offset >= args.get("max_results", 500):
break
return jobs
def fetch_phenom(args):
"""Phenom People careers search (POST /widgets with ddoKey=refineSearch). Used by Roche.
The public search-results page is a JS shell whose location filter silently fails: a
scrape of `?locationsearch=Switzerland` returns *recommendation-widget* cards (Shanghai,
Kyiv, Bogota) while the page state reports `no-results`. Verified 2026-08-18 — this is
why Roche contributed 0 Swiss roles for months while looking healthy. The underlying
refineSearch endpoint filters correctly (134 CH roles), so query it directly.
`country_facet` is the value for the `country` facet (e.g. "Switzerland"). `ref_num` and
`page_id` are tenant constants visible in any /widgets POST from the careers site."""
url = args["url"]
ref_num, page_id = args["ref_num"], args.get("page_id", "page11-ds")
lang = args.get("lang", "en_global")
page_size = args.get("page_size", 100)
headers = {
"Origin": "{0.scheme}://{0.netloc}".format(urllib.parse.urlsplit(url)),
"Referer": url,
# Phenom 403s the default library UA.
"User-Agent": ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"),
}
jobs, offset = [], 0
while True:
data = http_get_json(url, method="POST", headers=headers, data={
"lang": lang, "deviceType": "desktop", "country": "global",
"pageName": "search-results", "ddoKey": "refineSearch",
"sortBy": "", "subsearch": "", "from": offset, "jobs": True, "counts": True,
"all_fields": ["country", "state", "city", "category", "type"],
"size": page_size, "clearAll": False, "jdsource": "facets",
"isSliderEnable": False, "pageId": page_id, "siteType": "external",
"keywords": "", "global": True, "locationData": {},
"selected_fields": {"country": [args["country_facet"]]},
})
res = data.get("refineSearch", {}) or {}
batch = (res.get("data", {}) or {}).get("jobs", []) or []
for j in batch:
jobs.append({
"id": str(j.get("jobId") or j.get("jobSeqNo") or ""),
"title": j.get("title", ""),
"location": j.get("location") or j.get("cityStateCountry") or "",
"url": j.get("applyUrl", ""),
"posted": (j.get("postedDate") or "")[:10],
"description": (j.get("descriptionTeaser") or "")[:2000],
})
total = res.get("totalHits", 0)
offset += page_size
if not batch or offset >= total or offset >= args.get("max_results", 600):
break
return jobs
def fetch_onlyfy(args):
"""onlyfy.jobs board (XING E-Recruiting / ex-Prinzip), used by Bitcoin Suisse. The
candidate/job/ajax_list endpoint returns an HTML fragment listing every posting; each
@@ -1315,6 +1556,8 @@ ADAPTERS = {
"rss": fetch_rss,
"teamtailor": fetch_teamtailor,
"getro": fetch_getro,
"amazon": fetch_amazon,
"phenom": fetch_phenom,
"onlyfy": fetch_onlyfy,
"lever": fetch_lever,
"taleo": fetch_taleo,
@@ -1613,10 +1856,16 @@ def _process_company(cid, display, args, jobs, seen, today, last_scrape):
"0 jobs returned (verify board slug/selectors if this is unexpected)",
))
# Inclusion allowlist (fails closed — only for boards too large to score in full).
title_filter = args.get("_title_filter")
if title_filter:
jobs = [j for j in jobs
if any(_kw_in(k, (j.get("title") or "").lower()) for k in title_filter)]
# Exclusion denylist (fails open — preferred; see NOISE_TITLE_EXCLUDE).
title_exclude = args.get("_title_exclude")
if title_exclude:
jobs = [j for j in jobs
if not any(_kw_in(k, (j.get("title") or "").lower()) for k in title_exclude)]
dates = [d for j in jobs if (d := _parse_posted(j.get("posted")))]
newest = max(dates) if dates else None
@@ -1826,18 +2075,21 @@ def main():
# Automated (COMPANIES above):
# workday nvidia, novartis, equinor (norway_only)
# ashby kraken, openai, confluent, snowflake
# greenhouse anthropic, gitlab, grafana, databricks, datadog, elastic, dbtlabs
# greenhouse anthropic, gitlab, grafana, databricks, datadog, elastic, fivetran
# pcsx microsoft
# smartrecruiters metgroup, ldc
# smartrecruiters metgroup, cern
# rss bis
# getro coinbase_ventures
# amazon amazon (Amazon + AWS share one board)
# phenom roche (Cisco still uses the playwright path)
# teamtailor telenor, axpo (custom domain via base_url)
# getro (no company configured — adapter kept for future VC talent networks)
# onlyfy bitcoin_suisse
# lever palantir, quantco
# taleo nato (dk_no; nato.taleo.net §2 — marketing page is nato.int/vacancies)
# json swissgrid
# sbb sbb
# bkw bkw
# playwright google, apple, meta, roche, cisco, ruag, postfinance, bfh
# playwright google, apple, meta, cisco, ruag, postfinance, bfh
#
# MANUAL_CHECK: Oracle (ORC needs CH geographyId).
# ==============================================================================
+31 -3
View File
@@ -163,9 +163,9 @@
"https://job-boards.greenhouse.io/gitlab/jobs/8522408002": {
"company": "GitLab",
"title": "Forward Deployed Engineer - Germany (Staff)",
"decision": "shortlist",
"note": "Remote-CH eligible Staff FDE (Duo Agent Platform adoption, regulated/self-managed envs). CAUTION: JD body says 'strategic accounts in the APJ region' despite Germany title — clarify region/timezone with recruiter before tailoring. Gaps: Ruby/Go ideal, Terraform/Ansible/Helm expected (Kraken-style honest gap), GitLab-internals depth. Travel up to 50%.",
"date": "2026-07-03"
"decision": "skip",
"note": "HARD GATE FAIL: 'Strong Ruby on Rails or Go experience and the ability to contribute directly to GitLab product code.' Stack is Python/Java. JD explicitly states this is NOT a generic field-engineering role - it is a product-codebase contributor role. Terraform also listed (known honest gap).",
"date": "2026-08-18"
},
"https://www.google.com/about/careers/applications/jobs/results/135155660865053382-staff-research-generative-ai-cloud-ai-research-coscientist?location=Switzerland": {
"company": "Google",
@@ -1767,5 +1767,33 @@
"decision": "skip",
"note": "CLOSED - req taken down. Live Playwright scrape 2026-08-11 returns 'Job not found. This job may have been taken down.'; also absent from the current Google Zurich board listing (32 rows). Never applied.",
"date": "2026-08-11"
},
"https://www.amazon.jobs/en/jobs/10504263/senior-forward-deployed-engineer-aws-forward-deployed-engineering": {
"company": "",
"title": "",
"decision": "skip",
"note": "Phase 0 done, then NO-GO 2026-08-18. Evidence Fit 69/100. Minimum quals all Direct, but customer embedding is title-defining and globally forbidden in claims.json; multi-agent/retrieval is a second Gap. User bar: not worth a package below ~75. Do not re-surface this req.",
"date": "2026-08-18"
},
"https://www.amazon.jobs/en/jobs/10450340/senior-proserve-cloud-architect-healthcare-and-life-sciences-hcls-awsi-sales": {
"company": "",
"title": "",
"decision": "skip",
"note": "Bern location is attractive but the domain gate is clinical pharma: CDISC SDTM/ADaM, eCTD, GxP, CTMS, EDC, regulatory submissions. No evidence in any of that. Location alone does not carry it.",
"date": "2026-08-18"
},
"https://www.amazon.jobs/en/jobs/10478293/principal-delivery-consultant-technical-lead-genai-ml-data-science-professional-servic": {
"company": "",
"title": "",
"decision": "skip",
"note": "Scored highest (7) but that is the SA/architect overscoring trap. Basic quals require 8+ yrs enterprise architecture delivery INCLUDING 5+ yrs leading technical teams governing architecture on transformation programmes, plus VP+ executive communication. Level, people-leadership and exec-facing gaps compound; preferred quals add HCLS pharma + vector DB/RAG.",
"date": "2026-08-18"
},
"https://jobs.careers.microsoft.com/global/en/job/200044133": {
"company": "",
"title": "",
"decision": "skip",
"note": "MISLABELLED REQ. Title says Principal Forward Deployed Engineer - Data Scientist - German Speaking, but required quals are network engineering: BGP, MPLS, SD-WAN, IPv4/IPv6, Palo Alto firewalls, Azure Virtual WAN, DNS/DHCP, load balancers, IDS/IPS, Zero Trust. This is a network security/infra role. Complete mismatch - do not trust the title on Microsoft FDE siblings.",
"date": "2026-08-18"
}
}
@@ -0,0 +1,80 @@
Skip to main content
Amazon Jobs home page
My career
Senior Forward Deployed Engineer, AWS Forward Deployed Engineering
Job ID: 10504263 | AWS EMEA SARL (Switzerland Branch)
Apply now
Description
AWS has formed a new Forward Deployed Engineer (FDE) team dedicated to embedding AI Engineers and Scientists directly inside strategic enterprise customer environments to help design, build, and deploy AI-powered production systems. We dont build from a distance—we sit with customers, work in their infrastructure, and deliver production-grade AI solutions that transform how they operate. This initiative is scaling rapidly.
The Senior Forward Deployed Engineer (FDE) embeds directly inside a strategic enterprise customer to design, build, deploy, and run AI-powered production systems alongside the customer's engineering team. Senior FDEs write production-grade software and own outcomes end-to-end, from prototype through enterprise-scale deployment combining the technical rigor of an AWS SDE with the urgency and ownership required to deliver measurable customer business outcomes. They create reusable architectures, patterns, and engineering mechanisms that scale the entire FDE practice.
Key job responsibilities
• Embed within customer engineering teams. Understand the customer's business processes, technical architecture, and operational constraints. Translate ambiguous business problems into scalable AI-enabled production systems. Requires up to 30 50% travel.
• Build production AI applications. Design and develop production-grade software powering AI and agentic workflows — orchestration layers for multi-agent systems, retrieval pipelines, workflow automation, decision intelligence. Integrate foundation models, customer data sources, APIs, and existing applications into cohesive AI experiences. Optimize for latency, reliability, observability, cost, and security.
• Own production. Take systems from design through production rollout and operationalization. Troubleshoot production incidents across AI models, distributed systems, data pipelines, and application services. Put in place monitoring, evaluations, guardrails, and the operational mechanisms (testing, CI/CD, rollback, resiliency) that keep AI systems healthy at scale.
• Accelerate customer transformation. Identify opportunities to expand AI adoption across customer workflows. Codify reusable patterns, accelerators, and reference architectures that benefit future customers and feed back into AWS.
• Build and maintain internal AI tools and customer-facing assets and AI-enbled products to accelerate and scale the FDE motion.
• Route field signal into the closed-loop product feedback mechanism such as filing PFRs, escalating deployment-critical gaps, and feeding delivery learnings that become the next AWS primitives (as we already do with AWS Transform and Kiro).
• Raise the bar. Mentor engineers. Contribute to AWS engineering best practices for AI and forward deployment.
Basic Qualifications
- - 5+ years of non-internship professional software development experience
- - 5+ years of programming with at least one software programming language experience
- - 5+ years of leading design or architecture (design patterns, reliability and scaling) of new and existing systems experience
- - Experience as a mentor, tech lead or leading an engineering team
Preferred Qualifications
- Bachelor's degree in computer science or equivalent
- 5+ years of full software development life cycle, including coding standards, code reviews, source control management, build processes, testing, and operations experience
- Experience building production AI or ML applications, including agentic workflows
- Strong written and verbal communication skills; comfort working in customer-facing environments
Amazon is an equal opportunities employer. We believe passionately that employing a diverse workforce is central to our success. We make recruiting decisions based on your experience and skills. We value your passion to discover, invent, simplify and build. Protecting your privacy and the security of your data is a longstanding top priority for Amazon. Please consult our Privacy Notice (https://www.amazon.jobs/en/privacy_page) to know more about how we collect, use and transfer the personal data of our candidates.
Our inclusive culture empowers Amazonians to deliver the best results for our customers. If you have a disability and need a workplace accommodation or adjustment during the application and hiring process, including support for the interview or onboarding process, please visit https://amazon.jobs/content/en/how-we-hire/accommodations for more information. If the country/region youre applying in isnt listed, please contact your Recruiting Partner.
Job details
CHE, ZH, Zurich
Software Development
Share this job
JOIN US ON
DOWNLOAD OUR APP
Find Careers
Job Categories
Teams
Locations
Military careers
Hourly
Working At Amazon
Culture
Benefits
Amazon Newsletter
Inclusive experiences
Leadership Principles
Help
FAQ
How We Hire
Application status
Accommodations
Legal disclosures and notices
English
Amazon is an equal opportunity employer and does not discriminate on the basis of protected veteran status, disability, or other legally protected status.
Privacy and Data
Impressum
Cookies
© 1996-2026, Amazon.com, Inc. or its affiliates
Notice of Right to Opt-Out Sharing
We use cookies and similar tools to provide and improve our site and your candidate experience. We also use operational cookies to make our site work. If you agree, we will set certain analytics cookies to help us improve our website as explained in our cookies notice, as well as set advertising cookies to display ads. Advertising cookies includes first and third-party cookies, which store or access standard device information such as a unique identifier. Third-parties use cookies to serve you with relevant advertisements and job recommendations based on your interactions with Amazon.Jobs and third-party sites. We will only set analytics or advertising cookies if you accept them. Select “Accept all” to consent or “Customize cookies” to make more detailed choices and learn more.
For more information about how we use cookies and information we collect, please navigate to your countrys cookie notice (if applicable) via our Privacy Notice and Data Policy page.
Accept all
Continue without accepting
Customize cookies
@@ -0,0 +1,133 @@
# Session: Amazon Web Services (AWS EMEA SARL, Switzerland Branch) — Senior Forward Deployed Engineer, AWS Forward Deployed Engineering
## JD Integrity
- File/source: `output/AWS_Senior_FDE_Zurich/JD_aws_senior_fde_zurich.txt` — amazon.jobs job ID **10504263**, `https://www.amazon.jobs/en/jobs/10504263`
- Retrieval method and date: Playwright headless scrape via `job_scout/.venv`, **2026-08-18**. The `amazon.jobs/*.json` endpoint returns HTTP 406, so the rendered page body was captured.
- Verbatim posting: **YES** — full visible posting body, not reconstructed.
- Posting status: **LIVE**, posted **2026-08-17** (one day before retrieval). Legal entity AWS EMEA SARL (Switzerland Branch), Zürich.
## Application Decision
- Audience profile: **International Tech** (US-tech conventions, role in Europe — config.md default)
- Evidence Fit: **69/100**
- Fit class: **Adjacent** (6074)
- Hard gate: **PASS on minimum qualifications — but see the title-defining caveat below.** All four Basic Qualifications are Direct. No minimum qualification is a Gap.
- Channel Strength: **Weak** (cold application; no AWS contact recorded)
- Channel plan: Cold today. AWS Zurich + a brand-new org announced 2026-06-30 means recruiters are actively sourcing — a targeted note to the FDE recruiter is the highest-value warm action available.
- Cohort slot: Core 1/7, **Adjacent 1/2 → this would take the last Adjacent slot (2/2)**, Stretch 0/1
- Decision: **NO-GO — CLOSED 2026-08-18, user declined at the Phase 0 gate.**
69/100 is below the bar the user is willing to spend a package on, and the
title-defining Gap stands. **Cohort slot NOT consumed — Adjacent stays 1/2.**
The gate worked as designed: this was caught before any bullet was written.
### The caveat that must not be buried
`critique_framework.md` triggers a NO-GO flag when "a title-defining capability is not Direct."
**Forward deployment — embedding inside a strategic enterprise customer — is exactly that, and it is a Gap.**
The evidence base actively forbids the claim:
- `claims.json` **SW-4 forbidden:** `"customer-embedded delivery"`, `"strategic customer delivery"`, `"C-suite advisor"`
- `claims.json` **VZ-1 forbidden:** `"customer-embedded"`
- `claims.json` **global_forbidden_output_patterns:** `"customer-embedded delivery"`
- `application_strategy.md` lists **"strategic-account FDE" under Stretch targets**
- `historical_outputs.json` marks `output/Microsoft_ISE_Senior_SWE` unsafe for exactly this: *"customer-delivery framing exceeds verified evidence"*
So the single phrase that best describes this job is one we are never allowed to write about Dennis.
This is scored as Adjacent rather than No-Go because AWS's *published minimum bar is pure software
engineering* (see Requirements table) — they are hiring builders into a new org and transferring the
embedded model, not requiring prior consulting tenure. That is a real argument, not a rationalisation,
but it is an argument about AWS's intent, not about Dennis's evidence.
## Requirements
| # | Requirement | Required/preferred | Direct/Adjacent/Gap/Constraint | Canonical evidence | Gate? |
|---|---|---|---|---|---|
| B1 | 5+ years non-internship professional software development | Required | **Direct** | Continuous employment 2014-11 → present (~11.5 yrs) | Yes — PASS |
| B2 | 5+ years programming with at least one language | Required | **Direct** | Python, Java, C#, C++ across SWISSCOM/BOSCH/FRAUNHOFER/VIZRT (BS-2, VZ-1, FC-3) | Yes — PASS |
| B3 | 5+ years leading design or architecture (design patterns, reliability, scaling) of new **and existing** systems | Required | **Direct** | SW-2 Component Owner of business-critical Fulfillment ETL (operation, data quality, incidents, on-call); BS-3 Application Owner with SLOs; SW-3 Python apps on Kubernetes + GitLab CI/CD; SW-7 governed data products | Yes — PASS |
| B4 | Experience as a mentor, tech lead, or leading an engineering team | Required | **Adjacent** | Staff Engineer IV (Apr 2025→); BS-3 training and documentation; GN-1 trained teams on BDD/test automation; Leadership Cohort 2025. **No formal tech-lead title or direct reports.** | Yes — PASS (hedged) |
| P1 | Bachelor's in CS or equivalent | Preferred | **Direct** | M.Eng. Computer Aided Engineering (Software Design & Engineering), UniBw München | No |
| P2 | 5+ years full SDLC — coding standards, code review, source control, build, testing, operations | Preferred | **Direct** | VZ-2 automated A/V integration tests wired to CI/CD; FC-1 Jenkins CI/CD; SW-3 GitLab CI/CD; GN-1 test automation | No |
| P3 | Experience building production AI or ML applications, **including agentic workflows** | Preferred | **Gap (agentic) / Adjacent (production ML)** | BS-1 integrated containerized ML inference into 24/7 semiconductor production — genuine production ML. **But SW-8 forbids `"agent orchestration"`, `"built production LLM systems"`.** No RAG, no vector DB, no multi-agent framework anywhere in claims.json | No |
| P4 | Strong written/verbal communication; comfort in customer-facing environments | Preferred | **Adjacent** | SW-4 delivers data products with **internal B2B** stakeholders and product owners — explicitly *"not external consulting or strategic-account delivery"* | No |
| R1 | Embed within customer engineering teams; **up to 3050% travel** | Responsibility (title-defining) | **Gap + Constraint** | No evidence; forbidden phrasing (SW-4, VZ-1, global). Travel itself is workable — user is travel-OK from a Bern base, no relocation | — |
| R2 | Build production AI apps: orchestration layers for multi-agent systems, retrieval pipelines, workflow automation | Responsibility | **Gap** | SW-8 forbids agent orchestration. Real adjacent: configured domain-grounded LLM assistants, LiteLLM gateway, custom GPTs, Copilot, **Kiro** | — |
| R3 | Own production — rollout, incidents across models/distributed systems/data pipelines, monitoring, CI/CD, rollback, resiliency | Responsibility | **Direct** | SW-2 (incidents, on-call, data quality), SW-3 (K8s + CI/CD), BS-3 (SLOs), BS-4 (ELK/Kafka anomaly detection + monitoring) | — |
| R4 | Codify reusable patterns, accelerators, reference architectures | Responsibility | **Adjacent** | SW-7 data-product modelling and documentation; BS-5 Spotfire C# extensions co-owned | — |
| R5 | Build internal AI tools to scale the FDE motion | Responsibility | **Adjacent** | SW-8 LiteLLM APIs, custom GPTs with fed domain knowledge | — |
| R6 | Route field signal into product feedback (PFRs) | Responsibility | **Adjacent** | SW-4 stakeholder translation; BS-3 vendor management | — |
| C1 | Location Zürich; work authorization | Constraint | **Direct** | German citizen (EU) + Swiss B permit — no sponsorship. Bern→Zürich ~1h by rail | — |
| C2 | English working language | Constraint | **Direct** | English fluent; German native (bonus for DACH accounts) | — |
**Tally:** Required 3 Direct + 1 Adjacent, **0 Gap** → minimum-qualification gate PASSES.
Responsibilities: 1 Direct, 3 Adjacent, **2 Gap** — one of which is title-defining.
## Evidence Fit — dimension table
| Dimension | Weight | Score | Reasoning |
|---|---:|---:|---|
| Required qualifications | 35 | **29** | All four Basic Quals Direct/near-Direct; B4 hedged (no formal lead title). Preferred P3 agentic is a Gap. |
| Core responsibilities | 25 | **11** | Only R3 (own production) is Direct. R1 embedding and R2 agentic are Gaps; R1 is title-defining. |
| Level and ownership | 15 | **9** | Staff Engineer IV + Component/Application Owner matches "Senior" IC scope well. No external-account authority. |
| Recency and depth | 10 | **8** | Current, substantial: AWS, Kubernetes, Python, production ownership all present-tense at Swisscom. |
| Domain/tool transfer | 10 | **7** | **AWS is the ecosystem match** (contrast: claims.json marks GCP `output: forbidden`). Bedrock/AgentCore unused but adjacent to LiteLLM. Kiro genuinely used. |
| Practical constraints | 5 | **5** | Zürich commutable, EU citizen + B permit, English, travel acceptable. |
| **Total** | **100** | **69** | **Adjacent** |
## Competitive Read
- **Obvious-fit candidate:** a consulting-side senior engineer from AWS ProServe, Palantir, Accenture Applied Intelligence or a Big-4 AI practice who has already shipped LLM/agentic systems *inside* client environments, and who is used to 50% travel and client politics.
- **Dennis's advantage:** genuine **production ownership** — on-call, incidents, SLOs, data quality on business-critical pipelines. Many FDE applicants are strong at prototypes and weak at running things. He also brings AWS-native depth, native German for DACH accounts, and hands-on Kiro use (AWS's own agentic IDE, named in the JD).
- **Their advantage:** they have actually done the title-defining thing — embedded delivery against strategic accounts — and they have the agentic/RAG production track record listed in the preferred quals.
- **Level/scope comparison:** Level matches (Senior IC, not people-management). The gap is *function*, not seniority. That is the honest read.
## Company Context
- **The org is 7 weeks old.** AWS announced Forward Deployed Engineering on **2026-06-30** with a **$1bn** commitment, planning to deploy *thousands* of engineers. Model: small teams of ~56 embedded at customer sites for ~45-day engagements. Explicitly positioned as **not traditional consulting** — the stated goal is transferring expertise so customers operate the systems themselves. The JD's "This initiative is scaling rapidly" is literal.
- **Why that matters for Dennis:** a brand-new org hiring at volume screens differently from a mature consulting practice. They need builders who can run production, and they are training the embedded motion. This is the strongest structural argument for an Adjacent application.
- **Kiro** — the JD says "as we already do with AWS Transform and Kiro." Kiro is AWS's spec-driven agentic IDE, GA March 2026, successor to Amazon Q Developer, routing Claude Sonnet + Amazon Nova over Bedrock. **Dennis uses Kiro** (config.md verified GenAI toolchain). This is a rare, first-party, verifiable hook — not a vocabulary match.
- **AWS Zurich** office is operational with active hiring (Delivery Consultant, Practice Manager, Solutions Manager roles alongside this one).
## Framing Strategy
- **Professional identity:** Staff-level engineer who **builds and runs production systems on AWS** — pipelines, data products, containerized services — and has integrated ML inference into a 24/7 industrial environment.
- **Lead narrative:** *"I don't hand over prototypes; I own what happens at 3am."* Production ownership is the honest differentiator against a prototype-heavy FDE applicant pool.
- **Strongest proof points:** SW-2 Component Owner (incidents/on-call/data quality) · BS-1 containerized ML inference into 24/7 semiconductor production · SW-3 Python on Kubernetes + GitLab CI/CD · SW-7 governed data products on AWS · BS-4 ELK/Kafka anomaly detection.
- **Honest adjacent bridges:**
- AI work → frame as **integration and enablement** (configured domain-grounded assistants, LiteLLM gateway, Kiro, Copilot), never as agent orchestration.
- Customer-facing → frame as **internal B2B stakeholder delivery and vendor/Application ownership** (SW-4, BS-3), never as embedded or strategic-account delivery.
- **Explicit gaps — do not paper over:** no customer-embedded delivery; no multi-agent/RAG production systems; no Bedrock/AgentCore.
- **Downplay:** Security Champion (JD has no security requirement — CLAUDE.md default is OMIT); semiconductor domain depth beyond the ML-inference story.
- **User directives:** none given for this JD.
## Critique Context
- **Reviewer persona:** an AWS FDE hiring manager staffing a brand-new org at speed — pragmatic, bar-raiser-trained, scanning for "can this person build *and* operate under customer pressure."
- **Amazon-specific:** Leadership Principles matter. *Ownership*, *Bias for Action*, *Dive Deep*, *Deliver Results* are the ones his evidence genuinely supports. Amazon interviews are LP-heavy — worth noting for interview prep, not for resume prose.
- **Domain vocabulary:** forward deployed, production-grade, end-to-end ownership, foundation models, Bedrock, agentic workflows, evaluations, guardrails, observability, latency/cost optimization, reference architectures, PFR.
- **Likely first technical challenge:** *"Walk me through an AI system you took to production."* The honest answer is BS-1 (containerized ML inference, 24/7 fab) — classical ML, not LLM. Prepare that answer deliberately; do not let it drift toward implying LLM production ownership.
## Cover Letter Decision
- **YES**
- **Reason:** The resume cannot, on its own, explain why a Swisscom platform engineer is applying to an embedded customer-delivery role. That gap is visible on page one and will otherwise be resolved against him. A letter is the only place to address it directly and turn production ownership into the argument.
- **Information it adds beyond resume:** (1) the motivation for moving from internal platform work into forward-deployed delivery, stated plainly rather than disguised; (2) **hands-on Kiro use** — first-party AWS tooling named in the JD; (3) native German for DACH accounts; (4) travel/mobility willingness from a stable Swiss base.
- **Verified hook sources:** JD text (Kiro, AWS Transform, PFR mechanism); AWS FDE launch 2026-06-30 ($1bn, ~45-day embedded engagements); config.md verified GenAI toolchain (Kiro, Copilot, LiteLLM, custom GPTs).
- **Forbidden in the letter:** any phrasing implying prior customer-embedded or strategic-account delivery; any agent-orchestration claim.
## Resume Plan
- Summary: 23 lines — production ownership + AWS + ML-into-production
- Skills: 46 evidence-backed lines; AWS prominent; **no Bedrock, no LangGraph/CrewAI/ADK, no vector DB**
- Swisscom: SW-2, SW-3, SW-7, SW-1, SW-8 (integration framing only)
- Bosch: BS-1 (lead), BS-3, BS-4
- Earlier experience: VZ-1 or VZ-2 (distributed systems / CI/CD), FC-3 optional
- Total bullets: 1114
- Impact evidence still needed: **all Swisscom metrics are `unverified`** — this remains the standing weakness across every package.
## Output Files
- JD (verbatim): `output/AWS_Senior_FDE_Zurich/JD_aws_senior_fde_zurich.txt`
- Resume: pending Phase 2
- Cover letter: pending (decision YES)
- Critique: pending
## Status
- Fit gate: **CLOSED — NO-GO 2026-08-18** (Phase 0 completed, then declined)
- Original gate result: **Phase 0 DONE 2026-08-18** — Adjacent, Evidence Fit 69/100, minimum-qual gate PASS, title-defining Gap disclosed, Channel Weak
- Phase 0: DONE
- Phase 1: **NOT STARTED — will not start.**
- Resume: not generated
- Cover Letter: not generated (CL decision was YES, but moot)
- Critique: n/a