Skip to content

feat(subagent): classify terminal subagent failures with typed record - #1391

Merged
TheGreatAxios merged 3 commits into
mainfrom
cl-10202-surface-terminal-subagent-provider-failures-with-actionable
Oct 13, 2026
Merged

TheGreatAxios merged 3 commits into
mainfrom
cl-10202-surface-terminal-subagent-provider-failures-with-actionable

Conversation

@bwachman

@bwachman bwachman commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

PR 1 of 2: classification and record (stack base)

This is PR 1 of the two-PR CL-10202 delivery. It adds typed failure classification and the failure record, with no behavior change to spawning. The stacked follow-up PR 2 (enforced recovery, recovers on spawn_agent) builds on this branch.

Summary

  • Records every terminal subagent/provider failure as a typed terminal_failure record with a failure_class field, replacing prose-parsed failure strings.
  • Distinguishes terminal failure status from ordinary provider error paths in fleet dispatch and session state.
  • Classifies doom-loop worker stops as loop_guard, distinct from provider-level failures.
  • Releases wait/occupancy exactly once during terminal cleanup and ignores late events.
  • Delivers a handoff only when a typed failure record exists as evidence.
  • No behavior change to spawning: recovery.available mirrors today's continuable (invariant continuable === recovery.available) and the continue_with text is unchanged.

Verification

After the rebase onto main and the review fixes, CI passes on 3dbdbc3; the results below are from the original verification.

Gates run independently on tip 9a71c76 (exit code 0 everywhere):

Gate Result
bun install 0 (workspace resolves)
bun run typecheck 0
bun run lint 0 (0 warnings, 0 errors)
bun run check:dead-exports 0 (0 violations)
bun test ./src/subagent --randomize --seed 424242 0 (848 pass / 0 fail / 53 files)
bun run build 0
repo-wide bun test 0 (8629 pass / 0 fail / 558 files)

AC to code and test mapping

  • AC1 typed failure_class, no prose parsing: src/subagent/terminal-failure.ts:13-22,111-124 + src/subagent/fleet-terminal-failure.test.ts:63-119
  • AC2 status distinguishes terminal failure: src/subagent/agent-fleet.ts:457-475,1683-1693 + src/subagent/fleet-terminal-failure.test.ts:293-373
  • AC4 loop_guard distinct from provider: src/subagent/run.ts:1512-1518,689-694 + src/subagent/terminal-failure.ts:115 + src/subagent/run-loop-guard.test.ts:104-150 + src/subagent/terminal-failure.test.ts:43-56
  • AC5 cleanup releases wait/occupancy once, late events ignored: src/subagent/session-store.ts:824-860,1735-1792 + src/subagent/fleet-terminal-failure.test.ts:153-291 + src/subagent/session-store-failure-record.test.ts:401-483 + src/subagent/run-terminal-cleanup.test.ts
  • AC8 handoff never delivered without evidence: src/subagent/session-store.ts:756-757,1643-1649,2043,2106 + src/subagent/session-store-failure-record.test.ts:254-340
  • AC9 deterministic mocked tests, no real credentials: all listed test files

Deferred / Notes

  • Enforcement of recovery (spawn_agent recovery argument, replay-safety tracking, idempotent claim, chain cap one, D7 authority) is PR 2 (enforced recovery), the follow-up PR stacked on this branch.
  • Non-goals: user-facing recovery command, fleet-record persistence, CL-10200 WORKER WAITING strip, CL-10206 stall policy, watchdog behavior.

Refs CL-10202

@linear-code

linear-code Bot commented Oct 10, 2026

Copy link
Copy Markdown

CL-10202

@bwachman
bwachman force-pushed the cl-10202-surface-terminal-subagent-provider-failures-with-actionable branch from 9a71c76 to 633c75a Compare October 11, 2026 20:18
@bwachman
bwachman force-pushed the cl-10202-surface-terminal-subagent-provider-failures-with-actionable branch from d4ad7ef to 3347ae6 Compare October 11, 2026 20:50
@bwachman
bwachman changed the base branch from main to cl-10469-surface-off-tag-build-identity-in-tui-version-badge October 11, 2026 20:50
Comment thread src/subagent/session-store.ts Resolved
Comment thread src/subagent/agent-fleet.ts Resolved

@TheGreatAxios TheGreatAxios left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typed failure record implemented as claimed — classification, once-only cleanup, handoff gating, and the no-spawn-behavior-change invariant all verified (904/0 subagent suite). Three items: follow-up-turn failures bypass the classifier (should-fix — same failure records 'interrupted' via send_input vs 'provider_retryable' via resume_agent), ~270 comment-only lines referencing unrelated tickets, and the body's AC-to-code line map is stale after the rebase.

AC2 cites agent-fleet.ts:2168-2176 (past EOF; file is 2146 lines; actual 487-505/2123); AC8 cites session-store.ts:1690-1702 (actual handoff evidence 1589-1600); AC4/AC5 shifted after rebase (run.ts:692-694; session-store.ts:790-818). Refresh the map at head.
Plain: the description's line references point at the wrong places — one past the end of the file — after a rebase. Update them.

Comment thread src/subagent/terminal-failure.ts Resolved
Comment thread src/subagent/session-store.ts Resolved
@bwachman
bwachman force-pushed the cl-10469-surface-off-tag-build-identity-in-tui-version-badge branch from 30e4eca to fb9b903 Compare October 13, 2026 00:50
@bwachman
bwachman force-pushed the cl-10202-surface-terminal-subagent-provider-failures-with-actionable branch 2 times, most recently from 7d1bdcf to 3dbdbc3 Compare October 13, 2026 00:52
@bwachman
bwachman force-pushed the cl-10469-surface-off-tag-build-identity-in-tui-version-badge branch from fb9b903 to b406132 Compare October 13, 2026 00:52
@TheGreatAxios
TheGreatAxios force-pushed the cl-10469-surface-off-tag-build-identity-in-tui-version-badge branch from b406132 to 169e718 Compare October 13, 2026 02:49
A failed worker reached the parent as two booleans and error prose, so
the parent could not tell a transient provider fault from a stuck or
cancelled lane, and an answered ask_director left no trace once the run
died. The store now writes one frozen failure record in the same
mutation that makes a non-clean terminal visible, and provider_failure
and continuable derive from its class so every projection agrees.
The reactor's doom-loop guard already stops workers, but the run ended
as a plain error and its class survived only in the reactor message.
The doom_loop run end reaches the stream after the send rejects, so the
run notes it in its stream sink and rethrows a typed error once
teardown has drained the stream. A forced-stop reason would have taken
the salvage path and turned the failed lane into a done one.

The run also reports when its own teardown fails, which is the release
step behind a partial cleanup outcome.
@TheGreatAxios
TheGreatAxios force-pushed the cl-10202-surface-terminal-subagent-provider-failures-with-actionable branch from 3dbdbc3 to 694fbd2 Compare October 13, 2026 02:54
@TheGreatAxios
TheGreatAxios changed the base branch from cl-10469-surface-off-tag-build-identity-in-tui-version-badge to main October 13, 2026 02:54
@TheGreatAxios
TheGreatAxios merged commit a13cf88 into main Oct 13, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants