fix(transcript): keep steer frame promptIds and arrival order across cold rebuilds - #3426
fix(transcript): keep steer frame promptIds and arrival order across cold rebuilds#3426liruifengv wants to merge 6 commits into
Conversation
🦋 Changeset detectedLatest commit: c43a73c The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
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: a16b97081c
ℹ️ 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: 0c5a6057b8
ℹ️ 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: 7768880273
ℹ️ 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: 88b19841c7
ℹ️ 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".
…and preserve pre-clear steer state
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c43a73c947
ℹ️ 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".
| const steeredByKind = steeredContents.get(contentKey); | ||
| const steeredRemaining = steeredByKind?.get(steerKind) ?? 0; | ||
| const matchedSteer = steeredByKind !== undefined && steeredRemaining > 0; | ||
| const steeredPromptId = matchedSteer ? steeredPromptIds[steeredPromptIdIndex] : undefined; |
There was a problem hiding this comment.
Pair IDs with the actual steer occurrence
When an ordinary user prompt has the same content and origin as a later steer, steeredContents already contains the later record while messages are folded from the beginning, so this line assigns the later steer’s promptIds to the earlier prompt and exhausts the count before reaching the actual steer. The cold snapshot then omits the IDs from the real steer frame and may reconcile the wrong prompt entity during post-turn healing; pairing must preserve each surviving turn.steer record’s position rather than treating content matches as an unordered count.
AGENTS.md reference: packages/transcript/AGENTS.md:L9-L11
Useful? React with 👍 / 👎.
Related Issue
Companion to the code-app PR fixing stale steer echoes (MoonshotAI/kimi-code-app#490); no standalone issue.
Problem
A steered user message can reappear as a ghost bubble at the bottom of the chat after the client refreshes its transcript page, and the per-turn diff panel renders before the turn ends. The client-side root cause (paginated turns vs. unpaginated prompts) is fixed in the companion PR. On the server side, two latent inconsistencies in the transcript rebuild paths can destroy the same
promptIdspairing the fix relies on:promptIdson steer frames.groupMessagesIntoSnapshotfolds a steered user message into its turn as a user text frame but never stamps it with the prompt ids, even thoughprompt.steeredrecords carry them. When the post-turn heal (healEndedTurns, 250ms after every terminal turn) patches the live store with cold-rebuilt frames, a live frame that carriedpromptIdscan be replaced by a cold frame without them — breaking echo pairing for fresh steers, which the client-side age rule cannot suppress.pendingTaskNotificationsbeforependingSteersat step start, while the cold path keeps a single arrival-ordered queue. When a steer and a task notification land in the same inter-step gap, frameIds misalign between the two paths, so heal compares the wrong frames and can clobber or duplicate them.What changed
packages/kap-server/src/services/transcript/transcriptService.ts:readColdSnapshotnow recordsprompt.steeredrecords into per-content promptId queues and pairs them intoturn.steerentries (FIFO, so identical contents steered repeatedly pair in order; unmatched entries degrade toundefined, same as before).packages/transcript/src/history/groupTurns.ts:steeredContentsvalues changed from counts to promptId queues; a folded steer frame is stamped with the queuedpromptIds.packages/kap-server/src/services/transcript/coreEventMap.ts:pendingTaskNotificationsandpendingSteersmerged into one arrival-orderedpendingUserFramesqueue, flushed in arrival order at step start; turn-end semantics unchanged (steers flushed, notifications dropped).Tests
packages/transcript/test/layers.test.ts: 9 existing steer-map usages migrated to the queue shape; 2 new cases (promptIds stamped on the folded frame, repeated identical contents pair in order).packages/kap-server/test/services/transcript.test.ts: new cold-path case (readColdSnapshot stamps promptIds fromprompt.steered) and new live-path case (queued steer + notification flush in arrival order).pnpm --filter @moonshot-ai/transcript test— 111 passed;pnpm --filter @moonshot-ai/kap-server test— 1318 passed (one unrelated heartbeat timing flake ininstanceRegistry.test.ts, passes in isolation);pnpm lint— 0 errors.Checklist
/approve).gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.