# 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.
