Skip to content

fix: deadline on prompt dispatch — re-send once, then terminal error result#13

Closed
dn00 wants to merge 1 commit into
fix/windows-readinessfrom
fix/dispatch-deadline
Closed

fix: deadline on prompt dispatch — re-send once, then terminal error result#13
dn00 wants to merge 1 commit into
fix/windows-readinessfrom
fix/dispatch-deadline

Conversation

@dn00

@dn00 dn00 commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Stacked on #12 (base = fix/windows-readiness; uses its failWithTerminalError machinery). After #12 merges I'll rebase this onto main and retarget.

The bug (seen live in the parity replay)

Claude's status file reports idle a beat before the TUI input box accepts keystrokes. A prompt typed into that gap is silently eaten: busy never arrives, and the readiness watchdog is intentionally suppressed while a dispatch is in flight (promptDispatchInFlight), so nothing ever times out — an unbounded silent wedge with no terminal result.

Observed in the haiku replay run (permission-deny): idle at t=1.6s → prompt dispatched → only the startup quota probe ever reached the API → killed by the harness at 240s with zero output and no result. A sonnet re-run of the same case passed cleanly (control round-trip in 7.6s), confirming a 1-in-N input race rather than a logic regression — but the race deserves a bound.

The fix

Arm a 10s deadline after sendPrompt:

  • First expiry: re-send the same prompt once — by then the TUI is certainly accepting input, so the common race self-heals invisibly.
  • Second expiry: emit a terminal stream-json error result via failWithTerminalError and shut down non-zero — consumers get a parseable terminator, never a hang.
  • Stand-downs: turn started (busy), permission dialog appeared (the dialog machinery owns the session; re-typing would corrupt it), interrupt in flight, shutdown.

Tests

  • Race recovered by a single re-send, no error emitted.
  • Terminal error result (exactly one; no duplicate from the exit path) when the retry also produces no turn.
  • No re-send when the turn starts promptly.
  • Stand-down when the prompt produces a permission dialog.

Full suite: 428 tests green.

…minal result

Claude's status file reports idle a beat before the TUI input box accepts
keystrokes. A prompt typed into that gap is silently eaten: busy never arrives,
and the readiness watchdog is intentionally suppressed while a dispatch is in
flight, so nothing ever timed out — an unbounded silent wedge with no terminal
result. Hit live in the parity replay (permission-deny on haiku: idle at 1.6s,
prompt dispatched, only the startup quota probe ever reached the API, killed by
the harness at 240s with zero output).

After sendPrompt, arm a 10s deadline. If no turn starts: re-send the same
prompt once (the TUI is certainly accepting input by then — recovers the race
invisibly), then fail via failWithTerminalError so stream-json consumers get a
parseable error result instead of a hang. The deadline stands down when the
turn starts, when a permission dialog appears (the dialog machinery owns the
session; re-typing would corrupt it), and during interrupts/shutdown.

Tests: race recovered by a single re-send with no error; terminal error result
(exactly one, no duplicate from the exit path) when the retry also fails; no
re-send on a prompt turn start; stand-down on permission dialogs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant