Skip to content

Apply urgent realtime thread changes without flushing the debounce buffer - #2279

Open
vburojevic wants to merge 1 commit into
get-bb:mainfrom
vburojevic:perf/mobile-gaps-flush-split
Open

Apply urgent realtime thread changes without flushing the debounce buffer#2279
vburojevic wants to merge 1 commit into
get-bb:mainfrom
vburojevic:perf/mobile-gaps-flush-split

Conversation

@vburojevic

Copy link
Copy Markdown
Contributor

What was wrong

Any thread message containing an immediate change kind flushed the entire buffered invalidation state — including every debounced events-appended timeline invalidation for every thread. The queued-message send path publishes [events-appended, queue-changed, status-changed] as one message, so during streaming the 50/200ms coalescing collapsed exactly when it mattered, and one thread's status flip flushed every other streaming thread's buffer.

What changed

Partition each visible message by the registry's flush priority: immediate kinds run their dirty handlers synchronously against that message alone (threading #2169's statusChange snapshot); debounced kinds stay in the scheduler. Turn-completion bundles (eventTypes includes turn/completed) still flush atomically — a completed stream needs no storm protection, so composer re-enable and final text stay in sync. Hidden-document path unchanged. Immediate metadata is id-gated and routed through mergeThreadChangeMetadata so global broadcasts keep broad invalidation.

Behavior change

Mid-stream bundles only: their timeline invalidation waits ≤50ms (200ms max) instead of jumping the queue. Turn completion is unchanged (atomic).

How verified

65/65 realtime-cache-effects + cache-owner tests, including new: bundled-publish debounce hold, cross-thread isolation, bare status-changed snapshot refresh (#2169 invariant), id-less broadcast breadth, atomic completion. Each fails without its fix. Typecheck + oxlint clean; adversarially reviewed.

🤖 Generated with Claude Code

…ffer

Any thread message containing an immediate change kind (status-changed,
history-rewritten, environment-changed, tabs-changed) flushed the entire
buffered invalidation state, including every debounced events-appended
timeline invalidation for every thread. The queued-message send path
publishes [events-appended, queue-changed, status-changed] as one
message, so during streaming the 50/200ms coalescing window collapsed
exactly when it mattered, and one thread's status flip flushed every
other streaming thread's timeline invalidations with it.

Partition each message by the registry's flush priority: immediate kinds
run their dirty handlers synchronously against that message alone, and
debounced kinds stay in the scheduler. Turn completion is exempt: when a
message's eventTypes include turn/completed, every kind is recorded and
the buffer flushes at once (the old path), because the lifecycle publish
bundles the final events-appended with the status flip and splitting
them would re-enable the composer up to a debounce window before the
final assistant text renders; a completed stream needs no coalescing
protection. Hidden-document deferral is unchanged.

The immediate path routes message metadata through
mergeThreadChangeMetadata so its context (including get-bb#2169's statusChange
row snapshot) cannot drift from the buffered flush path, and passes
metadata only when the message carries a thread id: an id-less global
message runs its handlers with undefined metadata exactly like the
flush's global path, so a stray projectId cannot narrow
dirtyActiveThreadListQueries to one project.

Behavior change: only mid-stream bundles are partitioned, so a status
flip applies immediately while the timeline invalidation keeps its
coalescing window (up to 50ms); the turn-completion supersede stays
atomic. The "once per flush" search test now drives its two completions
through the hidden-document merge, the one place completions still
coalesce into a single flush.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant