Skip to content

fix(coding-agent): make daemon snapshot ids unique with a per-session serial - #1342

Open
Neocher wants to merge 1 commit into
PrimeIntellect-ai:mainfrom
Neocher:fix/1229-snapshot-serial-unique-id
Open

fix(coding-agent): make daemon snapshot ids unique with a per-session serial#1342
Neocher wants to merge 1 commit into
PrimeIntellect-ai:mainfrom
Neocher:fix/1229-snapshot-serial-unique-id

Conversation

@Neocher

@Neocher Neocher commented Aug 13, 2026

Copy link
Copy Markdown

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) throws Duplicate snapshot ... did not match cached bytes and kills a healthy worker. Users observe Daemon worker client closed on -p --mode text with --thinking high/max plus tool calls.

Fix

Decouple snapshot identity from the event position. Added a monotonic per-session snapshotSerial to ActiveSessionState, 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 check passes (biome 909 files, tsgo, installer render, browser smoke)
  • test/agent-connection-daemon.test.ts: 65/65 pass
  • Reproduction: the previously-failing combo (--mode text --offline --thinking high + file-read tool call) now completes end-to-end when run from source

Notes

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 a snapshotSerial counter to ActiveSessionState (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.

…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 jonaowen left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The serial allocation logic appears sound and wire-compatible, but this regression is not behaviorally tested yet.

  1. 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.
  2. test/daemon-mode.test.ts makeState and test/suite/regressions/4602-snapshot-transfer-idempotency.test.ts still omit snapshotSerial. Paths that postfix-increment those fixtures produce undefined and then NaN, 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v0.7.1: snapshot position is reused as transfer identity; byte mismatch disconnects a healthy worker

2 participants