/* dossier-hash — compute and verify certification dossier content hashes for integrity checks. Do not write dossiers — this module only hashes them. RFC-1097: sweep — werkstatt-engine clean Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics. */ import { snapshotCanonicalJsonObjectV1, canonicalJsonHashV1, } from "@warpgogol/werkstatt-shared/fingerprint"; import type { Sha256Digest } from "@warpgogol/werkstatt-shared/fingerprint"; import type { CertificationDossierEventV1 } from "./contracts/index.ts"; import { buildDossierEventIdentityV1 } from "./identity.ts"; export type DossierHashFailureV1 = { readonly ok: false; readonly code: string; readonly message: string; }; export type DossierEventHashResultV1 = | { readonly ok: true; readonly eventHash: Sha256Digest; } | DossierHashFailureV1; export function computeDossierEventHash( event: CertificationDossierEventV1, ): DossierEventHashResultV1 { const identityResult = buildDossierEventIdentityV1(event); if (!identityResult.ok) { return { ok: false, code: identityResult.diagnostic.code, message: identityResult.diagnostic.message, }; } return { ok: true, eventHash: identityResult.digest }; } export function computeDossierRoot( candidateId: string, orderedEventHashes: readonly Sha256Digest[], ): Sha256Digest { const payload = { schema: "werkstatt/dossier-root@1", candidateId, eventHashes: orderedEventHashes, }; const snapshotResult = snapshotCanonicalJsonObjectV1(payload); if (!snapshotResult.ok) { throw new Error( `CERT-DOSSIER-ROOT-01: failed to snapshot dossier root: ${snapshotResult.message}`, ); } return canonicalJsonHashV1(snapshotResult.value); }