fix(scout): Apple blind to CH for 2 months, BIS behind Cloudflare, NAV rate limit, EMEA leak; reputation for every board

Apple (the big one)
- The location=switzerland-CHE slug stopped resolving; Apple silently applied
  a US location, so every run from at least 2026-08-31 returned the same 21
  US/intern cards and 0 Swiss roles. Now location code CHEC (from
  /api/v1/refData/postlocation), result list item as the card (location
  readable), pagination, settle delay, longer wait and per-element timeout.
  Verified twice: 24 Swiss roles each run.

BIS
- bis.org went behind a Cloudflare challenge (403 even headless). Moved to the
  Workday tenant bis.wd3.myworkdayjobs.com/External, which also carries the
  office. Host alias + lower-cased jr-id keep all 9 bis.org#jr decisions
  linked (applied jr100498 included).

NAV
- Search API 429s after ~9 requests and stays blocked for hours: discovery
  capped at 8 searches (4s pacing). Posting text now comes from NAV's official
  third-party feed (pam-stilling-feed, public rotating token), with a small,
  slow website-page fallback for ads the feed lacks (~2/3). Verified live on
  15 real ads; fallback path tested on fixtures.

Location filter
- EMEA leak fixed: a country allowlist without CH/DK plus a trailing region
  tag is no longer Europe-remote (27 rows). Swiss/Danish segments in
  multi-location strings are evaluated per segment. Regression over all
  2026-10-22 rows: only the fenced rows changed.

Reputation
- Every board now has a dated verdict; kununu added as a primary source next
  to Glassdoor (the one with more reviews decides; user tip). Second-source
  scores now count (a low one means avoid). AVOID: BIS (Glassdoor 2.9),
  BFH (kununu 3.3), Kdo Cy (federal administration kununu 3.4).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
dennisthiessenandClaude Opus 5.5 committed 2026-10-22 10:44:45 +02:00
1 parent eee608a213
commit ff12f16545
3 files changed
+920 -77

No files matched your search

