import type { CheckpointId, SessionId, TenantId, TurnId } from '../../types/ids/index.js'; import { type Checkpoint } from '../../types/session/checkpoint.js'; import type { ProjectId } from '../../types/session/ids.js'; /** * The turn whose checkpoints are addressed. * * A checkpoint belongs to one turn of one session. Tenant and project are * part of the key so a shared backend can enforce isolation; the built-in * disk store is rooted in one project of one tenant's `NAMZU_HOME` and * addresses by session only. */ export interface CheckpointScope { readonly tenantId: TenantId; readonly projectId: ProjectId; readonly sessionId: SessionId; readonly turnId: TurnId; /** * The session's ancestors, root first, when it is a child session. A * layout hint only: the disk store nests a child's directory under * `/subagents/`, and a store keyed by id ignores it. */ readonly ancestors?: readonly SessionId[]; } /** * What a write hands back: exactly the payload of the `checkpoint_written` * record the caller appends next. The document is on disk before this * resolves, so the record never names a file that is not there. */ export interface CheckpointWriteReceipt { readonly checkpointId: CheckpointId; readonly iteration: number; readonly throughSeq: number; readonly throughSha256: string; /** Relative to the session directory: `checkpoints/.json`. */ readonly path: string; /** SHA-256 (lowercase hex) of the document's stored bytes. */ readonly docSha256: string; } /** * What a checkpoint store needs from the session log, injected so the store * does not depend on one log implementation. * * Every member answers from the log of `scope.sessionId`. */ export interface CheckpointLogView { /** * True when the record at `throughSeq` exists and hashes to * `throughSha256`. A checkpoint's context is the fold of the log through * that seq, so a log truncated or edited below it restores a context the * checkpoint never saw. */ verifyThrough(scope: CheckpointScope, throughSeq: number, throughSha256: string): Promise; /** `docSha256` of the `checkpoint_written` record for `checkpointId`, or null when there is none. */ writtenDocSha256(scope: CheckpointScope, checkpointId: CheckpointId): Promise; /** * Checkpoints named by a `decision_requested` record that has no * `decision_resolved` or `decision_expired` yet. `prune` never deletes one. */ openDecisionCheckpoints(scope: CheckpointScope): Promise>; } /** Why a restore refused a checkpoint. */ export type CheckpointRefusalReason = /** No `checkpoint_written` record names it: it was never committed to the log. */ 'not-recorded' /** The stored bytes do not hash to the record's `docSha256`. */ | 'document-mismatch' /** The record at `throughSeq` is missing or does not hash to `throughSha256`. */ | 'through-mismatch'; /** A checkpoint that exists but cannot be trusted to restore the turn it describes. */ export declare class CheckpointIntegrityError extends Error { readonly checkpointId: CheckpointId; readonly reason: CheckpointRefusalReason; readonly name = "CheckpointIntegrityError"; constructor(checkpointId: CheckpointId, reason: CheckpointRefusalReason); } /** * Checkpoint persistence for one project: documents under * `/checkpoints/`, addressed by turn. * * Reads return `null` or an empty list when nothing exists; `delete` of an * absent checkpoint is a no-op. A write never replaces an existing document: * the log records the hash of the bytes first written, and a replacement * would make that record lie. * * Writes are not fenced here. The document is inert until its * `checkpoint_written` record is appended, and that append is what the * session lease fences; a stale writer's document is refused on restore as * `not-recorded`. */ export interface SessionCheckpointStore { /** Persist a new checkpoint of `scope.turnId` and return the record payload that commits it. */ write(scope: CheckpointScope, checkpoint: Checkpoint): Promise; /** Read one of the turn's checkpoints without checking it against the log. */ read(scope: CheckpointScope, checkpointId: CheckpointId): Promise; /** * Read one of the turn's checkpoints for a resume: refused with * {@link CheckpointIntegrityError} unless its record exists, its bytes * hash to the record's `docSha256`, and the log still holds the record it * was taken through. */ restore(scope: CheckpointScope, checkpointId: CheckpointId): Promise; /** The turn's checkpoints, oldest first (`createdAt`, then id). */ list(scope: CheckpointScope): Promise; delete(scope: CheckpointScope, checkpointId: CheckpointId): Promise; /** * Delete the turn's oldest committed checkpoints until `keepLast` newer * committed ones remain, never one an open decision references. Only a * checkpoint a `checkpoint_written` record names is counted or deleted: a * document no record commits is inert and left alone, so it can never * stand in for the turn's resume point. Returns the deleted ids, oldest * first, for the `checkpoint_pruned` record (none: append nothing). */ prune(scope: CheckpointScope, keepLast: number): Promise; } /** Validate every id of a scope, so none can reach a path or a key unchecked. */ export declare function validateCheckpointScope(scope: CheckpointScope): CheckpointScope; /** The one serialisation every store writes and hashes. */ export declare function serializeCheckpoint(checkpoint: Checkpoint): string; export declare function sha256Hex(text: string): string; /** The record `path` of a checkpoint, relative to its session directory. */ export declare function checkpointRecordPath(checkpointId: CheckpointId): string; /** * Parse a document and check it belongs where it was found: a document * whose session or id differs from its address is damage, not a miss. */ export declare function parseStoredCheckpoint(text: string, scope: CheckpointScope, checkpointId: CheckpointId): Checkpoint; /** A checkpoint document stored under an address it does not name, or written for another scope. */ export declare class CheckpointOwnerError extends Error { readonly name = "CheckpointOwnerError"; } /** Refuse a write whose document names another session or turn than its scope. */ export declare function checkWriteOwner(scope: CheckpointScope, checkpoint: Checkpoint): Checkpoint; /** Build the receipt a successful write returns. */ export declare function writeReceipt(checkpoint: Checkpoint, text: string): CheckpointWriteReceipt; /** * The restore rule, shared by every store: the checkpoint's bytes must be * the ones its record committed, and the log prefix it covers must be intact. */ export declare function verifyCheckpoint(log: CheckpointLogView, scope: CheckpointScope, checkpoint: Checkpoint, text: string): Promise; //# sourceMappingURL=contract.d.ts.map