feat(guide): Esc interrupts the turn, and the floor is visible [spec 03-03] - #140
Merged
Conversation
…03-03] The conversation-partner boundary (grilling session, nine user-pinned decisions; spec 10 §3.4 + spec 03-03 §7) — boot-time slice: - Two identities: the input line always has exactly one partner — the DJ, or the setup guide (a real foreground agent session). The floor rides `hello.mode` / the `mode` message; the TUI paints a three-point face (strip, identity line, warm input ink + placeholder) while the guide holds it, and the floor returns the moment the conversation ends. - Esc interrupts, never dismisses: mid-turn it cuts only the turn in flight (query.interrupt() via the new GuideRequest.onSession handle — proven against the real SDK: a 45s tool was cut at 5.7s and the session answered a second turn); at the idle reply prompt it ends the conversation exactly like /done (the Esc-Esc exit); before the y it is "not now". Only /quit kills the session. No idle timeout — a waiting guide waits, with the exit written on the prompt. - The one-shot stop latch becomes an esc PULSE (answers the pending read, re-arms), and write_voice_config's abort is armed per call (escEpoch), so a cut noticed mid-validate still cancels that call after the next turn resets the flow flag. - Every way a quit begins prints "going off the air..." the moment it is heard (Director.beginQuit) — the teardown was honest work read as a hang. Peer review (codex gpt-5.6-sol, xhigh): 3 findings, 3 applied — the per-call abort watch, the floor returned before the closing re-probe, and the merged-/quit ack path — each locked with a regression test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Aug 19, 2026
…c 03-03] Found in the user's live verification of the Esc-Esc exit: ending the streaming input right after an interrupted turn makes the SDK iterator throw its error result ([ede_diagnostic] ... stop_reason=tool_use), and the throw rode runSetup straight through runApp — the engine died where the broadcast should have started. Reproduced against the real SDK. runSetup now absorbs whatever the session dies of: one honest info line, the floor handed back, the closing re-probe still running — the radio always launches (spec 03-03). Locked with a regression test on the exact crash shape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
User ask: the Esc-stop acknowledgment drowned in the tool flood. Rare flow-transition lines (the stop, the unexpected session end, the going-off ack) now ride `info` with `tone: 'flow'` — the TUI renders them warm with a block marker, the plain host prints them unchanged. The stop line also says where things stand: "stopped — the setup guide is waiting for you". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pec 10] The identity line and input turned warm in guide mode but the status strip kept the room accent (user report) — the third point of the three-point face now matches in both compositions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements specs/spec10/10-tui.md (§2.3, §3.4) and specs/spec03/03-03-guide-harness.md (§7) — the conversation-partner boundary, boot-time slice (PR 1 of 2; the mid-broadcast
/setuprecall is the follow-up and closes #97's reopen gap).Nine user-pinned decisions from this session's grilling, built:
hello.modeon attach and a newmodemessage live; the extension rule (at most one foreground agent, identity line names it) is written in spec 10 §3.4 — no framework until a second agent exists.in the workshop · the setup guide has the floor), identity line (setup guide · claude), input line (warm ink +talking to the setup guide · esc interrupts · /done hands back). The floor returns the moment the conversation ends — before the closing re-probe, so no line ever queues for the wrong partner.query.interrupt()via the newGuideRequest.onSessionhandle — the turn dies, the session lives, the next typed line still commands the guide ("continue" finally has an owner). Idle: Esc ends the conversation exactly like/done(the Esc-Esc exit). Before the y: "not now". Only/quitkills the session. No idle timeout.write_voice_config's abort is armed per call (escEpoch), so a cut noticed mid-validate still cancels that call even after the next turn resets the flow flag./quitacks instantly: every way a quit begins routes throughDirector.beginQuit, which printsgoing off the air...the moment the quit is heard — the ~3s teardown was honest work read as a hang.Verification
pnpm test849 green (new: turn-interrupt loop vs a fake SDK withinterrupt(), esc-pulse semantics, the three-state Esc router incl. the mid-validate race and Esc-Esc end-to-end, mode broadcast + late-attach hello, quit acks on all three paths);tsc+ oxlint clean.scratch/smoke-turn-interrupt.ts): a guide turn running a 45s tool was cut byinterruptTurn()at 5.7s, the SDK answered with the turn's result, the reply loop pulled the next input, and the session answered a second turn. The Esc contract holds at the real boundary.gpt-5.6-sol, xhigh): 3 findings, 3 applied (per-call abort watch; floor returned before the closing re-probe; merged-/quit ack), each locked with a regression test.AI coding brief
query.interrupt()was the one fact unit fakes could not supply and was worth its tokens.🤖 Generated with Claude Code