+2 -1
View File
@@ -184,7 +184,8 @@ _See `config.md` for user-specific corrections. Add verified errors here as you
| Date | Correction | Files fixed |
|------|-----------|-------------|
| 2026-10-21 | **Software design and architecture was under-recorded: the seventh canonical gap of the recurring shape, surfaced by the Google *Staff SWE, Shopping Graph* minimum *"3 years of experience with software design and architecture."*** Before this, the only design evidence was SW-7 (current, undated, 2026-10-03) and a *contribution* at Generali (GN-3), so the line read as unproven. User-confirmed: **software design and architecture were part of his work at Bosch (ingestion and inference scripts, 2020-2022) and at Swisscom (data products)**, and both count toward the year requirement; together they exceed three years. Recorded on BS-1, BS-2 and SW-7, with `designed` added to the BS-1/BS-2 allowed verbs. **Scope kept tight:** at Bosch, "designed" covers the ingestion scripts and the inference integration only, not the data services in general (the first patch over-extended it and was trimmed the same session). Design never means an architect title, design authority or shared-platform architecture. The Swisscom start date stays undated. **Lesson, the same as 10-08 and 10-14: when a JD has a years-of-X minimum that the canonical file states without a duration, ask for the duration before scoring.** | `claims.json` (BS-1, BS-2, SW-7); `config.md` (data-product design row); `knowledge_base/extractions/2026-10-21_software_design_architecture_clarification.md` |
| 2026-10-21 | **FIXED 2026-10-22 (Microsoft links); the EMEA leak below is still OPEN.** Fix: `fetch_pcsx` now emits `apply.careers.microsoft.com<positionUrl>?jobId=<displayJobId>`, a `?jobId=` pattern precedes the `/job/` one in `_JOB_ID_PATTERNS`, and `_HOST_ALIASES` maps the new host to the old so `_decision_key` is unchanged. Verified: all 7 logged Microsoft decisions still resolve (applied 200043897 included), and a new-form link opened the real posting with the job number on the page. Reports before 2026-10-22 still carry the dead form. Original finding: **every Microsoft link the scout emits is dead, in every report**, found in the 2026-10-20 triage. `fetch_pcsx` builds `jobs.careers.microsoft.com/global/en/job/<displayJobId>`, which now redirects to a generic `apply.careers.microsoft.com/careers?...&pid=1970393557041551` search page. Verified on 200060867 and on the **pending application 200043897** (Principal FDE). The application itself is unaffected; only the link is. The working form is `https://apply.careers.microsoft.com/careers/job/<pcsx id>`, the API's `positionUrl`. **Deliberately NOT patched yet:** 6 logged Microsoft decisions (including 200043897) are keyed on `displayJobId` through the `careers\.microsoft\.com /job/(\d+)` pattern. Swapping the URL would re-key them on the pcsx id and orphan them, the same failure as the 09-04 RUAG/BIS de-linking. **Safe fixes:** (a) keep `url` and add a working `apply_url` field to the row, or (b) emit the new URL with the display id carried in it, plus a host-normalised key pattern. Either way, verify all 6 rows still resolve through `find_decision_url` afterwards. Same triage, also OPEN: an **"EMEA" region suffix lets country-fenced roles through the location filter** (GitLab FR/DE/NL/ES/UK, Grafana ×5, Fivetran Serbia: 7 of 109 new rows), which breaks the docstring rule against multi-country allowlists that omit CH. | not yet fixed: `scout.py` (`fetch_pcsx`, location filter); evidence in `reports/2026-10-20.triage.md` |
| 2026-10-22 | **Scout findings fixed in one pass; the biggest one is that Apple had been blind to Switzerland for about two months.** (a) **Apple:** the `location=switzerland-CHE` slug stopped resolving and Apple silently applied a US location ("Chesterfield, Missouri"). Every run from at least 2026-08-31 to 2026-10-22 returned the same 21 US/intern cards and **0 Swiss roles**, which read as "Apple has nothing" rather than as a failure. The code is now `CHEC` (from `/api/v1/refData/postlocation`); the card is the result list item, so the location is readable; and there is pagination, a settle delay and per-element timeouts (one run took 876s, the next 25s). Result: **24 Swiss roles**, Zurich AIML/infra included. (b) **BIS:** bis.org went behind a Cloudflare challenge (403, even for a headless browser), so the board moved to its Workday tenant `bis.wd3.myworkdayjobs.com/External`, which also gives the real office. A host alias plus a lower-cased jr-id keep all 9 `bis.org#jr…` decisions linked (applied jr100498 included). (c) **NAV:** the search API 429s after ~9 requests and then for hours. Discovery now stays at 8 searches, and posting text comes from NAV's official third-party feed (`pam-stilling-feed`, public rotating token), which tolerated bursts. The feed lacks ~2/3 of ads, so a small, slow website-page fallback covers those, and verdicts are cached. (d) **EMEA leak fixed:** a country allowlist without CH/DK plus a trailing "EMEA" tag is no longer Europe-remote (27 rows removed). Swiss/Danish segments in multi-location strings are checked per segment, so "PL-Poland-Remote \| CH-Zurich-MSO" stays Swiss. A regression over all 2026-10-22 rows showed only the fenced rows changing. (e) **Reputation:** every board now has a dated verdict. Glassdoor and **kununu** are both primary sources, and whichever has more reviews decides (user tip: kununu is far better for Swiss employers). AVOID: **BIS** (Glassdoor 2.9/56, where an application is pending), **BFH** (kununu 3.3/132), **Kdo Cy** (federal-administration kununu 3.4/997, not unit-specific). **Lesson: a board that returns the same non-zero count with zero eligible rows for weeks is a silent failure, not an empty market. Check what filter the site actually applied.** | `scout.py` (Apple, BIS, NAV, location filter, reputation); `state/employer_reputation.json` |
| 2026-10-21 | **FIXED 2026-10-22 (Microsoft links; the EMEA leak below was fixed the same day, see the 2026-10-22 row).** Fix: `fetch_pcsx` now emits `apply.careers.microsoft.com<positionUrl>?jobId=<displayJobId>`, a `?jobId=` pattern precedes the `/job/` one in `_JOB_ID_PATTERNS`, and `_HOST_ALIASES` maps the new host to the old so `_decision_key` is unchanged. Verified: all 7 logged Microsoft decisions still resolve (applied 200043897 included), and a new-form link opened the real posting with the job number on the page. Reports before 2026-10-22 still carry the dead form. Original finding: **every Microsoft link the scout emits is dead, in every report**, found in the 2026-10-20 triage. `fetch_pcsx` builds `jobs.careers.microsoft.com/global/en/job/<displayJobId>`, which now redirects to a generic `apply.careers.microsoft.com/careers?...&pid=1970393557041551` search page. Verified on 200060867 and on the **pending application 200043897** (Principal FDE). The application itself is unaffected; only the link is. The working form is `https://apply.careers.microsoft.com/careers/job/<pcsx id>`, the API's `positionUrl`. **Deliberately NOT patched yet:** 6 logged Microsoft decisions (including 200043897) are keyed on `displayJobId` through the `careers\.microsoft\.com /job/(\d+)` pattern. Swapping the URL would re-key them on the pcsx id and orphan them, the same failure as the 09-04 RUAG/BIS de-linking. **Safe fixes:** (a) keep `url` and add a working `apply_url` field to the row, or (b) emit the new URL with the display id carried in it, plus a host-normalised key pattern. Either way, verify all 6 rows still resolve through `find_decision_url` afterwards. Same triage, also OPEN: an **"EMEA" region suffix lets country-fenced roles through the location filter** (GitLab FR/DE/NL/ES/UK, Grafana ×5, Fivetran Serbia: 7 of 109 new rows), which breaks the docstring rule against multi-country allowlists that omit CH. | not yet fixed: `scout.py` (`fetch_pcsx`, location filter); evidence in `reports/2026-10-20.triage.md` |
| 2026-10-15 | **Two scout adapters were reporting wrong data without failing; both were found by the 2026-10-14 triage.** (a) **BIS:** the RSS adapter stamped `default_location: Basel, Switzerland` on every vacancy, so **jr100491 (Hong Kong, BIS Asia office)** passed the CH filter and reached a JD read. The feed carries no location, but each vacancy page has a static *Geographical location* field. `fetch_rss` now reads it per item (`location_page_regex`), falls back to a *"based in ..."* sentence in the feed description, and only then uses `default_location`, printing a warning when it does. Verified: Basel reqs still pass, and jr100491 now reads *8 Finance Street, Central, Hong Kong* and is excluded. (b) **Confluent:** IBM closed the acquisition on 2026-03-17, and the Ashby board went from 17 jobs (10-08) to `{"jobs":[]}` (10-14). careers.confluent.io sits behind a Vercel bot checkpoint. The roles are now IBM requisitions, served by the open IBM careers search API (`www-api.ibm.com/search/api/v2`, POST, `size` capped at 100, pages with `from`). New `ibm` adapter; Confluent keeps its id, so seen-state and decisions still link. First run: 84 roles, 0 in CH/Europe-remote scope. **HashiCorp was dropped on 2026-06-06 for having "no clean public ATS API" after IBM absorbed it. That API exists, so HashiCorp can come back through the same adapter if wanted.** **Rule: when an adapter must assume a field, the assumption has to be visible. A silent default looks exactly like real data.** | `scout.py` (`fetch_rss`, `_rss_item_location`, `fetch_ibm`, BIS and Confluent config) |
| 2026-10-14 | **Spotfire was the sixth evidenced-but-unregistered skill, and junior mentoring was unrecorded - both surfaced by the BIS Basel jr100498 *Senior/Lead Data & Analytics Engineer* (MED IT) triage.** (a) **TIBCO Spotfire** sat in the BS-5 and BS-8 scopes (co-owned environment, technical Application Owner, C# extensions, TAF 2022, spatial wafer-data map charts) but not in the `skills` array, so the JD line *"using database reporting and business intelligence tools"* had no citable skill; registered `production-historical`, `allowed` on user instruction. It does not license Power BI, Tableau or Qlik. (b) The JD requires *"Experience providing general supervision and task-specific guidance to junior colleagues"*, and the only canonical evidence was BS-7 (students, one thesis as Zweitpruefer). User-confirmed: he **onboarded and mentored junior developers at Bosch and at Swisscom** - recorded as **BS-9** and **SW-10**, one per employer. The Swisscom phase (ART B2B or ART DPT) is not recorded, so write it in past tense. Neither is people management. (c) **SDMX: user-confirmed never used**; registered `forbidden` so the scanner catches it. It is an accountability line in the JD, not a qualification. (d) The same audit found **Teradata, Oracle Database and Hadoop/Impala** evidenced only in the SW-2/BS-2/BS-8 scopes and absent from the `skills` array, although every past skills line listed them; registered `production-historical` from those scopes (Oracle explicitly does not establish DBA work). **Lesson, same as 10-08: when a JD has a supervision or mentoring line, ask about junior colleagues before falling back on BS-7. Student supervision is weaker evidence and the stronger evidence was simply unrecorded.** | `claims.json` (BS-9, SW-10; skills TIBCO Spotfire, SDMX, Teradata, Oracle Database, Hadoop / Impala); `knowledge_base/extractions/2026-10-14_mentoring_spotfire_sdmx_clarification.md` |
| 2026-10-08 | **Three more canonical gaps of the recurring shape, surfaced by the Kongsberg Seatex *Lead Engineer, DevOps and Test Infrastructure* (Trondheim) package.** (a) **Jenkins and GitLab CI/CD** were evidenced in claim scopes (GN-1, FC-1, BS-6, SW-3) but absent from the `skills` array, so no skills line could cite them; registered as `production-historical`, with GitLab keeping SW-3's "used, not built" limit. (b) **Embedded coursework** was unrecorded: user-confirmed an Embedded Systems course (C/C++ and VHDL with an ARM platform) and Robotics during his studies, and **no embedded work since** - recorded as **ED-1**, coursework-only, degree attribution not yet given. (c) **Current unit testing** was unrecorded: he writes unit tests today and knows pytest - recorded as **SW-9**; whether pytest is the Swisscom framework is not confirmed. The JD's required line *"Experience working with embedded SW and Linux"* stays a **half Gap** (hard-gate FAIL); the user overrode it knowingly. **Lesson, again: for any DevOps/test JD ask about current testing practice and about academic hardware work before scoring - neither lives in `claims.json` by default.** | `claims.json` (ED-1, SW-9, 7 skills); `knowledge_base/extractions/2026-10-08_embedded_coursework_testing_clarification.md`; Kongsberg package |