Files
turnstone/tests
Patrick Buckley 476cce2e58 fix(streaming): scope stream bookkeeping to the send and discard dead segments server-side
Third review round on the retry window: two mediums fixed, one
observability gap closed.

- New UI-protocol method on_stream_discarded(): on_turn_committed clears
  only the inflight buffers — it cannot clear _ws_turn_content, the
  multi-segment buffer the IDLE payload drains, because earlier segments
  of a tool-looping turn must survive commits — so a dead attempt's text
  concatenated with the retried text in the dashboard's idle payload.
  SessionUIBase now truncates the turn buffer to a segment watermark
  (snapshotted in on_thinking_start, which precedes every stream
  segment), drops the never-displayed pending batch, and resets the
  inflight snapshot; the retry arm emits it in place of
  on_turn_committed. Server-side only — no SSE event, no client change;
  no-op on the CLI and eval UIs. Pinned with a real-SessionUIBase-buffer
  test: the recording fakes structurally cannot see this buffer.
- _active_stream_provider and _active_wire_msgs are send-scoped: cleared
  in send()'s finally, after the except arms' fatal formatting (the one
  legitimate fatal-path reader of the provider field). A later fatal on
  a utility lane falls back to self._provider instead of wearing a stale
  interactive-turn binding, and the full-context-sized wire fold no
  longer outlives its calibration use.
- stream.retry carries dead_usage and dead_content_chars: the abandoned
  generation's billed tokens are otherwise invisible (the wire reports
  usage only at stream end — Anthropic's early prompt tokens arrive, the
  OpenAI chat lane's usage chunk trails the finish), so the log line
  records what the wire delivered plus the discarded completion's char
  count for spend reconciliation.
2026-08-04 04:53:17 -07:00
..