Skip to content

fix(dashboard): drop a slot's buffered stream text on slot_clear - #6881

Merged
iamwhatever merged 1 commit into
mainfrom
fix/slot-clear-chunk-buffer
Aug 30, 2026
Merged

fix(dashboard): drop a slot's buffered stream text on slot_clear#6881
iamwhatever merged 1 commit into
mainfrom
fix/slot-clear-chunk-buffer

Conversation

@buluoray

Copy link
Copy Markdown
Contributor

Problem

slot_clear (the /clear command) clears the transcript but leaves the slot's entry in the streaming chunk buffer (chunkBufRef). The buffer flushes once per animation frame, so a chat_chunk — or chat_thinking text, which shares the same buffer entry since #6666 — that arrived just before the /clear landed flushes on the NEXT frame and resurrects discarded text into the just-cleared pane.

This gap predates recent work but was widened by it:

Flagged as a non-blocking finding while reviewing #6666 (see the review comment there); this PR is the promised follow-up fix.

What changed

One line in the slot_clear case of useWebSocket.ts: delete the cleared slot's chunk-buffer entry alongside clearing the transcript. The delete is keyed — other slots' in-flight buffers are untouched. This mirrors what chat_done already does for a finished turn.

Tests

New useWebSocket.slotClearBuffer.test.ts (4 cases), driving real WS envelopes through hand-driven rAF frames:

  1. A chunk buffered before slot_clear does not flush back into the cleared transcript.
  2. Buffered chat_thinking text is discarded too (shared buffer entry).
  3. Clearing one slot leaves another slot's in-flight buffer intact.
  4. Streaming resumes normally after a slot_clear (no stale prefix).

Mutation-verified:

  • Remove the delete → tests 1, 2, 4 red (test 3 stays green, as it should).
  • Replace the keyed delete with an over-broad .clear() → exactly test 3 red.

Full gates: tsc -b clean, eslint 0 errors on touched files, full vitest suite 26,049 passed on the rebased head.

Why no screenshot: no visual delta — the fix prevents a transient race (discarded text flashing back after /clear) that cannot be captured in a static frame; behavior is pinned by the four deterministic tests above.

No linked issue — the defect was found during code review of #6666 and is fixed directly here.

A chat_chunk (or chat_thinking — same buffer entry) buffered just before
a /clear lands would flush on the next animation frame and resurrect
discarded transcript text into the just-cleared pane. slot_clear now
deletes the slot's chunk-buffer entry alongside clearing the transcript.
Keyed delete: other slots' in-flight buffers are untouched.
@buluoray
buluoray requested a review from a team August 29, 2026 23:57
@buluoray
buluoray requested a review from a team as a code owner August 29, 2026 23:57
@buluoray
buluoray requested a review from iamwhatever August 29, 2026 23:57
@github-actions github-actions Bot added the readiness: checking Automated validation is still running label Aug 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

UX Review (Fable 5) — ✅ PASS

UX-level review of e0ef425616e24bd513eee4926e4ef3b04f3355c7 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

This is a one-line race-condition fix in useWebSocket.ts plus tests — no new UI, strings, or visual surfaces. The change purely improves the existing /clear experience by preventing discarded stream text from flashing back into a just-cleared pane. Nothing for any UX lens to flag.

UX-Verdict: PASS

Invisible-by-design fix: /clear now actually clears — buffered stream text no longer resurrects into the emptied pane; no new UI or copy to review.

[UX-REVIEWED] e0ef425

@github-actions

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ no blocking findings

GPT 5.6 completed its review of e0ef425616e24bd513eee4926e4ef3b04f3355c7 and found no blocking issues.

This comment is updated in place on each push.

Review details

No findings.
[GPT-REVIEWED] e0ef425

False positive or not applicable? A repository writer can comment:
/ai-review override gpt e0ef425616e24bd513eee4926e4ef3b04f3355c7: <one-sentence reason>

@github-actions

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — ✅ PASS

Design-level review of e0ef425616e24bd513eee4926e4ef3b04f3355c7 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

