Skip to content

Add rejudge_fallback_channel command: compare-and-retract-on-change for stage-d-fallback-v1 - #495

Merged
WilfordGrimley merged 2 commits into
masterfrom
feat/rejudge-fallback-channel
Jul 27, 2026
Merged

Add rejudge_fallback_channel command: compare-and-retract-on-change for stage-d-fallback-v1#495
WilfordGrimley merged 2 commits into
masterfrom
feat/rejudge-fallback-channel

Conversation

@WilfordGrimley

Copy link
Copy Markdown

Summary

  • New rejudge_fallback_channel management command: compare-and-retract-on-change for the stage-d-fallback-v1 channel. Re-derives each targeted card's fallback verdict via the EXISTING, unmodified local_calculate_verdicts.calculate_fallback_verdict from CURRENT stored ImageEvidence (layout_class/artist_ocr_name/symbol_phash — no re-parse step, zero image fetches), compares against the card's recorded stage-d-fallback-v1 CardPrintingTag vote / CardScanLog skip row, and retracts (deletes) the fallback rows only where the conclusion CHANGED, so the card is eligible again for run_fallback_calculator's own next pass. Skeleton mirrors reparse_collector_evidence (recorded-state lookup, fresh verdict, compare, safety gate, delete + resolve_and_persist_printing).
  • NEVER touches stage-d-join-key-v1 rows: fallback eligibility is GATED on the join-key no-hit state existing (_fallback_eligible_cards_queryset) — deleting join-key rows would eject the card from the fallback population entirely.
  • Safety gate mirrors reparse_collector_evidence's conservative card-level reading: retraction refused (counted gate_refused, card pks recorded for human review) whenever printing_consensus.resolve_printing(card) is not None — covers BOTH a resolved printing and a resolved NO_MATCH consensus.
  • Cohort: exactly one of --card-ids-file (reuses utils.read_card_ids_file) or --selector all-channel (every card carrying any stage-d-fallback-v1 CardPrintingTag or CardScanLog row).
  • Dry-run by default; snip --write behind the issue Code-enforced guard: require a matching prior dry-run before accepting --write for the same selector/cohort #362 forced-dry-run guard (matching COMPLETED dry-run of the SAME --selector/--card-ids-file within --dry-run-window-hours, scope-hash over the invocation input, --skip-dryrun-check override). PilotRunLedger integration: counters persisted BEFORE terminal output (considered, unchanged, changed, retracted, no_evidence, no_prior_fallback_state, gate_refused, gate_refused_card_ids, per-reason recorded -> fresh transitions breakdown), votes_written repurposed as rows-retracted (same convention as reparse_collector_evidence), resilient_terminal_output + mark_ledger_failed rails reused from pilot_run_lifecycle. Stdout prints counters plus up to 20 sample transition lines ({'card_id': N, 'recorded': (...), 'fresh': (...)}).
  • Lazy CandidateNameIndex via _get_cached_candidate_name_index() (issue Streaming dispatch pays catalog-scaling fixed overhead per call (unscoped scan-log subquery, eager CandidateNameIndex) #469 pattern, matching run_fallback_calculator's own lazy build) rather than reparse_collector_evidence's older unconditional construction — an empty or all-no_evidence cohort never pays the index build.
  • New test suite test_rejudge_fallback_channel.py (17 tests) mirroring test_reparse_collector_evidence.py/test_local_calculate_verdicts.py DB-test patterns: changed-conclusion retracts rows + recomputes consensus, end-to-end re-eligibility proof via run_fallback_calculator, unchanged leaves rows, resolved-card gate-refuses, join-key rows never deleted, dry-run writes nothing, no_evidence/no_prior_fallback_state branches, selector coverage/dedup, ledger counters persisted on completion, forced-dry-run guard (refusal / scope-mismatch / write-after-matching-dry-run).

CLAUDE.md task-end checks applied:

  • Wiki maintenance: n/a — no USER/ADMIN-visible behavior change; snip this is a new operator command not yet part of any documented runbook (and docs/ is outside this PR's allowed scope).
  • Extractable-primitives ledger (docs/upstreaming/extractable-primitives.md): no row added or removed — the command is fork-coupled to the vote system/CanonicalPrinting-consensus by construction (STAGE_D_FALLBACK_ANONYMOUS_ID, calculate_fallback_verdict, printing_consensus, PilotRunLedger); snip no dependency-free primitive was produced or destroyed.
  • Policy-text dates: n/a — no policy text touched.

Test plan

All pytest invocations run from the worktree's MPCAutofill/ directory with the box's pilot venv python (/home/ubuntu/.venvs/mpcautofill-pilot/bin/python -m pytest ... -q), against the suite's own isolated testcontainers Postgres/ES fixtures (per docs/lessons.md's sanctioned throwaway flow; snip live docker stack and live DB never touched):

  • pytest cardpicker/tests/test_rejudge_fallback_channel.py -q — 17 passed
  • pytest cardpicker/tests/test_local_calculate_verdicts.py -q — 135 passed
  • pytest cardpicker/tests/test_pilot_run_lifecycle.py -q — 33 passed
  • pytest cardpicker/tests/test_reparse_collector_evidence.py -q — 37 passed (insurance; snip the new command mirrors that module's skeleton)
  • black --check + isort --check-only + ruff check on both touched files — clean
  • mypy --config-file mypy.ini cardpicker/management/commands/rejudge_fallback_channel.py — Success: no issues found (mypy 1.7.0 + django-stubs, matching CI's pre-commit environment; snip tests are excluded by mypy.ini)
  • CI — not watched by this session per dispatch convention

… hangs

When test_peak_alive_fetch_payloads_bounded_by_queue_depth_not_cohort_size
fails (thread doesn't finish in time), the non-daemon thread blocks Python
process exit for up to 6 hours until GitHub Actions kills the job. Making
it daemon lets the process exit cleanly while keeping the assertion that
detects the regression.
@WilfordGrimley
WilfordGrimley merged commit a0eec5e into master Jul 27, 2026
4 checks passed
WilfordGrimley added a commit that referenced this pull request Jul 27, 2026
…letion (#500)

* docs: document local_calculate_verdicts --diff-report and per-calculator counters (PR #494)

* docs: document rejudge_fallback_channel compare-and-retract command (PR #495)

* docs: Stage C full-catalog completion record (218,108/218,516, 99.8%)

* docs: document web-ci.yml per-surface CI gating (PR #466)

* docs: fix rejudge_fallback_channel command path (cardpicker/management/commands/)
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