fix(web): reconcile session from snapshot on reopen - #1409
Conversation
🦋 Changeset detectedLatest commit: 26d60df The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c9064a5193
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 003d0de531
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d051f9b144
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d6c18a63c3
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 829da36dbf
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c12c42378c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 57b06efe87
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 49609017a8
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a5e312c793
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (!opts?.force && wasLoaded && !sessionsWithStaleCursor.has(sessionId)) { | ||
| if ((rawState.lastSeqBySession[sessionId] ?? 0) > snap.asOfSeq) return 'ok'; | ||
| if (rawState.promptIdBySession[sessionId] !== promptBefore) return 'ok'; | ||
| if (inFlightPromptSessions.has(sessionId) !== inFlightBefore) return 'ok'; |
There was a problem hiding this comment.
Guard snapshots against pending card resolutions
When a loaded session waiting on an approval/question is reopened, the UI remains usable while the snapshot GET is in flight, but this staleness guard only tracks seq, prompt id, and prompt sends. If the user approves or answers during that window and the REST call removes the card before the WS resolved event advances lastSeqBySession, a snapshot response that still contains the pending card will overwrite approvalsBySession/questionsBySession and resurrect the resolved prompt. Include pending approval/question actions in the guard or filter stale snapshot cards before applying them.
Useful? React with 👍 / 👎.
|
@codex review. I have rewritten the fix as a much simpler approach: reopenSession now always rebuilds from a fresh server snapshot with no staleness guard, accepting the optimistic-message-overwrite trade-off described in the PR body. |
|
@codex review. I have rewritten the fix as a much simpler approach: reopenSession now always rebuilds from a fresh server snapshot with no staleness guard, accepting the optimistic-message-overwrite trade-off described in the PR body. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dc8b992fab
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 26d60df9b7
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| ); | ||
| rawState.messagesHasMoreBySession = { | ||
| ...rawState.messagesHasMoreBySession, | ||
| [sessionId]: snap.hasMoreMessages, |
There was a problem hiding this comment.
Preserve exhausted pagination after snapshot merge
When a user has already loaded all older messages (messagesHasMoreBySession[sessionId] is false), reopening a long session now merges that full prefix with the latest snapshot but then resets the pagination flag to snap.hasMoreMessages. That flag is only relative to the snapshot's bounded tail, so sessions with more than the snapshot page size will incorrectly show “load older” again and issue an unnecessary empty request before returning to false.
Useful? React with 👍 / 👎.
Related Issue
No linked issue — the problem was reproduced live and is described below.
Problem
The web client builds the live transcript from WebSocket events. Assistant text deltas are volatile frames: they are never journaled and never replayed after a reconnect (
packages/protocol/src/events.ts). When a transport hiccup covers the tail of a turn — easy to hit during a swarm, where many subagents stream over the same socket — the projector's offset-based gap detection never fires (it needs a later delta to notice the hole), so the model's final report text is silently lost. The data is intact on disk and the server snapshot is authoritative, but the local transcript stayed broken forever: reopening the session only re-subscribed from the cursor, which has nothing to replay.User-facing symptom: the end of a long reply is missing and stays missing even after switching away and back.
What changed
Deliberately simple: re-opening an already-loaded session refreshes it from a fresh server snapshot (
reopenSession→syncSessionFromSnapshot). The snapshot is cheap server-side (LRU keyed on the wire file's size/mtime), so going to the authoritative record is the most reliable way to recover from any lost-tail scenario.One adjustment keeps this simple without a regression: the snapshot only carries the most recent message page, so applying it now merges into already-loaded messages — any older pages the user already fetched are preserved, and the snapshot is authoritative for its own window. This keeps scrollback intact while still repairing the latest turn tail.
Trade-off (accepted): a snapshot GET that returns during a live stream can briefly overwrite in-flight assistant delta text; the user notices immediately and a refresh or the next re-open reconciles.
Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update. — Reliability fix with no new user-facing behavior to document.