The fix is a one-line keyed delete mirroring the existing chat_done cleanup at line 1612, with the same buffer lifecycle pattern. WebSocket message ordering guarantees the delete-at-slot_clear-receipt point is correct: any chunk the backend emitted before processing /clear arrives before slot_clear, so a keyed delete at that point discards exactly the pre-clear text and nothing after. Deleting the entry also resets lastSeq, which matches chat_done semantics (no phantom gap marker spanning a discarded transcript). The tests match the description's four claimed cases, and the description accounts for every hunk. No design-level concerns survive the kill-filter.

Design-Verdict: PASS

A narrow lifecycle fix in the right handler, mirroring the established chat_done cleanup, with ordering-correct semantics and mutation-verified tests.

[DESIGN-REVIEWED] e0ef425

@github-actions

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5) — ✅ PASS

Premise-level review of e0ef425616e24bd513eee4926e4ef3b04f3355c7 — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

No shell was available, so the author's gate claims (vitest run, tsc) can't be re-executed — but everything this lane owns was verified by reading: the chat_done parity claim, the reconnect path, and the absence of unfixed siblings.

First-Principles-Verdict: PASS

A one-line keyed delete closing the last transcript-discard path that skipped the chunk buffer — every item traces to the reported defect.

What this change ships

Intent: text discarded by /clear must not flash back into the cleared pane a frame later. This is a FIX.

  1. /clear now also drops the slot's buffered stream/thinking text — justified (defect reported in the perf(dashboard): coalesce chat_thinking dispatches to one per frame #6666 review; description matches the diff exactly).
  2. Four deterministic tests pinning the drop, its keying, and post-clear streaming — justified (pins the fix and the over-broad .clear() regression).

Verification I ran, since the counts are the substance of a PASS here:

  • Duplication: none. Grepped chunkBufRef (8 sites) — the only existing purges are chat_done's keyed delete (useWebSocket.ts:1612) and the reconnect whole-buffer clear (:752). Neither covers slot_clear; this is the missing third, in the same idiom.
  • Siblings: grepped case 'slot_ (4 events) and the transcript-discarding reducers. slot_clear was the only discard path leaving a buffer entry; the parallel subagentChunkBufRef is not a sibling because clearMessages/clearSlotCache (chatSlice.ts:3293,3300) never discard subagent panel state, so nothing there resurrects.
  • Depth: the fix sits at mechanism level — the discard handler now owns its buffer entry, matching the documented buffer lifecycle ("reconnect clear, chat_done delete, unmount cancel", useWebSocket.ts:246-249). The deeper "cause" would be abandoning the per-frame buffer, which exists for a measured per-token dispatch cost — not up for relitigation.
  • New surface: zero — no key, flag, export, or event added.

[FIRST-PRINCIPLES-REVIEWED] e0ef425

@github-actions

Copy link
Copy Markdown
Contributor

Opus 4.8 Review — ✅ no blocking findings

Reviewed e0ef425616e24bd513eee4926e4ef3b04f3355c7 — this comment is updated in place on each push.

Review details

The change is a single, well-scoped one-line delete plus tests. The discovery pass found no candidates, and my inspection of the buffer machinery confirms the fix is correct (keyed delete closes the buffer-then-flush resurrection window; subagentChunkBufRef writes to state that clearMessages/clearSlotCache don't touch, so no parallel fix is owed). Nothing survives to report.

No findings.

[OPUS-REVIEWED] e0ef425

Verdict parsed from the review's SHA-scoped output markers for commit e0ef425616e24bd513eee4926e4ef3b04f3355c7.

False positive or not applicable? A repository writer can comment:
/ai-review override fable e0ef425616e24bd513eee4926e4ef3b04f3355c7: <one-sentence reason>

@bolichen97
bolichen97 enabled auto-merge August 30, 2026 00:09
@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels Aug 30, 2026

@NicholasRBowers NicholasRBowers left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tier 1 auto-approve: fix (2 files). Criteria: no conflict, no requested changes, security path denylist clean, design-doc gate clean, SAST annotations clean, security checklist all-NO, AI reviewers green. Category: fix with clear root cause -- slot_clear now drops the slot's buffered stream text (keyed delete) so a chunk buffered before /clear cannot flush back into the cleared pane; frontend-only, plus a pinning test.

@iamwhatever
iamwhatever merged commit ff7fe75 into main Aug 30, 2026
67 checks passed
@iamwhatever
iamwhatever deleted the fix/slot-clear-chunk-buffer branch August 30, 2026 00:59
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants