56%

S5 - Safe one-shot drain of parked refs

Goal

S5 - Safe one-shot drain of parked refs.

Implementation Sketch

Design record: plans/commit-push-durability/discussions/01-commit-push-durability/discussion.md. mission.md:15 names scripts/commit_push/design/2026-07-24-durability-redesign-tp-discuss.md; that path does not exist at HEAD and scripts/commit_push/design/ is not a directory. Do not search for it.

Mandatory work ordering — liveness before correctness-of-retirement:

  1. Escalation liveness (w-54c84aba): the crash and the permanent-stranding trap.
  2. Fail-closed path discovery (w-86af6f0c): an empty or undiscoverable path set never maps to exact.
  3. Oracle reconciliation (w-e206f51a), which MUST carry item 2’s cure whichever branch is chosen.
  4. Recovery-namespace design (w-6e270f37 -> w-c84f4b7e -> w-baf26cec -> w-bab17e36 -> w-75cc425e), then falsifier (e) (w-6e2ceeed).

Reconciling the two oracles while entries remain unreachable satisfies w-e206f51a and leaves the mission gate red.

Problem statement — three views that disagree by construction

ViewSeesSource
Parked side-refs359 (264 wrapper + 95 compiler_repo)git for-each-ref refs/commit-push-queue/
Defer-queue entries354 (261 + 93); 5 orphan refs have no entrydefer_queue.list_entries
Entries the drain can act on5 (wrapper); compiler_repo has ZEROqueue_drain._eligible_entries

The gap is the escalation branch: queue_drain.py:345-346 continues past the DRAIN_QUEUED reset at :362-369, _eligible_entries (:111-115) selects queued only, claim_for_drain (defer_queue.py:416) transitions only from queued, and no reaper, timeout, or reclaim path exists. 328 entries sit in draining; 247 wrapper entries carry attempt_count == 6 (DEFAULT_ATTEMPT_CAP 5 + 1).

Production is drain-only: the defer producers were removed in S1, so the parked population is closed and finite. The north-star gate is a bounded drain, not a moving target — but it is unreachable today for ~92% of that population.

Enumeration source contract — ABSOLUTE

  • Every manifest, recovery pass, and queue-zero assertion enumerates via queue_audit.iter_audit_refs (ref-driven, orphan-tolerant, entry_id=None on orphans).
  • defer_queue.list_entries is BANNED as a manifest source: it is entry-driven, blind to the 5 orphan refs, and blind to any entry that has left the eligible set.
  • Queue-zero is declared only when EVERY row of the iter_audit_refs enumeration carries exact-head or an explicit reviewed disposition — never when the eligible set empties.

Git-verb envelope — never widened

  • _ALLOWED_GIT (queue_git.py:49-55), _BANNED_GIT (:58), and FORBIDDEN_AUTOMATIC_GIT_VERBS (shared_tree_safety.py:8-21) are a deliberate safety invariant, mechanically pinned by test_shared_tree_safety.py:87-129 and backed by CLAUDE.md §Git Safety.
  • push / fetch / clone / merge are forbidden to the automatic queue path. Widening the allow-list to satisfy w-c84f4b7e / w-bab17e36 / w-75cc425e is BANNED (INVERTED-TDD:widened-exemption).
  • Compliant shape: a separate, narrowly-scoped recovery module operating on a throwaway clone outside the shared checkout, carrying its own narrower allow-list. Fast-forward landing uses merge-base + update-ref (both already allowed) or an explicit human-reviewed merge outside the automated path.

