Gate crash records a nil-verdict completion and wedges the implementation #470

Closed
opened 2026-08-21 18:38:16 +00:00 by jared · 3 comments
Owner

Context

During the #467 drive, a gate harness error (TargetSelectionError) during os-sdlc-runner subagent-stop left the completion recorded with verdict nil. next then fails permanently with unroutable_verdict: no nil edge declared from "test-writer"; the only recovery is a fresh implementation-open and full replay (two implementations wedged this way in one session). completion_intake.rb settles the verdict (settle_verdict, :122-124) after the completion row exists, so any raise inside gate execution strands the row. Wanted: fail-loud atomicity — either the completion records with a settled verdict, or the crash leaves the dispatch pending/abortable with clear details, never a routable-nowhere nil.

Skeptic verdict: CREATE — real observed failure, design gap in completion_intake.rb crash atomicity, fail-loud floor issue.

Origin

  • Trigger: #467 first supervised POODR-map drive, gate crash at test-writer (2026-08-21); reproduction inline above.
  • Improvised this session: fresh implementation-open + manual replay of recorded handoffs.
  • Chain: wedged implementation ← nil-verdict completion row ← verdict settled after row insert (completion_intake.rb:122-124) ← DESIGN (no ADR covers crash-during-gate atomicity).
  • Root candidate: this ticket.
## Context During the #467 drive, a gate harness error (TargetSelectionError) during os-sdlc-runner subagent-stop left the completion recorded with verdict nil. next then fails permanently with unroutable_verdict: no nil edge declared from "test-writer"; the only recovery is a fresh implementation-open and full replay (two implementations wedged this way in one session). completion_intake.rb settles the verdict (settle_verdict, :122-124) after the completion row exists, so any raise inside gate execution strands the row. Wanted: fail-loud atomicity — either the completion records with a settled verdict, or the crash leaves the dispatch pending/abortable with clear details, never a routable-nowhere nil. Skeptic verdict: CREATE — real observed failure, design gap in completion_intake.rb crash atomicity, fail-loud floor issue. ## Origin - Trigger: #467 first supervised POODR-map drive, gate crash at test-writer (2026-08-21); reproduction inline above. - Improvised this session: fresh implementation-open + manual replay of recorded handoffs. - Chain: wedged implementation ← nil-verdict completion row ← verdict settled after row insert (completion_intake.rb:122-124) ← DESIGN (no ADR covers crash-during-gate atomicity). - Root candidate: this ticket.
Author
Owner

ADR-0140 (detached gate settlement) changes this wedge's surface: a completed dispatch with a nil verdict and a dead settlement now fails loudly via Settlement::Unsettled naming the dispatch and log path, instead of unroutable_verdict. Skeptic-rejected follow-up recorded here per its verdict: a settle-gates --retry re-queue path was proposed and DROPPED (better-seam: recovery design belongs to this ticket; ADR-0132 tension). When this ticket is designed, weigh re-running settlement for a verdict-less completed dispatch against the one-path-through-the-map rule.

ADR-0140 (detached gate settlement) changes this wedge's surface: a completed dispatch with a nil verdict and a dead settlement now fails loudly via Settlement::Unsettled naming the dispatch and log path, instead of unroutable_verdict. Skeptic-rejected follow-up recorded here per its verdict: a settle-gates --retry re-queue path was proposed and DROPPED (better-seam: recovery design belongs to this ticket; ADR-0132 tension). When this ticket is designed, weigh re-running settlement for a verdict-less completed dispatch against the one-path-through-the-map rule.
jared closed this issue 2026-08-23 12:33:03 +00:00
Author
Owner

Closed via code-probe verification (agent ad6001728e920c751, model claude-sonnet-5, 2026-08-23).

The wedge this ticket describes (a raise inside gate execution stranding a nil-verdict completion row, requiring fresh implementation-open + full replay to recover) was real when filed on 2026-08-21, but has since been designed around:

  • ADR-0140 (now Superseded) named this exact defect ("the #470 wedge") and introduced detached gate settlement with a Settlement::Unsettled loud-exit path.
  • ADR-0141 (Accepted, 2026-08-22) superseded ADR-0140 by moving gate execution in-turn — agents invoke the runner-owned gate CLI before stopping — which removes the async crash window entirely. SubagentStop is now a presence check, not a settlement point.

