import { WorkspaceStorageError } from "../domain/errors.js"; import type { EvidenceFilePolicy } from "../domain/evidenceBundle.js"; import { parseReconstructionCoverageWorkspace, serializeReconstructionCoverageWorkspace, type ReconstructionCoverageWorkspace, } from "../domain/reconstructionCoverage.js"; import { err, ok, type Result } from "../domain/result.js"; import { readRevisionedWorkspace, writeRevisionedWorkspace, type RevisionedWorkspaceCodec, } from "./RevisionedWorkspaceStore.js"; const codec: RevisionedWorkspaceCodec = { parse: parseReconstructionCoverageWorkspace, serialize: serializeReconstructionCoverageWorkspace, validateNext: (current, next, expectedRevision) => { if ((current?.revision ?? null) !== expectedRevision) return err(new WorkspaceStorageError("update", "revision-conflict")); if (current === null) return next.revision === 1 && next.previous_revision_sha256 === null ? ok(null) : err(new WorkspaceStorageError("update", "revision-conflict")); if ( current.name !== next.name || current.workspace_id !== next.workspace_id ) return err(new WorkspaceStorageError("update", "name-conflict")); return next.revision === current.revision + 1 && next.previous_revision_sha256 === current.revision_sha256 ? ok(null) : err(new WorkspaceStorageError("update", "revision-conflict")); }, }; /** Read a validated reconstruction coverage workspace revision. */ export const readReconstructionCoverageWorkspace = ( path: string, policy: EvidenceFilePolicy, ): Promise< Result > => readRevisionedWorkspace(path, policy, codec); /** Atomically append one reconstruction coverage workspace CAS revision. */ export const writeReconstructionCoverageWorkspace = ( workspace: ReconstructionCoverageWorkspace, path: string, expectedRevision: number | null, policy: EvidenceFilePolicy, ): Promise< Result< { readonly path: string; readonly bytes: number }, WorkspaceStorageError > > => writeRevisionedWorkspace(path, policy, { document: workspace, expectedRevision, codec, });