diff --git a/CHANGELOG.md b/CHANGELOG.md index a990d204ab..e56a32a6de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ ## [Unreleased] +### Fixed + +- Clarify prompt SSE fallback polling now preserves its owner session id, matching approval polling behavior so terminal events from another session cannot stop the active clarify fallback poller. + ## [v0.51.152] — 2026-05-28 — Release DX (stage-batch34 — single-PR optional gateway-backed browser chat) ### Added diff --git a/static/messages.js b/static/messages.js index c21951506c..143a1611bb 100644 --- a/static/messages.js +++ b/static/messages.js @@ -3147,7 +3147,8 @@ function startClarifyPolling(sid) { }); _clarifyEventSource.onerror = function() { - stopClarifyPolling(); + if (_clarifyEventSource) { try { _clarifyEventSource.close(); } catch(_){} _clarifyEventSource = null; } + if (_clarifyHealthTimer) { clearInterval(_clarifyHealthTimer); _clarifyHealthTimer = null; } _startClarifyFallbackPoll(sid); }; @@ -3177,6 +3178,7 @@ function startClarifyPolling(sid) { } function _startClarifyFallbackPoll(sid) { + _clarifyPollingSessionId = sid || null; _clarifyFallbackTimer = setInterval(async () => { if (!S.session || S.session.session_id !== sid) { stopClarifyPolling(); _hideClarifyCardIfOwner(sid, true, 'session'); return; diff --git a/tests/test_session_runtime_ownership_invariants.py b/tests/test_session_runtime_ownership_invariants.py index 68e1a10c09..152d79b1fe 100644 --- a/tests/test_session_runtime_ownership_invariants.py +++ b/tests/test_session_runtime_ownership_invariants.py @@ -117,6 +117,21 @@ def test_approval_and_clarify_pollers_are_stopped_by_owner_session(self): "the active pane currently owns." ) + def test_clarify_sse_fallback_preserves_owner_session_id(self): + messages = read("static/messages.js") + start_clarify = _function_body(messages, "startClarifyPolling") + fallback = _function_body(messages, "_startClarifyFallbackPoll") + + assert "_clarifyPollingSessionId = sid || null" in fallback, ( + "Any clarify fallback poller should retain its owner session id." + ) + onerror_idx = start_clarify.index("_clarifyEventSource.onerror") + onerror_body = start_clarify[onerror_idx:start_clarify.index("};", onerror_idx)] + assert "stopClarifyPolling();" not in onerror_body, ( + "SSE fallback must not clear _clarifyPollingSessionId before starting the fallback poller." + ) + assert "_startClarifyFallbackPoll(sid)" in onerror_body + def test_live_stream_transport_and_inflight_state_remain_session_keyed(self): messages = read("static/messages.js") close_live = _function_body(messages, "closeLiveStream")