@actuarial-ts/compliance 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,8 @@
1
1
  import {
2
2
  CORE_PACKAGE_VERSION,
3
+ DiagnosticValidationError,
3
4
  canonicalJson,
5
+ compileDiagnosticDefinition,
4
6
  fnv1a64,
5
7
  getMetricDiagnosticsResultIdentity,
6
8
  getPreparedDiagnosticDataIdentity,
@@ -8,15 +10,19 @@ import {
8
10
  verifyPreparedDiagnosticDataIntegrity,
9
11
  type DiagnosticDeepReadonly,
10
12
  type CompiledDiagnosticDefinition,
13
+ type DiagnosticDefinition,
11
14
  type JsonValue as CoreDiagnosticJsonValue,
12
15
  type NormalizedDiagnosticDefinitionIdentity,
13
16
  type NormalizedDiagnosticPreparationIdentity,
14
17
  type NormalizedDiagnosticResultIdentity,
18
+ type MetricDiagnosticsResult,
15
19
  } from "@actuarial-ts/core";
16
20
  import {
17
21
  DATA_PACKAGE_VERSION,
18
22
  assertCompletedValidatedMetricDiagnosticsRun,
19
23
  reviewPreparedDiagnosticData,
24
+ runValidatedMetricDiagnostics,
25
+ validateDiagnosticRunInput,
20
26
  type CompletedValidatedMetricDiagnosticsRun,
21
27
  type DiagnosticReviewIdentityBody,
22
28
  type DiagnosticReviewReceipt,
@@ -24,28 +30,84 @@ import {
24
30
  import { ComplianceError } from "./errors.js";
25
31
  import { COMPLIANCE_PACKAGE_VERSION } from "./version.js";
26
32
 
27
- export interface DiagnosticArtifactDigestBase { readonly id: string; readonly scope: "input" | "preparation"; readonly algorithm: string; readonly value: string; readonly byteLength: number }
28
- export type DiagnosticArtifactDigest = DiagnosticArtifactDigestBase & { readonly assurance: "sdk-computed" | "caller-declared" };
33
+ export interface DiagnosticArtifactDigestBase {
34
+ readonly id: string;
35
+ readonly value: string;
36
+ readonly scope: "input" | "preparation";
37
+ }
38
+ export type DiagnosticArtifactDigest = DiagnosticArtifactDigestBase &
39
+ (
40
+ | {
41
+ readonly assurance: "sdk-computed";
42
+ readonly algorithm: "sha256";
43
+ readonly byteLength: number;
44
+ }
45
+ | { readonly assurance: "caller-declared"; readonly algorithm: string }
46
+ );
29
47
  export type DiagnosticArtifactEvidence =
30
- | { readonly id: string; readonly scope: "input" | "preparation"; readonly assurance: "sdk-computed"; readonly bytes: Uint8Array }
31
- | { readonly id: string; readonly scope: "input" | "preparation"; readonly assurance: "caller-declared"; readonly algorithm: string; readonly value: string; readonly byteLength: number };
32
- export interface DiagnosticPreparationLineage { readonly artifactId: string; readonly inputArtifactIds: readonly string[] }
48
+ | {
49
+ readonly id: string;
50
+ readonly scope: "input" | "preparation";
51
+ readonly assurance: "sdk-computed";
52
+ readonly bytes: Uint8Array;
53
+ }
54
+ | {
55
+ readonly id: string;
56
+ readonly scope: "input" | "preparation";
57
+ readonly assurance: "caller-declared";
58
+ readonly algorithm: string;
59
+ readonly value: string;
60
+ };
61
+ export interface DiagnosticPreparationLineage {
62
+ readonly outputArtifactId: string;
63
+ readonly inputArtifactIds: readonly string[];
64
+ readonly transformationArtifactIds: readonly string[];
65
+ }
33
66
 
34
67
  export interface DiagnosticRunManifest {
35
68
  readonly definitionIntegrity: string;
36
69
  readonly runPresetId: string | null;
37
70
  readonly datasetArtifactId: string | null;
38
- readonly packageVersions: Readonly<Record<string, string>>;
39
- readonly preparation: DiagnosticDeepReadonly<NormalizedDiagnosticPreparationIdentity>;
40
71
  readonly preparationFingerprint: string;
41
- readonly expectedGridFingerprint: string | null;
42
- readonly executionPolicy: { readonly review: { readonly body: DiagnosticReviewIdentityBody; readonly reportFingerprint: string }; readonly gate: CompletedValidatedMetricDiagnosticsRun["gate"] };
72
+ readonly inputArtifacts: readonly DiagnosticArtifactDigest[];
73
+ readonly preparationArtifacts: readonly DiagnosticArtifactDigest[];
74
+ readonly preparationLineage: readonly DiagnosticPreparationLineage[];
75
+ readonly inputAudit: DiagnosticDeepReadonly<
76
+ NormalizedDiagnosticPreparationIdentity["inputAudit"]
77
+ >;
78
+ readonly filter: DiagnosticDeepReadonly<
79
+ NormalizedDiagnosticPreparationIdentity["filter"]
80
+ >;
43
81
  readonly groupMap: Readonly<Record<string, string>>;
44
82
  readonly groupDimensions: Readonly<Record<string, CoreDiagnosticJsonValue>>;
45
- readonly artifacts: readonly DiagnosticArtifactDigest[];
46
- readonly lineage: readonly DiagnosticPreparationLineage[];
83
+ readonly completePeriodCutoffs: DiagnosticDeepReadonly<
84
+ NormalizedDiagnosticPreparationIdentity["completePeriodCutoffs"]
85
+ >;
86
+ readonly expectedCellGridFingerprint: string | null;
87
+ readonly executionPolicy: {
88
+ readonly review: DiagnosticReviewReceipt;
89
+ readonly gate: CompletedValidatedMetricDiagnosticsRun["gate"];
90
+ };
91
+ readonly engine: {
92
+ readonly packages: {
93
+ readonly core: string;
94
+ readonly data: string;
95
+ readonly compliance: string;
96
+ };
97
+ readonly algorithmVersion: "diagnostics-1";
98
+ };
47
99
  }
48
- export type NormalizedDiagnosticRunManifestIdentity = DiagnosticDeepReadonly<DiagnosticRunManifest>;
100
+ export type NormalizedDiagnosticRunManifestIdentity = DiagnosticDeepReadonly<
101
+ Omit<DiagnosticRunManifest, "executionPolicy"> & {
102
+ readonly executionPolicy: {
103
+ readonly review: {
104
+ readonly body: DiagnosticReviewIdentityBody;
105
+ readonly reportFingerprint: string;
106
+ };
107
+ readonly gate: DiagnosticRunManifest["executionPolicy"]["gate"];
108
+ };
109
+ }
110
+ >;
49
111
 
50
112
  export interface DiagnosticRunIdentity {
51
113
  readonly runFingerprint: string;
@@ -53,96 +115,1337 @@ export interface DiagnosticRunIdentity {
53
115
  readonly runResultFingerprint: string;
54
116
  }
55
117
  export interface DiagnosticRunProvenance extends DiagnosticRunIdentity {
56
- readonly definition: DiagnosticDeepReadonly<NormalizedDiagnosticDefinitionIdentity>;
57
- readonly definitionIdentities: { readonly algorithm: "fnv1a64-jcs-v1"; readonly formulaById: Readonly<Record<string,string>>; readonly calculationByInstanceId: Readonly<Record<string,string>>; readonly definition: string };
58
- readonly manifest: NormalizedDiagnosticRunManifestIdentity;
118
+ readonly definition: {
119
+ readonly definition: DiagnosticDeepReadonly<NormalizedDiagnosticDefinitionIdentity>;
120
+ readonly identities: {
121
+ readonly algorithm: "fnv1a64-jcs-v1";
122
+ readonly formulaById: Readonly<Record<string, string>>;
123
+ readonly calculationByInstanceId: Readonly<Record<string, string>>;
124
+ readonly definition: string;
125
+ };
126
+ };
127
+ readonly manifest: DiagnosticDeepReadonly<DiagnosticRunManifest>;
59
128
  readonly review: DiagnosticReviewReceipt;
60
- readonly result: DiagnosticDeepReadonly<NormalizedDiagnosticResultIdentity>;
129
+ readonly result: DiagnosticDeepReadonly<MetricDiagnosticsResult>;
61
130
  }
62
131
  declare const verifiedDiagnosticRunProvenanceBrand: unique symbol;
63
- export interface VerifiedDiagnosticRunProvenance extends DiagnosticRunProvenance { readonly [verifiedDiagnosticRunProvenanceBrand]: true }
64
- export interface CreateDiagnosticRunIdentityInput { readonly completedRun: CompletedValidatedMetricDiagnosticsRun; readonly artifacts?: readonly DiagnosticArtifactEvidence[]; readonly lineage?: readonly DiagnosticPreparationLineage[] }
132
+ export interface VerifiedDiagnosticRunProvenance
133
+ extends DiagnosticRunProvenance {
134
+ readonly [verifiedDiagnosticRunProvenanceBrand]: true;
135
+ }
136
+ export interface CreateDiagnosticRunIdentityInput {
137
+ readonly completedRun: CompletedValidatedMetricDiagnosticsRun;
138
+ readonly inputArtifacts: readonly DiagnosticArtifactEvidence[];
139
+ readonly preparationArtifacts: readonly DiagnosticArtifactEvidence[];
140
+ readonly preparationLineage: readonly DiagnosticPreparationLineage[];
141
+ }
65
142
 
66
143
  const verified = new WeakMap<object, CompletedValidatedMetricDiagnosticsRun>();
67
- const token = (value:string,path:string) => {
68
- if (value.length === 0 || /^[\t-\r ]|[\t-\r ]$/.test(value) || value.includes("\0")) throw new ComplianceError("BAD_DIAGNOSTIC_RUN", `${path} must be a nonempty token`, path);
69
- for(let index=0;index<value.length;index++){const unit=value.charCodeAt(index);if(unit>=0xd800&&unit<=0xdbff){const next=value.charCodeAt(index+1);if(!(next>=0xdc00&&next<=0xdfff))throw new ComplianceError("BAD_DIAGNOSTIC_RUN",`${path} contains malformed Unicode`,path);index++}else if(unit>=0xdc00&&unit<=0xdfff)throw new ComplianceError("BAD_DIAGNOSTIC_RUN",`${path} contains malformed Unicode`,path)}
144
+ const token = (value: string, path: string) => {
145
+ if (
146
+ value.length === 0 ||
147
+ /^[\t-\r ]|[\t-\r ]$/.test(value) ||
148
+ value.includes("\0")
149
+ )
150
+ throw new ComplianceError(
151
+ "BAD_DIAGNOSTIC_RUN",
152
+ `${path} must be a nonempty token`,
153
+ path,
154
+ );
155
+ for (let index = 0; index < value.length; index++) {
156
+ const unit = value.charCodeAt(index);
157
+ if (unit >= 0xd800 && unit <= 0xdbff) {
158
+ const next = value.charCodeAt(index + 1);
159
+ if (!(next >= 0xdc00 && next <= 0xdfff))
160
+ throw new ComplianceError(
161
+ "BAD_DIAGNOSTIC_RUN",
162
+ `${path} contains malformed Unicode`,
163
+ path,
164
+ );
165
+ index++;
166
+ } else if (unit >= 0xdc00 && unit <= 0xdfff)
167
+ throw new ComplianceError(
168
+ "BAD_DIAGNOSTIC_RUN",
169
+ `${path} contains malformed Unicode`,
170
+ path,
171
+ );
172
+ }
70
173
  };
71
- function freeze<T>(value:T,seen=new WeakSet<object>()):DiagnosticDeepReadonly<T>{if(value===null||typeof value!=="object"||seen.has(value))return value as DiagnosticDeepReadonly<T>;seen.add(value);for(const child of Object.values(value as Record<string,unknown>))freeze(child,seen);return Object.freeze(value) as DiagnosticDeepReadonly<T>}
72
- function tag(kind:string,key:string,value:unknown):string{return `fnv1a64-jcs-v1:${fnv1a64(canonicalJson({identityVersion:1,kind,[key]:value}))}`}
73
- type SnapshottedArtifact=DiagnosticArtifactDigest|{readonly id:string;readonly scope:"input"|"preparation";readonly assurance:"sdk-computed";readonly bytes:Uint8Array};
74
- function snapshotArtifacts(evidence:readonly DiagnosticArtifactEvidence[]):readonly SnapshottedArtifact[]{
75
- const seen=new Set<string>();const result:SnapshottedArtifact[]=[];
76
- for(const [index,item] of evidence.entries()){
77
- token(item.id,`$.artifacts[${index}].id`);token(item.scope,`$.artifacts[${index}].scope`);if(seen.has(item.id))throw new ComplianceError("BAD_DIAGNOSTIC_RUN",`Duplicate artifact ID ${item.id}`,`$.artifacts[${index}].id`);seen.add(item.id);
78
- if(item.assurance==="sdk-computed"){
79
- if(!(item.bytes instanceof Uint8Array))throw new ComplianceError("BAD_DIAGNOSTIC_RUN","SDK-computed artifact evidence requires actual Uint8Array bytes",`$.artifacts[${index}].bytes`);
80
- const bytes=new Uint8Array(item.bytes.byteLength);bytes.set(item.bytes);result.push({id:item.id,scope:item.scope,assurance:item.assurance,bytes});
81
- }else{token(item.algorithm,`$.artifacts[${index}].algorithm`);token(item.value,`$.artifacts[${index}].value`);if(!Number.isSafeInteger(item.byteLength)||item.byteLength<0)throw new ComplianceError("BAD_DIAGNOSTIC_RUN","Artifact byteLength must be a nonnegative safe integer",`$.artifacts[${index}].byteLength`);result.push({...item})}
82
- }
83
- return result.sort((a,b)=>a.id<b.id?-1:a.id>b.id?1:0);
84
- }
85
- async function digestArtifacts(snapshot:readonly SnapshottedArtifact[]):Promise<readonly DiagnosticArtifactDigest[]>{
86
- if(snapshot.some((item)=>"bytes" in item)&&globalThis.crypto?.subtle===undefined)throw new ComplianceError("CRYPTO_UNAVAILABLE","Web Crypto SHA-256 is unavailable","$.artifacts");
87
- return Promise.all(snapshot.map(async(item)=>{if(!("bytes" in item))return item;const hash=await globalThis.crypto.subtle.digest("SHA-256",item.bytes);return {id:item.id,scope:item.scope,assurance:item.assurance,algorithm:"sha-256",value:[...new Uint8Array(hash)].map((b)=>b.toString(16).padStart(2,"0")).join(""),byteLength:item.bytes.byteLength}}));
88
- }
89
-
90
- function snapshotLineage(lineage:readonly DiagnosticPreparationLineage[]):readonly DiagnosticPreparationLineage[]{
91
- return lineage.map((item,index)=>{token(item.artifactId,`$.lineage[${index}].artifactId`);if(!Array.isArray(item.inputArtifactIds))throw new ComplianceError("BAD_DIAGNOSTIC_RUN","Lineage inputs must be an array",`$.lineage[${index}].inputArtifactIds`);const inputs=item.inputArtifactIds.map((id,inputIndex)=>{token(id,`$.lineage[${index}].inputArtifactIds[${inputIndex}]`);return id});if(new Set(inputs).size!==inputs.length)throw new ComplianceError("BAD_DIAGNOSTIC_RUN","Lineage inputs must be unique",`$.lineage[${index}].inputArtifactIds`);return {artifactId:item.artifactId,inputArtifactIds:[...inputs].sort()}}).sort((a,b)=>a.artifactId<b.artifactId?-1:a.artifactId>b.artifactId?1:0);
92
- }
93
-
94
- function validateArtifactGraph(run:CompletedValidatedMetricDiagnosticsRun,artifacts:readonly DiagnosticArtifactDigest[],lineage:readonly DiagnosticPreparationLineage[]):void{
95
- const byId=new Map(artifacts.map((item)=>[item.id,item]));
96
- const referenced=new Set<string>();
97
- const requireArtifact=(id:string,scope:"input"|"preparation",path:string)=>{const artifact=byId.get(id);if(!artifact)throw new ComplianceError("BAD_DIAGNOSTIC_RUN",`Artifact reference ${id} is unresolved`,path);if(artifact.scope!==scope)throw new ComplianceError("BAD_DIAGNOSTIC_RUN",`Artifact ${id} must have ${scope} scope`,path);referenced.add(id)};
98
- let unsourced=false;
99
- for(const [index,item] of run.prepared.inputAudit.entries()){const source=item.record.source;if(source)requireArtifact(source.artifactId,"input",`$.completedRun.prepared.inputAudit[${index}].record.source.artifactId`);else unsourced=true}
100
- const evidence=run.review.evidence;
101
- if(evidence){for(const [index,item] of evidence.groupingAssignments.entries()){if(item.source)requireArtifact(item.source.artifactId,"input",`$.completedRun.review.evidence.groupingAssignments[${index}].source.artifactId`);else unsourced=true}for(const [index,item] of evidence.cachedFormulas.entries()){if(item.source)requireArtifact(item.source.artifactId,"input",`$.completedRun.review.evidence.cachedFormulas[${index}].source.artifactId`);else unsourced=true}}
102
- if(unsourced){if(run.datasetArtifactId===null)throw new ComplianceError("BAD_DIAGNOSTIC_RUN","Unsourced diagnostic input requires datasetArtifactId","$.completedRun.datasetArtifactId");const fallback=byId.get(run.datasetArtifactId);if(!fallback||fallback.scope!=="input"||fallback.assurance!=="sdk-computed")throw new ComplianceError("BAD_DIAGNOSTIC_RUN","datasetArtifactId must resolve to SDK-computed input evidence","$.completedRun.datasetArtifactId");referenced.add(run.datasetArtifactId)}
103
- else if(run.datasetArtifactId!==null)requireArtifact(run.datasetArtifactId,"input","$.completedRun.datasetArtifactId");
104
- for(const [basisIndex,basis] of run.prepared.definition.definition.amountBases.entries())for(const [componentIndex,component] of basis.components.entries())if(component.limitation.kind!=="unlimited"&&component.limitation.kind!=="unknown"&&component.limitation.derivation.kind==="external")requireArtifact(component.limitation.derivation.transformationRef,"preparation",`$.definition.amountBases[${basisIndex}].components[${componentIndex}].limitation.derivation.transformationRef`);
105
- for(const [ruleIndex,rule] of run.prepared.definition.definition.reviewRules.entries())if(rule.kind==="layer-order"&&rule.comparability.kind==="caller-asserted")requireArtifact(rule.comparability.rationaleArtifactId,"preparation",`$.definition.reviewRules[${ruleIndex}].comparability.rationaleArtifactId`);
106
- if(run.gate.rationaleRef!==null)requireArtifact(run.gate.rationaleRef,"preparation","$.completedRun.gate.rationaleRef");
107
- const edges=new Map<string,readonly string[]>();for(const [index,edge] of lineage.entries()){if(edges.has(edge.artifactId))throw new ComplianceError("BAD_DIAGNOSTIC_RUN","An artifact may have only one producing lineage edge",`$.lineage[${index}].artifactId`);const downstream=byId.get(edge.artifactId);if(!downstream)throw new ComplianceError("BAD_DIAGNOSTIC_RUN",`Lineage artifact ${edge.artifactId} is unresolved`,`$.lineage[${index}].artifactId`);if(downstream.scope!=="input")throw new ComplianceError("BAD_DIAGNOSTIC_RUN","Lineage downstream artifact must have input scope",`$.lineage[${index}].artifactId`);for(const [inputIndex,id] of edge.inputArtifactIds.entries()){if(id===edge.artifactId)throw new ComplianceError("BAD_DIAGNOSTIC_RUN","Lineage may not reference itself",`$.lineage[${index}].inputArtifactIds[${inputIndex}]`);if(!byId.has(id))throw new ComplianceError("BAD_DIAGNOSTIC_RUN",`Lineage reference ${id} is unresolved`,`$.lineage[${index}].inputArtifactIds[${inputIndex}]`)}edges.set(edge.artifactId,edge.inputArtifactIds)}
108
- const visiting=new Set<string>(),visited=new Set<string>();const walk=(id:string,path:string)=>{if(visiting.has(id))throw new ComplianceError("BAD_DIAGNOSTIC_RUN","Artifact lineage contains a cycle",path);if(visited.has(id))return;visiting.add(id);for(const upstream of edges.get(id)??[]){referenced.add(upstream);walk(upstream,path)}visiting.delete(id);visited.add(id)};for(const id of [...referenced])walk(id,"$.lineage");
109
- for(const [index,artifact] of artifacts.entries())if(!referenced.has(artifact.id))throw new ComplianceError("BAD_DIAGNOSTIC_RUN",`Artifact ${artifact.id} is orphaned`, `$.artifacts[${index}].id`);
110
- }
111
-
112
- function rerunAndVerify(run:CompletedValidatedMetricDiagnosticsRun):{review:DiagnosticReviewReceipt;result:DiagnosticDeepReadonly<NormalizedDiagnosticResultIdentity>}{
113
- assertCompletedValidatedMetricDiagnosticsRun(run);verifyPreparedDiagnosticDataIntegrity(run.prepared);
114
- const review=reviewPreparedDiagnosticData({prepared:run.prepared,evidence:run.review.evidence});
115
- if(review.reportFingerprint!==run.review.reportFingerprint||canonicalJson(review.identityBody)!==canonicalJson(run.review.identityBody))throw new ComplianceError("DIAGNOSTIC_MISMATCH","Stored diagnostic review does not match a regenerated review","$.review");
116
- const rerun=runMetricDiagnostics({prepared:run.prepared,groupMap:run.groupMap,groupDimensions:run.groupDimensions});
117
- if(canonicalJson(getMetricDiagnosticsResultIdentity(rerun))!==canonicalJson(getMetricDiagnosticsResultIdentity(run.result)))throw new ComplianceError("DIAGNOSTIC_MISMATCH","Stored diagnostic result does not match deterministic replay","$.result");
118
- const reviewBlocked=review.report.checks.some((check)=>!run.gate.allowedReviewStatuses.includes(check.status));
119
- const metricBlocked=rerun.findings.some((finding)=>finding.category!=="structural"&&!run.gate.allowedMetricFindingSeverities.includes(finding.severity));
120
- if(reviewBlocked||metricBlocked||run.gate.reviewGate!=="passed"||run.gate.metricGate!=="passed")throw new ComplianceError("DIAGNOSTIC_MISMATCH","Diagnostic execution gates do not recompute as passed","$.gate");
121
- return {review,result:getMetricDiagnosticsResultIdentity(run.result)};
122
- }
123
-
124
- export async function createDiagnosticRunIdentity(input:CreateDiagnosticRunIdentityInput):Promise<VerifiedDiagnosticRunProvenance>{
125
- const run=input.completedRun;const authenticated=rerunAndVerify(run);const artifactSnapshot=snapshotArtifacts(input.artifacts??[]);const lineage=snapshotLineage(input.lineage??[]);const artifacts=await digestArtifacts(artifactSnapshot);validateArtifactGraph(run,artifacts,lineage);
126
- const preparation=getPreparedDiagnosticDataIdentity(run.prepared);
127
- const expectedGridFingerprint=preparation.expectedCellsProvided?tag("diagnostic-expected-grid","expectedCells",preparation.expectedCells):null;
128
- const manifest=freeze({definitionIntegrity:run.prepared.definition.definitionIntegrity,runPresetId:run.runPresetId,datasetArtifactId:run.datasetArtifactId,packageVersions:{"@actuarial-ts/core":CORE_PACKAGE_VERSION,"@actuarial-ts/data":DATA_PACKAGE_VERSION,"@actuarial-ts/compliance":COMPLIANCE_PACKAGE_VERSION},preparation,preparationFingerprint:run.prepared.preparationFingerprint,expectedGridFingerprint,executionPolicy:{review:{body:authenticated.review.identityBody,reportFingerprint:authenticated.review.reportFingerprint},gate:run.gate},groupMap:{...run.groupMap},groupDimensions:{...run.groupDimensions},artifacts,lineage});
129
- const runFingerprint=tag("diagnostic-run","run",manifest);const resultFingerprint=tag("diagnostic-result","result",authenticated.result);const runResultFingerprint=tag("diagnostic-run-result","binding",{runFingerprint,resultFingerprint});
130
- const definition=run.prepared.definition;
131
- const provenance=freeze({definition:definition.definition,definitionIdentities:{algorithm:"fnv1a64-jcs-v1" as const,formulaById:{...definition.formulaFingerprints},calculationByInstanceId:{...definition.calculationFingerprints},definition:definition.definitionIntegrity},manifest,review:authenticated.review,result:run.result,runFingerprint,resultFingerprint,runResultFingerprint}) as unknown as VerifiedDiagnosticRunProvenance;
132
- verified.set(provenance,run);return provenance;
133
- }
134
-
135
- export function assertVerifiedDiagnosticRunProvenance(value:unknown):asserts value is VerifiedDiagnosticRunProvenance{if(value===null||typeof value!=="object"||!verified.has(value))throw new ComplianceError("BAD_DIAGNOSTIC_RUN","Value is not authentic verified diagnostic provenance","$")}
174
+ function freeze<T>(
175
+ value: T,
176
+ seen = new WeakSet<object>(),
177
+ ): DiagnosticDeepReadonly<T> {
178
+ if (value === null || typeof value !== "object" || seen.has(value))
179
+ return value as DiagnosticDeepReadonly<T>;
180
+ seen.add(value);
181
+ for (const child of Object.values(value as Record<string, unknown>))
182
+ freeze(child, seen);
183
+ return Object.freeze(value) as DiagnosticDeepReadonly<T>;
184
+ }
185
+ function tag(kind: string, key: string, value: unknown): string {
186
+ return `fnv1a64-jcs-v1:${fnv1a64(canonicalJson({ identityVersion: 1, kind, [key]: value }))}`;
187
+ }
188
+ function manifestIdentity(
189
+ manifest: DiagnosticRunManifest,
190
+ ): NormalizedDiagnosticRunManifestIdentity {
191
+ return {
192
+ ...manifest,
193
+ executionPolicy: {
194
+ gate: manifest.executionPolicy.gate,
195
+ review: {
196
+ body: manifest.executionPolicy.review.identityBody,
197
+ reportFingerprint: manifest.executionPolicy.review.reportFingerprint,
198
+ },
199
+ },
200
+ };
201
+ }
202
+ function bindingTag(runFingerprint: string, resultFingerprint: string): string {
203
+ return `fnv1a64-jcs-v1:${fnv1a64(canonicalJson({ identityVersion: 1, kind: "diagnostic-run-result", runFingerprint, resultFingerprint }))}`;
204
+ }
205
+ type SnapshottedArtifact =
206
+ | DiagnosticArtifactDigest
207
+ | {
208
+ readonly id: string;
209
+ readonly scope: "input" | "preparation";
210
+ readonly assurance: "sdk-computed";
211
+ readonly bytes: Uint8Array;
212
+ };
213
+ function plain(value: unknown): value is Record<string, unknown> {
214
+ if (value === null || typeof value !== "object" || Array.isArray(value))
215
+ return false;
216
+ const prototype = Object.getPrototypeOf(value);
217
+ return prototype === Object.prototype || prototype === null;
218
+ }
219
+ function exactKeys(
220
+ value: Record<string, unknown>,
221
+ allowed: readonly string[],
222
+ path: string,
223
+ ): void {
224
+ for (const key of Object.keys(value))
225
+ if (!allowed.includes(key))
226
+ throw new ComplianceError(
227
+ "BAD_DIAGNOSTIC_RUN",
228
+ `Unknown field ${key}`,
229
+ `${path}.${key}`,
230
+ );
231
+ }
232
+ function snapshotArtifacts(
233
+ evidence: unknown,
234
+ scope: "input" | "preparation",
235
+ path: string,
236
+ ): readonly SnapshottedArtifact[] {
237
+ if (!Array.isArray(evidence))
238
+ throw new ComplianceError(
239
+ "BAD_DIAGNOSTIC_RUN",
240
+ `${path} must be an array`,
241
+ path,
242
+ );
243
+ const seen = new Set<string>();
244
+ const result: SnapshottedArtifact[] = [];
245
+ for (const [index, item] of evidence.entries()) {
246
+ const itemPath = `${path}[${index}]`;
247
+ if (!plain(item))
248
+ throw new ComplianceError(
249
+ "BAD_DIAGNOSTIC_RUN",
250
+ "Artifact evidence must be a plain object",
251
+ itemPath,
252
+ );
253
+ if (typeof item.id !== "string")
254
+ throw new ComplianceError(
255
+ "BAD_DIAGNOSTIC_RUN",
256
+ "Artifact id must be a string",
257
+ `${itemPath}.id`,
258
+ );
259
+ token(item.id, `${itemPath}.id`);
260
+ if (item.scope !== scope)
261
+ throw new ComplianceError(
262
+ "BAD_DIAGNOSTIC_RUN",
263
+ `Artifact scope must be ${scope}`,
264
+ `${itemPath}.scope`,
265
+ );
266
+ if (seen.has(item.id))
267
+ throw new ComplianceError(
268
+ "BAD_DIAGNOSTIC_RUN",
269
+ `Duplicate artifact ID ${item.id}`,
270
+ `${itemPath}.id`,
271
+ );
272
+ seen.add(item.id);
273
+ if (item.assurance === "sdk-computed") {
274
+ exactKeys(item, ["id", "scope", "assurance", "bytes"], itemPath);
275
+ if (!(item.bytes instanceof Uint8Array))
276
+ throw new ComplianceError(
277
+ "BAD_DIAGNOSTIC_RUN",
278
+ "SDK-computed artifact evidence requires actual Uint8Array bytes",
279
+ `${itemPath}.bytes`,
280
+ );
281
+ const bytes = new Uint8Array(item.bytes.byteLength);
282
+ bytes.set(item.bytes);
283
+ result.push({ id: item.id, scope, assurance: item.assurance, bytes });
284
+ } else if (item.assurance === "caller-declared") {
285
+ exactKeys(
286
+ item,
287
+ ["id", "scope", "assurance", "algorithm", "value"],
288
+ itemPath,
289
+ );
290
+ if (typeof item.algorithm !== "string")
291
+ throw new ComplianceError(
292
+ "BAD_DIAGNOSTIC_RUN",
293
+ "Artifact algorithm must be a string",
294
+ `${itemPath}.algorithm`,
295
+ );
296
+ if (typeof item.value !== "string")
297
+ throw new ComplianceError(
298
+ "BAD_DIAGNOSTIC_RUN",
299
+ "Artifact value must be a string",
300
+ `${itemPath}.value`,
301
+ );
302
+ token(item.algorithm, `${itemPath}.algorithm`);
303
+ token(item.value, `${itemPath}.value`);
304
+ result.push({
305
+ id: item.id,
306
+ scope,
307
+ assurance: item.assurance,
308
+ algorithm: item.algorithm,
309
+ value: item.value,
310
+ });
311
+ } else
312
+ throw new ComplianceError(
313
+ "BAD_DIAGNOSTIC_RUN",
314
+ "Unknown artifact assurance",
315
+ `${itemPath}.assurance`,
316
+ );
317
+ }
318
+ return result.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
319
+ }
320
+ async function digestArtifacts(
321
+ snapshot: readonly SnapshottedArtifact[],
322
+ path: string,
323
+ ): Promise<readonly DiagnosticArtifactDigest[]> {
324
+ if (
325
+ snapshot.some((item) => "bytes" in item) &&
326
+ globalThis.crypto?.subtle === undefined
327
+ )
328
+ throw new ComplianceError(
329
+ "CRYPTO_UNAVAILABLE",
330
+ "Web Crypto SHA-256 is unavailable",
331
+ path,
332
+ );
333
+ return Promise.all(
334
+ snapshot.map(async (item) => {
335
+ if (!("bytes" in item)) return item;
336
+ const hash = await globalThis.crypto.subtle.digest("SHA-256", item.bytes);
337
+ return {
338
+ id: item.id,
339
+ scope: item.scope,
340
+ assurance: item.assurance,
341
+ algorithm: "sha256" as const,
342
+ value: [...new Uint8Array(hash)]
343
+ .map((b) => b.toString(16).padStart(2, "0"))
344
+ .join(""),
345
+ byteLength: item.bytes.byteLength,
346
+ };
347
+ }),
348
+ );
349
+ }
350
+
351
+ function snapshotLineage(
352
+ lineage: unknown,
353
+ ): readonly DiagnosticPreparationLineage[] {
354
+ if (!Array.isArray(lineage))
355
+ throw new ComplianceError(
356
+ "BAD_DIAGNOSTIC_RUN",
357
+ "$.preparationLineage must be an array",
358
+ "$.preparationLineage",
359
+ );
360
+ return lineage
361
+ .map((raw, index) => {
362
+ const path = `$.preparationLineage[${index}]`;
363
+ if (!plain(raw))
364
+ throw new ComplianceError(
365
+ "BAD_DIAGNOSTIC_RUN",
366
+ "Lineage edge must be a plain object",
367
+ path,
368
+ );
369
+ exactKeys(
370
+ raw,
371
+ ["outputArtifactId", "inputArtifactIds", "transformationArtifactIds"],
372
+ path,
373
+ );
374
+ if (typeof raw.outputArtifactId !== "string")
375
+ throw new ComplianceError(
376
+ "BAD_DIAGNOSTIC_RUN",
377
+ "Lineage output must be a string",
378
+ `${path}.outputArtifactId`,
379
+ );
380
+ token(raw.outputArtifactId, `${path}.outputArtifactId`);
381
+ const readIds = (value: unknown, key: string) => {
382
+ if (!Array.isArray(value))
383
+ throw new ComplianceError(
384
+ "BAD_DIAGNOSTIC_RUN",
385
+ `Lineage ${key} must be an array`,
386
+ `${path}.${key}`,
387
+ );
388
+ const result = value.map((id, inputIndex) => {
389
+ if (typeof id !== "string")
390
+ throw new ComplianceError(
391
+ "BAD_DIAGNOSTIC_RUN",
392
+ "Lineage artifact id must be a string",
393
+ `${path}.${key}[${inputIndex}]`,
394
+ );
395
+ token(id, `${path}.${key}[${inputIndex}]`);
396
+ return id;
397
+ });
398
+ if (new Set(result).size !== result.length)
399
+ throw new ComplianceError(
400
+ "BAD_DIAGNOSTIC_RUN",
401
+ `Lineage ${key} must be unique`,
402
+ `${path}.${key}`,
403
+ );
404
+ return [...result].sort();
405
+ };
406
+ const inputs = readIds(raw.inputArtifactIds, "inputArtifactIds"),
407
+ transformations = readIds(
408
+ raw.transformationArtifactIds,
409
+ "transformationArtifactIds",
410
+ );
411
+ if (inputs.length + transformations.length === 0)
412
+ throw new ComplianceError(
413
+ "BAD_DIAGNOSTIC_RUN",
414
+ "Lineage edge must have at least one upstream artifact",
415
+ path,
416
+ );
417
+ return {
418
+ outputArtifactId: raw.outputArtifactId,
419
+ inputArtifactIds: inputs,
420
+ transformationArtifactIds: transformations,
421
+ };
422
+ })
423
+ .sort((a, b) =>
424
+ a.outputArtifactId < b.outputArtifactId
425
+ ? -1
426
+ : a.outputArtifactId > b.outputArtifactId
427
+ ? 1
428
+ : 0,
429
+ );
430
+ }
431
+
432
+ function validateArtifactGraph(
433
+ run: CompletedValidatedMetricDiagnosticsRun,
434
+ inputArtifacts: readonly Pick<
435
+ DiagnosticArtifactDigest,
436
+ "id" | "scope" | "assurance"
437
+ >[],
438
+ preparationArtifacts: readonly Pick<
439
+ DiagnosticArtifactDigest,
440
+ "id" | "scope" | "assurance"
441
+ >[],
442
+ lineage: readonly DiagnosticPreparationLineage[],
443
+ ): void {
444
+ const byId = new Map<
445
+ string,
446
+ Pick<DiagnosticArtifactDigest, "id" | "scope" | "assurance">
447
+ >();
448
+ for (const [index, item] of [
449
+ ...inputArtifacts,
450
+ ...preparationArtifacts,
451
+ ].entries()) {
452
+ if (byId.has(item.id))
453
+ throw new ComplianceError(
454
+ "BAD_DIAGNOSTIC_RUN",
455
+ `Duplicate artifact ID ${item.id}`,
456
+ `$.${index < inputArtifacts.length ? "inputArtifacts" : "preparationArtifacts"}[${index < inputArtifacts.length ? index : index - inputArtifacts.length}].id`,
457
+ );
458
+ byId.set(item.id, item);
459
+ }
460
+ const referenced = new Set<string>();
461
+ const requireArtifact = (
462
+ id: string,
463
+ scope: "input" | "preparation",
464
+ path: string,
465
+ ) => {
466
+ const artifact = byId.get(id);
467
+ if (!artifact)
468
+ throw new ComplianceError(
469
+ "BAD_DIAGNOSTIC_RUN",
470
+ `Artifact reference ${id} is unresolved`,
471
+ path,
472
+ );
473
+ if (artifact.scope !== scope)
474
+ throw new ComplianceError(
475
+ "BAD_DIAGNOSTIC_RUN",
476
+ `Artifact ${id} must have ${scope} scope`,
477
+ path,
478
+ );
479
+ referenced.add(id);
480
+ };
481
+ let unsourced = false;
482
+ for (const [index, item] of run.prepared.inputAudit.entries()) {
483
+ const source = item.record.source;
484
+ if (source)
485
+ requireArtifact(
486
+ source.artifactId,
487
+ "input",
488
+ `$.completedRun.prepared.inputAudit[${index}].record.source.artifactId`,
489
+ );
490
+ else unsourced = true;
491
+ }
492
+ const evidence = run.review.evidence;
493
+ if (evidence) {
494
+ for (const [index, item] of evidence.groupingAssignments.entries()) {
495
+ if (item.source)
496
+ requireArtifact(
497
+ item.source.artifactId,
498
+ "input",
499
+ `$.completedRun.review.evidence.groupingAssignments[${index}].source.artifactId`,
500
+ );
501
+ else unsourced = true;
502
+ }
503
+ for (const [index, item] of evidence.cachedFormulas.entries()) {
504
+ if (item.source)
505
+ requireArtifact(
506
+ item.source.artifactId,
507
+ "input",
508
+ `$.completedRun.review.evidence.cachedFormulas[${index}].source.artifactId`,
509
+ );
510
+ else unsourced = true;
511
+ }
512
+ }
513
+ if (unsourced) {
514
+ if (run.datasetArtifactId === null)
515
+ throw new ComplianceError(
516
+ "BAD_DIAGNOSTIC_RUN",
517
+ "Unsourced diagnostic input requires datasetArtifactId",
518
+ "$.completedRun.datasetArtifactId",
519
+ );
520
+ const fallback = byId.get(run.datasetArtifactId);
521
+ if (
522
+ !fallback ||
523
+ fallback.scope !== "input" ||
524
+ fallback.assurance !== "sdk-computed"
525
+ )
526
+ throw new ComplianceError(
527
+ "BAD_DIAGNOSTIC_RUN",
528
+ "datasetArtifactId must resolve to SDK-computed input evidence",
529
+ "$.completedRun.datasetArtifactId",
530
+ );
531
+ referenced.add(run.datasetArtifactId);
532
+ } else if (run.datasetArtifactId !== null) {
533
+ requireArtifact(
534
+ run.datasetArtifactId,
535
+ "input",
536
+ "$.completedRun.datasetArtifactId",
537
+ );
538
+ if (byId.get(run.datasetArtifactId)!.assurance !== "sdk-computed")
539
+ throw new ComplianceError(
540
+ "BAD_DIAGNOSTIC_RUN",
541
+ "datasetArtifactId must resolve to SDK-computed input evidence",
542
+ "$.completedRun.datasetArtifactId",
543
+ );
544
+ }
545
+ for (const [
546
+ basisIndex,
547
+ basis,
548
+ ] of run.prepared.definition.definition.amountBases.entries())
549
+ for (const [componentIndex, component] of basis.components.entries())
550
+ if (
551
+ component.limitation.kind !== "unlimited" &&
552
+ component.limitation.kind !== "unknown" &&
553
+ component.limitation.derivation.kind === "external"
554
+ )
555
+ requireArtifact(
556
+ component.limitation.derivation.transformationRef,
557
+ "preparation",
558
+ `$.definition.amountBases[${basisIndex}].components[${componentIndex}].limitation.derivation.transformationRef`,
559
+ );
560
+ for (const [
561
+ ruleIndex,
562
+ rule,
563
+ ] of run.prepared.definition.definition.reviewRules.entries())
564
+ if (
565
+ rule.kind === "layer-order" &&
566
+ rule.comparability.kind === "caller-asserted"
567
+ )
568
+ requireArtifact(
569
+ rule.comparability.rationaleArtifactId,
570
+ "preparation",
571
+ `$.definition.reviewRules[${ruleIndex}].comparability.rationaleArtifactId`,
572
+ );
573
+ if (run.gate.rationaleRef !== null)
574
+ requireArtifact(
575
+ run.gate.rationaleRef,
576
+ "preparation",
577
+ "$.completedRun.gate.rationaleRef",
578
+ );
579
+ const edges = new Map<string, readonly string[]>();
580
+ for (const [index, edge] of lineage.entries()) {
581
+ const path = `$.preparationLineage[${index}]`;
582
+ if (edges.has(edge.outputArtifactId))
583
+ throw new ComplianceError(
584
+ "BAD_DIAGNOSTIC_RUN",
585
+ "An artifact may have only one producing lineage edge",
586
+ `${path}.outputArtifactId`,
587
+ );
588
+ const downstream = byId.get(edge.outputArtifactId);
589
+ if (!downstream)
590
+ throw new ComplianceError(
591
+ "BAD_DIAGNOSTIC_RUN",
592
+ `Lineage artifact ${edge.outputArtifactId} is unresolved`,
593
+ `${path}.outputArtifactId`,
594
+ );
595
+ if (downstream.scope !== "input")
596
+ throw new ComplianceError(
597
+ "BAD_DIAGNOSTIC_RUN",
598
+ "Lineage output artifact must have input scope",
599
+ `${path}.outputArtifactId`,
600
+ );
601
+ for (const [inputIndex, id] of edge.inputArtifactIds.entries()) {
602
+ if (id === edge.outputArtifactId)
603
+ throw new ComplianceError(
604
+ "BAD_DIAGNOSTIC_RUN",
605
+ "Lineage may not reference itself",
606
+ `${path}.inputArtifactIds[${inputIndex}]`,
607
+ );
608
+ const artifact = byId.get(id);
609
+ if (!artifact || artifact.scope !== "input")
610
+ throw new ComplianceError(
611
+ "BAD_DIAGNOSTIC_RUN",
612
+ `Lineage input ${id} must resolve to input evidence`,
613
+ `${path}.inputArtifactIds[${inputIndex}]`,
614
+ );
615
+ }
616
+ for (const [
617
+ transformIndex,
618
+ id,
619
+ ] of edge.transformationArtifactIds.entries()) {
620
+ const artifact = byId.get(id);
621
+ if (!artifact || artifact.scope !== "preparation")
622
+ throw new ComplianceError(
623
+ "BAD_DIAGNOSTIC_RUN",
624
+ `Lineage transformation ${id} must resolve to preparation evidence`,
625
+ `${path}.transformationArtifactIds[${transformIndex}]`,
626
+ );
627
+ }
628
+ edges.set(edge.outputArtifactId, [
629
+ ...edge.inputArtifactIds,
630
+ ...edge.transformationArtifactIds,
631
+ ]);
632
+ }
633
+ const visiting = new Set<string>(),
634
+ visited = new Set<string>();
635
+ for (const root of [...referenced]) {
636
+ const stack = [{ id: root, exit: false }];
637
+ while (stack.length > 0) {
638
+ const { id, exit } = stack.pop()!;
639
+ if (exit) {
640
+ visiting.delete(id);
641
+ visited.add(id);
642
+ continue;
643
+ }
644
+ if (visiting.has(id))
645
+ throw new ComplianceError(
646
+ "BAD_DIAGNOSTIC_RUN",
647
+ "Artifact lineage contains a cycle",
648
+ "$.preparationLineage",
649
+ );
650
+ if (visited.has(id)) continue;
651
+ visiting.add(id);
652
+ stack.push({ id, exit: true });
653
+ for (const upstream of [...(edges.get(id) ?? [])].reverse()) {
654
+ referenced.add(upstream);
655
+ stack.push({ id: upstream, exit: false });
656
+ }
657
+ }
658
+ }
659
+ for (const [index, artifact] of inputArtifacts.entries())
660
+ if (!referenced.has(artifact.id))
661
+ throw new ComplianceError(
662
+ "BAD_DIAGNOSTIC_RUN",
663
+ `Artifact ${artifact.id} is orphaned`,
664
+ `$.inputArtifacts[${index}].id`,
665
+ );
666
+ for (const [index, artifact] of preparationArtifacts.entries())
667
+ if (!referenced.has(artifact.id))
668
+ throw new ComplianceError(
669
+ "BAD_DIAGNOSTIC_RUN",
670
+ `Artifact ${artifact.id} is orphaned`,
671
+ `$.preparationArtifacts[${index}].id`,
672
+ );
673
+ }
674
+
675
+ function rerunAndVerify(run: CompletedValidatedMetricDiagnosticsRun): {
676
+ review: DiagnosticReviewReceipt;
677
+ result: DiagnosticDeepReadonly<NormalizedDiagnosticResultIdentity>;
678
+ } {
679
+ assertCompletedValidatedMetricDiagnosticsRun(run);
680
+ verifyPreparedDiagnosticDataIntegrity(run.prepared);
681
+ const review = reviewPreparedDiagnosticData({
682
+ prepared: run.prepared,
683
+ evidence: run.review.evidence,
684
+ });
685
+ if (
686
+ review.reportFingerprint !== run.review.reportFingerprint ||
687
+ canonicalJson(review.identityBody) !==
688
+ canonicalJson(run.review.identityBody)
689
+ )
690
+ throw new ComplianceError(
691
+ "DIAGNOSTIC_MISMATCH",
692
+ "Stored diagnostic review does not match a regenerated review",
693
+ "$.review",
694
+ );
695
+ const rerun = runMetricDiagnostics({
696
+ prepared: run.prepared,
697
+ groupMap: run.groupMap,
698
+ groupDimensions: run.groupDimensions,
699
+ });
700
+ if (
701
+ canonicalJson(getMetricDiagnosticsResultIdentity(rerun)) !==
702
+ canonicalJson(getMetricDiagnosticsResultIdentity(run.result))
703
+ )
704
+ throw new ComplianceError(
705
+ "DIAGNOSTIC_MISMATCH",
706
+ "Stored diagnostic result does not match deterministic replay",
707
+ "$.result",
708
+ );
709
+ const reviewBlocked =
710
+ review.report.checks.some(
711
+ (check) => !run.gate.allowedReviewStatuses.includes(check.status),
712
+ ) ||
713
+ review.evaluations.some((evaluation) => {
714
+ const status =
715
+ evaluation.expressionOverflows.length > 0
716
+ ? "fail"
717
+ : evaluation.status === "triggered"
718
+ ? evaluation.severity
719
+ : evaluation.status;
720
+ return !run.gate.allowedReviewStatuses.includes(status);
721
+ });
722
+ const metricBlocked = rerun.findings.some(
723
+ (finding) =>
724
+ finding.category !== "structural" &&
725
+ !run.gate.allowedMetricFindingSeverities.includes(finding.severity),
726
+ );
727
+ if (
728
+ reviewBlocked ||
729
+ metricBlocked ||
730
+ run.gate.reviewGate !== "passed" ||
731
+ run.gate.metricGate !== "passed"
732
+ )
733
+ throw new ComplianceError(
734
+ "DIAGNOSTIC_MISMATCH",
735
+ "Diagnostic execution gates do not recompute as passed",
736
+ "$.gate",
737
+ );
738
+ return { review, result: getMetricDiagnosticsResultIdentity(run.result) };
739
+ }
740
+
741
+ function buildManifest(
742
+ run: CompletedValidatedMetricDiagnosticsRun,
743
+ review: DiagnosticReviewReceipt,
744
+ inputArtifacts: readonly DiagnosticArtifactDigest[],
745
+ preparationArtifacts: readonly DiagnosticArtifactDigest[],
746
+ lineage: readonly DiagnosticPreparationLineage[],
747
+ ): DiagnosticDeepReadonly<DiagnosticRunManifest> {
748
+ const preparation = getPreparedDiagnosticDataIdentity(run.prepared);
749
+ return freeze({
750
+ definitionIntegrity: run.prepared.definition.definitionIntegrity,
751
+ preparationFingerprint: run.prepared.preparationFingerprint,
752
+ runPresetId: run.runPresetId,
753
+ datasetArtifactId: run.datasetArtifactId,
754
+ inputArtifacts: [...inputArtifacts].sort((a, b) =>
755
+ a.id < b.id ? -1 : a.id > b.id ? 1 : 0,
756
+ ),
757
+ preparationArtifacts: [...preparationArtifacts].sort((a, b) =>
758
+ a.id < b.id ? -1 : a.id > b.id ? 1 : 0,
759
+ ),
760
+ preparationLineage: lineage,
761
+ inputAudit: preparation.inputAudit,
762
+ filter: preparation.filter,
763
+ groupMap: { ...run.groupMap },
764
+ groupDimensions: { ...run.groupDimensions },
765
+ completePeriodCutoffs: preparation.completePeriodCutoffs,
766
+ expectedCellGridFingerprint: preparation.expectedCellsProvided
767
+ ? tag(
768
+ "diagnostic-expected-cell-grid",
769
+ "expectedCells",
770
+ preparation.expectedCells,
771
+ )
772
+ : null,
773
+ executionPolicy: { review, gate: run.gate },
774
+ engine: {
775
+ packages: {
776
+ core: CORE_PACKAGE_VERSION,
777
+ data: DATA_PACKAGE_VERSION,
778
+ compliance: COMPLIANCE_PACKAGE_VERSION,
779
+ },
780
+ algorithmVersion: "diagnostics-1" as const,
781
+ },
782
+ });
783
+ }
784
+
785
+ export async function createDiagnosticRunIdentity(
786
+ input: CreateDiagnosticRunIdentityInput,
787
+ ): Promise<VerifiedDiagnosticRunProvenance> {
788
+ if (!plain(input))
789
+ throw new ComplianceError(
790
+ "BAD_DIAGNOSTIC_RUN",
791
+ "Diagnostic evidence must be a plain object",
792
+ "$",
793
+ );
794
+ exactKeys(
795
+ input,
796
+ [
797
+ "completedRun",
798
+ "inputArtifacts",
799
+ "preparationArtifacts",
800
+ "preparationLineage",
801
+ ],
802
+ "$",
803
+ );
804
+ const run = input.completedRun;
805
+ let authenticated: ReturnType<typeof rerunAndVerify>;
806
+ try {
807
+ authenticated = rerunAndVerify(run);
808
+ } catch (error) {
809
+ if (error instanceof ComplianceError) throw error;
810
+ throw new ComplianceError(
811
+ "BAD_DIAGNOSTIC_RUN",
812
+ "completedRun must be an authentic completed diagnostic run",
813
+ "$.completedRun",
814
+ );
815
+ }
816
+ const inputSnapshot = snapshotArtifacts(
817
+ (input as unknown as Record<string, unknown>).inputArtifacts,
818
+ "input",
819
+ "$.inputArtifacts",
820
+ );
821
+ const preparationSnapshot = snapshotArtifacts(
822
+ (input as unknown as Record<string, unknown>).preparationArtifacts,
823
+ "preparation",
824
+ "$.preparationArtifacts",
825
+ );
826
+ const lineage = snapshotLineage(
827
+ (input as unknown as Record<string, unknown>).preparationLineage,
828
+ );
829
+ validateArtifactGraph(run, inputSnapshot, preparationSnapshot, lineage);
830
+ const [inputArtifacts, preparationArtifacts] = await Promise.all([
831
+ digestArtifacts(inputSnapshot, "$.inputArtifacts"),
832
+ digestArtifacts(preparationSnapshot, "$.preparationArtifacts"),
833
+ ]);
834
+ const manifest = buildManifest(
835
+ run,
836
+ authenticated.review,
837
+ inputArtifacts,
838
+ preparationArtifacts,
839
+ lineage,
840
+ );
841
+ const runFingerprint = tag(
842
+ "diagnostic-run",
843
+ "manifest",
844
+ manifestIdentity(manifest),
845
+ );
846
+ const resultFingerprint = tag(
847
+ "diagnostic-result",
848
+ "result",
849
+ authenticated.result,
850
+ );
851
+ const runResultFingerprint = bindingTag(runFingerprint, resultFingerprint);
852
+ const definition = run.prepared.definition;
853
+ const provenance = freeze({
854
+ definition: {
855
+ definition: definition.definition,
856
+ identities: {
857
+ algorithm: "fnv1a64-jcs-v1" as const,
858
+ formulaById: { ...definition.formulaFingerprints },
859
+ calculationByInstanceId: { ...definition.calculationFingerprints },
860
+ definition: definition.definitionIntegrity,
861
+ },
862
+ },
863
+ manifest,
864
+ review: authenticated.review,
865
+ result: run.result,
866
+ runFingerprint,
867
+ resultFingerprint,
868
+ runResultFingerprint,
869
+ }) as unknown as VerifiedDiagnosticRunProvenance;
870
+ verified.set(provenance, run);
871
+ return provenance;
872
+ }
873
+
874
+ export function assertVerifiedDiagnosticRunProvenance(
875
+ value: unknown,
876
+ ): asserts value is VerifiedDiagnosticRunProvenance {
877
+ if (value === null || typeof value !== "object" || !verified.has(value))
878
+ throw new ComplianceError(
879
+ "BAD_DIAGNOSTIC_RUN",
880
+ "Value is not authentic verified diagnostic provenance",
881
+ "$",
882
+ );
883
+ }
884
+
885
+ function readArtifactDigests(
886
+ value: unknown,
887
+ scope: "input" | "preparation",
888
+ path: string,
889
+ ): DiagnosticArtifactDigest[] {
890
+ if (!Array.isArray(value))
891
+ throw new ComplianceError(
892
+ "BAD_DIAGNOSTIC_RUN",
893
+ "Artifact digests must be an array",
894
+ path,
895
+ );
896
+ return value.map((item, index) => {
897
+ const itemPath = `${path}[${index}]`;
898
+ if (!plain(item))
899
+ throw new ComplianceError(
900
+ "BAD_DIAGNOSTIC_RUN",
901
+ "Artifact digest must be a plain object",
902
+ itemPath,
903
+ );
904
+ for (const key of ["id", "algorithm", "value"] as const) {
905
+ if (typeof item[key] !== "string")
906
+ throw new ComplianceError(
907
+ "BAD_DIAGNOSTIC_RUN",
908
+ `${key} must be a token`,
909
+ `${itemPath}.${key}`,
910
+ );
911
+ token(item[key], `${itemPath}.${key}`);
912
+ }
913
+ if (item.scope !== scope)
914
+ throw new ComplianceError(
915
+ "BAD_DIAGNOSTIC_RUN",
916
+ `Artifact scope must be ${scope}`,
917
+ `${itemPath}.scope`,
918
+ );
919
+ if (item.assurance === "sdk-computed") {
920
+ exactKeys(
921
+ item,
922
+ ["id", "scope", "assurance", "algorithm", "value", "byteLength"],
923
+ itemPath,
924
+ );
925
+ if (item.algorithm !== "sha256")
926
+ throw new ComplianceError(
927
+ "BAD_DIAGNOSTIC_RUN",
928
+ "SDK digests must use sha256",
929
+ `${itemPath}.algorithm`,
930
+ );
931
+ if (!/^[0-9a-f]{64}$/.test(item.value as string))
932
+ throw new ComplianceError(
933
+ "BAD_DIAGNOSTIC_RUN",
934
+ "Invalid SHA-256 digest",
935
+ `${itemPath}.value`,
936
+ );
937
+ if (
938
+ !Number.isSafeInteger(item.byteLength) ||
939
+ (item.byteLength as number) < 0
940
+ )
941
+ throw new ComplianceError(
942
+ "BAD_DIAGNOSTIC_RUN",
943
+ "Invalid byte length",
944
+ `${itemPath}.byteLength`,
945
+ );
946
+ } else if (item.assurance === "caller-declared") {
947
+ exactKeys(
948
+ item,
949
+ ["id", "scope", "assurance", "algorithm", "value"],
950
+ itemPath,
951
+ );
952
+ } else {
953
+ throw new ComplianceError(
954
+ "BAD_DIAGNOSTIC_RUN",
955
+ "Unknown artifact assurance",
956
+ `${itemPath}.assurance`,
957
+ );
958
+ }
959
+ return item as unknown as DiagnosticArtifactDigest;
960
+ });
961
+ }
962
+
963
+ function readRecordedEngine(value: unknown): DiagnosticRunManifest["engine"] {
964
+ if (!plain(value))
965
+ throw new ComplianceError(
966
+ "BAD_DIAGNOSTIC_RUN",
967
+ "Invalid diagnostic engine",
968
+ "$.manifest.engine",
969
+ );
970
+ exactKeys(value, ["packages", "algorithmVersion"], "$.manifest.engine");
971
+ if (value.algorithmVersion !== "diagnostics-1")
972
+ throw new ComplianceError(
973
+ "BAD_DIAGNOSTIC_RUN",
974
+ "Unsupported diagnostic algorithm",
975
+ "$.manifest.engine.algorithmVersion",
976
+ );
977
+ if (!plain(value.packages))
978
+ throw new ComplianceError(
979
+ "BAD_DIAGNOSTIC_RUN",
980
+ "Invalid diagnostic package versions",
981
+ "$.manifest.engine.packages",
982
+ );
983
+ exactKeys(
984
+ value.packages,
985
+ ["core", "data", "compliance"],
986
+ "$.manifest.engine.packages",
987
+ );
988
+ for (const name of ["core", "data", "compliance"] as const) {
989
+ if (typeof value.packages[name] !== "string")
990
+ throw new ComplianceError(
991
+ "BAD_DIAGNOSTIC_RUN",
992
+ "Package version must be a token",
993
+ `$.manifest.engine.packages.${name}`,
994
+ );
995
+ token(value.packages[name], `$.manifest.engine.packages.${name}`);
996
+ }
997
+ return value as unknown as DiagnosticRunManifest["engine"];
998
+ }
999
+
1000
+ function auditedNumber(value: unknown, path: string): number | null {
1001
+ if (!plain(value))
1002
+ throw new ComplianceError(
1003
+ "BAD_DIAGNOSTIC_RUN",
1004
+ "Invalid audited number",
1005
+ path,
1006
+ );
1007
+ if (
1008
+ value.status === "observed" &&
1009
+ typeof value.value === "number" &&
1010
+ Number.isFinite(value.value)
1011
+ ) {
1012
+ exactKeys(value, ["status", "value"], path);
1013
+ return value.value;
1014
+ }
1015
+ if (value.status === "missing" && value.value === null) {
1016
+ exactKeys(value, ["status", "value"], path);
1017
+ return null;
1018
+ }
1019
+ if (value.status === "non-finite" && value.value === null) {
1020
+ exactKeys(value, ["status", "value", "nonFiniteKind"], path);
1021
+ if (value.nonFiniteKind === "nan") return NaN;
1022
+ if (value.nonFiniteKind === "positive-infinity") return Infinity;
1023
+ if (value.nonFiniteKind === "negative-infinity") return -Infinity;
1024
+ }
1025
+ throw new ComplianceError(
1026
+ "BAD_DIAGNOSTIC_RUN",
1027
+ "Invalid audited number",
1028
+ path,
1029
+ );
1030
+ }
1031
+
1032
+ /** Normalized optional nulls are omitted only when rebuilding authored input. */
1033
+ function omitNulls(value: unknown): unknown {
1034
+ return plain(value)
1035
+ ? Object.fromEntries(
1036
+ Object.entries(value).filter(([, item]) => item !== null),
1037
+ )
1038
+ : value;
1039
+ }
1040
+
1041
+ /** Human descriptions/details are regenerated, but are not identity-bearing. */
1042
+ function reviewIdentityView(value: unknown): unknown {
1043
+ if (
1044
+ !plain(value) ||
1045
+ !plain(value.report) ||
1046
+ !Array.isArray(value.report.checks)
1047
+ )
1048
+ return value;
1049
+ return {
1050
+ ...value,
1051
+ report: {
1052
+ ...value.report,
1053
+ checks: value.report.checks.map((check) => {
1054
+ if (!plain(check)) return check;
1055
+ const {
1056
+ description: _description,
1057
+ details: _details,
1058
+ ...identity
1059
+ } = check;
1060
+ return identity;
1061
+ }),
1062
+ },
1063
+ };
1064
+ }
1065
+
1066
+ function provenanceIdentityView(value: unknown): unknown {
1067
+ if (!plain(value)) return value;
1068
+ const manifest = value.manifest;
1069
+ const executionPolicy = plain(manifest) ? manifest.executionPolicy : null;
1070
+ return {
1071
+ ...value,
1072
+ review: reviewIdentityView(value.review),
1073
+ ...(plain(manifest) && plain(executionPolicy)
1074
+ ? {
1075
+ manifest: {
1076
+ ...manifest,
1077
+ executionPolicy: {
1078
+ ...executionPolicy,
1079
+ review: reviewIdentityView(executionPolicy.review),
1080
+ },
1081
+ },
1082
+ }
1083
+ : {}),
1084
+ };
1085
+ }
1086
+
1087
+ function replaySerializedRun(
1088
+ compiled: CompiledDiagnosticDefinition,
1089
+ manifest: Record<string, unknown>,
1090
+ review: Record<string, unknown>,
1091
+ ): CompletedValidatedMetricDiagnosticsRun {
1092
+ if (!Array.isArray(manifest.inputAudit))
1093
+ throw new ComplianceError(
1094
+ "BAD_DIAGNOSTIC_RUN",
1095
+ "Input audit must be an array",
1096
+ "$.manifest.inputAudit",
1097
+ );
1098
+ const losses: unknown[] = [],
1099
+ exposures: unknown[] = [],
1100
+ expectedCells: unknown[] = [];
1101
+ for (const [index, item] of manifest.inputAudit.entries()) {
1102
+ const path = `$.manifest.inputAudit[${index}]`;
1103
+ if (!plain(item) || !plain(item.record))
1104
+ throw new ComplianceError(
1105
+ "BAD_DIAGNOSTIC_RUN",
1106
+ "Invalid input audit entry",
1107
+ path,
1108
+ );
1109
+ exactKeys(item, ["kind", "record", "disposition"], path);
1110
+ const record = { ...item.record };
1111
+ if (record.source === null) delete record.source;
1112
+ else if (record.source !== undefined)
1113
+ record.source = omitNulls(record.source);
1114
+ if (item.kind === "loss") {
1115
+ if (!plain(record.measures))
1116
+ throw new ComplianceError(
1117
+ "BAD_DIAGNOSTIC_RUN",
1118
+ "Invalid audited measures",
1119
+ `${path}.record.measures`,
1120
+ );
1121
+ record.measures = Object.fromEntries(
1122
+ Object.entries(record.measures).map(([id, value]) => [
1123
+ id,
1124
+ auditedNumber(value, `${path}.record.measures.${id}`),
1125
+ ]),
1126
+ );
1127
+ if (record.claimId === null) delete record.claimId;
1128
+ losses.push(record);
1129
+ } else if (item.kind === "exposure") {
1130
+ record.value = auditedNumber(record.value, `${path}.record.value`);
1131
+ if (record.valuation === null) delete record.valuation;
1132
+ exposures.push(record);
1133
+ } else if (item.kind === "expected-cell") expectedCells.push(record);
1134
+ else
1135
+ throw new ComplianceError(
1136
+ "BAD_DIAGNOSTIC_RUN",
1137
+ "Unknown input audit kind",
1138
+ `${path}.kind`,
1139
+ );
1140
+ }
1141
+ if (!plain(manifest.executionPolicy) || !plain(manifest.executionPolicy.gate))
1142
+ throw new ComplianceError(
1143
+ "BAD_DIAGNOSTIC_RUN",
1144
+ "Missing execution gate",
1145
+ "$.manifest.executionPolicy.gate",
1146
+ );
1147
+ const gate = manifest.executionPolicy.gate;
1148
+ exactKeys(
1149
+ gate,
1150
+ [
1151
+ "allowedReviewStatuses",
1152
+ "allowedMetricFindingSeverities",
1153
+ "rationaleRef",
1154
+ "reviewGate",
1155
+ "metricGate",
1156
+ ],
1157
+ "$.manifest.executionPolicy.gate",
1158
+ );
1159
+ let outcome: ReturnType<typeof runValidatedMetricDiagnostics>;
1160
+ try {
1161
+ outcome = runValidatedMetricDiagnostics(
1162
+ validateDiagnosticRunInput({
1163
+ definition: compiled.definition,
1164
+ losses,
1165
+ exposures,
1166
+ ...(manifest.filter === null
1167
+ ? {}
1168
+ : { filter: omitNulls(manifest.filter) }),
1169
+ completePeriodCutoffs: manifest.completePeriodCutoffs,
1170
+ ...(manifest.expectedCellGridFingerprint === null
1171
+ ? {}
1172
+ : { expectedCells }),
1173
+ reviewEvidence: review.evidence,
1174
+ ...(manifest.runPresetId === null
1175
+ ? {}
1176
+ : { runPresetId: manifest.runPresetId }),
1177
+ ...(manifest.datasetArtifactId === null
1178
+ ? {}
1179
+ : { datasetArtifactId: manifest.datasetArtifactId }),
1180
+ groupMap: manifest.groupMap,
1181
+ groupDimensions: manifest.groupDimensions,
1182
+ policy: {
1183
+ allowedReviewStatuses: gate.allowedReviewStatuses,
1184
+ allowedMetricFindingSeverities: gate.allowedMetricFindingSeverities,
1185
+ ...(gate.rationaleRef === null
1186
+ ? {}
1187
+ : { rationaleRef: gate.rationaleRef }),
1188
+ },
1189
+ }),
1190
+ );
1191
+ } catch (error) {
1192
+ if (!(error instanceof DiagnosticValidationError)) throw error;
1193
+ const issue = error.issues[0];
1194
+ let issuePath = issue?.path ?? "$";
1195
+ const recordPath =
1196
+ /^\$\.(losses|exposures|expectedCells)\[(\d+)\](.*)$/.exec(issuePath);
1197
+ if (recordPath) {
1198
+ const kind =
1199
+ recordPath[1] === "losses"
1200
+ ? "loss"
1201
+ : recordPath[1] === "exposures"
1202
+ ? "exposure"
1203
+ : "expected-cell";
1204
+ const auditIndices = manifest.inputAudit.flatMap((item, index) =>
1205
+ plain(item) && item.kind === kind ? [index] : [],
1206
+ );
1207
+ issuePath = `$.manifest.inputAudit[${auditIndices[Number(recordPath[2])]}].record${recordPath[3]}`;
1208
+ } else if (issuePath.startsWith("$.reviewEvidence"))
1209
+ issuePath = issuePath.replace("$.reviewEvidence", "$.review.evidence");
1210
+ else if (issuePath.startsWith("$.policy"))
1211
+ issuePath = issuePath.replace(
1212
+ "$.policy",
1213
+ "$.manifest.executionPolicy.gate",
1214
+ );
1215
+ else if (issuePath.startsWith("$.definition"))
1216
+ issuePath = issuePath.replace("$.definition", "$.definition.definition");
1217
+ else issuePath = issuePath.replace(/^\$\./, "$.manifest.");
1218
+ throw new ComplianceError(
1219
+ "BAD_DIAGNOSTIC_RUN",
1220
+ issue?.message ?? "Invalid diagnostic replay input",
1221
+ issuePath,
1222
+ );
1223
+ }
1224
+ if (outcome.status !== "completed")
1225
+ throw new ComplianceError(
1226
+ "DIAGNOSTIC_MISMATCH",
1227
+ "Stored execution does not pass its declared gates",
1228
+ "$.manifest.executionPolicy.gate",
1229
+ );
1230
+ return outcome;
1231
+ }
1232
+
1233
+ /** Verify serialized evidence by replaying the owning core/data public workflows. */
1234
+ export function serializedDiagnosticRunMismatch(
1235
+ value: unknown,
1236
+ path = "$.diagnosticRuns[0]",
1237
+ ): string | null {
1238
+ try {
1239
+ if (!plain(value)) return path;
1240
+ const fields = [
1241
+ "definition",
1242
+ "manifest",
1243
+ "review",
1244
+ "result",
1245
+ "runFingerprint",
1246
+ "resultFingerprint",
1247
+ "runResultFingerprint",
1248
+ ];
1249
+ exactKeys(value, fields, "$");
1250
+ for (const key of fields)
1251
+ if (!Object.hasOwn(value, key)) return `${path}.${key}`;
1252
+ if (!plain(value.definition)) return `${path}.definition`;
1253
+ exactKeys(value.definition, ["definition", "identities"], "$.definition");
1254
+ let compiled: CompiledDiagnosticDefinition;
1255
+ try {
1256
+ compiled = compileDiagnosticDefinition(
1257
+ value.definition.definition as DiagnosticDefinition,
1258
+ );
1259
+ } catch (error) {
1260
+ const issuePath =
1261
+ error instanceof DiagnosticValidationError
1262
+ ? error.issues[0]?.path
1263
+ : undefined;
1264
+ return `${path}.definition.definition${issuePath?.startsWith("$") ? issuePath.slice(1) : ""}`;
1265
+ }
1266
+ const identities = {
1267
+ algorithm: "fnv1a64-jcs-v1",
1268
+ formulaById: compiled.formulaFingerprints,
1269
+ calculationByInstanceId: compiled.calculationFingerprints,
1270
+ definition: compiled.definitionIntegrity,
1271
+ };
1272
+ let mismatch = firstDifference(
1273
+ value.definition.identities,
1274
+ identities,
1275
+ `${path}.definition.identities`,
1276
+ );
1277
+ if (mismatch !== null) return mismatch;
1278
+ if (!plain(value.manifest)) return `${path}.manifest`;
1279
+ if (!plain(value.review)) return `${path}.review`;
1280
+ const manifest = value.manifest;
1281
+ const engine = readRecordedEngine(manifest.engine);
1282
+ const inputArtifacts = readArtifactDigests(
1283
+ manifest.inputArtifacts,
1284
+ "input",
1285
+ "$.manifest.inputArtifacts",
1286
+ );
1287
+ const preparationArtifacts = readArtifactDigests(
1288
+ manifest.preparationArtifacts,
1289
+ "preparation",
1290
+ "$.manifest.preparationArtifacts",
1291
+ );
1292
+ const lineage = snapshotLineage(manifest.preparationLineage);
1293
+ const run = replaySerializedRun(compiled, manifest, value.review);
1294
+ if (manifest.preparationFingerprint !== run.prepared.preparationFingerprint)
1295
+ return `${path}.manifest.preparationFingerprint`;
1296
+ validateArtifactGraph(run, inputArtifacts, preparationArtifacts, lineage);
1297
+ mismatch = firstDifference(
1298
+ reviewIdentityView(value.review),
1299
+ reviewIdentityView(run.review),
1300
+ `${path}.review`,
1301
+ );
1302
+ if (mismatch !== null) return mismatch;
1303
+ const expectedManifest = {
1304
+ ...buildManifest(
1305
+ run,
1306
+ run.review,
1307
+ inputArtifacts,
1308
+ preparationArtifacts,
1309
+ lineage,
1310
+ ),
1311
+ // Historical package versions describe the original run; reproduction
1312
+ // checks the supported algorithm and bundle-wide version agreement.
1313
+ engine,
1314
+ };
1315
+ mismatch = firstDifference(
1316
+ (provenanceIdentityView({ manifest }) as Record<string, unknown>)
1317
+ .manifest,
1318
+ (
1319
+ provenanceIdentityView({ manifest: expectedManifest }) as Record<
1320
+ string,
1321
+ unknown
1322
+ >
1323
+ ).manifest,
1324
+ `${path}.manifest`,
1325
+ );
1326
+ if (mismatch !== null) return mismatch;
1327
+ const result = getMetricDiagnosticsResultIdentity(run.result);
1328
+ let candidateResult: DiagnosticDeepReadonly<NormalizedDiagnosticResultIdentity>;
1329
+ try {
1330
+ candidateResult = getMetricDiagnosticsResultIdentity(
1331
+ value.result as MetricDiagnosticsResult,
1332
+ );
1333
+ } catch (error) {
1334
+ const issuePath =
1335
+ error instanceof DiagnosticValidationError
1336
+ ? error.issues[0]?.path
1337
+ : undefined;
1338
+ return `${path}.result${issuePath?.startsWith("$") ? issuePath.slice(1) : ""}`;
1339
+ }
1340
+ mismatch = firstDifference(candidateResult, result, `${path}.result`);
1341
+ if (mismatch !== null) return mismatch;
1342
+ const runFingerprint = tag(
1343
+ "diagnostic-run",
1344
+ "manifest",
1345
+ manifestIdentity(expectedManifest),
1346
+ );
1347
+ const resultFingerprint = tag("diagnostic-result", "result", result);
1348
+ if (value.runFingerprint !== runFingerprint)
1349
+ return `${path}.runFingerprint`;
1350
+ if (value.resultFingerprint !== resultFingerprint)
1351
+ return `${path}.resultFingerprint`;
1352
+ if (
1353
+ value.runResultFingerprint !==
1354
+ bindingTag(runFingerprint, resultFingerprint)
1355
+ )
1356
+ return `${path}.runResultFingerprint`;
1357
+ return null;
1358
+ } catch (error) {
1359
+ if (error instanceof ComplianceError && error.path) {
1360
+ const relative = error.path
1361
+ .replace(/^\$\.completedRun\.prepared/, "$.manifest")
1362
+ .replace(/^\$\.completedRun\.review/, "$.review")
1363
+ .replace(/^\$\.completedRun\.gate/, "$.manifest.executionPolicy.gate")
1364
+ .replace(/^\$\.completedRun\./, "$.manifest.")
1365
+ .replace(
1366
+ /^\$\.(inputArtifacts|preparationArtifacts|preparationLineage)/,
1367
+ "$.manifest.$1",
1368
+ );
1369
+ return `${path}${relative.slice(1)}`;
1370
+ }
1371
+ return path;
1372
+ }
1373
+ }
136
1374
 
137
1375
  /** @internal Bundle authoring uses owner state rather than trusting the public snapshot. */
138
- export function verifiedDefinitionForBundle(value:VerifiedDiagnosticRunProvenance):CompiledDiagnosticDefinition{assertVerifiedDiagnosticRunProvenance(value);return verified.get(value)!.prepared.definition}
1376
+ export function verifiedDefinitionForBundle(
1377
+ value: VerifiedDiagnosticRunProvenance,
1378
+ ): CompiledDiagnosticDefinition {
1379
+ assertVerifiedDiagnosticRunProvenance(value);
1380
+ return verified.get(value)!.prepared.definition;
1381
+ }
139
1382
 
140
- export async function verifyDiagnosticRunIdentity(candidate:unknown,input:CreateDiagnosticRunIdentityInput):Promise<VerifiedDiagnosticRunProvenance>{
141
- const regenerated=await createDiagnosticRunIdentity(input);
142
- let left:string;try{left=canonicalJson(candidate)}catch{throw new ComplianceError("DIAGNOSTIC_MISMATCH","Stored diagnostic provenance is not canonical JSON","$")}
143
- if(left!==canonicalJson(regenerated))throw new ComplianceError("DIAGNOSTIC_MISMATCH","Stored diagnostic provenance differs from regenerated provenance",firstDifference(candidate,regenerated,"$")??"$");
1383
+ export async function verifyDiagnosticRunIdentity(
1384
+ candidate: unknown,
1385
+ input: CreateDiagnosticRunIdentityInput,
1386
+ ): Promise<VerifiedDiagnosticRunProvenance> {
1387
+ let left: string;
1388
+ let snapshot: unknown;
1389
+ try {
1390
+ left = canonicalJson(candidate);
1391
+ snapshot = JSON.parse(left);
1392
+ } catch {
1393
+ throw new ComplianceError(
1394
+ "DIAGNOSTIC_MISMATCH",
1395
+ "Stored diagnostic provenance is not canonical JSON",
1396
+ "$",
1397
+ );
1398
+ }
1399
+ const regenerated = await createDiagnosticRunIdentity(input);
1400
+ const comparedSnapshot = provenanceIdentityView(snapshot);
1401
+ const comparedRegenerated = provenanceIdentityView(regenerated);
1402
+ if (canonicalJson(comparedSnapshot) !== canonicalJson(comparedRegenerated))
1403
+ throw new ComplianceError(
1404
+ "DIAGNOSTIC_MISMATCH",
1405
+ "Stored diagnostic provenance differs from regenerated provenance",
1406
+ firstDifference(comparedSnapshot, comparedRegenerated, "$") ?? "$",
1407
+ );
144
1408
  return regenerated;
145
1409
  }
146
1410
 
147
- function plain(value:unknown):value is Record<string,unknown>{if(value===null||typeof value!=="object"||Array.isArray(value))return false;const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}
148
- function firstDifference(left:unknown,right:unknown,path:string):string|null{if(plain(left)&&plain(right)){const keys=[...new Set([...Object.keys(left),...Object.keys(right)])].sort();for(const key of keys){if(!(key in left)||!(key in right))return `${path}.${key}`;const found=firstDifference(left[key],right[key],`${path}.${key}`);if(found)return found}return null}if(Array.isArray(left)&&Array.isArray(right)){const shared=Math.min(left.length,right.length);for(let index=0;index<shared;index++){const found=firstDifference(left[index],right[index],`${path}[${index}]`);if(found)return found}return left.length===right.length?null:`${path}[${shared}]`}try{return canonicalJson(left)===canonicalJson(right)?null:path}catch{return path}}
1411
+ function firstDifference(
1412
+ left: unknown,
1413
+ right: unknown,
1414
+ path: string,
1415
+ ): string | null {
1416
+ if (plain(left) && plain(right)) {
1417
+ const keys = [
1418
+ ...new Set([...Object.keys(left), ...Object.keys(right)]),
1419
+ ].sort();
1420
+ for (const key of keys) {
1421
+ const childPath = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)
1422
+ ? `${path}.${key}`
1423
+ : `${path}[${JSON.stringify(key)}]`;
1424
+ if (
1425
+ !Object.prototype.hasOwnProperty.call(left, key) ||
1426
+ !Object.prototype.hasOwnProperty.call(right, key)
1427
+ )
1428
+ return childPath;
1429
+ const found = firstDifference(left[key], right[key], childPath);
1430
+ if (found) return found;
1431
+ }
1432
+ return null;
1433
+ }
1434
+ if (Array.isArray(left) && Array.isArray(right)) {
1435
+ const shared = Math.min(left.length, right.length);
1436
+ for (let index = 0; index < shared; index++) {
1437
+ const found = firstDifference(
1438
+ left[index],
1439
+ right[index],
1440
+ `${path}[${index}]`,
1441
+ );
1442
+ if (found) return found;
1443
+ }
1444
+ return left.length === right.length ? null : `${path}[${shared}]`;
1445
+ }
1446
+ try {
1447
+ return canonicalJson(left) === canonicalJson(right) ? null : path;
1448
+ } catch {
1449
+ return path;
1450
+ }
1451
+ }