Repository navigation
fix(transcript): preserve message order when HTTP is ahead of live events - #1294
Conversation
…ents A native message page can contain later assistant steps before their SSE events reach the renderer. The live reducer then projects a smaller, overlapping set of rows into the already loaded transcript. Treating every omitted resident as older history prepended those later steps ahead of the first user prompt and its initial assistant response while the session was still working. Keep each omitted resident run after its preceding shared row, retaining the incoming native order for shared rows and the existing optimistic-send tail. Leading history and disjoint live appends retain their established placement; authoritative page replacement, pending-send confirmation, message contents and window membership limits keep their existing contracts. No timestamp or ID sorting, extra reads, service changes or new dependencies are needed. The shared UI store applies the correction equally to Electron, Tauri and web clients. Add a deterministic regression using the real native event dispatcher and loadMessages path: an HTTP page with a later step is followed by the first step's final live event. It fails against origin/dev by producing later, user, first instead of user, first, later, then passes with the fix. Cover omitted prefixes, interior and trailing runs, disjoint appends, incoming delivery order, pending sends, repeated projections and authoritative replacements in store tests. Document the ordering contract in the transcript agent conventions. Validation: 174 focused store/reducer/action/pagination tests pass; UI typecheck passes; three real Chromium SessionView regressions pass for optimistic send reordering, long-transcript sends and queued delivery after a history rewrite. The shared OpenCode daemon was not accessed or stopped. Public help usage and controls are unchanged. Fixes #1293
pascalandr
left a comment
There was a problem hiding this comment.
Verdict: PASS — P0: 0 · P1: 0 · P2: 0 · P3: 0.
Reviewed exact head 7dd71d9e546f0fc4327f2040e85844755bcedbc5 against dev. No reproduced defects found.
Root cause verified
Read #1293 and its comments and inspected the screenshot. The reported ordering is reproducible through the real native dispatcher, loadMessages, shared message store, and Solid SessionView.
- With the
origin/devstore implementation (4bac37339fb79ce63cd535ec7cd3bf6e568f716c), the new regression fails atsession-api-running-open.test.ts:73:[later assistant, user, first assistant]. - At the reviewed head it passes:
[user, first assistant, later assistant]. - Independently reproduced both orders in Chromium using the existing real SessionView fixture. Baseline source substitution was in memory; no checkout edits or dependency sharing were used.
Merge and adjacent paths
Reviewed instance-store.ts:607–634 and every hydration/projection caller. The merge visits resident and incoming IDs linearly, preserves each omitted run after its preceding shared row, retains leading/disjoint residents, follows incoming shared-row order, and keeps omitted pending sends at the tail. It introduces no ID/timestamp sorting. Authoritative omission removal, empty snapshots, cancellation/revert handling, compaction, history-window isolation, pagination cursors, and same-ID optimistic confirmation retain their existing authority paths.
An additional read-only check passed 15,876 combinations against the real store: multiple omitted runs, head/tail omissions, disjoint inputs, incoming reorderings, repeated projections, authoritative deletions, pending identity confirmation, and exact membership without duplicates.
Validation
- Primary touched/adjacent unit run: 310/310 passed (projection, reconnect, settlement, replay, pruning/pagination, request authority, message windows, optimistic sends, and running-session opening).
- Expanded adjacent unit run: 124/124 passed, with overlap with the first run (all message-v2 suites, rehydration/eviction, send lifecycle, native events, navigation and timeline projections).
- Chromium: 154/154 passed across
session-rendering,history-navigation,history,session-search,system-messages,timeline-sync, andtranscript-presets. - UI typecheck and
git diff --checkpassed. - Added regressions exercise production logic, with no added sleeps, retries, or timeout increases; browser checks mount real components.
The author worktree was clean at the exact head before and after validation. Its own root dependency directory and npm ls --workspace @codenomad/ui --depth=0 passed preflight. Validation covers Windows Node/Chromium; installed Electron/Tauri hosts were not exercised.
Summary
Fixes #1293
Keep later assistant steps after the user prompt they answer when a native HTTP message page gets ahead of SSE delivery.
Root cause and reproduction
projectOpenCodeMessagesprojects the live SDK reducer throughseedSessionMessagesV2intohydrateMessages. The native HTTP page may already include[user, first assistant, later assistant]while the reducer still holds[user, first assistant]. Its next event previously prepended every omitted resident, producing[later assistant, user, first assistant], matching the report's screenshot.The new deterministic
session-api-running-open.test.tsregression uses the realhandleInstanceInvalidationdispatcher andloadMessages, with only native API responses stubbed. It fails on cleanorigin/devat the order assertion after the first assistant's final live event, before applying this fix. No sleeps, retries, clock skew, pagination boundary, worktree move or reconnect are needed. IDs and timestamps deliberately disagree with sequence order to prevent introducing either as a sort key.Change
The correction is in the common UI store used by Electron, Tauri and web. The Windows tests do not claim native desktop-host qualification. Public help steps, labels, controls and configuration remain unchanged.
Validation
msg_b_later, msg_z_user, msg_a_firstinstead ofmsg_z_user, msg_a_first, msg_b_later.instance-store, message-window/hydration authority, running-session opening, native data projection/read merging/trailing reads/reconnect/idle, session actions and pagination.npm run typecheck --workspace @codenomad/uipasses.session-rendering.test.ts: optimistic-send ordering and return, sends from a long transcript, queued delivery after a history rewrite.git diff --checkpasses.npm ci --prefer-offline --no-audit --no-fund; no shared-daemon access or modification and no changes to other worktrees.Touched oversized source:
packages/ui/src/stores/message-v2/instance-store.ts(approximately 1,531 lines).