These three all cost roles BEFORE a human ever read them, which is the
expensive kind of defect: a job that never reaches the report cannot be
evaluated at all.
F11 - dedupe by requisition, not title
- The old rule collapsed everything sharing a normalised title within one
employer. Two different reqs called "Senior Data Engineer" in Bern and Zurich
became one row, and different teams hiring the same title vanished.
- Requisition identity is now the key, parsed from the URL with the same
patterns the decision log uses, employer-scoped so two boards cannot collide.
- The legitimate case the old rule existed for - one role republished per
location - is a SAME-REQUISITION case, so those merge their locations.
- A shared title across different requisitions is now a warning, never a
deletion.
F12 - location filters
- Substring matching accepted "Bernau bei Berlin" as Bern. Place matching is
now whole-word.
- Thun, Zimmerwald, Baar, Olten and ~25 more Swiss towns were rejected outright
when the adapter supplied no country. Zimmerwald is the Kdo Cy site he applied
to; Thun is where he lives.
- Aarhus, Odense and other Danish cities added alongside Copenhagen.
- A stray "Europe" no longer implies remote eligibility next to an explicit
onsite marker or a single-country residence restriction.
- All 14 cases named in the review now resolve correctly.
F13 - decision identity
- The generic fallback key dropped the query string, so /vacancy?job=1 and
?job=2 were the same key and one decision silently covered both. Identifying
query parameters are now kept; tracking noise is not.
- The READ path had no slug fallback although the WRITE path got one on
2026-09-04. Every RUAG repost therefore came back undecided despite a recorded
decision - which is what happened to Lead-Architekt Network- und Richtfunk on
2026-09-10, days after 63 RUAG rule-outs were written.
- Both paths now share `lookup_decision`. Verified on a live RUAG run: 7
reposted requisitions recovered their decisions.
- A slug match is reported as RELATED with the matched URL, never applied as if
it were the same requisition: a repost can differ materially, as RUAG
demonstrated when it moved a disqualifier into a job title.
tests/test_scout_matching.py added. Full suite 34/34 pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qej5SBvhcbGXHwLqNWiskM