fix(ui): guard chat adoption against stale end-of-turn snapshots - #3119
fix(ui): guard chat adoption against stale end-of-turn snapshots#3119daryllimyt wants to merge 6 commits into
Conversation
|
✅ No security or compliance issues detected. Reviewed everything up to 72f038d. Security Overview
Detected Code Changes
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2346c12119
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@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: f0f0ca83c5
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@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: 4a78a46499
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@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: af38a29ddc
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@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: 7bac3ab54b
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Summary
Frontend backstop for ENG-1554: the final assistant message streams in fully, then vanishes at end of turn until reload.
Root cause is a backend end-of-turn race: the stream END token is emitted before
finalize_turnclearscurr_run_id, so theonFinishrefetch ofGET /sessions/{id}/vercelcan return a snapshot that hides the just-finished turn.useAdoptServerTranscriptthen replaces the live transcript wholesale — its count-based guard passes because DB row segmentation can make a stale snapshot equal-or-longer than the live transcript. With no follow-up refetch until remount, the message stays gone until reload.The backend root fix (emit terminal END only after finalize) ships separately. This PR is the defense-in-depth layer that kills the user-visible symptom and self-corrects without a reload.
Changes
useAdoptServerTranscript): in addition to the existing count guard, a server snapshot must contain the live transcript's final assistant text (concatenated text parts; substring containment across all server messages tolerates DB row-splitting). Tool-only / textless final messages fall back to the count guard — tool, reasoning, and approval parts serialize too differently to compare./verceltranscript query at 1s / 3s / 8s. Timers cancel on adoption, unmount, or a new streaming turn. After the final retry, a snapshot that still fails the content check but passes the count guard is adopted anyway — the server is canonical at rest, so eventual convergence beats a stuck transcript.status === "ready"; resolved-approval snapshots still adopt.Tests
frontend/src/hooks/use-chat.test.tsxcovering: stale equal-length snapshot rejection + scheduled retries, adoption once the snapshot covers the final text (including text split across DB rows), resolved-approval adoption, retry-exhaustion eventual adoption, tool-only fallback, streaming/unmount timer cancellation.chat-session-pane.test.tsx"adopts a same-length server copy with different content" expectation — that test pinned exactly the residual hole (it used a user-role message, so it never exercised the assistant-content path). It now asserts a same-length snapshot missing the final assistant content is not adopted immediately.pnpm -C frontend check,typecheck, andtest(99 suites / 556 tests) all pass.Summary by cubic
Fixes ENG-1554 where the final assistant message disappears at end of turn by guarding adoption against stale server snapshots. Coverage is anchored on the final turn’s user prompt and assistant text, with bounded refetch that self-corrects without reload and retires failed retry series so recovery stays possible.
useAdoptServerTranscriptnow acceptschatIdandworkspaceId; added tests for repeated-prompt anchoring, retry freshness and series retirement, split-row adoption, retry cancellation, and not adopting same-length snapshots missing final assistant content.Written for commit 72f038d. Summary will update on new commits.