@openprose/reactor 0.1.0-rc.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.
Files changed (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +231 -0
  3. package/dist/adapters/agent-sdk-passthrough/index.d.ts +8 -0
  4. package/dist/adapters/agent-sdk-passthrough/index.d.ts.map +1 -0
  5. package/dist/adapters/agent-sdk-passthrough/index.js +25 -0
  6. package/dist/adapters/clock-system/index.d.ts +9 -0
  7. package/dist/adapters/clock-system/index.d.ts.map +1 -0
  8. package/dist/adapters/clock-system/index.js +39 -0
  9. package/dist/adapters/connector-static/index.d.ts +11 -0
  10. package/dist/adapters/connector-static/index.d.ts.map +1 -0
  11. package/dist/adapters/connector-static/index.js +35 -0
  12. package/dist/adapters/event-sink-memory/index.d.ts +10 -0
  13. package/dist/adapters/event-sink-memory/index.d.ts.map +1 -0
  14. package/dist/adapters/event-sink-memory/index.js +20 -0
  15. package/dist/adapters/index.d.ts +10 -0
  16. package/dist/adapters/index.d.ts.map +1 -0
  17. package/dist/adapters/index.js +25 -0
  18. package/dist/adapters/json.d.ts +3 -0
  19. package/dist/adapters/json.d.ts.map +1 -0
  20. package/dist/adapters/json.js +61 -0
  21. package/dist/adapters/model-gateway-record-replay/index.d.ts +24 -0
  22. package/dist/adapters/model-gateway-record-replay/index.d.ts.map +1 -0
  23. package/dist/adapters/model-gateway-record-replay/index.js +55 -0
  24. package/dist/adapters/sandbox-null/index.d.ts +3 -0
  25. package/dist/adapters/sandbox-null/index.d.ts.map +1 -0
  26. package/dist/adapters/sandbox-null/index.js +8 -0
  27. package/dist/adapters/storage-fs/index.d.ts +14 -0
  28. package/dist/adapters/storage-fs/index.d.ts.map +1 -0
  29. package/dist/adapters/storage-fs/index.js +65 -0
  30. package/dist/adapters/storage-memory/index.d.ts +11 -0
  31. package/dist/adapters/storage-memory/index.d.ts.map +1 -0
  32. package/dist/adapters/storage-memory/index.js +34 -0
  33. package/dist/adapters/types.d.ts +22 -0
  34. package/dist/adapters/types.d.ts.map +1 -0
  35. package/dist/adapters/types.js +97 -0
  36. package/dist/composition/index.d.ts +79 -0
  37. package/dist/composition/index.d.ts.map +1 -0
  38. package/dist/composition/index.js +280 -0
  39. package/dist/cost/index.d.ts +49 -0
  40. package/dist/cost/index.d.ts.map +1 -0
  41. package/dist/cost/index.js +206 -0
  42. package/dist/evidence-plan/index.d.ts +57 -0
  43. package/dist/evidence-plan/index.d.ts.map +1 -0
  44. package/dist/evidence-plan/index.js +164 -0
  45. package/dist/forecast/index.d.ts +39 -0
  46. package/dist/forecast/index.d.ts.map +1 -0
  47. package/dist/forecast/index.js +119 -0
  48. package/dist/index.d.ts +14 -0
  49. package/dist/index.d.ts.map +1 -0
  50. package/dist/index.js +29 -0
  51. package/dist/judge/index.d.ts +29 -0
  52. package/dist/judge/index.d.ts.map +1 -0
  53. package/dist/judge/index.js +138 -0
  54. package/dist/kernel/index.d.ts +170 -0
  55. package/dist/kernel/index.d.ts.map +1 -0
  56. package/dist/kernel/index.js +637 -0
  57. package/dist/memo/index.d.ts +59 -0
  58. package/dist/memo/index.d.ts.map +1 -0
  59. package/dist/memo/index.js +189 -0
  60. package/dist/policy/index.d.ts +249 -0
  61. package/dist/policy/index.d.ts.map +1 -0
  62. package/dist/policy/index.js +1463 -0
  63. package/dist/projection/index.d.ts +119 -0
  64. package/dist/projection/index.d.ts.map +1 -0
  65. package/dist/projection/index.js +506 -0
  66. package/dist/reactor/index.d.ts +54 -0
  67. package/dist/reactor/index.d.ts.map +1 -0
  68. package/dist/reactor/index.js +1861 -0
  69. package/dist/receipt/index.d.ts +190 -0
  70. package/dist/receipt/index.d.ts.map +1 -0
  71. package/dist/receipt/index.js +646 -0
  72. package/dist/sdk/exit-bundle.d.ts +144 -0
  73. package/dist/sdk/exit-bundle.d.ts.map +1 -0
  74. package/dist/sdk/exit-bundle.js +1034 -0
  75. package/dist/sdk/index.d.ts +201 -0
  76. package/dist/sdk/index.d.ts.map +1 -0
  77. package/dist/sdk/index.js +418 -0
  78. package/package.json +89 -0
@@ -0,0 +1,1034 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EXIT_BUNDLE_VERSION = exports.EXIT_BUNDLE_SCHEMA = void 0;
4
+ exports.buildReactorExitBundleV0 = buildReactorExitBundleV0;
5
+ exports.verifyReactorExitBundleV0 = verifyReactorExitBundleV0;
6
+ exports.createReactorExitBundleFailureV0 = createReactorExitBundleFailureV0;
7
+ const receipt_1 = require("../receipt");
8
+ const evidence_plan_1 = require("../evidence-plan");
9
+ const memo_1 = require("../memo");
10
+ const policy_1 = require("../policy");
11
+ exports.EXIT_BUNDLE_SCHEMA = "openprose.reactor.exit-bundle";
12
+ exports.EXIT_BUNDLE_VERSION = 0;
13
+ const EXIT_BUNDLE_RECEIPT_LOG_SCHEMA = "openprose.reactor.exit-bundle.receipt-log";
14
+ const EXIT_BUNDLE_RUNTIME_REGISTRY_SCHEMA = "openprose.reactor.exit-bundle.runtime-registry";
15
+ const EXIT_BUNDLE_MANIFEST_SCHEMA = "openprose.reactor.exit-bundle.manifest";
16
+ const EXIT_BUNDLE_IMPORT_FAILURE_SCHEMA = "openprose.reactor.exit-bundle.import-failure";
17
+ const CONTENT_HASH_PATTERN = /^sha256:[a-f0-9]{64}$/;
18
+ const ISO_INSTANT_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;
19
+ const VALIDATION_STATES = new Set(["validated", "degraded", "blocked"]);
20
+ const VERDICT_STATUSES = new Set([
21
+ "up",
22
+ "drifting",
23
+ "down",
24
+ "blocked",
25
+ ]);
26
+ const CALIBRATION_GRADES = new Set([
27
+ "authored",
28
+ "accrued",
29
+ "none",
30
+ ]);
31
+ const INTERRUPT_CAUSES = new Set([
32
+ "needs-judgment",
33
+ "needs-input",
34
+ "contract-declared",
35
+ ]);
36
+ function buildReactorExitBundleV0(input) {
37
+ const contractRevision = expectContentHashString(input.contract_revision, "contract_revision");
38
+ const asOf = expectIsoInstantString(input.as_of, "as_of");
39
+ const activePolicyArtifact = normalizePolicyArtifact(input.active_policy_artifact ?? input.policy_artifact, "policy_artifact");
40
+ const memoNamespaceBinding = normalizeMemoNamespaceBinding(input.memo_namespace_binding ?? input.memo_namespace ?? {
41
+ policy_artifact_namespace: activePolicyArtifact.namespace,
42
+ policy_artifact_revision: activePolicyArtifact.revision,
43
+ }, "memo_namespace_binding");
44
+ assertMemoNamespaceMatchesArtifact(memoNamespaceBinding, activePolicyArtifact);
45
+ const runtimeRegistry = normalizeRuntimeRegistryProjection(input.runtime_registry ??
46
+ runtimeRegistryProjectionFromPolicyArtifact({
47
+ contract_revision: contractRevision,
48
+ policy_artifact: activePolicyArtifact,
49
+ }), {
50
+ contract_revision: contractRevision,
51
+ active_policy_artifact: activePolicyArtifact,
52
+ memo_namespace_binding: memoNamespaceBinding,
53
+ require_envelope: false,
54
+ }, "runtime_registry");
55
+ const receipts = normalizeVerifiedReceipts(input.receipts, contractRevision, "receipts");
56
+ assertReceiptLogNotAfterBundleAsOf(receipts, asOf);
57
+ const dependencyReceiptPins = collectDependencyReceiptPins(receipts, input.dependency_receipt_pins ?? []);
58
+ const receiptLog = buildReceiptLog(receipts);
59
+ const manifest = buildManifest({
60
+ contract_revision: contractRevision,
61
+ active_policy_artifact_identity: activePolicyArtifact.identity,
62
+ runtime_registry: runtimeRegistry,
63
+ receipt_log: receiptLog,
64
+ dependency_receipt_pins: dependencyReceiptPins,
65
+ as_of: asOf,
66
+ memo_namespace_binding: memoNamespaceBinding,
67
+ });
68
+ const safeState = deriveSafeState(receipts);
69
+ const bundle = {
70
+ schema: exports.EXIT_BUNDLE_SCHEMA,
71
+ v: exports.EXIT_BUNDLE_VERSION,
72
+ contract_revision: contractRevision,
73
+ policy_artifact: activePolicyArtifact,
74
+ runtime_registry: runtimeRegistry,
75
+ receipt_log: receiptLog,
76
+ dependency_receipt_pins: dependencyReceiptPins,
77
+ manifest,
78
+ memo_namespace: memoNamespaceBinding,
79
+ safe_state: safeState,
80
+ as_of: asOf,
81
+ };
82
+ const verification = verifyReactorExitBundleV0(bundle);
83
+ if (!verification.ok) {
84
+ throw new Error(`Built exit bundle failed verification: ${verification.errors.join("; ")}`);
85
+ }
86
+ return bundle;
87
+ }
88
+ function verifyReactorExitBundleV0(value) {
89
+ try {
90
+ const bundle = normalizeBundle(value);
91
+ return {
92
+ ok: true,
93
+ bundle,
94
+ manifest_hash: bundle.manifest.content_hash,
95
+ receipt_log_hash: bundle.receipt_log.content_hash,
96
+ safe_state: bundle.safe_state,
97
+ };
98
+ }
99
+ catch (error) {
100
+ const message = error instanceof Error ? error.message : "exit bundle verification failed";
101
+ return createReactorExitBundleFailureV0(classifyVerificationFailure(message), [message]);
102
+ }
103
+ }
104
+ function createReactorExitBundleFailureV0(codeOrInput, errors = []) {
105
+ const code = typeof codeOrInput === "string"
106
+ ? codeOrInput
107
+ : coerceFailureCode(codeOrInput.code ?? codeOrInput.reason);
108
+ const normalizedErrors = typeof codeOrInput === "string"
109
+ ? errors.length === 0
110
+ ? ["exit bundle import failed safe"]
111
+ : [...errors]
112
+ : normalizeFailureInputErrors(codeOrInput);
113
+ const payload = {
114
+ ok: false,
115
+ schema: EXIT_BUNDLE_IMPORT_FAILURE_SCHEMA,
116
+ v: exports.EXIT_BUNDLE_VERSION,
117
+ code,
118
+ errors: normalizedErrors,
119
+ };
120
+ return {
121
+ ...payload,
122
+ content_hash: (0, receipt_1.hashCanonicalReceiptV0)((0, receipt_1.canonicalizeForReceiptV0)(payload)),
123
+ };
124
+ }
125
+ function normalizeBundle(value) {
126
+ const bundle = expectPlainRecord(value, "exit bundle");
127
+ expectExactKeys(bundle, "exit bundle", [
128
+ "schema",
129
+ "v",
130
+ "contract_revision",
131
+ "policy_artifact",
132
+ "active_policy_artifact",
133
+ "runtime_registry",
134
+ "receipt_log",
135
+ "dependency_receipt_pins",
136
+ "manifest",
137
+ "memo_namespace",
138
+ "memo_namespace_binding",
139
+ "safe_state",
140
+ "as_of",
141
+ ]);
142
+ expectLiteral(bundle["schema"], exports.EXIT_BUNDLE_SCHEMA, "exit bundle.schema");
143
+ expectLiteral(bundle["v"], exports.EXIT_BUNDLE_VERSION, "exit bundle.v");
144
+ const contractRevision = expectContentHashString(bundle["contract_revision"], "exit bundle.contract_revision");
145
+ const asOf = expectIsoInstantString(bundle["as_of"], "exit bundle.as_of");
146
+ const activePolicyArtifact = normalizePolicyArtifact(bundle["policy_artifact"] ?? bundle["active_policy_artifact"], "exit bundle.policy_artifact");
147
+ const memoNamespaceBinding = normalizeMemoNamespaceBinding(bundle["memo_namespace"] ?? bundle["memo_namespace_binding"], "exit bundle.memo_namespace");
148
+ assertMemoNamespaceMatchesArtifact(memoNamespaceBinding, activePolicyArtifact);
149
+ const runtimeRegistry = normalizeRuntimeRegistryProjection(bundle["runtime_registry"], {
150
+ contract_revision: contractRevision,
151
+ active_policy_artifact: activePolicyArtifact,
152
+ memo_namespace_binding: memoNamespaceBinding,
153
+ require_envelope: true,
154
+ }, "exit bundle.runtime_registry");
155
+ const receiptLog = normalizeReceiptLog(bundle["receipt_log"], contractRevision, "exit bundle.receipt_log");
156
+ assertReceiptLogNotAfterBundleAsOf(receiptLog.entries, asOf);
157
+ const dependencyReceiptPins = normalizeDependencyPins(bundle["dependency_receipt_pins"], "exit bundle.dependency_receipt_pins");
158
+ assertCanonicalEqual(bundle["dependency_receipt_pins"], dependencyReceiptPins, "exit bundle.dependency_receipt_pins");
159
+ assertDependencyPinsCoverReceiptLog(receiptLog.entries, dependencyReceiptPins);
160
+ const manifest = normalizeManifest(bundle["manifest"], {
161
+ contract_revision: contractRevision,
162
+ active_policy_artifact_identity: activePolicyArtifact.identity,
163
+ runtime_registry: runtimeRegistry,
164
+ receipt_log: receiptLog,
165
+ dependency_receipt_pins: dependencyReceiptPins,
166
+ as_of: asOf,
167
+ memo_namespace_binding: memoNamespaceBinding,
168
+ }, "exit bundle.manifest");
169
+ const safeState = normalizeSafeState(bundle["safe_state"], "exit bundle.safe_state");
170
+ assertCanonicalEqual(safeState, deriveSafeState(receiptLog.entries), "exit bundle.safe_state");
171
+ return {
172
+ schema: exports.EXIT_BUNDLE_SCHEMA,
173
+ v: exports.EXIT_BUNDLE_VERSION,
174
+ contract_revision: contractRevision,
175
+ policy_artifact: activePolicyArtifact,
176
+ runtime_registry: runtimeRegistry,
177
+ receipt_log: receiptLog,
178
+ dependency_receipt_pins: dependencyReceiptPins,
179
+ manifest,
180
+ memo_namespace: memoNamespaceBinding,
181
+ safe_state: safeState,
182
+ as_of: asOf,
183
+ };
184
+ }
185
+ function normalizePolicyArtifact(value, path) {
186
+ const artifact = expectPlainRecord(value, path);
187
+ expectExactKeys(artifact, path, [
188
+ "id",
189
+ "identity",
190
+ "namespace",
191
+ "revision",
192
+ "content_hash",
193
+ "bytes",
194
+ "policy_artifact_identity",
195
+ "policy_artifact_namespace",
196
+ "policy_artifact_revision",
197
+ "validation_state",
198
+ "artifact_content_hash",
199
+ "artifact_bytes",
200
+ ]);
201
+ const policyArtifactIdentity = expectNonEmptyString(artifact["identity"] ?? artifact["policy_artifact_identity"] ?? artifact["id"], `${path}.identity`);
202
+ const policyArtifactId = expectNonEmptyString(artifact["id"] ?? artifact["policy_artifact_identity"] ?? artifact["identity"], `${path}.id`);
203
+ const policyArtifactNamespace = expectNonEmptyString(artifact["namespace"] ?? artifact["policy_artifact_namespace"], `${path}.namespace`);
204
+ const policyArtifactRevision = expectNonEmptyString(artifact["revision"] ?? artifact["policy_artifact_revision"], `${path}.revision`);
205
+ const validationState = normalizeValidationState(artifact["validation_state"], `${path}.validation_state`);
206
+ const artifactContentHash = (artifact["content_hash"] ?? artifact["artifact_content_hash"]) === undefined
207
+ ? undefined
208
+ : expectContentHashString(artifact["content_hash"] ?? artifact["artifact_content_hash"], `${path}.content_hash`);
209
+ const artifactBytes = (artifact["bytes"] ?? artifact["artifact_bytes"]) === undefined
210
+ ? undefined
211
+ : expectNonEmptyString(artifact["bytes"] ?? artifact["artifact_bytes"], `${path}.bytes`);
212
+ if (artifactContentHash === undefined &&
213
+ artifactBytes === undefined &&
214
+ !CONTENT_HASH_PATTERN.test(policyArtifactIdentity)) {
215
+ throw new Error(`${path} must include artifact_bytes, artifact_content_hash, or a content-addressed policy_artifact_identity`);
216
+ }
217
+ return {
218
+ id: policyArtifactId,
219
+ identity: policyArtifactIdentity,
220
+ namespace: policyArtifactNamespace,
221
+ revision: policyArtifactRevision,
222
+ validation_state: validationState,
223
+ ...(artifactContentHash === undefined
224
+ ? {}
225
+ : { content_hash: artifactContentHash }),
226
+ ...(artifactBytes === undefined ? {} : { bytes: artifactBytes }),
227
+ };
228
+ }
229
+ function runtimeRegistryProjectionFromPolicyArtifact(input) {
230
+ return {
231
+ contract_revision: input.contract_revision,
232
+ policy_artifact_id: input.policy_artifact.id,
233
+ policy_artifact_identity: input.policy_artifact.identity,
234
+ policy_artifact_namespace: input.policy_artifact.namespace,
235
+ policy_artifact_revision: input.policy_artifact.revision,
236
+ policy_artifact_validation_state: input.policy_artifact.validation_state,
237
+ validation_state: input.policy_artifact.validation_state,
238
+ ...(input.policy_artifact.content_hash === undefined
239
+ ? {}
240
+ : { policy_artifact_content_hash: input.policy_artifact.content_hash }),
241
+ ...(input.policy_artifact.bytes === undefined
242
+ ? {}
243
+ : { policy_artifact_bytes: input.policy_artifact.bytes }),
244
+ };
245
+ }
246
+ function normalizeRuntimeRegistryProjection(value, expected, path) {
247
+ const registry = expectPlainRecord(value, path);
248
+ expectExactKeys(registry, path, [
249
+ "schema",
250
+ "v",
251
+ "content_hash",
252
+ "contract_revision",
253
+ "policy_artifact_id",
254
+ "policy_artifact_identity",
255
+ "policy_artifact_namespace",
256
+ "policy_artifact_revision",
257
+ "policy_artifact_validation_state",
258
+ "validation_state",
259
+ "policy_artifact_content_hash",
260
+ "policy_artifact_bytes",
261
+ "transitive_freshness_function",
262
+ "compiled_evidence_plan",
263
+ "forecast_schedule",
264
+ ]);
265
+ if (expected.require_envelope || registry["schema"] !== undefined) {
266
+ expectLiteral(registry["schema"], EXIT_BUNDLE_RUNTIME_REGISTRY_SCHEMA, `${path}.schema`);
267
+ }
268
+ if (expected.require_envelope || registry["v"] !== undefined) {
269
+ expectLiteral(registry["v"], exports.EXIT_BUNDLE_VERSION, `${path}.v`);
270
+ }
271
+ const contractRevision = expectContentHashString(registry["contract_revision"], `${path}.contract_revision`);
272
+ const policyArtifactId = expectNonEmptyString(registry["policy_artifact_id"], `${path}.policy_artifact_id`);
273
+ const policyArtifactIdentity = expectNonEmptyString(registry["policy_artifact_identity"], `${path}.policy_artifact_identity`);
274
+ const policyArtifactNamespace = expectNonEmptyString(registry["policy_artifact_namespace"], `${path}.policy_artifact_namespace`);
275
+ const policyArtifactRevision = expectNonEmptyString(registry["policy_artifact_revision"], `${path}.policy_artifact_revision`);
276
+ const validationState = normalizeValidationState(registry["policy_artifact_validation_state"], `${path}.policy_artifact_validation_state`);
277
+ const validationStateAlias = registry["validation_state"] === undefined
278
+ ? undefined
279
+ : normalizeValidationState(registry["validation_state"], `${path}.validation_state`);
280
+ if (validationStateAlias !== undefined &&
281
+ (0, receipt_1.canonicalizeForReceiptV0)(validationStateAlias) !==
282
+ (0, receipt_1.canonicalizeForReceiptV0)(validationState)) {
283
+ throw new Error(`${path}.validation_state must match policy_artifact_validation_state`);
284
+ }
285
+ const policyArtifactContentHash = registry["policy_artifact_content_hash"] === undefined
286
+ ? undefined
287
+ : expectContentHashString(registry["policy_artifact_content_hash"], `${path}.policy_artifact_content_hash`);
288
+ const policyArtifactBytes = registry["policy_artifact_bytes"] === undefined
289
+ ? undefined
290
+ : expectNonEmptyString(registry["policy_artifact_bytes"], `${path}.policy_artifact_bytes`);
291
+ const transitiveFreshnessFunction = registry["transitive_freshness_function"] === undefined
292
+ ? undefined
293
+ : (0, policy_1.normalizePolicyTransitiveFreshnessFunctionV0)(registry["transitive_freshness_function"], `${path}.transitive_freshness_function`);
294
+ const compiledEvidencePlan = registry["compiled_evidence_plan"] === undefined
295
+ ? undefined
296
+ : normalizeCompiledEvidencePlan(registry["compiled_evidence_plan"], `${path}.compiled_evidence_plan`);
297
+ const forecastSchedule = registry["forecast_schedule"] === undefined
298
+ ? undefined
299
+ : normalizeForecastSchedule(registry["forecast_schedule"], `${path}.forecast_schedule`);
300
+ const projection = runtimeRegistryProjectionPayload({
301
+ contract_revision: contractRevision,
302
+ policy_artifact_id: policyArtifactId,
303
+ policy_artifact_identity: policyArtifactIdentity,
304
+ policy_artifact_namespace: policyArtifactNamespace,
305
+ policy_artifact_revision: policyArtifactRevision,
306
+ policy_artifact_validation_state: validationState,
307
+ ...(validationStateAlias === undefined
308
+ ? {}
309
+ : { validation_state: validationStateAlias }),
310
+ ...(policyArtifactContentHash === undefined
311
+ ? {}
312
+ : { policy_artifact_content_hash: policyArtifactContentHash }),
313
+ ...(policyArtifactBytes === undefined
314
+ ? {}
315
+ : { policy_artifact_bytes: policyArtifactBytes }),
316
+ ...(transitiveFreshnessFunction === undefined
317
+ ? {}
318
+ : { transitive_freshness_function: transitiveFreshnessFunction }),
319
+ ...(compiledEvidencePlan === undefined
320
+ ? {}
321
+ : { compiled_evidence_plan: compiledEvidencePlan }),
322
+ ...(forecastSchedule === undefined
323
+ ? {}
324
+ : { forecast_schedule: forecastSchedule }),
325
+ });
326
+ const contentHash = (0, receipt_1.hashCanonicalReceiptV0)((0, receipt_1.canonicalizeForReceiptV0)(projection));
327
+ if (expected.require_envelope || registry["content_hash"] !== undefined) {
328
+ const suppliedContentHash = expectContentHashString(registry["content_hash"], `${path}.content_hash`);
329
+ if (suppliedContentHash !== contentHash) {
330
+ throw new Error(`${path}.content_hash does not match canonical runtime registry projection`);
331
+ }
332
+ }
333
+ const normalized = {
334
+ ...projection,
335
+ content_hash: contentHash,
336
+ };
337
+ assertRuntimeRegistryMatchesBundleEdges(normalized, expected, path);
338
+ assertRuntimeRegistryRuntimeFields(normalized, path);
339
+ return normalized;
340
+ }
341
+ function runtimeRegistryProjectionPayload(input) {
342
+ return {
343
+ schema: EXIT_BUNDLE_RUNTIME_REGISTRY_SCHEMA,
344
+ v: exports.EXIT_BUNDLE_VERSION,
345
+ ...input,
346
+ };
347
+ }
348
+ function assertRuntimeRegistryMatchesBundleEdges(registry, expected, path) {
349
+ if (registry.contract_revision !== expected.contract_revision) {
350
+ throw new Error(`${path}.contract_revision must match exit bundle.contract_revision`);
351
+ }
352
+ if (registry.policy_artifact_id !== expected.active_policy_artifact.id) {
353
+ throw new Error(`${path}.policy_artifact_id must match policy_artifact.id`);
354
+ }
355
+ if (registry.policy_artifact_identity !== expected.active_policy_artifact.identity) {
356
+ throw new Error(`${path}.policy_artifact_identity must match policy_artifact.identity`);
357
+ }
358
+ if (registry.policy_artifact_namespace !== expected.active_policy_artifact.namespace) {
359
+ throw new Error(`${path}.policy_artifact_namespace must match policy_artifact.namespace`);
360
+ }
361
+ if (registry.policy_artifact_revision !== expected.active_policy_artifact.revision) {
362
+ throw new Error(`${path}.policy_artifact_revision must match policy_artifact.revision`);
363
+ }
364
+ if ((0, receipt_1.canonicalizeForReceiptV0)(registry.policy_artifact_validation_state) !==
365
+ (0, receipt_1.canonicalizeForReceiptV0)(expected.active_policy_artifact.validation_state)) {
366
+ throw new Error(`${path}.policy_artifact_validation_state must match policy_artifact.validation_state`);
367
+ }
368
+ if (registry.policy_artifact_content_hash !== undefined &&
369
+ expected.active_policy_artifact.content_hash !== undefined &&
370
+ registry.policy_artifact_content_hash !== expected.active_policy_artifact.content_hash) {
371
+ throw new Error(`${path}.policy_artifact_content_hash must match policy_artifact.content_hash`);
372
+ }
373
+ if (registry.policy_artifact_bytes !== undefined &&
374
+ expected.active_policy_artifact.bytes !== undefined &&
375
+ registry.policy_artifact_bytes !== expected.active_policy_artifact.bytes) {
376
+ throw new Error(`${path}.policy_artifact_bytes must match policy_artifact.bytes`);
377
+ }
378
+ if (registry.policy_artifact_namespace !==
379
+ expected.memo_namespace_binding.policy_artifact_namespace ||
380
+ registry.policy_artifact_revision !==
381
+ expected.memo_namespace_binding.policy_artifact_revision) {
382
+ throw new Error(`${path} must match memo_namespace policy artifact binding`);
383
+ }
384
+ }
385
+ function assertRuntimeRegistryRuntimeFields(registry, path) {
386
+ const plan = registry.compiled_evidence_plan;
387
+ if (plan !== undefined) {
388
+ if (plan.contract_revision !== registry.contract_revision) {
389
+ throw new Error(`${path}.compiled_evidence_plan.contract_revision must match registry`);
390
+ }
391
+ if (plan.policy_artifact_namespace !== registry.policy_artifact_namespace) {
392
+ throw new Error(`${path}.compiled_evidence_plan.policy_artifact_namespace must match registry`);
393
+ }
394
+ if (plan.policy_artifact_revision !== registry.policy_artifact_revision) {
395
+ throw new Error(`${path}.compiled_evidence_plan.policy_artifact_revision must match registry`);
396
+ }
397
+ }
398
+ const schedule = registry.forecast_schedule;
399
+ if (schedule !== undefined) {
400
+ if (schedule.contract_revision !== registry.contract_revision) {
401
+ throw new Error(`${path}.forecast_schedule.contract_revision must match registry`);
402
+ }
403
+ }
404
+ if (plan !== undefined &&
405
+ schedule !== undefined &&
406
+ plan.responsibility_id !== schedule.responsibility_id) {
407
+ throw new Error(`${path}.compiled_evidence_plan and forecast_schedule responsibility_id must match`);
408
+ }
409
+ }
410
+ function normalizeCompiledEvidencePlan(value, path) {
411
+ const plan = expectPlainRecord(value, path);
412
+ expectExactKeys(plan, path, [
413
+ "responsibility_id",
414
+ "contract_revision",
415
+ "policy_artifact_namespace",
416
+ "policy_artifact_revision",
417
+ "plan_revision",
418
+ "as_of",
419
+ "evidence_order",
420
+ "sources",
421
+ ]);
422
+ const normalized = {
423
+ responsibility_id: expectNonEmptyString(plan["responsibility_id"], `${path}.responsibility_id`),
424
+ contract_revision: expectContentHashString(plan["contract_revision"], `${path}.contract_revision`),
425
+ policy_artifact_namespace: expectNonEmptyString(plan["policy_artifact_namespace"], `${path}.policy_artifact_namespace`),
426
+ policy_artifact_revision: expectNonEmptyString(plan["policy_artifact_revision"], `${path}.policy_artifact_revision`),
427
+ plan_revision: expectNonEmptyString(plan["plan_revision"], `${path}.plan_revision`),
428
+ as_of: expectIsoInstantString(plan["as_of"], `${path}.as_of`),
429
+ evidence_order: expectEvidenceReceiptOrder(plan["evidence_order"], `${path}.evidence_order`),
430
+ sources: normalizeCompiledEvidenceSources(plan["sources"], `${path}.sources`),
431
+ };
432
+ const errors = (0, evidence_plan_1.validateCompiledEvidencePlan)(normalized);
433
+ if (errors.length > 0) {
434
+ throw new Error(`${path} is malformed: ${errors.join("; ")}`);
435
+ }
436
+ return normalized;
437
+ }
438
+ function normalizeCompiledEvidenceSources(value, path) {
439
+ return expectArray(value, path).map((item, index) => {
440
+ const itemPath = `${path}[${index}]`;
441
+ const source = expectPlainRecord(item, itemPath);
442
+ expectExactKeys(source, itemPath, ["id", "kind", "required", "receipt_order"]);
443
+ const kind = expectEnumString(source["kind"], new Set(["adapter", "forecast", "dependency"]), `${itemPath}.kind`);
444
+ const required = source["required"];
445
+ if (typeof required !== "boolean") {
446
+ throw new Error(`${itemPath}.required must be boolean`);
447
+ }
448
+ const receiptOrder = source["receipt_order"] === undefined
449
+ ? undefined
450
+ : expectEvidenceReceiptOrder(source["receipt_order"], `${itemPath}.receipt_order`);
451
+ return {
452
+ id: expectNonEmptyString(source["id"], `${itemPath}.id`),
453
+ kind: kind,
454
+ required,
455
+ ...(receiptOrder === undefined ? {} : { receipt_order: receiptOrder }),
456
+ };
457
+ });
458
+ }
459
+ function expectEvidenceReceiptOrder(value, path) {
460
+ return expectEnumString(value, new Set(["unordered", "declared"]), path);
461
+ }
462
+ function normalizeForecastSchedule(value, path) {
463
+ const schedule = expectPlainRecord(value, path);
464
+ expectExactKeys(schedule, path, [
465
+ "responsibility_id",
466
+ "contract_revision",
467
+ "memo_key",
468
+ "evidence_input_ids",
469
+ "next_evidence_recheck",
470
+ "next_plan_recheck",
471
+ ]);
472
+ return {
473
+ responsibility_id: expectNonEmptyString(schedule["responsibility_id"], `${path}.responsibility_id`),
474
+ contract_revision: expectContentHashString(schedule["contract_revision"], `${path}.contract_revision`),
475
+ memo_key: expectNonEmptyString(schedule["memo_key"], `${path}.memo_key`),
476
+ evidence_input_ids: expectContentHashArray(schedule["evidence_input_ids"], `${path}.evidence_input_ids`),
477
+ next_evidence_recheck: expectIsoInstantString(schedule["next_evidence_recheck"], `${path}.next_evidence_recheck`),
478
+ next_plan_recheck: expectIsoInstantString(schedule["next_plan_recheck"], `${path}.next_plan_recheck`),
479
+ };
480
+ }
481
+ function normalizeValidationState(value, path) {
482
+ if (typeof value === "string") {
483
+ return expectEnumString(value, VALIDATION_STATES, path);
484
+ }
485
+ const state = expectPlainRecord(value, path);
486
+ expectExactKeys(state, path, [
487
+ "status",
488
+ "reason",
489
+ "validator_id",
490
+ "validated_as_of",
491
+ "validation_receipt_hash",
492
+ ]);
493
+ const status = expectEnumString(state["status"], VALIDATION_STATES, `${path}.status`);
494
+ const reason = state["reason"] === undefined
495
+ ? undefined
496
+ : expectNonEmptyString(state["reason"], `${path}.reason`);
497
+ const validatorId = state["validator_id"] === undefined
498
+ ? undefined
499
+ : expectNonEmptyString(state["validator_id"], `${path}.validator_id`);
500
+ const validatedAsOf = state["validated_as_of"] === undefined
501
+ ? undefined
502
+ : expectIsoInstantString(state["validated_as_of"], `${path}.validated_as_of`);
503
+ const validationReceiptHash = state["validation_receipt_hash"] === undefined
504
+ ? undefined
505
+ : expectContentHashString(state["validation_receipt_hash"], `${path}.validation_receipt_hash`);
506
+ if ((status === "degraded" || status === "blocked") && reason === undefined) {
507
+ throw new Error(`${path}.reason is required when status is ${status}`);
508
+ }
509
+ return {
510
+ status,
511
+ ...(reason === undefined ? {} : { reason }),
512
+ ...(validatorId === undefined ? {} : { validator_id: validatorId }),
513
+ ...(validatedAsOf === undefined ? {} : { validated_as_of: validatedAsOf }),
514
+ ...(validationReceiptHash === undefined
515
+ ? {}
516
+ : { validation_receipt_hash: validationReceiptHash }),
517
+ };
518
+ }
519
+ function normalizeMemoNamespaceBinding(value, path) {
520
+ const binding = expectPlainRecord(value, path);
521
+ expectExactKeys(binding, path, ["policy_artifact_namespace", "policy_artifact_revision"]);
522
+ const normalized = {
523
+ policy_artifact_namespace: expectNonEmptyString(binding["policy_artifact_namespace"], `${path}.policy_artifact_namespace`),
524
+ policy_artifact_revision: expectNonEmptyString(binding["policy_artifact_revision"], `${path}.policy_artifact_revision`),
525
+ };
526
+ (0, memo_1.namespaceKey)(normalized);
527
+ return normalized;
528
+ }
529
+ function normalizeReceiptLog(value, contractRevision, path) {
530
+ const log = expectPlainRecord(value, path);
531
+ expectExactKeys(log, path, [
532
+ "schema",
533
+ "v",
534
+ "content_hash",
535
+ "head",
536
+ "member_hashes",
537
+ "entries",
538
+ ]);
539
+ expectLiteral(log["schema"], EXIT_BUNDLE_RECEIPT_LOG_SCHEMA, `${path}.schema`);
540
+ expectLiteral(log["v"], exports.EXIT_BUNDLE_VERSION, `${path}.v`);
541
+ expectContentHashString(log["content_hash"], `${path}.content_hash`);
542
+ expectNullableContentHash(log["head"], `${path}.head`);
543
+ expectContentHashArray(log["member_hashes"], `${path}.member_hashes`);
544
+ const rawReceipts = expectArray(log["entries"], `${path}.entries`);
545
+ const receipts = normalizeVerifiedReceipts(rawReceipts, contractRevision, `${path}.entries`);
546
+ const expected = buildReceiptLog(receipts);
547
+ assertCanonicalEqual(log, expected, path);
548
+ return expected;
549
+ }
550
+ function normalizeManifest(value, input, path) {
551
+ const manifest = expectPlainRecord(value, path);
552
+ expectExactKeys(manifest, path, [
553
+ "schema",
554
+ "v",
555
+ "content_hash",
556
+ "contract_revision",
557
+ "active_policy_artifact_identity",
558
+ "runtime_registry_content_hash",
559
+ "receipt_log_content_hash",
560
+ "receipt_log_head",
561
+ "receipt_member_hashes",
562
+ "dependency_receipt_pins",
563
+ "as_of",
564
+ "memo_namespace",
565
+ ]);
566
+ expectLiteral(manifest["schema"], EXIT_BUNDLE_MANIFEST_SCHEMA, `${path}.schema`);
567
+ expectLiteral(manifest["v"], exports.EXIT_BUNDLE_VERSION, `${path}.v`);
568
+ expectContentHashString(manifest["content_hash"], `${path}.content_hash`);
569
+ expectContentHashString(manifest["contract_revision"], `${path}.contract_revision`);
570
+ expectNonEmptyString(manifest["active_policy_artifact_identity"], `${path}.active_policy_artifact_identity`);
571
+ expectContentHashString(manifest["runtime_registry_content_hash"], `${path}.runtime_registry_content_hash`);
572
+ expectContentHashString(manifest["receipt_log_content_hash"], `${path}.receipt_log_content_hash`);
573
+ expectNullableContentHash(manifest["receipt_log_head"], `${path}.receipt_log_head`);
574
+ expectContentHashArray(manifest["receipt_member_hashes"], `${path}.receipt_member_hashes`);
575
+ normalizeDependencyPins(manifest["dependency_receipt_pins"], `${path}.dependency_receipt_pins`);
576
+ expectIsoInstantString(manifest["as_of"], `${path}.as_of`);
577
+ normalizeMemoNamespaceBinding(manifest["memo_namespace"], `${path}.memo_namespace`);
578
+ const expected = buildManifest(input);
579
+ assertCanonicalEqual(manifest, expected, path);
580
+ return expected;
581
+ }
582
+ function normalizeSafeState(value, path) {
583
+ const safeState = expectPlainRecord(value, path);
584
+ const status = expectEnumString(safeState["status"], new Set(["ready", "degraded", "blocked"]), `${path}.status`);
585
+ if (status === "ready") {
586
+ expectExactKeys(safeState, path, ["status", "reasons", "receipt_hash", "as_of"]);
587
+ const reasons = expectStringArray(safeState["reasons"], `${path}.reasons`);
588
+ if (reasons.length > 0) {
589
+ throw new Error(`${path}.reasons must be empty when status is ready`);
590
+ }
591
+ const receiptHash = expectNullableContentHash(safeState["receipt_hash"], `${path}.receipt_hash`);
592
+ const asOf = expectNullableIsoInstant(safeState["as_of"], `${path}.as_of`);
593
+ if ((receiptHash === null) !== (asOf === null)) {
594
+ throw new Error(`${path}.receipt_hash and ${path}.as_of must be paired`);
595
+ }
596
+ return {
597
+ status: "ready",
598
+ reasons,
599
+ receipt_hash: receiptHash,
600
+ as_of: asOf,
601
+ };
602
+ }
603
+ if (status === "degraded") {
604
+ expectExactKeys(safeState, path, [
605
+ "status",
606
+ "reasons",
607
+ "receipt_hash",
608
+ "as_of",
609
+ "verdict_status",
610
+ "calibration_grade",
611
+ "reason",
612
+ ]);
613
+ const verdictStatus = expectEnumString(safeState["verdict_status"], VERDICT_STATUSES, `${path}.verdict_status`);
614
+ if (verdictStatus === "blocked") {
615
+ throw new Error(`${path}.verdict_status must not be blocked for degraded state`);
616
+ }
617
+ return {
618
+ status: "degraded",
619
+ reasons: expectNonEmptyStringArray(safeState["reasons"], `${path}.reasons`),
620
+ receipt_hash: expectContentHashString(safeState["receipt_hash"], `${path}.receipt_hash`),
621
+ as_of: expectIsoInstantString(safeState["as_of"], `${path}.as_of`),
622
+ verdict_status: verdictStatus,
623
+ calibration_grade: expectEnumString(safeState["calibration_grade"], CALIBRATION_GRADES, `${path}.calibration_grade`),
624
+ reason: expectNonEmptyString(safeState["reason"], `${path}.reason`),
625
+ };
626
+ }
627
+ expectExactKeys(safeState, path, [
628
+ "status",
629
+ "reasons",
630
+ "receipt_hash",
631
+ "as_of",
632
+ "reason",
633
+ "fix_target",
634
+ "interrupt_cause",
635
+ ]);
636
+ return {
637
+ status: "blocked",
638
+ reasons: expectNonEmptyStringArray(safeState["reasons"], `${path}.reasons`),
639
+ receipt_hash: expectContentHashString(safeState["receipt_hash"], `${path}.receipt_hash`),
640
+ as_of: expectIsoInstantString(safeState["as_of"], `${path}.as_of`),
641
+ reason: expectNonEmptyString(safeState["reason"], `${path}.reason`),
642
+ fix_target: expectNonEmptyString(safeState["fix_target"], `${path}.fix_target`),
643
+ interrupt_cause: expectEnumString(safeState["interrupt_cause"], INTERRUPT_CAUSES, `${path}.interrupt_cause`),
644
+ };
645
+ }
646
+ function normalizeVerifiedReceipts(value, contractRevision, path) {
647
+ const receipts = [];
648
+ const seen = new Set();
649
+ for (const [index, receipt] of value.entries()) {
650
+ const verification = (0, receipt_1.verifyReceiptV0)(receipt);
651
+ if (!verification.ok) {
652
+ throw new Error(`${path}[${index}] failed receipt v0 verification: ${verification.errors.join("; ")}`);
653
+ }
654
+ const verifiedReceipt = receipt;
655
+ if (verifiedReceipt.core.contract_revision !== contractRevision) {
656
+ throw new Error(`${path}[${index}].core.contract_revision must match bundle contract_revision`);
657
+ }
658
+ if (seen.has(verification.content_hash)) {
659
+ throw new Error(`${path}[${index}] duplicates receipt ${verification.content_hash}`);
660
+ }
661
+ seen.add(verification.content_hash);
662
+ receipts.push(verifiedReceipt);
663
+ }
664
+ return receipts.sort(compareReceiptsForLog);
665
+ }
666
+ function collectDependencyReceiptPins(receipts, explicitPins) {
667
+ const receiptPins = [];
668
+ for (const receipt of receipts) {
669
+ receiptPins.push(...receipt.composition.consumed_receipts);
670
+ }
671
+ return normalizeDependencyPins([...explicitPins, ...receiptPins], "dependency_receipt_pins");
672
+ }
673
+ function normalizeDependencyPins(value, path) {
674
+ const pins = expectArray(value, path);
675
+ const normalized = [];
676
+ const byUpstreamHash = new Map();
677
+ const seen = new Set();
678
+ for (const [index, item] of pins.entries()) {
679
+ const itemPath = `${path}[${index}]`;
680
+ const pin = expectPlainRecord(item, itemPath);
681
+ expectExactKeys(pin, itemPath, [
682
+ "upstream_content_hash",
683
+ "contract_revision",
684
+ "acceptable_signer_set",
685
+ ]);
686
+ const upstreamContentHash = expectContentHashString(pin["upstream_content_hash"], `${itemPath}.upstream_content_hash`);
687
+ const contractRevision = expectContentHashString(pin["contract_revision"], `${itemPath}.contract_revision`);
688
+ const acceptableSignerSet = normalizeSignerSet(pin["acceptable_signer_set"], `${itemPath}.acceptable_signer_set`);
689
+ const pinIdentity = (0, receipt_1.canonicalizeForReceiptV0)({
690
+ upstream_content_hash: upstreamContentHash,
691
+ contract_revision: contractRevision,
692
+ acceptable_signer_set: acceptableSignerSet,
693
+ });
694
+ const existingIdentity = byUpstreamHash.get(upstreamContentHash);
695
+ if (existingIdentity !== undefined && existingIdentity !== pinIdentity) {
696
+ throw new Error(`${itemPath}.upstream_content_hash has conflicting pins`);
697
+ }
698
+ if (seen.has(pinIdentity)) {
699
+ continue;
700
+ }
701
+ byUpstreamHash.set(upstreamContentHash, pinIdentity);
702
+ seen.add(pinIdentity);
703
+ normalized.push({
704
+ upstream_content_hash: upstreamContentHash,
705
+ contract_revision: contractRevision,
706
+ acceptable_signer_set: acceptableSignerSet,
707
+ });
708
+ }
709
+ return normalized.sort(compareDependencyPins);
710
+ }
711
+ function normalizeSignerSet(value, path) {
712
+ const signers = expectStringArray(value, path);
713
+ if (signers.length === 0) {
714
+ throw new Error(`${path} must not be empty`);
715
+ }
716
+ const seen = new Set();
717
+ for (const signer of signers) {
718
+ if (signer.length === 0) {
719
+ throw new Error(`${path} must not contain empty signer ids`);
720
+ }
721
+ if (seen.has(signer)) {
722
+ throw new Error(`${path} must not contain duplicate signer ${signer}`);
723
+ }
724
+ seen.add(signer);
725
+ }
726
+ return [...signers].sort((left, right) => left.localeCompare(right));
727
+ }
728
+ function buildManifest(input) {
729
+ const payload = {
730
+ schema: EXIT_BUNDLE_MANIFEST_SCHEMA,
731
+ v: exports.EXIT_BUNDLE_VERSION,
732
+ contract_revision: input.contract_revision,
733
+ active_policy_artifact_identity: input.active_policy_artifact_identity,
734
+ runtime_registry_content_hash: input.runtime_registry.content_hash,
735
+ receipt_log_content_hash: input.receipt_log.content_hash,
736
+ receipt_log_head: input.receipt_log.head,
737
+ receipt_member_hashes: input.receipt_log.member_hashes,
738
+ dependency_receipt_pins: input.dependency_receipt_pins,
739
+ as_of: input.as_of,
740
+ memo_namespace: input.memo_namespace_binding,
741
+ };
742
+ return {
743
+ ...payload,
744
+ content_hash: (0, receipt_1.hashCanonicalReceiptV0)((0, receipt_1.canonicalizeForReceiptV0)(payload)),
745
+ };
746
+ }
747
+ function buildReceiptLog(receipts) {
748
+ const sortedReceipts = [...receipts].sort(compareReceiptsForLog);
749
+ const memberHashes = sortedReceipts
750
+ .map((receipt) => receipt.content_hash)
751
+ .sort((left, right) => left.localeCompare(right));
752
+ const head = sortedReceipts.length === 0
753
+ ? null
754
+ : sortedReceipts[sortedReceipts.length - 1]?.content_hash ?? null;
755
+ const payload = {
756
+ schema: EXIT_BUNDLE_RECEIPT_LOG_SCHEMA,
757
+ v: exports.EXIT_BUNDLE_VERSION,
758
+ head,
759
+ member_hashes: memberHashes,
760
+ entries: sortedReceipts,
761
+ };
762
+ return {
763
+ ...payload,
764
+ content_hash: (0, receipt_1.hashCanonicalReceiptV0)((0, receipt_1.canonicalizeForReceiptV0)(payload)),
765
+ };
766
+ }
767
+ function deriveSafeState(receipts) {
768
+ const latestReceipt = latestReceiptByAsOf(receipts);
769
+ if (latestReceipt === undefined) {
770
+ return {
771
+ status: "ready",
772
+ reasons: [],
773
+ receipt_hash: null,
774
+ as_of: null,
775
+ };
776
+ }
777
+ if (latestReceipt.verdict.status === "blocked") {
778
+ const blocked = latestReceipt.verdict.blocked;
779
+ if (blocked === undefined) {
780
+ throw new Error("latest blocked receipt is missing blocked details");
781
+ }
782
+ return {
783
+ status: "blocked",
784
+ reasons: [blocked.reason],
785
+ receipt_hash: latestReceipt.content_hash,
786
+ as_of: latestReceipt.core.as_of,
787
+ reason: blocked.reason,
788
+ fix_target: blocked.fix_target,
789
+ interrupt_cause: blocked.interrupt_cause,
790
+ };
791
+ }
792
+ if (latestReceipt.verdict.status !== "up" ||
793
+ latestReceipt.verdict.confidence.calibration_grade === "none") {
794
+ const reason = degradedReason(latestReceipt);
795
+ return {
796
+ status: "degraded",
797
+ reasons: [reason],
798
+ receipt_hash: latestReceipt.content_hash,
799
+ as_of: latestReceipt.core.as_of,
800
+ verdict_status: latestReceipt.verdict.status,
801
+ calibration_grade: latestReceipt.verdict.confidence.calibration_grade,
802
+ reason,
803
+ };
804
+ }
805
+ return {
806
+ status: "ready",
807
+ reasons: [],
808
+ receipt_hash: latestReceipt.content_hash,
809
+ as_of: latestReceipt.core.as_of,
810
+ };
811
+ }
812
+ function degradedReason(receipt) {
813
+ if (receipt.verdict.status !== "up") {
814
+ return `latest receipt verdict is ${receipt.verdict.status}`;
815
+ }
816
+ return "latest receipt has no calibrated confidence";
817
+ }
818
+ function assertDependencyPinsCoverReceiptLog(receipts, dependencyReceiptPins) {
819
+ const pinned = new Set(dependencyReceiptPins.map((pin) => (0, receipt_1.canonicalizeForReceiptV0)({
820
+ upstream_content_hash: pin.upstream_content_hash,
821
+ contract_revision: pin.contract_revision,
822
+ acceptable_signer_set: pin.acceptable_signer_set,
823
+ })));
824
+ for (const receipt of receipts) {
825
+ const requiredPins = normalizeDependencyPins(receipt.composition.consumed_receipts, "receipt.composition.consumed_receipts");
826
+ for (const pin of requiredPins) {
827
+ const key = (0, receipt_1.canonicalizeForReceiptV0)(pin);
828
+ if (!pinned.has(key)) {
829
+ throw new Error(`exit bundle.dependency_receipt_pins is missing consumed receipt ${pin.upstream_content_hash}`);
830
+ }
831
+ }
832
+ }
833
+ }
834
+ function assertReceiptLogNotAfterBundleAsOf(receipts, asOf) {
835
+ const latestReceipt = latestReceiptByAsOf(receipts);
836
+ if (latestReceipt !== undefined && latestReceipt.core.as_of > asOf) {
837
+ throw new Error("exit bundle.as_of must be at or after the latest receipt");
838
+ }
839
+ }
840
+ function assertMemoNamespaceMatchesArtifact(memoNamespaceBinding, activePolicyArtifact) {
841
+ if (memoNamespaceBinding.policy_artifact_namespace !==
842
+ activePolicyArtifact.namespace ||
843
+ memoNamespaceBinding.policy_artifact_revision !==
844
+ activePolicyArtifact.revision) {
845
+ throw new Error("memo_namespace_binding must match active policy artifact namespace and revision");
846
+ }
847
+ }
848
+ function assertCanonicalEqual(left, right, path) {
849
+ const leftCanonical = (0, receipt_1.canonicalizeForReceiptV0)(left);
850
+ const rightCanonical = (0, receipt_1.canonicalizeForReceiptV0)(right);
851
+ if (leftCanonical !== rightCanonical) {
852
+ throw new Error(`${path} does not match canonical exit-bundle content`);
853
+ }
854
+ }
855
+ function latestReceiptByAsOf(receipts) {
856
+ return [...receipts].sort(compareReceiptsForLog).at(-1);
857
+ }
858
+ function compareReceiptsForLog(left, right) {
859
+ const asOf = left.core.as_of.localeCompare(right.core.as_of);
860
+ if (asOf !== 0) {
861
+ return asOf;
862
+ }
863
+ return left.content_hash.localeCompare(right.content_hash);
864
+ }
865
+ function compareDependencyPins(left, right) {
866
+ const upstream = left.upstream_content_hash.localeCompare(right.upstream_content_hash);
867
+ if (upstream !== 0) {
868
+ return upstream;
869
+ }
870
+ const contract = left.contract_revision.localeCompare(right.contract_revision);
871
+ if (contract !== 0) {
872
+ return contract;
873
+ }
874
+ return left.acceptable_signer_set
875
+ .join("\0")
876
+ .localeCompare(right.acceptable_signer_set.join("\0"));
877
+ }
878
+ function classifyVerificationFailure(message) {
879
+ if (message.includes(".v") || message.includes("unsupported")) {
880
+ return "unsupported-version";
881
+ }
882
+ if (message.includes("contract_revision")) {
883
+ return "invalid-contract-revision";
884
+ }
885
+ if (message.includes("active_policy_artifact") || message.includes("policy_artifact")) {
886
+ return "invalid-policy-artifact";
887
+ }
888
+ if (message.includes("runtime_registry")) {
889
+ return "invalid-manifest";
890
+ }
891
+ if (message.includes("receipt_log") || message.includes("receipt v0")) {
892
+ return "invalid-receipt-log";
893
+ }
894
+ if (message.includes("manifest")) {
895
+ return "invalid-manifest";
896
+ }
897
+ if (message.includes("memo_namespace_binding") || message.includes("memo_namespace")) {
898
+ return "memo-namespace-mismatch";
899
+ }
900
+ if (message.includes("safe_state")) {
901
+ return "unsafe-state-mismatch";
902
+ }
903
+ if (message.includes("dependency_receipt_pins")) {
904
+ return "invalid-dependency-pins";
905
+ }
906
+ return "malformed-bundle";
907
+ }
908
+ function coerceFailureCode(code) {
909
+ if (code === undefined) {
910
+ return "malformed-bundle";
911
+ }
912
+ if (code === "malformed-bundle" ||
913
+ code === "unsupported-version" ||
914
+ code === "invalid-contract-revision" ||
915
+ code === "invalid-policy-artifact" ||
916
+ code === "invalid-receipt-log" ||
917
+ code === "invalid-manifest" ||
918
+ code === "memo-namespace-mismatch" ||
919
+ code === "unsafe-state-mismatch" ||
920
+ code === "invalid-dependency-pins") {
921
+ return code;
922
+ }
923
+ return classifyVerificationFailure(code);
924
+ }
925
+ function normalizeFailureInputErrors(input) {
926
+ if (input.errors !== undefined && input.errors.length > 0) {
927
+ return [...input.errors];
928
+ }
929
+ if (input.message !== undefined && input.message.length > 0) {
930
+ return [input.message];
931
+ }
932
+ if (input.code !== undefined && input.code.length > 0) {
933
+ return [input.code];
934
+ }
935
+ return ["exit bundle import failed safe"];
936
+ }
937
+ function expectPlainRecord(value, path) {
938
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
939
+ throw new Error(`${path} must be an object`);
940
+ }
941
+ const prototype = Object.getPrototypeOf(value);
942
+ if (prototype !== Object.prototype && prototype !== null) {
943
+ throw new Error(`${path} must be a plain object`);
944
+ }
945
+ return value;
946
+ }
947
+ function expectExactKeys(value, path, allowedKeys) {
948
+ const allowed = new Set(allowedKeys);
949
+ for (const key of Object.keys(value)) {
950
+ if (!allowed.has(key)) {
951
+ throw new Error(`${path}.${key} is not pinned in exit-bundle v0`);
952
+ }
953
+ }
954
+ }
955
+ function expectLiteral(value, expected, path) {
956
+ if (value !== expected) {
957
+ throw new Error(`${path} must be ${JSON.stringify(expected)}`);
958
+ }
959
+ }
960
+ function expectNonEmptyString(value, path) {
961
+ if (typeof value !== "string" || value.length === 0) {
962
+ throw new Error(`${path} must be a non-empty string`);
963
+ }
964
+ return value;
965
+ }
966
+ function expectEnumString(value, allowed, path) {
967
+ if (typeof value !== "string" || !allowed.has(value)) {
968
+ throw new Error(`${path} must be one of ${Array.from(allowed).join(", ")}`);
969
+ }
970
+ return value;
971
+ }
972
+ function expectContentHashString(value, path) {
973
+ if (typeof value !== "string" || !CONTENT_HASH_PATTERN.test(value)) {
974
+ throw new Error(`${path} must use sha256:<64 lowercase hex>`);
975
+ }
976
+ return value;
977
+ }
978
+ function expectNullableContentHash(value, path) {
979
+ if (value === null) {
980
+ return null;
981
+ }
982
+ return expectContentHashString(value, path);
983
+ }
984
+ function expectContentHashArray(value, path) {
985
+ const items = expectArray(value, path).map((item, index) => expectContentHashString(item, `${path}[${index}]`));
986
+ const sorted = [...items].sort((left, right) => left.localeCompare(right));
987
+ const seen = new Set();
988
+ for (const item of sorted) {
989
+ if (seen.has(item)) {
990
+ throw new Error(`${path} must not contain duplicate content hash ${item}`);
991
+ }
992
+ seen.add(item);
993
+ }
994
+ return items;
995
+ }
996
+ function expectIsoInstantString(value, path) {
997
+ if (typeof value !== "string" || !ISO_INSTANT_PATTERN.test(value)) {
998
+ throw new Error(`${path} must be a replayable ISO instant`);
999
+ }
1000
+ return value;
1001
+ }
1002
+ function expectNullableIsoInstant(value, path) {
1003
+ if (value === null) {
1004
+ return null;
1005
+ }
1006
+ return expectIsoInstantString(value, path);
1007
+ }
1008
+ function expectStringArray(value, path) {
1009
+ const items = expectArray(value, path);
1010
+ for (const [index, item] of items.entries()) {
1011
+ if (typeof item !== "string") {
1012
+ throw new Error(`${path}[${index}] must be a string`);
1013
+ }
1014
+ }
1015
+ return items;
1016
+ }
1017
+ function expectNonEmptyStringArray(value, path) {
1018
+ const items = expectStringArray(value, path);
1019
+ if (items.length === 0) {
1020
+ throw new Error(`${path} must not be empty`);
1021
+ }
1022
+ for (const [index, item] of items.entries()) {
1023
+ if (item.length === 0) {
1024
+ throw new Error(`${path}[${index}] must be non-empty`);
1025
+ }
1026
+ }
1027
+ return items;
1028
+ }
1029
+ function expectArray(value, path) {
1030
+ if (!Array.isArray(value)) {
1031
+ throw new Error(`${path} must be an array`);
1032
+ }
1033
+ return value;
1034
+ }