export declare const PS_MARKER_FILE = ".ps-snapshot-version"; export declare const PS_SENTINEL_FILE = ".ps-turn-inprogress"; export declare const PS_TURN_COMMIT_FILE = ".ps-turn-commit.json"; export interface SnapshotMarker { version: number; turnKey?: string; contentHash?: string; /** * Transcript epoch the local files belong to (session regeneration). * Absent = 0 (legacy). A marker whose epoch differs from the * orchestration's current epoch names a DEAD incarnation: the lifecycle * preamble must treat the dir as untrusted and resolve from the * epoch-scoped store — never trust it warm, never throw. */ epoch?: number; updatedAt: string; } export interface TurnSentinel { turnKey?: string; startedAt: string; } export interface SnapshotProbe { exists: boolean; /** Monotonic version; 0 when the snapshot predates the protocol (legacy). */ version: number; turnKey?: string; contentHash?: string; /** Compressed (stored) tar size in bytes. */ sizeBytes?: number; /** Uncompressed tar-stream size in bytes (feeds the compression-ratio stat). */ rawSizeBytes?: number; /** True when a snapshot exists but carries no version metadata. */ legacy?: boolean; } export interface SnapshotCommitInput { /** The stored version this commit is based on (preamble-resolved). */ baseVersion: number; /** Deterministic per-turn key — makes commit retries idempotent. */ turnKey: string; } export interface SnapshotCommitResult { version: number; contentHash: string; /** Committed (compressed) tar size — feeds session persistence stats. */ sizeBytes?: number; /** Uncompressed tar-stream size — feeds the compression-ratio stat. */ rawSizeBytes?: number; /** * True when the store already held baseVersion+1 under the same turnKey — * a prior attempt of this same turn committed. The caller must treat this * as success without re-writing. */ alreadyCommitted: boolean; } export interface SnapshotHydrateResult { version: number; turnKey?: string; contentHash?: string; sizeBytes?: number; rawSizeBytes?: number; legacy?: boolean; } /** * Foreign writer advanced the session past the caller's base — split-brain * fence. Loud by design: the activity fails and re-validates via retry. */ export declare class SnapshotConflictError extends Error { storedVersion: number; storedTurnKey?: string; constructor(sessionId: string, baseVersion: number, storedVersion: number, storedTurnKey?: string); } /** * Versioned CAS contract implemented by session snapshot stores * (filesystem + Azure blob in this phase; PG later). All methods operate on * whole snapshots — the same tar the legacy dehydrate/hydrate/checkpoint * paths move around. */ export interface VersionedSnapshotStore { /** Cheap metadata read — no snapshot bytes transferred. */ probeSnapshot(sessionId: string, epoch?: number): Promise; /** * Tar the local session dir and CAS-write it: succeed iff the stored * version equals `baseVersion` (or the same turnKey already committed * baseVersion+1 → `alreadyCommitted`). Local files are NOT removed. * Throws {@link SnapshotConflictError} on a foreign advance. */ commitSnapshot(sessionId: string, input: SnapshotCommitInput, epoch?: number): Promise; /** * Download the stored snapshot and atomically replace the local session * dir (unpack to a temp dir, then rename — a crash mid-hydrate never * leaves a plausible-looking dir). Does NOT write the marker; the * lifecycle layer does, so marker semantics live in one place. */ hydrateSnapshot(sessionId: string, epoch?: number): Promise; } /** * Epoch key scoping (session regeneration, proposal §6): * * epoch 0 (or absent) → the LEGACY key family, byte-for-byte — blob * `S.tar.gz`, fs `S.v.tar.{br,gz}` + `S.meta.json`. * Every pre-regen session keeps its storage forever; * there is no migration. * epoch >= 1 → a separate CAS chain per epoch whose version * numbering restarts at 1. KEY-SHAPE INVARIANT: no * epoch-scoped BLOB name may end in `.tar.gz` or * `.meta.json` — those are the only shapes the * shipped 1.0.66 resource-manager purge collects as * delete candidates (resourcemgr-tools.ts:441-449), * and fail-closed parsing in NEW code cannot protect * against an OLD binary. Epoch blobs are * `S.e.tar.br` (brotli is the only codec for new * chains) with `psepoch` metadata and no meta.json * mirror. * * Separate chains are the fence that makes a zombie old-epoch commit harmless * to the new epoch: it lands on its own key with its own CAS counter. */ export declare function isLegacyEpoch(epoch: number | undefined): boolean; export declare function supportsVersionedSnapshots(store: unknown): store is VersionedSnapshotStore; export declare function turnCommitFilePath(sessionDir: string): string; export declare function readSnapshotMarker(sessionDir: string): SnapshotMarker | null; export declare function writeSnapshotMarker(sessionDir: string, marker: Omit): void; export declare function readTurnSentinel(sessionDir: string): TurnSentinel | null; export declare function writeTurnSentinel(sessionDir: string, turnKey?: string): void; export declare function clearTurnSentinel(sessionDir: string): void; export declare function writeTurnCommitFile(sessionDir: string, turnKey: string, result: unknown): void; export declare function readTurnCommitFile(sessionDir: string): { turnKey: string; result: unknown; } | null; export declare function sha256File(filePath: string): string; //# sourceMappingURL=snapshot-protocol.d.ts.map