Finding (confirmed live, 2026-07-23; surfaced by the orchestrator's discrepancy sampling on cards 77046/31096/14961). local_ocr.py's _SET_CODE_RE = re.compile(r"\b([A-Za-z0-9]{3,5})\b") accepts any 3–5 character alnum token near a parsed collector number as a candidate set code — there is no check anywhere that the token is a real MTG set code. parse_collector_line's own docstring is explicit that this is deliberate ("tolerant extraction, not validation... the validation rail... is what decides trust") — but the validation rail it's referring to (find_matching_candidates/validate_against_candidates) only ever checks the token against this one card's own name-narrowed candidate list, never against the full, real set-code lexicon (CanonicalExpansion.code, ~1,047 real codes).
The result: OCR noise that happens to look like a plausible token — "sew", "ree", "eee" (artwork/border noise, not text) — reads as a genuine (but wrong) set-code attempt. Since it obviously won't match this card's own real candidates (it isn't a real set code at all), validate_against_candidates returns "parsed-but-no-match", which calculate_join_key_verdict treats as genuine whole-candidate-set negative evidence and casts a confident is_no_match=True vote (JOIN_KEY_NO_MATCH_CONFIDENCE=0.6) — indistinguishable from a card where OCR genuinely read a real-but-wrong set code.
Sizing, DB-verified 2026-07-23, read-only:
- Total
stage-d-join-key-v1 is_no_match=True votes: 61,247
- Of those, current stored
collector_line_set_code is not present in the known-set-code lexicon (CanonicalExpansion.code, case-insensitive): 52,349 (85.5%)
- Blank
set_code (the legitimate pre-M15 collector-number-only path — unaffected by this defect): 4,586
- Real, lexicon-valid set code that simply doesn't match this card's own candidates (working as intended): 4,312
- Restricting to cards that also carry a
deductive-backfill-v1 deduction vote (a potential double-signal-conflict population): 6,772 cards carry both a no-match vote and a deduction vote, of which 5,906 (87.2%) rest on a lexicon-invalid set code. (Note: I could not reproduce the specific "4,768" figure referenced when this was flagged to me under any cohort definition I tried — a truly blank-collector-line-OCR card structurally can never reach a parsed-but-no-match no-match vote in the first place, since that requires a parsed collector number. Flagging this as an open item for reconciliation rather than asserting a number I couldn't verify.)
Ask: validate parsed.set_code against the real set-code lexicon before calculate_join_key_verdict is allowed to treat a "parsed-but-no-match" result as confident negative evidence. A set code that isn't in the lexicon should downgrade to a "no-text"-style (rescannable) abstention, not a confident is_no_match vote — the OCR didn't find a genuine (if wrong) set-code attempt, it found noise. This directly inflates the no-match vote pool with false negatives at ~85% of its current volume, which matters for any downstream consumer treating a no-match vote as trustworthy signal (e.g. review-queue routing, #262's clustering).
Finding (confirmed live, 2026-07-23; surfaced by the orchestrator's discrepancy sampling on cards 77046/31096/14961).
local_ocr.py's_SET_CODE_RE = re.compile(r"\b([A-Za-z0-9]{3,5})\b")accepts any 3–5 character alnum token near a parsed collector number as a candidate set code — there is no check anywhere that the token is a real MTG set code.parse_collector_line's own docstring is explicit that this is deliberate ("tolerant extraction, not validation... the validation rail... is what decides trust") — but the validation rail it's referring to (find_matching_candidates/validate_against_candidates) only ever checks the token against this one card's own name-narrowed candidate list, never against the full, real set-code lexicon (CanonicalExpansion.code, ~1,047 real codes).The result: OCR noise that happens to look like a plausible token — "sew", "ree", "eee" (artwork/border noise, not text) — reads as a genuine (but wrong) set-code attempt. Since it obviously won't match this card's own real candidates (it isn't a real set code at all),
validate_against_candidatesreturns"parsed-but-no-match", whichcalculate_join_key_verdicttreats as genuine whole-candidate-set negative evidence and casts a confidentis_no_match=Truevote (JOIN_KEY_NO_MATCH_CONFIDENCE=0.6) — indistinguishable from a card where OCR genuinely read a real-but-wrong set code.Sizing, DB-verified 2026-07-23, read-only:
stage-d-join-key-v1is_no_match=Truevotes: 61,247collector_line_set_codeis not present in the known-set-code lexicon (CanonicalExpansion.code, case-insensitive): 52,349 (85.5%)set_code(the legitimate pre-M15 collector-number-only path — unaffected by this defect): 4,586deductive-backfill-v1deduction vote (a potential double-signal-conflict population): 6,772 cards carry both a no-match vote and a deduction vote, of which 5,906 (87.2%) rest on a lexicon-invalid set code. (Note: I could not reproduce the specific "4,768" figure referenced when this was flagged to me under any cohort definition I tried — a truly blank-collector-line-OCR card structurally can never reach aparsed-but-no-matchno-match vote in the first place, since that requires a parsed collector number. Flagging this as an open item for reconciliation rather than asserting a number I couldn't verify.)Ask: validate
parsed.set_codeagainst the real set-code lexicon beforecalculate_join_key_verdictis allowed to treat a"parsed-but-no-match"result as confident negative evidence. A set code that isn't in the lexicon should downgrade to a"no-text"-style (rescannable) abstention, not a confidentis_no_matchvote — the OCR didn't find a genuine (if wrong) set-code attempt, it found noise. This directly inflates the no-match vote pool with false negatives at ~85% of its current volume, which matters for any downstream consumer treating a no-match vote as trustworthy signal (e.g. review-queue routing, #262's clustering).