Deferred from #4506 (items 2 and 3 of its scope). #4506 shipped keepalives and as-produced delivery of onChat replay events, but not these two, because measurements did not justify them yet.
1. Paint full-replay rows before caught-up
The renderer buffers every historical row until caught-up (WorkspaceStore historicalMessages). On a full replay (first view after reload) the server emits all rows in one burst right after the history read. The gap between the last row and caught-up is only the server-cursor fingerprint, stream replay and init replay:
Doing it needs a protocol marker ("history rows complete") so the renderer can apply history provisionally while the #4291 mutation barrier stays closed, and must coordinate with isIncrementalCatchUp (#4505). Worth it only if huge epochs are common.
2. Since-mode work proportional to the delta
Since mode still reads and parses the whole active epoch (historyScanner.ts) and hashes every prior row (onChatCursorFingerprint.ts). On 164 MB: historyRead ~1.2 s, fingerprint 0.4-0.56 s. On the perf scenario's 0.9 MB epoch the fingerprint is ~4 ms. Options: read from the cursor offset, keep an incremental prior-history fingerprint invalidated by every history mutation path. Mutation-path invalidation is the risky part.
Trigger
Pick up when a real user report or a nightly scenario shows multi-hundred-ms since/full replays on large epochs.
Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $2.40
Deferred from #4506 (items 2 and 3 of its scope). #4506 shipped keepalives and as-produced delivery of onChat replay events, but not these two, because measurements did not justify them yet.
1. Paint full-replay rows before
caught-upThe renderer buffers every historical row until
caught-up(WorkspaceStorehistoricalMessages). On a full replay (first view after reload) the server emits all rows in one burst right after the history read. The gap between the last row andcaught-upis only the server-cursor fingerprint, stream replay and init replay:Doing it needs a protocol marker ("history rows complete") so the renderer can apply history provisionally while the #4291 mutation barrier stays closed, and must coordinate with
isIncrementalCatchUp(#4505). Worth it only if huge epochs are common.2. Since-mode work proportional to the delta
Since mode still reads and parses the whole active epoch (
historyScanner.ts) and hashes every prior row (onChatCursorFingerprint.ts). On 164 MB: historyRead ~1.2 s, fingerprint 0.4-0.56 s. On the perf scenario's 0.9 MB epoch the fingerprint is ~4 ms. Options: read from the cursor offset, keep an incremental prior-history fingerprint invalidated by every history mutation path. Mutation-path invalidation is the risky part.Trigger
Pick up when a real user report or a nightly scenario shows multi-hundred-ms since/full replays on large epochs.
Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high• Cost:$2.40