fix(coding-agent): make daemon snapshot ids unique with a per-session serial - #1342
Open
Neocher wants to merge 1 commit into
Open
fix(coding-agent): make daemon snapshot ids unique with a per-session serial#1342Neocher wants to merge 1 commit into
Neocher wants to merge 1 commit into
Conversation
…ssion serial
Snapshot ids reused (activeSessionId, eventGeneration, lastEventSequence)
as transfer identity. When that position is reused with different bytes
(e.g. heavy thinking + file-read snapshots), the supervisor's duplicate
validation throws 'Duplicate snapshot ... did not match cached bytes' and
kills a healthy worker ('Daemon worker client closed').
Decouple identity from position: add a monotonic per-session snapshotSerial
to ActiveSessionState and append it to all three snapshot id construction
sites. The id stays opaque on the wire, so no protocol change.
Fixes upstream issue PrimeIntellect-ai#1229 symptom without the full redesign.
jonaowen
suggested changes
Aug 13, 2026
jonaowen
left a comment
There was a problem hiding this comment.
The serial allocation logic appears sound and wire-compatible, but this regression is not behaviorally tested yet.
- Add a focused #1229 regression that forces two snapshot materializations at the same
(activeSessionId, eventGeneration, lastEventSequence)with different transcript bytes. Assert distinct snapshot IDs and that the supervisor installs/caches both without closing the worker channel. Cover the attach, replacement, and catch-up allocation sites directly or through a shared allocator test. test/daemon-mode.test.tsmakeStateandtest/suite/regressions/4602-snapshot-transfer-idempotency.test.tsstill omitsnapshotSerial. Paths that postfix-increment those fixtures produceundefinedand thenNaN, while passing because IDs are not asserted. Initialize them to zero and assert the emitted IDs.
The protocol claim is otherwise credible: snapshot IDs are opaque strings, and a recovered worker gets a fresh event generation while same-state replacement retains the counter.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Fixes #1229's kill-a-healthy-worker symptom.
Worker snapshot ids reuse
(activeSessionId, eventGeneration, lastEventSequence)as transfer identity (daemon-mode.ts). When that position is reused with different bytes - e.g. a long-thinking turn with file reads produces multiple snapshots between event cursor advances - the supervisor's duplicate validation (daemon-supervisor.ts) throwsDuplicate snapshot ... did not match cached bytesand kills a healthy worker. Users observeDaemon worker client closedon-p --mode textwith--thinking high/maxplus tool calls.Fix
Decouple snapshot identity from the event position. Added a monotonic per-session
snapshotSerialtoActiveSessionState, incremented at each snapshot construction, appended to the id in all three construction sites (normal snapshot, replacement snapshot, and the attach-snapshot path). The id remains an opaque string on the wire, so there is no protocol or capability change.Validation
npm run checkpasses (biome 909 files, tsgo, installer render, browser smoke)test/agent-connection-daemon.test.ts: 65/65 pass--mode text --offline --thinking high+ file-read tool call) now completes end-to-end when run from sourceNotes
This is the minimal stopgap the issue describes; a broader redesign of the snapshot identity/transfer model can build on it later. Behavior change: duplicate-snapshot byte mismatches can no longer occur for distinct content, so the supervisor's duplicate-validation path only sees true retransmissions.
Note
Make daemon snapshot IDs unique with a per-session incrementing serial
Snapshot IDs in the coding agent daemon were not unique across repeated emissions because they only encoded
(activeSessionId, eventGeneration, lastEventSequence). This adds asnapshotSerialcounter toActiveSessionState(initialized to 0) and appends an incrementing suffix to snapshot IDs in all three emission paths: initial/attach streaming, replacement snapshots, and catch-up snapshots.Macroscope summarized 12f45e8.