fix(server): hydrate provider history atomically - #2763
Conversation
…ydration-atomic-current-main
…ydration-atomic-current-main
|
Independent final rereview: #2763 is READY at 68837a9 (tree ee048eb043a9fff35f1b9a07d7606322046cfc6b; base 048b82f). 262 changed-server tests passed, 4 skipped; typecheck and diff clean; no P0-P2 findings. Integration note: #2765 is an independent material-progress branch, not a semantic superset. When rebasing either order, preserve this PR reserved-occurrence reconciliation and admission-terminal child retention while layering #2765 checkpointing; union tests are required. |
|
| Filename | Overview |
|---|---|
| packages/server/src/server/agent/agent-manager.ts | Adds hydration admission, generation serialization, reconciliation, and buffered replay, but stale session events can cross a concurrent reload boundary. |
| packages/server/src/server/agent/file-agent-timeline-store.ts | Adds per-agent serialized atomic timeline replacement with cache updates only after durable success. |
| packages/server/src/server/agent/agent-timeline-store-types.ts | Extends the durable timeline interface with atomic replacement and committed-row access. |
| packages/server/src/server/bootstrap.ts | Wires the file-backed durable timeline store into daemon startup. |
| packages/server/src/server/session.ts | Adjusts refresh handling to await the new reload and hydration behavior. |
Sequence Diagram
sequenceDiagram
participant H as Hydration caller
participant M as AgentManager
participant P as Provider session
participant D as Durable timeline store
participant L as Live writers/events
H->>M: hydrateTimelineFromProvider()
M->>M: Install per-agent gate
L-->>M: Buffer live operations
M->>P: streamHistory()
P-->>M: Staged history events
M->>D: replaceCommitted(rows)
D-->>M: New epoch
M->>M: Replace in-memory timeline
M->>M: Replay buffered operations
M-->>H: Hydration complete
Reviews (1): Last reviewed commit: "fix(server): close hydration reconciliat..." | Re-trigger Greptile
| activeHydration.bufferedOperations.push({ | ||
| kind: "session_event", | ||
| run: async () => this.processSessionEvent(agentId, event, activeHydration.token), | ||
| }); |
There was a problem hiding this comment.
Stale events cross session reloads
When a session reload occurs while hydration has buffered an event from the old session, replay looks up the replacement by the same agent ID and dispatches the stale event through it, corrupting the replacement session's timeline, provider-subagent projection, or turn state.
Knowledge Base Used: Agent Orchestration
Successor to #2723. This keeps the replacement narrowly focused on provider-history hydration atomicity; it does not close or modify the earlier pull request.
What changes
Non-goals
Verification
Upstream baseline observations
Two additional daemon E2Es were attempted and fail identically on the detached upstream base (
9ddc3e0c4253b4cf3a1a7b864b7a92294cf2e8d4):agent-refresh-rehydrates-timeline.e2e.test.tssees an empty initial Claude import before reaching refreshtimeline-reconnect-contract.e2e.test.tstimes out waiting for an existing provisional live eventThose unrelated baseline behaviors are intentionally not changed here.