-
Notifications
You must be signed in to change notification settings - Fork 3
plat 351
PLAT-351 — Retained-turn observer settles on durable runner outcome when the pane never reports idle
| Field | Value |
|---|---|
| Status | implemented and pushed; live acceptance pending (localhost restart) |
| Priority | P1 retained-turn correctness |
| Owner | server agent runtime |
| Reported | 2026-09-22 |
| Related | PLAT-179 (shared finalResponse tool-call guard), PLAT-346 (retained lifecycle timers) |
observeRetainedMainTurnStream settled a retained main-agent turn only on
llmproviders.CodingAgentPaneReady pixels, with a stability gate. That
dispatch has no Muse case and returns false forever for muse-cli, and the
observer loop had no deadline and never consulted the provider's durable
turn sidecar (it only did so in handleRetainedMainTurnStreamClosed, after
the tmux control stream died).
A quiet-but-finished Muse retained turn therefore stayed in
retainedMainTurns indefinitely: the session stayed busy, the global
activity monitor showed a false "running" (1hr+ in the reported News
Monitor case), and no log line distinguished it from a genuinely active
turn. The provider's own completion contract already existed and was
correct — museRetainedTurnReady (5s log quiet + TUI at prompt + pane
stable, with pending-question auto-answer serviced first) feeds
musecli.ReadRetainedTurnMessages → retainedturn.FinalResponse — but
nothing on the live path asked it.
- After
retainedMainTurnDurableQuietWindow(15s) of tmux-output quiet with a never-idle pane, the observer consultsretainedturn.FinalResponse(at most everyretainedMainTurnDurableRecheckWindow, 5s) and settlescompletedon runner outcome instead of pixels. The completion event carries the sidecar's final text via the existing emit path. - Providers without a retained-turn reader return "" and keep exact pane-only behavior. Silent long tool runs cannot settle early: while a tool is in flight the newest assistant message carries the ToolCall (PLAT-179 guard) or the TUI is not at its prompt, so the sidecar stays empty.
- The live-loop settle is additionally allowlisted to readers that assert completion (Muse, Codex, Claude, Cursor). Pi is excluded: its reader returns all in-turn messages with no completion gate, so a question awaiting a slow user would settle early. Follow-up: gate Pi's reader on completion (or a provider-contract capability flag) and re-admit it.
- One diagnostic
WARNINGper observer at 30m when neither pane-idle nor a durable final response has fired. It never settles the turn: marathon turns are untouched by design (no hard observer deadline). - Consolidated the two inline final-response seam blocks (stream-closed
reconcile, completion emit) onto one
retainedTurnFinalResponsehelper. Windows are vars, not consts, so tests can shrink them.
Commit: 7e887ec3d.
- New
TestRetainedMainTurnSettlesOnDurableFinalResponseWhenPaneNeverIdles: Muse pane stays busy forever; an empty sidecar keeps the turn open (consult observed), then a durable final settles it to completed withunified_completion, live tmux kept. Passes. - Full
Retained|LiveAttach|LiveInput|MCPAgentSession|TerminalStream|TmuxStreamset passes;go vetandgofmtclean. - Full
cmd/serversuite shows only the 3 pre-existing failures, byte-identical on the pristine tree (a 4th flaked once under load and passed on rerun with the change). - Live acceptance pending: restart localhost, confirm the next quiet Muse retained turn settles within ~15s of its final response and the global monitor clears, and that a still-unsettled turn emits the 30m warning with provider/elapsed/quiet.
Auto-synced from docs/ on main. Edit there, not here.