Repository navigation
fix(ui): returning to a live conversation intermittently re-streams accumulated output — regression from #2975, flaking CI #3044
Description
Symptom
streaming-remount.spec.ts:65 ("returning to a live conversation settles output accumulated while away") fails intermittently on main: after switching back to a backgrounded live conversation, the output that accumulated while away is replayed progressively (partial-text paints) instead of appearing settled. This is a user-visible product regression, not only a flaky assertion: the transcript visibly re-streams content the model already produced.
Observed failures on main CI: run 31791670100 (2026-08-14). It has also hit unrelated PRs twice (#3032).
Bisect
Locally reproducible at high rate on macOS (Darwin 25.6.0, Node 24.18):
| commit | result (--repeat-each 4) |
|---|---|
0f943f57e (parent of #2975) |
4/4 pass |
6b8e3db26 (perf(ui): virtualize long chat transcripts, #2975) |
1/4 fail |
current main (2632b85) |
3/4 fail |
Evidence
Instrumenting the spec's MutationObserver shows the streaming bubble's text after switching back growing in small per-paint steps until it reaches the full accumulated text (fail run):
"…stop the Turn."
"…stop the Turn.Acknowle"
"…stop the Turn.Acknowledged steer"
"…stop the Turn.Acknowledged steering: backg"
"…stop the Turn.Acknowledged steering: background outp"
… (ends at the full string)
The fake backend emits the steering echo as a single text_delta, and the projector's seedActive emits accumulated text as one cumulative delta — so these partials are not source chunks; the catch-up is being applied/painted incrementally after the remount.
Two mechanisms interact, both new or newly-exposed in #2975:
app-shell-session-events.tsnow defers active-sessiontext_delta/thinking_deltaapplication to a per-frame flush (scheduleDisplayEvent, rAF + 100ms fallback). A catch-up burst that spans multiple tasks/frames is committed in several partial paints.- The virtualizer mounts the streaming turn (and paints) earlier on session switch than the previous progressive-mount path did, so the first paint now lands before the catch-up burst has finished arriving — pre-perf(ui): virtualize long chat transcripts #2975 the burst had effectively completed before the streaming bubble mounted, which is why the same spec passed.
Additional diagnostic: holding a second persistent window.maka.sessions.subscribeEvents(sessionId, …) subscription open across the switch makes the failure deterministic and total — the returning view then never receives the accumulated echo at all (bubble stuck at the pre-steer text past a 10s timeout). That experiment perturbs observer registration, but it points at the catch-up/seed path racing observer lifecycle rather than at paint timing alone.
Expected
Switching back to a live conversation renders everything that accumulated while away settled in the first paint (the spec's contract); only genuinely new output streams.
Notes
- Reproduce:
cd apps/desktop && npm run build:with-deps && npm run build:test && npx playwright test e2e/streaming-remount.spec.ts:65 --config e2e/playwright.config.ts --repeat-each 4. - A fix probably wants the session-activation path to drain/apply the pending catch-up for the newly active session atomically before the streaming bubble's first paint, rather than letting it trickle through the per-frame display batch — but that touches perf(ui): virtualize long chat transcripts #2975's frame-batching design, so deferring the approach to its author.
Bisect and analysis by Claude Code.
Activity
Sun-GLiang commentedon Aug 15, 2026
Additional reproduction from #3047:
3e2d84bc4: the focused test failed 4/5 runs with the same assertion atstreaming-remount.spec.ts:153(expectedfalse, receivedtrue).maincommit1ce0bc308: the same focused test failed 5/5 runs.This provides another independent confirmation that the failure is a baseline Desktop/UI regression rather than being introduced by #3047.
1625567290 commentedon Aug 15, 2026
I'm working on this. I'll stop remounting a live conversation from replaying already-accumulated assistant text as a fresh stream, and lock it with the existing
streaming-remountspec so the #2975 virtualization path stays settled when switching back.Grok is assisting with the implementation; I will review the change and remain the human contributor of record.
简体中文对照
我来修。切回正在流式的会话时,已经产出的文本不应再按新流逐步重播;用现有的
streaming-remount规格锁住 #2975 虚拟化路径在切回时保持 settled。Grok 协助实现;我会审阅改动,并作为 human contributor of record。
fix(desktop): bind live catch-up readiness to observation generation
fix(desktop): settle catch-up text before remounting a live conversat…