{"version":3,"file":"contract-digest.d.ts","sourceRoot":"","sources":["../../../src/core/long-horizon/contract-digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAShF","sourcesContent":["/**\n * Deterministic SHA-256 contract digest.\n *\n * Computes a cryptographic hash of a MissionContractV1 for\n * binding the Requirement Ledger to an exact contract revision.\n *\n * The digest covers every semantically relevant contract field.\n * Metadata is excluded from the digest (by default).\n */\n\nimport { createHash } from \"crypto\";\nimport { toCanonicalJson } from \"./canonical-json.js\";\nimport type { MissionContractV1 } from \"./types.js\";\n\n/**\n * Compute a deterministic SHA-256 digest of a mission contract.\n *\n * Returns a lowercase hexadecimal string.\n */\nexport function computeMissionContractDigest(contract: MissionContractV1): string {\n\t// Build a canonicalized representation of the contract,\n\t// excluding metadata (which is non-semantic).\n\tconst canonical = canonicalizeContract(contract);\n\tconst json = toCanonicalJson(canonical);\n\n\tconst hash = createHash(\"sha256\");\n\thash.update(json, \"utf-8\");\n\treturn hash.digest(\"hex\");\n}\n\n/**\n * Produce a canonical contract representation for hashing.\n * Excludes metadata and normalizes field ordering.\n */\nfunction canonicalizeContract(contract: MissionContractV1): unknown {\n\treturn {\n\t\tcontractVersion: contract.contractVersion,\n\t\tmissionId: contract.missionId,\n\t\trevision: contract.revision,\n\t\ttitle: contract.title,\n\t\tobjective: contract.objective,\n\t\tworkstreams: contract.workstreams.map(canonicalizeWorkstream),\n\t\trequirements: contract.requirements.map(canonicalizeRequirement),\n\t\tconstraints: contract.constraints.map(canonicalizeConstraint),\n\t\tforbiddenActions: contract.forbiddenActions.map(canonicalizeForbiddenAction),\n\t\tevidencePolicy: canonicalizeEvidencePolicy(contract.evidencePolicy),\n\t};\n}\n\nfunction canonicalizeWorkstream(ws: {\n\tid: string;\n\ttitle: string;\n\tdescription?: string;\n\tparentId?: string;\n\torder?: number;\n}): unknown {\n\tconst result: Record<string, unknown> = { id: ws.id, title: ws.title };\n\tif (ws.description !== undefined) result.description = ws.description;\n\tif (ws.parentId !== undefined) result.parentId = ws.parentId;\n\tif (ws.order !== undefined) result.order = ws.order;\n\treturn result;\n}\n\nfunction canonicalizeRequirement(req: {\n\tid: string;\n\tworkstreamId: string;\n\tkind: \"EXPLICIT\" | \"INFERRED\";\n\tstatement: string;\n\trationale?: string;\n\tsourceRefs: string[];\n\tdependencies: string[];\n\tacceptanceCriteria: Array<{\n\t\tid: string;\n\t\tstatement: string;\n\t\trequiredEvidence: Array<{\n\t\t\tallowedTypes?: string[];\n\t\t\tminAuthority?: string;\n\t\t\trequiredCollectorClass?: string;\n\t\t\tminPassingStatus?: string;\n\t\t}>;\n\t}>;\n\tinitialApplicability?: string;\n}): unknown {\n\tconst result: Record<string, unknown> = {\n\t\tid: req.id,\n\t\tworkstreamId: req.workstreamId,\n\t\tkind: req.kind,\n\t\tstatement: req.statement,\n\t\tsourceRefs: [...req.sourceRefs].sort(),\n\t\tdependencies: [...req.dependencies].sort(),\n\t\tacceptanceCriteria: req.acceptanceCriteria.map(canonicalizeCriterion),\n\t};\n\tif (req.rationale !== undefined) result.rationale = req.rationale;\n\tif (req.initialApplicability !== undefined) result.initialApplicability = req.initialApplicability;\n\treturn result;\n}\n\nfunction canonicalizeCriterion(crit: {\n\tid: string;\n\tstatement: string;\n\trequiredEvidence: Array<{\n\t\tallowedTypes?: string[];\n\t\tminAuthority?: string;\n\t\trequiredCollectorClass?: string;\n\t\tminPassingStatus?: string;\n\t}>;\n}): unknown {\n\treturn {\n\t\tid: crit.id,\n\t\tstatement: crit.statement,\n\t\trequiredEvidence: crit.requiredEvidence.map(canonicalizeEvidenceRequirement),\n\t};\n}\n\nfunction canonicalizeEvidenceRequirement(evReq: {\n\tallowedTypes?: string[];\n\tminAuthority?: string;\n\trequiredCollectorClass?: string;\n\tminPassingStatus?: string;\n}): unknown {\n\tconst result: Record<string, unknown> = {};\n\tif (evReq.allowedTypes !== undefined && evReq.allowedTypes.length > 0) {\n\t\tresult.allowedTypes = [...evReq.allowedTypes].sort();\n\t}\n\tif (evReq.minAuthority !== undefined) result.minAuthority = evReq.minAuthority;\n\tif (evReq.requiredCollectorClass !== undefined) result.requiredCollectorClass = evReq.requiredCollectorClass;\n\tif (evReq.minPassingStatus !== undefined) result.minPassingStatus = evReq.minPassingStatus;\n\treturn result;\n}\n\nfunction canonicalizeConstraint(con: {\n\tid: string;\n\tkind: string;\n\tstatement: string;\n\tsourceRefs: string[];\n\tseverity: string;\n}): unknown {\n\treturn {\n\t\tid: con.id,\n\t\tkind: con.kind,\n\t\tstatement: con.statement,\n\t\tsourceRefs: [...con.sourceRefs].sort(),\n\t\tseverity: con.severity,\n\t};\n}\n\nfunction canonicalizeForbiddenAction(fa: {\n\tid: string;\n\tstatement: string;\n\tsourceRefs: string[];\n\tseverity: string;\n\tmatchHint?: string;\n}): unknown {\n\tconst result: Record<string, unknown> = {\n\t\tid: fa.id,\n\t\tstatement: fa.statement,\n\t\tsourceRefs: [...fa.sourceRefs].sort(),\n\t\tseverity: fa.severity,\n\t};\n\tif (fa.matchHint !== undefined) result.matchHint = fa.matchHint;\n\treturn result;\n}\n\nfunction canonicalizeEvidencePolicy(policy: {\n\tauthoritativeSources: string[];\n\trules?: Array<{\n\t\tid: string;\n\t\tdescription: string;\n\t\tallowedTypes?: string[];\n\t\tminAuthority?: string;\n\t\trequiredCollectorClass?: string;\n\t}>;\n}): unknown {\n\tconst result: Record<string, unknown> = {\n\t\tauthoritativeSources: [...policy.authoritativeSources].sort(),\n\t};\n\tif (policy.rules && policy.rules.length > 0) {\n\t\tresult.rules = policy.rules.map((r) => canonicalizePolicyRule(r));\n\t}\n\treturn result;\n}\n\nfunction canonicalizePolicyRule(rule: {\n\tid: string;\n\tdescription: string;\n\tallowedTypes?: string[];\n\tminAuthority?: string;\n\trequiredCollectorClass?: string;\n}): unknown {\n\tconst result: Record<string, unknown> = { id: rule.id, description: rule.description };\n\tif (rule.allowedTypes !== undefined && rule.allowedTypes.length > 0) {\n\t\tresult.allowedTypes = [...rule.allowedTypes].sort();\n\t}\n\tif (rule.minAuthority !== undefined) result.minAuthority = rule.minAuthority;\n\tif (rule.requiredCollectorClass !== undefined) result.requiredCollectorClass = rule.requiredCollectorClass;\n\treturn result;\n}\n"]}