Oracle reconciliation decision rule

  • The divergence is deliberate and documented on ONE side only: queue_audit.py:79-98 carries the SECOND RETIREMENT ORACLE note; queue_drain.py carries no reciprocal pointer, only an advisory string at :195.
  • queue_drain.py imports only .queue_git; there are zero CALLS edges between the two oracles.
  • Choose exactly one branch and record it:
    • Shared exactness predicate homed in queue_git.py (the community-consistent home — both files already funnel through it), consumed by BOTH queue_audit.drop_ref and queue_drain._drain_one_locked; or
    • Reciprocal comments on both sides PLUS widening the honesty test to assert both directions.
  • A one-sided comment is not a cure — it leaves the drift hazard queue_audit.py:93-97 already names.
  • ABSOLUTE — either branch MUST carry the fail-closed behavioral cure of w-86af6f0c. A reciprocal-comments-only branch does NOT satisfy w-e206f51a: _exact_in_head (queue_drain.py:132-136) returns True on an empty path set WITHOUT invoking git, and _entry_paths (:128-129) reaches that state whenever entry_touched_paths returns [] on git failure (queue_git.py:291-296) and scoped_paths is empty — so _retire_exact dequeues the entry and drops the side-ref. Documentation cannot make an unclassifiable snapshot safe to auto-retire, and the current population’s non-reachability does not satisfy the mission’s terminal invariant.
  • test_queue_audit.py:414 test_second_retirement_oracle_still_matches_this_comment asserts queue_audit does not appear in queue_drain’s source. The shared-predicate branch REDs it BY DESIGN. Rewrite the comment and re-point the assertions in the SAME commit; never delete or weaken the pin, and never file the red as a regression.
  • AUTO_DROPPABLE_VERDICTS membership stays exactly two while factoring. Widening it is the documented silent-loss mode.

Dedup rule

  • Dedup ONLY on tree-OID identity (same parent SHA + same tree SHA), extending defer_path._find_content_duplicate (defer_path.py:76-104).
  • No patch-id and no path/delete-mode-metadata equivalence: that machinery exists nowhere in scripts/commit_push/, and inventing it creates a second unverified duplicate-detection oracle exactly where the mission demands the opposite.
  • Any delta not exactly tree-OID-identical is never auto-deduped; it is preserved as conflict evidence.

Escalation disposition contract

  • An escalated entry MUST reach a named disposition. Reuse the existing terminal DRAIN_QUARANTINED (defer_queue.py:47, already pinned at test_queue_drain.py:191) — terminal for the automatic path, reachable by an explicit recovery command. Inventing a second state is LEAK:scattered-knowledge.
  • Any re-queue-on-escalation carries BOTH loop-safety.md §1 protections: a bounded iteration cap AND a strict-progress fail-safe, failing closed. A naive reset to queued re-claims the same entry every pass forever.
  • claimed_iso (defer_queue.py:69, written at :420) is recorded but read by no consumer — there is no stale-claim timeout to lean on.
  • The escalation message (commit_push_dispatch.py:555-614) currently ends “surfaced for resolution” while naming no resolution. Per diagnostic-ux.md §2 it must name the concrete next command, with a regression pin on the friendly content.
  • ESCALATION_HALT_REASON is carried but never acted on: _thread_drain_summary is additive and never changes the envelope’s action or halt_reason. Decide explicitly whether that stays true.

Ownership boundaries and plan terminus

  • No other plan claims queue_drain.py (symbol-plans _retire_exact -> 0 rows). No cross-plan coordination needed.
  • S5 is the plan’s LAST section: its close fires the plan-wide kind: functional criterion, whose probe_ref is the parked-ref count. Landing S5 without draining the parked refs reads the mission gate RED at close and routes to plan amendment (state-discipline.md §1).
  • Therefore S5’s deliverable includes the one-shot recovery RUN over the already-stranded population, not only the code that would have prevented the accumulation.
  • The two live defects are in queue_drain.py — S5’s own file — so they are S5 scope as preparatory work per CLAUDE.md §Scope Expansion, not new tracker entries. routing.md §2 active-fix containment does not apply (S5 is a plan section, not a /fix-bug run), so a genuinely INDEPENDENT defect discovered here still routes via /add-bug.

