Resume
Resume answers one question: after a disconnect, a client restart, or a fresh attach, how does a client get back to a state that equals the fold of the session’s events? The invariant is exactly that — client state must always equal a function of the events since its cursor — and every rule on this page exists to keep it.
Cursors, anchors, and boundaries
Section titled “Cursors, anchors, and boundaries”Three different position words appear in the contract, and they are not interchangeable:
- A cursor is an opaque position in the session view that the server minted and the client observed — on every view event and in every resume result. Clients store cursors and hand them back; they never parse them.
- An anchor is the position a read request names — the cursor you pass to
session/resumeorview/page. An anchor can also be an observed compaction anchor, which the server resolves to its boundary position. - A boundary is an installed compaction boundary in the session: a durable point the server can serve an anchored snapshot from, at a cost proportional to the events since that boundary rather than the full history.
Suffix versus inline versus snapshot
Section titled “Suffix versus inline versus snapshot”Passing a cursor you previously observed asks for only the suffix: no inline history, subscription starting strictly after the cursor, and a history mode of none in the result. This is the cheap reconnect path.
Resuming without a cursor asks the server to serve history, and the server picks a rung on a ladder, downgrading when the requested form does not fit the history budget — the maximum history it will materialize into one result. The rungs, in order:
- Anchored snapshot — a folded state anchored at the latest installed compaction boundary plus the suffix after it; the default first rung, and fail-closed: a missing or unusable boundary makes the rung unavailable rather than triggering a fold from genesis.
- Inline — the full folded item array, for small sessions.
- Snapshot — a folded view state at a cursor plus the streamed suffix; snapshot plus suffix must equal a from-genesis fold, because the snapshot is a transport optimization and never a second source of truth.
- Elided snapshot — a must-attempt rung before giving up: every ref-bearing item’s payload is dropped in a structurally decidable way, so the client can page the bytes later.
- None — the client pages everything itself via
view/pagefrom the returned cursor.
The mode field in the result reports what was actually served, never what was asked for, and a client must treat an unknown mode as “page it yourself”. The result also carries the pending-request pointers — one entry per unresolved approval or user-input prompt — after which the server re-issues each pending request on the new connection; that re-issue is the whole late-joiner recovery story.
The failure vocabulary: three different “no”
Section titled “The failure vocabulary: three different “no””A resume or page anchored at a bad position fails in one of three deliberately distinct ways, and a client branches on which one it got:
notFoundwithdata.reasonmissingAnchor— the cursor never existed in this session’s view, including cursors from another session. This is a client bug or crossed wires, not something to retry.boundaryPruned— a compaction anchor names an installed boundary that retention has since pruned: a typed error carrying the latest boundary cursor so re-anchoring at the newer boundary is one step; never conflated withmissingAnchor, because the anchor did exist.viewTruncated— the anchor predates the retained fold. Trigger (a) is retention: the state does not exist to serve at any budget, and recovery is a fresh resume with snapshot semantics. Trigger (b) is the history budget: a stale-cursor resume where even the fully-elided snapshot does not fit — the server must fail typed, carrying the earliest cursor, rather than serve none and silently skip events.
Here is the missing-anchor case from a recorded scenario — a resume naming a cursor from a different session, answered by the typed not-found error:
{"dir":"client","raw":"{\"jsonrpc\":\"2.0\",\"id\":9,\"method\":\"session/resume\",\"params\":{\"commandId\":\"0198f0ab-8888-7000-8000-0000000000c4\",\"sessionId\":\"0198f0aa-1111-7000-8000-0000000000aa\",\"cursor\":\"v:0198f0aa-2222-7000-8000-0000000000bb:9\"}}"}{"dir":"server","raw":"{\"jsonrpc\":\"2.0\",\"id\":9,\"error\":{\"code\":-32011,\"message\":\"unknown cursor anchor\",\"data\":{\"kind\":\"notFound\",\"reason\":\"missingAnchor\",\"sessionId\":\"0198f0aa-1111-7000-8000-0000000000aa\"}}}"}A stale-but-real cursor is different from all three: it falls back to snapshot semantics and says so in the reported history mode — the server never silently skips events.
What resume writes, and what it costs
Section titled “What resume writes, and what it costs”A resume that loads a session from disk writes a durable resumed marker; a connection merely attaching to an already-loaded session writes nothing. The anchored rung exists to bound the cost: an anchored resume costs time proportional to the events since the latest boundary, never the full history. For very large sessions a client can also ask for metadata only and page history separately.
Under the ephemeral profile there is no resume at all — the method is withheld, and an evicted in-memory prefix makes the truncation error terminal with the earliest cursor as the hard floor of the observable transcript. See durability profiles.
What the snapshot state contains and how items fold within it is covered by the fold model; this page only covers how you get positioned.