Process-discipline gap found and documented in docs/features/catalog-completion-plan.md, currently enforced only by a runbook rule, not by code.
What happened. During the 2026-07-21 recovery arc, one state-clear step (reparse_collector_evidence --selector no-text ...) ran straight to --write with no preceding dry-run — the one place in that whole runbook this happened, skipped as "redundant" because the selector "should be mechanical." That was also the one step whose omission caused a real, silent scope gap: a 3,032-card cohort was missed entirely by a later pass, only caught by re-reading the runbook afterward, not by any automated check.
The binding rule this produced (runbook-only today). A dry-run of the exact same selector/run-id/card-ids-file invocation is mandatory before its corresponding --write — no exceptions for a selector that "should be mechanical." This is documented process discipline, not a code-enforced gate.
What to build. A guard in the relevant management command(s) that refuses --write for a given selector/cohort unless it can find evidence of a matching prior dry-run for that exact invocation (e.g. a recent PilotRunLedger row with the same command/selector/scope and dry_run=True) — turning today's honor-system rule into something that fails loudly instead of silently.
Prerequisites. None blocking; this only needs a design decision on what "matching prior dry-run" means precisely (same selector + same cohort scope + some freshness window) before implementation.
Gate points. Needs its own test coverage (a case where the guard correctly refuses a write with no prior dry-run, and a case where it correctly allows one with a matching prior dry-run) before landing, same as every other safety mechanism in this pipeline.
Source: docs/features/catalog-completion-plan.md, the "3. State-clear safety" section.
Process-discipline gap found and documented in
docs/features/catalog-completion-plan.md, currently enforced only by a runbook rule, not by code.What happened. During the 2026-07-21 recovery arc, one state-clear step (
reparse_collector_evidence --selector no-text ...) ran straight to--writewith no preceding dry-run — the one place in that whole runbook this happened, skipped as "redundant" because the selector "should be mechanical." That was also the one step whose omission caused a real, silent scope gap: a 3,032-card cohort was missed entirely by a later pass, only caught by re-reading the runbook afterward, not by any automated check.The binding rule this produced (runbook-only today). A dry-run of the exact same selector/run-id/card-ids-file invocation is mandatory before its corresponding
--write— no exceptions for a selector that "should be mechanical." This is documented process discipline, not a code-enforced gate.What to build. A guard in the relevant management command(s) that refuses
--writefor a given selector/cohort unless it can find evidence of a matching prior dry-run for that exact invocation (e.g. a recentPilotRunLedgerrow with the same command/selector/scope anddry_run=True) — turning today's honor-system rule into something that fails loudly instead of silently.Prerequisites. None blocking; this only needs a design decision on what "matching prior dry-run" means precisely (same selector + same cohort scope + some freshness window) before implementation.
Gate points. Needs its own test coverage (a case where the guard correctly refuses a write with no prior dry-run, and a case where it correctly allows one with a matching prior dry-run) before landing, same as every other safety mechanism in this pipeline.
Source:
docs/features/catalog-completion-plan.md, the "3. State-clear safety" section.