Skip to content

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

Merged
dn00 merged 1 commit into
mainfrom
fix/dispatch-deadline
Jun 10, 2026
Merged

fix: deadline on prompt dispatch — re-send once, then terminal error result#16
dn00 merged 1 commit into
mainfrom
fix/dispatch-deadline

Conversation

@dn00

@dn00 dn00 commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Re-files #13 against main (the original auto-closed when its stacked base branch was deleted by #12's merge; same single commit, rebased onto current main, 431 tests green locally).

See #13 for the full description and review context: 10s deadline after sendPrompt — re-send once (self-heals the TUI input race seen live in the parity replay), then emit a terminal stream-json error result via failWithTerminalError instead of wedging silently. Stands down on turn start, permission dialogs, interrupts, and shutdown.

…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.
dn00 added a commit that referenced this pull request Jun 10, 2026
…pe, thinking signature

Closes the consumed-field parity gaps confirmed by replay against the
2026-06-09 goldens (PARITY-GAPS #2/#3/#14/#15/#16), and adds the parity-policy
tiers to PARITY-GAPS.md (contract / consumed fields / on-demand / won't-fix).

- --max-turns now counts assistant API rounds (SSE message_start) like native,
  not user prompts — a single prompt chaining tools can exhaust it. On
  exceeding: interrupt, then report result.error_max_turns (is_error, NO
  result field, num_turns = rounds) and exit 1, even in stream-json mode,
  whether or not the interrupt beat the turn's natural completion. The old
  prompt-count check remains as a fallback for backends without SSE.
- Ack initialize (truthful payload: commands from transcript init,
  output_style, pid) and set_permission_mode (echo mode) using native's
  nested control_response shape {type, response: {subtype, request_id,
  response}}; migrated the interrupt ack from clarp's old flat shape.
- Turn-level backend API errors report subtype "success" with is_error: true
  (invalid-model golden), not subtype "error"; emitResult decouples is_error
  from subtype and can omit the result field (error_max_turns has none).
- Assembler accumulates signature_delta; thinking blocks are {type, thinking,
  signature} like native.
- Exit code now reflects the last result's is_error on stdin-drain shutdown
  (native exits 1 after an invalid-model turn even though the stream ends
  normally).
@dn00 dn00 merged commit 5322dea into main Jun 10, 2026
10 checks passed
@dn00 dn00 deleted the fix/dispatch-deadline branch June 10, 2026 23:01
dn00 added a commit that referenced this pull request Jun 10, 2026
…pe, thinking signature

Closes the consumed-field parity gaps confirmed by replay against the
2026-06-09 goldens (PARITY-GAPS #2/#3/#14/#15/#16), and adds the parity-policy
tiers to PARITY-GAPS.md (contract / consumed fields / on-demand / won't-fix).

- --max-turns now counts assistant API rounds (SSE message_start) like native,
  not user prompts — a single prompt chaining tools can exhaust it. On
  exceeding: interrupt, then report result.error_max_turns (is_error, NO
  result field, num_turns = rounds) and exit 1, even in stream-json mode,
  whether or not the interrupt beat the turn's natural completion. The old
  prompt-count check remains as a fallback for backends without SSE.
- Ack initialize (truthful payload: commands from transcript init,
  output_style, pid) and set_permission_mode (echo mode) using native's
  nested control_response shape {type, response: {subtype, request_id,
  response}}; migrated the interrupt ack from clarp's old flat shape.
- Turn-level backend API errors report subtype "success" with is_error: true
  (invalid-model golden), not subtype "error"; emitResult decouples is_error
  from subtype and can omit the result field (error_max_turns has none).
- Assembler accumulates signature_delta; thinking blocks are {type, thinking,
  signature} like native.
- Exit code now reflects the last result's is_error on stdin-drain shutdown
  (native exits 1 after an invalid-model turn even though the stream ends
  normally).
dn00 added a commit that referenced this pull request Jun 10, 2026
…pe, thinking signature

Closes the consumed-field parity gaps confirmed by replay against the
2026-06-09 goldens (PARITY-GAPS #2/#3/#14/#15/#16), and adds the parity-policy
tiers to PARITY-GAPS.md (contract / consumed fields / on-demand / won't-fix).

- --max-turns now counts assistant API rounds (SSE message_start) like native,
  not user prompts — a single prompt chaining tools can exhaust it. On
  exceeding: interrupt, then report result.error_max_turns (is_error, NO
  result field, num_turns = rounds) and exit 1, even in stream-json mode,
  whether or not the interrupt beat the turn's natural completion. The old
  prompt-count check remains as a fallback for backends without SSE.
- Ack initialize (truthful payload: commands from transcript init,
  output_style, pid) and set_permission_mode (echo mode) using native's
  nested control_response shape {type, response: {subtype, request_id,
  response}}; migrated the interrupt ack from clarp's old flat shape.
- Turn-level backend API errors report subtype "success" with is_error: true
  (invalid-model golden), not subtype "error"; emitResult decouples is_error
  from subtype and can omit the result field (error_max_turns has none).
- Assembler accumulates signature_delta; thinking blocks are {type, thinking,
  signature} like native.
- Exit code now reflects the last result's is_error on stdin-drain shutdown
  (native exits 1 after an invalid-model turn even though the stream ends
  normally).
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