fix: reserve cold loads across repair

This commit is contained in:
_Kerman
2026-07-23 20:58:20 +08:00
parent 816907ba2d
commit 4e5166828b
10 changed files with 79 additions and 15 deletions

View File

@@ -920,6 +920,8 @@ abstract append(id: SessionId, events: readonly SessionEvent[]): Promise<void>
* versions and corruption in the committed prefix reject. Implementations
* MUST NOT crash-repair an identity still bound to a live Session: a balanced
* live log may return as a durable snapshot, while an open live turn rejects.
* A coordinator-backed cold load reserves the identity across storage awaits,
* so concurrent publication of a same-id live Session rejects.
* @param id - the persisted session to reload.
* @returns the header and a log ending on a balanced `turn/end`.
*/

View File

@@ -12,7 +12,7 @@ The seam is a textbook [capability seam](../../.agents/notes/implemented/archite
A backend that reloads a log crashed mid-turn finds an open `turn/start` with no `turn/end`. It does **not** truncate — a single turn can be huge in a long-horizon task (many steps, large tool output), and those events were durably appended before the crash. Instead it closes the orphaned turn with a synthetic `turn/end { reason: { kind: 'interrupted' } }`, keeping the log balanced and the turn-enclosure invariant intact. `interrupted` is the one `TurnEndReason` no loop emits (see [session.md](session.md#why-a-turn-ended-turnendreasonmap)).
Repair applies only to cold sessions. For a live id, `SessionPersistence.load(id)` snapshots the in-memory log, waits until that snapshot is durable, and returns it only when balanced; an open live turn rejects rather than receiving synthetic interruption boundaries. HMR also adopts a live prefix without closing its active turn.
Repair applies only to cold sessions. For a live id, `SessionPersistence.load(id)` snapshots the in-memory log, waits until that snapshot is durable, and returns it only when balanced; an open live turn rejects rather than receiving synthetic interruption boundaries. A coordinator-backed cold load reserves the id across backend reads and repair writes, so concurrent publication of a same-id live session rejects and rolls back. HMR also adopts a live prefix without closing its active turn.
## `SessionLocation` — optional per-session artifact target