From f5e8488ddc5fb7cbd5b48aa9047dfad7d596be4e Mon Sep 17 00:00:00 2001 From: Patrick Buckley Date: Fri, 8 May 2026 18:20:40 -0700 Subject: [PATCH] style(sse): align comments with always-advance seq invariant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doc-debt cleanup flagged by /review on 9dc29db7. The cap+seq fix flipped the seq-advance rule but left two doc sites describing the old "incremented only on actual append" shape — exactly the buggy invariant the previous commit removed. Future readers trusting the stale docs would be one wrong assumption away from re-introducing the silent-drop bug. Updates the field-init comment block and the docstring on register_listener_with_in_progress_snapshot (which sits at the snap_seq capture site, so its contract is consumer-facing). Also drops the now-dead `seq: int = 0` initializer in on_reasoning_token and on_content_token — under the new shape, the unconditional `seq = self._ws_inflight_seq` inside the lock makes the initializer unreachable. Was load-bearing under the old else-branch; harmless now but signals "some path leaves seq at 0" to a reader. --- turnstone/core/session_ui_base.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/turnstone/core/session_ui_base.py b/turnstone/core/session_ui_base.py index 66d71485..15aee379 100644 --- a/turnstone/core/session_ui_base.py +++ b/turnstone/core/session_ui_base.py @@ -220,10 +220,13 @@ class SessionUIBase: # each turn by :meth:`on_turn_start` (separate from the multi- # turn IDLE-piggyback buffer above so prior committed turns # don't leak into the snapshot and double-render against the - # replayed history). ``_ws_inflight_seq`` is a monotonic per- - # turn counter incremented only on actual append; the events - # handler dedups live events whose ``_seq`` is at-or-below the - # snapshot's seq (already in the snapshot payload). + # replayed history). ``_ws_inflight_seq`` is a monotonic + # counter incremented on EVERY emit (even when the cap + # rejected the buffer append) so a subscriber registering + # after the cap is hit doesn't have subsequent live tokens + # filter-dropped against a stalled ``snap_seq`` — the events + # handler dedups live events whose ``_seq`` is at-or-below + # the snapshot's seq (already in the snapshot payload). self._ws_inflight_content: list[str] = [] self._ws_inflight_content_size: int = 0 self._ws_inflight_reasoning: list[str] = [] @@ -304,9 +307,12 @@ class SessionUIBase: Race-free composition with the on-token writers, even though ``on_content_token`` / ``on_reasoning_token`` cross two locks (``_ws_lock`` for the buffer append, ``_listeners_lock`` for - the fan-out enqueue). The trick is the per-turn seq counter — - ``_ws_inflight_seq`` is incremented under ``_ws_lock`` only on - actual append; this method captures it alongside the buffer + the fan-out enqueue). The trick is the seq counter — + ``_ws_inflight_seq`` is incremented under ``_ws_lock`` on + every emit (even when the cap rejected the append, so a + subscriber that registers after the cap is hit doesn't have + subsequent live tokens filter-dropped against a stalled + snap_seq). This method captures it alongside the buffer contents under the same ``_ws_lock``, and the events handler's live drain drops any incoming event whose ``_seq`` is at-or- below the captured ``snap.seq`` (already in the snapshot @@ -1315,7 +1321,6 @@ class SessionUIBase: with a visual gap equal to the past-cap chunk. No silent drop of subsequent tokens. """ - seq: int = 0 with self._ws_lock: if self._ws_inflight_reasoning_size < _MAX_TURN_CONTENT_CHARS: self._ws_inflight_reasoning.append(text) @@ -1352,7 +1357,6 @@ class SessionUIBase: orphaned list reference the snapshot just swapped out. Lock hold is microseconds. """ - seq: int = 0 with self._ws_lock: if self._ws_turn_content_size < _MAX_TURN_CONTENT_CHARS: self._ws_turn_content.append(text)