Verification and layer coverage

  • Scope is TOOLING (scripts/commit_push/**/*.py) per CLAUDE.md §HYGIENE / CODING RULES SCOPE. L1-L11 are N/A: no .ori corpus, no compiler-runtime surface, no executor parity or leak dimension.
  • L12 production-entry-point is MANDATORY. Every existing test_queue_drain.py pin calls queue_drain.drain_queue directly; none drives /commit-push’s real entry (run_state_machine -> _drain_on_entry_all). The crash lives precisely in that gap. Absent an L12 pin this section closes with LAYER_GAP:production-entry-point (Critical, close-blocking). test_state_machine_wiring.py:439’s literal "escalations": [] is a stub, not coverage.
  • Must-fail-first pins (both reproduced against HEAD; a pin that passes before AND after pins nothing):
    • an escalation-only pass returns a DrainResult and does not raise (today: IndexError at queue_drain.py:379);
    • an escalated entry is reachable by a subsequent pass or a named recovery command (today: permanently draining).
  • The escalation branch has ZERO real coverage: _escalation_record reports covering_tests: 9, direct_tests: 0, and not one of the 9 tests constructs an escalating entry. Transitive reachability is not coverage.
  • Falsifier (e) (w-6e2ceeed) is the dedup/conflict matrix-clamping negative; no dedup or conflict-preservation pin exists today.
  • Small adjacent cleanups to land while in these files: add the drain_one(entry_id=<quarantined>) leg of the quarantine invariant (drain_one bypasses _eligible_entries via its explicit-entry_id path at queue_drain.py:183-187); fix the stale test_state_machine_wiring.py:383/:400 docstrings claiming the gate is disabled by default when commit-push-rules.json has enabled: true; and correct queue_drain.py:342 reading _age_exceeded against the PRE-claim entry while :338/:340 read the post-claim one.
  • The not paths -> True auto-retire branch (queue_drain.py:133-134) is a REQUIRED cure, not a latent note: it is owned by w-86af6f0c and gated by an executable NEGATIVE pin that must FAIL against HEAD today. Adversarially probed — _exact_in_head(NeverCalled(), entry, []) returns True with zero git calls. Reachable whenever entry_touched_paths returns [] on git failure (queue_git.py:291-296) and scoped_paths is empty, after which _retire_exact dequeues the entry and drops the side-ref. S4 hardened exactly this class on the audit side with VERDICT_UNCLASSIFIABLE; the drain side MUST reach parity. Non-reachability for today’s population is NOT a disposition — the pin proves the preserved-and-surfaced behavior directly.

Recon probes and known-dark intel facets

  • Measure before reading code: the entry-state distribution snippet on both repos, and python -m scripts.commit_push queue-audit --repo <path> --json. Their disagreement IS the problem statement.
  • Ordered entry points: queue_drain.py:330-380 (claim/escalate/reset); defer_queue.py:387-431 +:42-53 (the DRAIN_* vocabulary and the absent exit from draining); queue_audit.py:79-98 + :192-277; queue_git.py:49-58 + shared_tree_safety.py:8-21.
  • Intel facets that are DARK for this target — absence here is NOT evidence:
    • ori-platform embedding is NULL (not stale): the similar tier is structurally unavailable for scripts/commit_push/**. Do not run it and do not read its silence as absence-of-duplication.
    • insights stale: communities, surprise-coupling (0 rows), and the MISSING_ABSTRACTION bundle (0 rows pairing the two oracles) cannot corroborate the duplication. The source read plus queue_audit.py:79-98 plus test_queue_audit.py:414 are the COMPLETE evidence base.
    • test_topology stale: positive rows were source-confirmed; covering_tests counts are transitive reachability.
    • co_change stale and 0 rows: no historical blast-radius signal. Use the CALLS adjacency instead.
  • scripts/commit_push/** is indexed under --repo ori-platform, NOT --repo ori; omitting it returns not-indexed.
  • Related open bugs to read before touching lock timing or the apply envelope: BUG-07-532 (apply() drops already-landed commits when a later repo defers — same silent-loss-reported-as-progress shape), BUG-07-256 (flaky concurrent-enqueue under the same flock substrate S5’s 8-thread drain test exercises), BUG-07-444 (that flake’s earlier flock-retry fix).
  • Prior art is in-repo, not cross-corpus: S4’s streaming + fail-closed VERDICT_UNCLASSIFIABLE shape is the pattern the escalation branch mirrors — an unknown or unreachable state gets an explicit named disposition rather than falling through a boolean. No reference-language corpus has an analogue; no sentiment signal exists for these repos.
  • Consume S4’s dossier §0 point 1, §3.1, §5 only. Its §0 points 2 and 3 are OBSOLETE now that S4 landed: the audit CLI derives its exit code from the verdict mix and iter_audit_refs streams.

Constrained symbols — edit only under the stated condition

SymbolCondition
_exact_in_head / _retire_exactS5 owns them, but they are the live auto-retirement surface for 359 parked refs with no confirm gate. Never edit ahead of the liveness fix; a retirement-semantics change shipped first silently retires real work.
AUTO_DROPPABLE_VERDICTSMembership stays exactly two while factoring a shared predicate.
FORBIDDEN_AUTOMATIC_GIT_VERBS / _ALLOWED_GIT / _BANNED_GITNever widened. Cure is a separate scoped module.
test_second_retirement_oracle_still_matches_this_commentREDs by design on the shared-predicate branch; rewrite the comment and re-point the assertions in the same commit. Never delete or weaken.

Work Items

  • Fix drain_queue’s escalation branch (queue_drain.py:330-380) to be safe and terminating — the section’s largest unaddressed hazard, currently unnamed by any existing work item: (a) the all-empty guard at queue_drain.py:375 must not index [-1] into an empty list when escalation is the only outcome of a pass — today it raises an unhandled IndexError on the live production path (state_machine.py:2574 and :2902, no try/except in the call chain, deterministically reachable within days on live queue data) with zero test coverage of the escalation branch (9 tests in test_queue_drain.py, none construct an escalating entry); add a must-fail-first pin reproducing the crash, then fix. (b) An escalated entry must get a reachable disposition instead of being left permanently ‘draining’ forever (the queue_drain.py:362-369 DRAIN_QUEUED reset is skipped by the escalation continue at :345-346, and no reaper/timeout/reclaim path exists anywhere) — reuse the existing terminal DRAIN_QUARANTINED state (defer_queue.py:47, already pinned by test_queue_drain.py:191) rather than inventing a new one, transitioned loop-safely (bounded iteration cap + strict-progress fail-safe per loop-safety.md Sec1) so the automatic path can never re-claim the same entry forever. (c) Run a one-shot recovery pass reclaiming the 328 entries already stuck in ‘draining’ today (247 wrapper + 90 compiler_repo, almost all at attempt_count==6 = cap+1) plus the 5 orphan side-refs with no defer-queue entry — enumerate via queue_audit.iter_audit_refs (ref-driven), not defer_queue.list_entries (entry-driven, blind to orphans and to entries once they leave the eligible set). (d) Fix ESCALATION_HALT_REASON’s user-facing message (commit_push_dispatch.py:555-614, currently ends ‘surfaced for resolution’ naming no resolution) to name the concrete next command, per diagnostic-ux.md, with a regression pin on the friendly content. (e) Add a production-entry-point (L12) pin driving state_machine._drain_on_entry_all end-to-end (every existing pin calls queue_drain.drain_queue directly, none drive the real /commit-push entry point), proving an escalation-only pass does not raise, plus a drain_one(entry_id=) refusal pin (test_queue_drain.py:191 only covers the drain_queue leg of that invariant today, and drain_one’s explicit-entry_id path bypasses the eligibility filter entirely).
  • Make drain-side path discovery FAIL CLOSED: _exact_in_head (queue_drain.py:132-136) returns True on an empty path set WITHOUT invoking git, and _entry_paths (:128-129) falls back to entry.scoped_paths after entry_touched_paths returns [] on git failure (queue_git.py:291-296) — so a ref whose path discovery FAILED is declared exact and _retire_exact dequeues it and drops the side-ref. Adversarially probed: _exact_in_head(NeverCalled(), entry, []) returns True with zero git calls. Cure: an empty or undiscoverable path set MUST NEVER map to exact; it is the drain-side analogue of S4’s VERDICT_UNCLASSIFIABLE and must be preserved and surfaced for review, never auto-retired. Distinguish ‘the diff genuinely touched nothing’ from ‘path discovery failed’ at the source, the way S4 distinguished empty from unclassifiable. Add an executable NEGATIVE pin proving such a ref survives a full drain pass with its side-ref intact and appears in the escalation/review surface; the pin must FAIL against HEAD today. This requirement binds w-e206f51a regardless of which reconciliation branch is chosen — a reciprocal-comments-only branch does NOT satisfy it, because documentation cannot make an unclassifiable snapshot safe to auto-retire.
  • Reconcile queue_drain._exact_in_head/_retire_exact (queue_drain.py:132-139) with S4’s fail-closed exact-in-head/diverged-needs-review audit model: either factor a single shared exactness predicate both queue_audit.drop_ref and queue_drain._drain_one_locked consume, or explicitly document (code comment/design note) why the two legitimately diverge — queue_drain._retire_exact currently auto-retires (dequeues + drops the side-ref) via a single all-paths git diff --quiet boolean with NO confirm gate and ZERO code sharing with queue_audit’s per-file classifier, on the SAME production path /commit-push runs on every invocation via drain_queue (queue_drain.py’s hottest symbol). Consume S4’s intel dossier (plans/commit-push-durability/content/intel/fail-closed-audit—s-f5aef78c.intel.md) sections 0/3.1/5 directly — do not rediscover the duplication independently.
  • Freeze queue mutation; enumerate the full (ref,sha,parent,tree) manifest via queue_audit.iter_audit_refs (S4’s landed, ref-driven, orphan-tolerant streaming enumerator) — not defer_queue.list_entries, which only sees 354 of the 359 parked refs and is blind to the 5 orphan side-refs with no defer-queue entry.
  • Push every exact SHA to refs/commit-push-recovery// and fetch-verify remotely BEFORE any local mutation, implemented in a NEW, narrowly-scoped recovery module outside scripts/commit_push/queue_git.py — push and fetch are BANNED verbs in the queue plumbing’s shared-tree envelope (queue_git.py _BANNED_GIT) and that envelope must never be widened to admit them.
  • Dedup ONLY mechanically-identical deltas via tree-OID identity (same parent SHA + same tree SHA), extending the existing defer_path._find_content_duplicate precedent. Do not invent a patch-id or path/delete-mode-metadata equivalence path — no such machinery exists anywhere in scripts/commit_push/, and inventing one risks a second, unverified duplicate-detection oracle; any delta that is not exactly tree-OID-identical is never auto-deduped and is preserved as conflict evidence.
  • Integrate in a FRESH isolated clone from the pushed target branch, in the same new scoped recovery module as the recovery-namespace push (clone and checkpoint-push are both banned in the queue plumbing’s allow-list); apply each unique delta on a recovery branch in deterministic order; checkpoint-push each; preserve conflicts as evidence.
  • Land the reviewed recovery branch into target using only allowed verbs — prove fast-forward eligibility via merge-base and move the pointer via update-ref (both already in queue_git.py’s _ALLOWED_GIT), or require an explicit human-reviewed manual merge performed outside the automated path; never invoke git merge as an automatic verb (FORBIDDEN_AUTOMATIC_GIT_VERBS, pinned by test_shared_tree_safety.py, and banned by CLAUDE.md Git Safety). Push; re-audit; retire local refs ONLY for exact postimage matches; declare queue-zero only when every manifest row (all refs from the w-6e270f37 iter_audit_refs enumeration, not just defer-queue entries) has exact-head or explicit reviewed disposition.
  • Falsifier (e): mechanically-duplicate + conflicting snapshots -> dedup only mechanically-identical, conflicts preserved

Intel dossier — pointer and tier disposition

Dossier: safe-drain--s-6c240bce.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 tierTitleLinesDispositionWhere / why
00. Bottom line up front24integrated## Implementation Sketch (mandatory work ordering: liveness -> oracle -> recovery namespace, with the explicit statement that reconciling the oracles first leaves the mission gate red); ## Problem statement — three views that disagree by construction; ## Git-verb envelope — never widened (the fourth decision the BLUF flags)
11. The target, verbatim33integrated## Implementation Sketch (corrects the dead mission.md:15 design-file pointer to the discussions/ transcript that actually exists); ## Enumeration source contract; ## Git-verb envelope — never widened; ## Dedup rule (each work item’s live-code verdict folded into the contract it constrains rather than restated per item)
22. Terrain — symbols in the objective area58integrated## Git-verb envelope — never widened (the _ALLOWED_GIT/_BANNED_GIT/FORBIDDEN_AUTOMATIC_GIT_VERBS triad with file:line); ## Oracle reconciliation decision rule (queue_git.py named as the community-consistent home both files funnel through); ## Recon probes and known-dark intel facets (ordered entry points across the four owning files)
33. Code-graph recon109integrated## Oracle reconciliation decision rule (zero CALLS edges, one-sided documentation, the by-design RED of test_queue_audit.py:414 and the same-commit rewrite requirement); ## Recon probes and known-dark intel facets (the —repo ori-platform scoping gotcha; hotspot/churn and CALLS adjacency as the change surface); ## Verification and layer coverage (the escalation branch’s zero real coverage: covering_tests 9 / direct_tests 0)
3L3L. Live-state forensics — what the running system is actually doing76integrated## Problem statement — three views that disagree by construction (the 359/354/5 table, the stranding mechanism with file:line, the attempt_count==6 fingerprint, drain-only production); ## Escalation disposition contract (unread claimed_iso, the non-acting ESCALATION_HALT_REASON, the unactionable message); ## Verification and layer coverage (both reproductions as must-fail-first pins); ## Ownership boundaries and plan terminus (the one-shot recovery RUN as part of the deliverable)
3D3D. Diagnostic / observability surface24integrated## Recon probes and known-dark intel facets (measure-before-reading: the entry-state snippet plus queue-audit —json on both repos, and that their disagreement is the problem statement); ## Enumeration source contract (queue-audit as the only surface reaching all 359 refs). The compiler diagnostic catalogue is excluded by the tier’s own negative relevance gate, recorded in ## Verification and layer coverage as the tooling-scope N/A.
3H3H. Hygiene constraints the S5 design inherits22integrated## Escalation disposition contract (loop-safety.md Sec1 both-protections requirement, DRAIN_QUARANTINED reuse vs LEAK:scattered-knowledge, diagnostic-ux.md message requirement); ## Git-verb envelope — never widened (INVERTED-TDD:widened-exemption); ## Oracle reconciliation decision rule (symmetric SSOT cure); ## Verification and layer coverage (tooling-scope L1-L11 N/A with reason, L12 mandatory and close-blocking, must-fail-first falsifiers); ## Ownership boundaries and plan terminus (scope-expansion vs /add-bug routing)
44. Cluster / family22integrated## Recon probes and known-dark intel facets (BUG-07-532, BUG-07-256, BUG-07-444 named with why each bears on S5 and when to read them); ## Verification and layer coverage (S4’s landed surfaces as the substrate); plus the explicit obsolescence note on S4 dossier §0 points 2 and 3
55. Conformance audit — MISSING_ABSTRACTION (stale facet; nominations only)24integrated## Recon probes and known-dark intel facets (MISSING_ABSTRACTION pairs zero rows across the two oracles, and the directive that this is a three-way graph blind spot rather than evidence of no duplication — so the source read plus the comment plus the honesty test are the COMPLETE evidence base)
66. Plan ownership — clean, with one intra-plan dependency15integrated## Ownership boundaries and plan terminus (no cross-plan claim on queue_drain.py; S5 as the plan’s last section whose close fires the plan-wide functional criterion; the consequence that landing without draining reads RED and routes to amendment)
77. Prior art — N/A (verified, not assumed)7integrated## Recon probes and known-dark intel facets (records prior art as in-repo only — S4’s streaming fail-closed VERDICT_UNCLASSIFIABLE shape as the pattern the escalation branch mirrors — and states that no reference-language corpus has an analogue, so the N/A is verified rather than assumed)
88. Sentiment — N/A5integrated## Recon probes and known-dark intel facets (states no sentiment signal exists or could exist for these repos, so the tier’s silence is not a gap a later pass should try to fill)
99. Declared coverage gaps31integrated## Recon probes and known-dark intel facets (the DARK-facet list: embedding NULL not stale, insights/test_topology/co_change stale, each with what may and may not be inferred); ## Implementation Sketch (the missing design file); ## Constrained symbols — edit only under the stated condition (the constrained-symbols block with its per-symbol condition); ## Verification and layer coverage (the latent not-paths auto-retire branch and the stale test_state_machine_wiring docstrings)
1010. Recommended recon entry points (ordered)23integrated## Recon probes and known-dark intel facets (measure-first directive plus the ordered entry points); ## Verification and layer coverage (write the two must-fail pins FIRST; the drain_one quarantine leg, the stale-docstring fix, and the _age_exceeded pre-claim ordering as small adjacent cleanups); ## Enumeration source contract (iter_audit_refs as the manifest source); ## Oracle reconciliation decision rule (decide the branch at queue_audit.py:79-98)