S4 - Fail-closed streaming audit
Goal
S4 - Fail-closed streaming audit.
Implementation Sketch
Mission anchor: mission.md north-star gate. The tp-discuss design file mission.md cites (scripts/commit_push/design/2026-07-24-durability-redesign-tp-discuss.md) does NOT exist at HEAD — do not wait on it or treat it as readable spec; the work items plus the contracts below are the executable design.
Verified live starting state — re-verify against source before editing, never from memory:
- DEFECT —
cli._run_queue_auditreturnsEXIT_OKon every path (cli.py:765JSON,cli.py:768empty-queue,cli.py:781terminal) regardless of verdict mix. Fail-closed is NOT implemented at the CLI boundary today; the only nonzero exit available is an uncaught Python exception. - DEFECT —
queue_audit.audit_refsfully BUFFERS: buildsout: list[RefAudit](queue_audit.py:143), appends per ref (:161), returns only after the loop closes (:170). Nothing prints until every ref is classified, so an interrupted audit yields NOTHING — not a partial fail-closed report. Falsifier (d) cannot pass against this shape. - COST — per ref:
2 + 3Fsubprocess spawns (F = files the ref touches):_rev_parse+entry_touched_paths+_subject, then_classify_file(queue_audit.py:105) x F, each running 3_blob_oid(:97). At the live depth (264 parked refs in the wrapper, 95 incompiler_repoat recon time) that is 1000+ spawns before the first line of output. Streaming fixes visibility and interrupt-safety; batching_blob_oid(git cat-file --batch-check-style) is a SEPARATE wall-clock lever — out of scope unless streaming alone leaves the run unusable. - ALREADY CORRECT — do NOT re-implement, widen, or weaken:
AUTO_DROPPABLE_VERDICTS == frozenset({landed, empty})(queue_audit.py:55); superseded-but-not-missing already classifiesVERDICT_DIVERGED(:152-158);drop_ref’s gate refuses any non-auto-droppable verdict withoutconfirm=True(:260);test_superseded_change_classifiedis already aligned to that sound behavior. S4 adds streaming, an unclassifiable branch, and the CLI exit code — it does NOT author a new classifier. - DESIGN NOTE —
drop_refre-audits the FULL ref set to drop ONE ref (queue_audit.py:256). After the streaming rewrite that pays the whole streaming cost for a single ref: either narrow the fresh re-audit to the target ref or record in-code why the full re-audit is the fail-closed choice.
Verdict model
Rename the four verdict constants (queue_audit.py:45-48) to the plan vocabulary. Leave the per-file vocabulary (FILE_LANDED_EXACT / FILE_SUPERSEDED / FILE_MISSING, queue_audit.py:57-59) and _classify_file’s three-way blob logic unchanged.
| Today | After S4 | Auto-retires without confirm |
|---|---|---|
landed | exact-in-head | yes |
empty | empty | yes |
diverged | diverged-needs-review | NEVER |
unique | missing | NEVER |
| (does not exist) | unclassifiable (new) | NEVER |
- Rename the members inside
AUTO_DROPPABLE_VERDICTSwithout widening it — membership stays exactly two. - Re-point the existing negative pin (
test_superseded_change_classified) at the renamed constant; the rename must not silently un-pin the diverged-never-auto-drops guarantee. - Add
unclassifiableas a NAMED branch — a git-command failure inside_classify_file/_subject/_rev_parseappends an explicit unclassifiable record. A bare traceback is not the unclassifiable path. - Per
diagnostic-ux.md, an unclassifiable line names the cause (which ref; unresolvable side-ref vs failed git command) AND the next step (queue-extractfirst, then re-runqueue-audit). A bareunclassifiabletoken is not acceptable output.
Exit-code contract
_run_queue_audit (cli.py:757) derives its exit from the verdict mix, never a constant. Codes come from the existing enum (cli.py:63-71) or extend it.
| Observed verdict mix | Exit |
|---|---|
every ref in AUTO_DROPPABLE_VERDICTS (exact-in-head / empty), or zero refs parked | EXIT_OK |
any diverged-needs-review or missing | distinct nonzero — review needed; not an error, never a silent success |
any unclassifiable, or the audit ended before every ref was reached | further distinct nonzero |
--jsoncarries the SAME exit code as the human path; the JSON body staysRefAudit.to_dict()-compatible or is deliberately versioned.- A ref never reached is never reported
emptyor clean — unreached is fail-closed, not absent.
Ownership boundaries
- S4 owns
scripts/commit_push/queue_audit.py, thequeue-auditsurface inscripts/commit_push/cli.py, andscripts/commit_push/tests/test_queue_audit.py. queue_drain._exact_in_head/_retire_exact(queue_drain.py:132-139) is a SECOND, independent auto-retirement oracle: one all-pathsgit diff --quiet <ref> HEAD -- <paths>boolean, NO confirm gate, ZERO code sharing withqueue_audit(queue_drain.pyimports only.queue_git), sitting on the path/commit-pushruns on EVERY invocation viadrain_on_entry->drain_queue.- S4 does NOT modify
queue_drain.py. Renamingqueue_audit’s verdicts changes NOTHING about that surface’s behavior — assuming otherwise is this section’s primary false-safety risk. - S4’s only action on it is
w-93aa788f: an in-code cross-reference comment inqueue_audit.py, so the two-oracle situation is visible where S4 works. - Reconciliation (a shared exactness predicate both
drop_refandqueue_drain._drain_one_lockedconsume, or a documented reason to diverge) belongs to S5safe-drain(s-6c240bce) work itemw-e206f51a— plan boundaries are implementation boundaries. - Preserve-constraints, do not disturb as a side effect:
drain_on_entryand the parked-queue machinery S5 depends on;AUTO_DROPPABLE_VERDICTSmembership;_classify_file’s classification logic.
Verification and layer coverage
scripts/commit_push/** is TOOLING scope per CLAUDE.md §HYGIENE / CODING RULES SCOPE — compiler layers L1-L11 are N/A: wrapper Python tooling, with no compiler pipeline, executor, or .ori corpus surface. The binding requirements:
- L12 production entry point — MANDATORY. No test today drives
cli._run_queue_auditor thequeue-auditsubprocess; every existing pin callsqa.audit_refs()/qa.drop_ref()directly, so the always-EXIT_OKdefect is untestable by the current suite even in principle. A pin that drives_run_queue_audit(or the subprocess) and asserts the exit code is required; a green suite resting only onaudit_refs()isLAYER_GAP:production-entry-point. - Falsifier (c) pin — a diverged ref (HEAD evolved past the parked change, one file superseded) classifies
diverged-needs-reviewANDdrop_ref(confirm=False)refuses it. Porttest_superseded_change_classified’s fixture; re-point the assertion at the renamed constant. - Falsifier (d) pin — a
runnerstub raising after N refs asserts: (a) the already-classified refs’ lines are present in stdout, (b) the exit code is nonzero, (c) no unreached ref is reportedemptyor clean. loop-safety.md— NOT triggered: the iteration source stays the boundedlist_side_refs()result; a generator/streaming rewrite introduces no unbounded or non-advancing loop.- SRP/SSOT still bind (
LEAK:algorithmic-duplicationacross the two exactness oracles) — discharged in S4 byw-93aa788f’s cross-reference, closed by S5’sw-e206f51a.
Work Items
- Rewrite queue-audit to stream one record per ref with progress
- Split verdicts: exact-in-head | diverged-needs-review | missing | empty
- Only exact-in-head|empty auto-retire; drop_ref(confirm=False) permits only those two; superseded/diverged NEVER auto-drop
- Document, in a code comment in queue_audit.py near AUTO_DROPPABLE_VERDICTS/drop_ref, the relationship between this section’s exact-in-head/diverged-needs-review verdict model and queue_drain._exact_in_head’s separate, ungated auto-retirement predicate (queue_drain.py:132-139, owned by S5 safe-drain, s-6c240bce) — so the two-oracle situation is visible in the code S4 owns and S5 does not have to rediscover it independently when it starts. Do NOT modify queue_drain.py in this section; that reconciliation is S5’s (queue_drain.py owner) decision per plan-boundaries=impl-boundaries.
- Exit nonzero on any unclassifiable ref (fail-closed)
- Wire _run_queue_audit’s (cli.py:757) exit code to the audit’s actual verdict mix, not a constant EXIT_OK: return EXIT_OK only when every audited ref’s verdict is in AUTO_DROPPABLE_VERDICTS (exact-in-head or empty); return a distinct nonzero code when any ref classifies diverged-needs-review or missing (review needed, not an error, but never a silent-success exit); return a further distinct nonzero code when any ref is unclassifiable — add a named unclassifiable branch (a git-command failure inside _classify_file/_subject/_rev_parse) that appends an explicit unclassifiable record instead of the only path today, an uncaught exception. Pin the fix with a test that drives _run_queue_audit itself (or the queue-audit subprocess), not just audit_refs() — today’s suite (12 tests) exercises only the library function and would pass unchanged even with the exit-code bug present, per layer-coverage.md L12 production-entry-point.
- Falsifier (c): diverged-file-omitting-parked -> diverged-needs-review never auto-dropped
- Falsifier (d): interrupt-audit -> streamed fail-closed nonzero, never empty-looks-clean
Recon probes and known coverage gaps
- Run BEFORE touching code:
python -m scripts.commit_push queue-audit --repo .— feel the buffering and the always-0 exit directly. Thenpython -m scripts.commit_push queue-audit --repo . --json— theRefAudit.to_dict()shape the rewrite must preserve or deliberately version. - Queue depth is the plan’s north-star metric:
git for-each-ref refs/commit-push-queue/ | wc -l(264 wrapper, 95compiler_repoat recon time). compiler_repo/diagnostics/and theORI_*env-var catalogue are NOT relevant here — this section has no compiler-runtime surface. The queue probes above ARE the diagnostic surface.- Intel-graph facets are STALE for this surface:
insights,sibling_divergence(MISSING_ABSTRACTION),co_change,test_topology.test-posturereports zero covering tests foraudit_refs— a proven false negative; use rawCALLS-inbound-from-test edges as ground truth for this file. - The two-oracle finding is a graph BLIND SPOT, not a recoverable stale-facet miss:
queue_drain._exact_in_headhas no embedding, noCALLSedge to or fromqueue_audit, and the cross-fileMISSING_ABSTRACTIONquery returns zero rows. Direct source read is the only route to it — do not expect aninsightsrefresh to resurface it, and do not treat graph silence as absence. - No bug-tracker entry is filed against this plan (proactive hardening). The identical silent-loss-reported-as-success shape is currently OPEN in
tooling-cli— BUG-07-532, BUG-07-543, BUG-07-522, BUG-07-442, BUG-07-239 — corroboration that the fail-closed requirement is not hypothetical, not work items for this section. - Prior art and sentiment are verified-absent, not unexamined: the reference-language corpora are compiler trees with no analogue for a parked-git-ref audit (top cross-repo
similarhit is semantic noise), andori/ori-platformcarry zero indexed issues. Do not re-spend recon there. - No other plan claims this code (
symbol-plansreturns zero hits foraudit_refs/_classify_file/_exact_in_head). The only ownership coordination is the intra-plan S4 -> S5 handoff above.
Intel dossier — pointer and tier disposition
Dossier: fail-closed-audit--s-f5aef78c.intel.md (this section’s content/intel/ sidecar)
Read that dossier from line 1 through EOF before acting on this section. This block is a pointer and an audit record, never a substitute: not the BLUF, not a summary, not selected tiers.
| Dossier tier | Title | Lines | Disposition | Where / why |
|---|---|---|---|---|
| 0 | 0. Bottom line up front | 20 | integrated | ## Implementation Sketch (the two VERIFIED live defects: cli._run_queue_audit always EXIT_OK at cli.py:765/:768/:781, and audit_refs fully buffering at queue_audit.py:143/:161/:170 so falsifier (d) cannot pass); ## Ownership boundaries (the second ungated auto-retirement oracle queue_drain._exact_in_head/_retire_exact and the S4-records / S5-reconciles split); ## Exit-code contract (the verdict-mix-derived exit that replaces the constant); ## Implementation Sketch ALREADY CORRECT bullet (AUTO_DROPPABLE_VERDICTS == {landed, empty}, VERDICT_DIVERGED classification, aligned superseded pin — do not re-implement) |
| 1 | 1. The target, verbatim | 21 | integrated | ## Implementation Sketch — mission anchor stated and the dangling pointer removed: the section no longer defers to the tp-discuss transcript, and records that scripts/commit_push/design/2026-07-24-durability-redesign-tp-discuss.md does not exist at HEAD, so the work items plus this section’s contracts ARE the executable design |
| 2 | 2. The terrain — symbols in the objective area (with files) | 49 | integrated | ## Implementation Sketch, ## Verdict model, ## Exit-code contract, ## Ownership boundaries — every constraint now carries its own file:line pointer (queue_audit.py:45-48/:55/:57-59/:97/:105/:143/:152-158/:161/:170/:256/:260; cli.py:63-71/:757/:765/:768/:781; queue_drain.py:132-139) instead of naming symbols abstractly |
| 3 | 3. Code-graph recon | 74 | integrated | ## Ownership boundaries (zero CALLS edges and zero imports between queue_drain and queue_audit; drain_on_entry -> drain_queue is the every-invocation path); ## Verification and layer coverage (test coverage read from raw CALLS-inbound edges: no test drives cli._run_queue_audit); ## Implementation Sketch (the 2+3F subprocess cost per ref, streaming vs batching as separate levers, and the drop_ref full-re-audit design note at queue_audit.py:256) |
| 3D | 3D. Diagnostic / observability surface | 19 | integrated | ## Recon probes and known coverage gaps — the queue-audit human/—json runs and the refs/commit-push-queue count are named as this section’s diagnostic surface, with the explicit statement that compiler_repo/diagnostics and the ORI_* catalogue do not apply here |
| 3H | 3H. Hygiene constraints | 17 | integrated | ## Verification and layer coverage (tooling scope so L1-L11 are N/A with the reason stated; L12 production-entry-point MANDATORY with the LAYER_GAP consequence; falsifier (c)/(d) pins as the matrix-clamping negatives; loop-safety.md explicitly not triggered; SRP/SSOT LEAK:algorithmic-duplication routed to w-93aa788f then S5’s w-e206f51a); ## Verdict model (diagnostic-ux.md requirement that an unclassifiable line names cause and next step) |
| 4 | 4. Cluster / family — the open-bug shape this section exists to close | 22 | integrated | ## Recon probes and known coverage gaps (the five open tooling-cli bugs recorded as corroboration of the failure shape, explicitly not work items here); ## Ownership boundaries (the sibling-section handoff to S5 safe-drain s-6c240bce w-e206f51a) |
| 5 | 5. Conformance audit — MISSING_ABSTRACTION (graph-computed, ori-platform-only, stale facet) | 19 | integrated | ## Recon probes and known coverage gaps — the two-oracle finding recorded as a graph BLIND SPOT (no embedding on _exact_in_head, no CALLS edge, zero cross-file MISSING_ABSTRACTION rows), with the directive not to treat graph silence as absence; ## Ownership boundaries carries the LEAK:algorithmic-duplication consequence |
| 6 | 6. Plan ownership — clean territory | 13 | integrated | ## Recon probes and known coverage gaps (symbol-plans returns zero hits; no competing plan claim) and ## Ownership boundaries (the only coordination is the intra-plan S4 -> S5 handoff) |
| 7 | 7. Prior art — N/A (verified, not assumed) | 10 | integrated | ## Recon probes and known coverage gaps — prior art recorded as verified-absent (reference-language corpora are compiler trees with no analogue; top cross-repo similar hit is semantic noise) with the directive not to re-spend recon there |
| 8 | 8. Sentiment — N/A (no issue linkage; ori/ori-platform carry zero indexed issues) | 5 | integrated | ## Recon probes and known coverage gaps — same bullet: ori/ori-platform carry zero indexed issues, so no sentiment signal exists or can exist; recorded so it is not re-attempted |
| 9 | 9. Declared coverage gaps | 16 | integrated | ## Recon probes and known coverage gaps (insights / sibling_divergence / co_change / test_topology staleness, the proven test-posture false negative on audit_refs, and the graph blind spot); ## Implementation Sketch (the missing tp-discuss design doc gap) |
| 10 | 10. Recommended recon entry points | 28 | integrated | ## Recon probes and known coverage gaps (run queue-audit first, both human and —json, plus the ref-count north-star probe); ## Implementation Sketch (audit_refs as the streaming rewrite target preserving _classify_file); ## Verdict model (the rename map plus the deliberate unclassifiable branch); ## Exit-code contract (wire _run_queue_audit to the verdict mix); ## Verification and layer coverage (the falsifier (c) and (d) pin shapes and the L12 CLI pin); ## Ownership boundaries (decide-and-document the _classify_file vs _exact_in_head relationship before S4 closes) |