The file:line citation in the ticket body (completion_intake.rb:122-124) is also stale; settle_verdict now lives at line 97 with the same structural ordering, unaffected by the fix.

Closing as superseded. Follow-up: confirm whether plugins/os-sdlc/lib/os_sdlc/runner/gate_settlement.rb is dead ADR-0140 scaffolding that should be removed.

Closed via code-probe verification (agent ad6001728e920c751, model claude-sonnet-5, 2026-08-23). The wedge this ticket describes (a raise inside gate execution stranding a nil-verdict completion row, requiring fresh implementation-open + full replay to recover) was real when filed on 2026-08-21, but has since been designed around: - ADR-0140 (now Superseded) named this exact defect ("the #470 wedge") and introduced detached gate settlement with a Settlement::Unsettled loud-exit path. - ADR-0141 (Accepted, 2026-08-22) superseded ADR-0140 by moving gate execution in-turn — agents invoke the runner-owned gate CLI before stopping — which removes the async crash window entirely. SubagentStop is now a presence check, not a settlement point. The file:line citation in the ticket body (completion_intake.rb:122-124) is also stale; settle_verdict now lives at line 97 with the same structural ordering, unaffected by the fix. Closing as superseded. Follow-up: confirm whether plugins/os-sdlc/lib/os_sdlc/runner/gate_settlement.rb is dead ADR-0140 scaffolding that should be removed.
Author
Owner

Follow-up resolved 2026-08-23 (verification agent a858bb96d23f91824, claude-sonnet-5) — no code change needed.

Correction to my earlier closing comment: gate_settlement.rb is NOT dead code. It is the live implementation of the ADR-0141 in-turn gate mechanism itself, not leftover ADR-0140 scaffolding:

  • plugins/os-sdlc/lib/os_sdlc/runner/gate_settlement.rb:6 defines GateSettlement, whose header states it runs a dispatch's map-declared gates 'in the calling agent's own turn' — this is the ADR-0141 design, built to replace hook-based settlement after hooks were timing out on slow gate operations (test runs, etc.).
  • round_commands.rb:40-44 (RoundCommands.gate) calls GateSettlement.call and rescues GateSettlement::Failed / GateSettlement::UnknownDispatch.
  • cli.rb:8,41-42 wires the 'gate' CLI subcommand (os-sdlc-runner gate DISPATCH_ID) to RoundCommands.gate — the runner-owned gate CLI agents now call as their final tool call before stopping.
  • subagent_stop.rb:7-9 confirms the split: gates already ran in-turn, so SubagentStop is reduced to a millisecond presence check.

I also named the wrong class in my earlier comment (Settlement::Unsettled). That constant never existed in this codebase; the real ADR-0140 artifact was GateSettlement::UnknownDispatch/Failed, and both are still in active use under the new architecture — they were carried forward, not superseded.

No file needs deletion. Closing this follow-up with no action taken.

Follow-up resolved 2026-08-23 (verification agent a858bb96d23f91824, claude-sonnet-5) — no code change needed. Correction to my earlier closing comment: gate_settlement.rb is NOT dead code. It is the live implementation of the ADR-0141 in-turn gate mechanism itself, not leftover ADR-0140 scaffolding: - plugins/os-sdlc/lib/os_sdlc/runner/gate_settlement.rb:6 defines GateSettlement, whose header states it runs a dispatch's map-declared gates 'in the calling agent's own turn' — this is the ADR-0141 design, built to replace hook-based settlement after hooks were timing out on slow gate operations (test runs, etc.). - round_commands.rb:40-44 (RoundCommands.gate) calls GateSettlement.call and rescues GateSettlement::Failed / GateSettlement::UnknownDispatch. - cli.rb:8,41-42 wires the 'gate' CLI subcommand (os-sdlc-runner gate DISPATCH_ID) to RoundCommands.gate — the runner-owned gate CLI agents now call as their final tool call before stopping. - subagent_stop.rb:7-9 confirms the split: gates already ran in-turn, so SubagentStop is reduced to a millisecond presence check. I also named the wrong class in my earlier comment (Settlement::Unsettled). That constant never existed in this codebase; the real ADR-0140 artifact was GateSettlement::UnknownDispatch/Failed, and both are still in active use under the new architecture — they were carried forward, not superseded. No file needs deletion. Closing this follow-up with no action taken.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#470
No description provided.