Skip to content

Code-enforced guard: require a matching prior dry-run before accepting --write for the same selector/cohort #362

Description

@WilfordGrimley

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions