Skip to content

Proxy-marker weaken-don't-withhold + OCR pre-classification short-circuit - #294

Merged
WilfordGrimley merged 3 commits into
masterfrom
sark/proxy-marker-weaken-and-shortcircuit
Jul 21, 2026
Merged

Proxy-marker weaken-don't-withhold + OCR pre-classification short-circuit#294
WilfordGrimley merged 3 commits into
masterfrom
sark/proxy-marker-weaken-and-shortcircuit

Conversation

@WilfordGrimley

Copy link
Copy Markdown

Summary

Two independent, pre-197k-remainder correctness fixes (owner-approved), landed as separate commits on this branch so either is separately revertable:

1. fix: proxy-marker weakens no longer withholds a join-key match (MPCAutofill/cardpicker/local_calculate_verdicts.py)

  • _apply_agreement_checks no longer returns a proxy-marker-veto skip when legal_line_proxy_marker_detected — a live read-only trace (2026-07-21) found this discarding 1,552 already-validated candidate matches, 99.4% with a real, DB-matching set/number parse.
  • Owner ruling (docs/features/catalog-completion-plan.md's "Recovery-arc lessons" item 1's own "CRITICAL correction," encoded verbatim there): the marker is catalog-required on every genuine upload, real printings' proxies included — its presence carries no discriminating power over whether a specific match is right or wrong.
  • Confidence-tier choice: no change at all (not a weaker tier). Reasoning: unlike artist-OCR disagreement (a genuine, informative cross-check that covaries with match correctness), a catalog-required field that's true across nearly the whole eligible population is closer to a constant than a signal — inventing a specific weaker number for it would repeat the exact "threshold invented, not measured" mistake this module's own quality/integrity gating note already declines to make for blur_variance/image_entropy. Full reasoning is in the inline comment at the check's former location.
  • reparse_collector_evidence gets a new --selector proxy-marker-veto --stage-d-run-id RUN_ID (mirrors --selector no-text structurally) to retract the ~1,552 stale skip rows — immediately actionable (unlike no-text, no re-extraction needed; the code fix alone changes the conclusion for the same stored evidence). Dry-run by default.
  • docs/theory.md §7's g4 enumeration and docs/features/catalog-completion-plan.md's "moderator-flag veto"/slow-path sections updated in place to describe the corrected behavior.

2. perf: short-circuit collector_line_ocr escalation on digit-free tier 1 (MPCAutofill/cardpicker/image_evidence.py)

  • Implements the merged plan's spec exactly (docs/features/catalog-completion-plan.md's "Recovery-arc lessons" item 1): once both tier-1 attempts fail to parse a collector number, if neither attempt's raw text contains a single digit character, skip tiers 2-3 (6 more tesseract calls) and go straight to no-text — measured at 99.7% of a real no-text cohort, zero-loss on that sample.
  • A digit-bearing tier-1 failure still escalates through every tier exactly as before (_contains_digit is a coarser, cheaper check than _COLLECTOR_NUMBER_RE, so this can only ever short-circuit a strict subset of the existing no-text population).
  • Escape hatch: compute_card_evidence(..., short_circuit=...) param, run_image_evidence_cohort --no-shortcircuit CLI flag, and STAGE_C_NO_SHORTCIRCUIT env var — all default to short-circuit ON.
  • run_image_evidence_cohort now counts and reports short_circuited=N in its progress/DONE summary lines, so the real 197k-card remainder run itself produces the plan's own "open verification gap" measurement data (whether any short-circuited card would have recovered at a later tier).

Test plan

  • test_local_calculate_verdicts.py (58 tests): proxy-marker no longer vetoes a direct match, a symbol-tiebroken match; marker present/absent reaches the identical verdict; marker still doesn't affect a genuine no-match; marker no longer masks a real copyright-year mismatch (that withhold now fires instead).
  • test_reparse_collector_evidence.py (22 tests): new TestSelectCardIdsProxyMarkerVeto (2 tests) + test_proxy_marker_veto_selector_recovers_immediately_no_reextraction_needed + test_proxy_marker_veto_selector_end_to_end_recasts_the_real_vote (full two-step runbook proof, resolved-consensus safety gate covered by existing shared tests) + CLI --stage-d-run-id requirement test.
  • test_image_evidence.py: short-circuit fires by default on a digit-free blank crop (2 tesseract calls, not 8); --short_circuit=False preserves the full 8-attempt escalation; a digit-bearing-but-unparseable tier-1 read still escalates through every tier by default; short-circuit only fires once both tier-1 attempts are confirmed digit-free.
  • test_run_image_evidence_cohort.py: _compute_one_card/_run_cohort thread the new short_circuit param and 4th return value through correctly.
  • Full backend suite (host venv against live prod containers' exposed Postgres/ES, ephemeral test_* DB, no prod data touched): 1370 passed, 4 skipped (same CI-documented named skips), zero regressions.
  • Full pre-commit (ruff/isort/black/mypy/prettier) clean on every changed file.
  • No migration involved — nothing to run against the live DB, nothing deferred for that reason.

Runbook additions (for the 197k remainder run)

Re-scan for the ~1,552 stale proxy-marker-veto rows (dry-run first per the binding "mandatory dry-run before any --selector state-clear write" rule):

manage.py reparse_collector_evidence --selector proxy-marker-veto --stage-d-run-id <RUN_ID>
manage.py reparse_collector_evidence --selector proxy-marker-veto --stage-d-run-id <RUN_ID> --write

New flag for the remainder harvest command (default is short-circuit ON — no flag needed for the normal run; only pass this for a measurement/comparison run):

manage.py run_image_evidence_cohort --no-shortcircuit ...

🤖 Generated with Claude Code

WilfordGrimley and others added 2 commits July 21, 2026 16:23
legal_line_proxy_marker_detected was a hard veto in _apply_agreement_checks
(named skip "proxy-marker-veto"), discarding 1,552 already-validated
matches per a live trace (99.4% with a real set/number parse). The marker
is catalog-required on every genuine upload, real printings' proxies
included, so its presence carries no discriminating power over whether a
specific match is right - the match now proceeds unaffected (no withhold,
no confidence change).

Adds reparse_collector_evidence --selector proxy-marker-veto to retract the
stale skip rows this veto left behind (dry-run default, mirrors --selector
no-text).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
collector_line_ocr's multi-tier attempt loop escalated through tiers 2-3
(6 more tesseract calls) for every card whose tier-1 attempts failed to
parse a collector number, regardless of whether tier 1 found any digit at
all. A 6,643-card no-text cohort measured 99.7% digit-free at tier 1 with
zero tier-2/3 recovery gain.

compute_card_evidence now skips straight to "no-text" once both tier-1
attempts are confirmed digit-free (short_circuit param, default on,
--no-shortcircuit/STAGE_C_NO_SHORTCIRCUIT escape hatch for measurement
runs). A digit-bearing tier-1 failure still escalates exactly as before.
run_image_evidence_cohort counts and reports how many cards short-circuit
each run, so the 197k remainder run itself produces validation data for
the plan's open verification gap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mirrors test_dry_run_counts_without_writing_anything (parser-bug only)
for the new --selector proxy-marker-veto - confirms dry_run=True counts
the cohort without retracting the stale scan-log row or casting a vote.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@WilfordGrimley
WilfordGrimley merged commit 86fca80 into master Jul 21, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant