import { EVIDENCE_PATH_PREFIX, computeSourceDigest } from '@enterprise-skills/core'; /** * Evidence → reviewed-code binding (Release Governance Architecture §8). * * The Governor's `on_stale` policy has always been able to reject evidence that * belongs to a different commit — but only if somebody actually READS the * binding. Until this module existed, `es govern` stamped the current HEAD onto * whatever YAML happened to sit in `.project-ai/skill-outputs/`, which made the * binding self-fulfilling: `on_stale` was unreachable and a single committed * evidence file passed every future commit forever. * * The binding is DECLARED BY THE PRODUCER and VERIFIED here. Anything the * reader cannot verify is unbound, and unbound is treated exactly like stale — * fail-closed. * * TWO binding forms are accepted (see docs/adr/0002): * * - `commit: ` — the original. Verified by identity with the deciding * commit, or by ancestry plus an evidence-only delta. * - `source_digest: sha256:` — a digest of the reviewed source tree, * evidence excluded. Verified by recomputing it at the deciding commit. * * The digest exists because commit identity does not survive squash-merge. A * squash mints a new sha, so evidence committed on a feature branch is bound to * a sha that is no longer an ancestor of anything on the default branch — * `merge-base --is-ancestor` then fails forever and the domain is stale for * every future commit. That made the gate satisfiable only by redoing the review * on every PR, or by re-stamping the sha, and re-stamping is a fabrication: it * claims a review describes code it never saw. A content digest removes the * incentive, because it survives any rewrite that preserves the tree (squash, * rebase, cherry-pick) and goes stale exactly when the reviewed code changes. * * Both forms remain valid: evidence in the wild declares only `commit:`, and a * reader that stopped honouring it would fail every existing customer closed. */ /** * Re-exported from core, which owns the protocol primitives the server also * implements (ADR 0002). Kept exported here so existing importers do not have to * care which package the constant moved to. */ export { EVIDENCE_PATH_PREFIX, computeSourceDigest }; /** The declared `commit:` of an evidence document, or null when absent/unusable. */ export declare function readDeclaredCommit(doc: unknown): string | null; /** Same, straight from a file. Fail-soft: an unreadable file is simply unbound. */ export declare function readDeclaredCommitFile(filePath: string): string | null; /** A declared binding may be abbreviated, so long as it prefixes the real sha. */ export declare function bindsToCommit(declared: string, commitSha: string): boolean; /** The declared `source_digest:` of an evidence document, or null when unusable. */ export declare function readDeclaredSourceDigest(doc: unknown): string | null; /** Same, straight from a file. Fail-soft: an unreadable file simply declares none. */ export declare function readDeclaredSourceDigestFile(filePath: string): string | null; export type BindingVerdict = { fresh: true; via: 'head' | 'evidence-only-delta' | 'source-identical'; } | { fresh: false; reason: string; }; /** * Does the declared binding make this evidence fresh for `commitSha`? * * Four outcomes, cheapest and strongest first: * * 1. `commit:` IS the deciding commit — nothing to prove. * 2. `source_digest:` recomputes equal at the deciding commit — the reviewed * source is still what would ship, whatever happened to the sha. This is the * only form that survives a squash-merge. * 3. `commit:` is a verifiable ancestor and the only delta since is evidence — * the original allowance, kept for evidence that declares no digest. Evidence * FOR a commit can only be committed AFTER it, so the evidence commit is * necessarily a descendant. * 4. Otherwise stale, and the reason says which check failed. * * The digest is tried before ancestry deliberately: after a squash the ancestry * check cannot succeed, and reporting "not a verifiable ancestor" for evidence * that is provably describing the current source would be actively misleading. */ export declare function verifyBinding(params: { declared: string | null; /** Declared `source_digest:`, when the producer wrote one. */ declaredSourceDigest?: string | null; commitSha: string; git: (args: string) => string; /** * The deciding commit's digest, when the caller already computed it. * * `es govern` computes it once per run for the decision it posts, and a domain * can have several feeders that each declare a digest — recomputing per feeder * meant N identical `ls-tree` calls for one answer. Passing it in makes the * cost one call per run. Omit it and this computes on demand, so no caller is * obliged to pre-compute. */ computedSourceDigest?: string | null; }): BindingVerdict; //# sourceMappingURL=evidence-binding.d.ts.map