@kungfu-tech/buildchain 4.0.2-alpha.9 → 4.0.2

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 (157) hide show
  1. package/AGENTS.md +10 -1
  2. package/CONTRIBUTING.md +24 -0
  3. package/README.md +2 -2
  4. package/actions/promote-buildchain-ref/README.md +1 -1
  5. package/actions/v4-release-candidate-promote/README.md +28 -0
  6. package/architecture/agent-change-map.md +64 -7
  7. package/architecture/ci-lane-change-budget.json +366 -0
  8. package/architecture/internal-capabilities.json +53 -8
  9. package/architecture/maintainability-debt.json +147 -93
  10. package/architecture/maintainability-policy.json +32 -28
  11. package/architecture/release-tail-contract-inventory.json +6 -6
  12. package/architecture/v4-architecture-constitution.md +23 -20
  13. package/architecture/v4-cross-platform-adopter-qualification.json +1 -1
  14. package/architecture/v4-delivery-authority-parity.json +2 -2
  15. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +1 -1
  16. package/architecture/v4-floating-consumer-policy.json +2 -2
  17. package/architecture/v4-next-development-parity.json +5 -5
  18. package/architecture/v4-partial-mutation-recovery-qualification.json +4 -1
  19. package/architecture/v4-platform-stage-checkpoints.json +1 -1
  20. package/architecture/v4-provider-operation-journal-contract.json +5 -2
  21. package/architecture/v4-publication-facade-patches.json +64 -0
  22. package/architecture/v4-release-activation-shadow-domain.json +5 -2
  23. package/architecture/v4-release-topology.json +74 -39
  24. package/architecture/v4-rust-wasm-production-authority.json +58 -0
  25. package/architecture/v4-stable-publication-fence.json +5 -2
  26. package/architecture/v4-stage-capsule-qualification.json +2 -2
  27. package/architecture/v4-tail-reseal-parity.json +8 -6
  28. package/architecture/v4-universal-workflow-bootstrap.json +171 -0
  29. package/architecture/v4-universal-workflow-fault-campaign.json +72 -0
  30. package/architecture/v4-universal-workflow-train-admission.json +40 -0
  31. package/architecture/workflow-taxonomy.json +1451 -0
  32. package/bin/buildchain.mjs +7 -7
  33. package/contracts/buildchain-v2-residuals-v1.json +57 -48
  34. package/contracts/dev-delivery-authority-v2.schema.json +16 -2
  35. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
  36. package/contracts/v4-canonical-contracts-v1.schema.json +1 -0
  37. package/dist/site/buildchain-contract.json +93 -48
  38. package/dist/site/buildchain-site.json +222 -69
  39. package/dist/site/capability-registry.json +4 -4
  40. package/dist/site/controller-registry.json +50 -13
  41. package/dist/site/kfd-claims.json +2585 -1000
  42. package/dist/site/kfd-upstream-aggregate.json +1 -1
  43. package/dist/site/manual-registry.json +13 -13
  44. package/dist/site/node-api-registry.json +120 -115
  45. package/dist/site/page-registry.json +204 -51
  46. package/dist/site/public-surface-audit.json +3205 -1219
  47. package/dist/site/publication-authority-registry.json +1124 -362
  48. package/dist/site/publication-registry.json +4 -4
  49. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +16 -2
  50. package/dist/site/site-manifest.json +17 -17
  51. package/dist/site/workflow-registry.json +5061 -1659
  52. package/docs/MAP.md +1 -0
  53. package/docs/auditable-demo.md +1 -1
  54. package/docs/cli.md +21 -8
  55. package/docs/dev-delivery-warrant.md +1 -1
  56. package/docs/engineering-housekeeper.md +3 -3
  57. package/docs/kfd-support.md +26 -2
  58. package/docs/next-development-transition.md +2 -2
  59. package/docs/node-api-reference.md +190 -190
  60. package/docs/publication-authority.md +2 -2
  61. package/docs/release-candidate.md +3 -3
  62. package/docs/release-flow.md +67 -19
  63. package/docs/release-governance.md +8 -8
  64. package/docs/release-passport.md +27 -2
  65. package/docs/reusable-build-surface.md +16 -0
  66. package/docs/v4-adopter-delivery.md +2 -2
  67. package/docs/v4-production-release.md +71 -8
  68. package/docs/v4-rust-wasm-production-authority.md +58 -0
  69. package/docs/v4-stage-capsule.md +2 -2
  70. package/docs/v4-tail-reseal.md +1 -1
  71. package/docs/workflow-catalog.md +154 -0
  72. package/docs/workflow-path-migration.md +109 -0
  73. package/package.json +10 -6
  74. package/packages/core/artifact-verification-envelope.js +5 -5
  75. package/packages/core/buildchain-contract.js +1 -1
  76. package/packages/core/buildchain-kfd-claims.js +2 -2
  77. package/packages/core/buildchain-publication-authority.js +42 -26
  78. package/packages/core/buildchain-v4-domain.wasm +0 -0
  79. package/packages/core/ci-lane-change-budget.js +14 -1
  80. package/packages/core/controller-evidence.js +4 -1
  81. package/packages/core/dev-delivery-candidate-identity.js +40 -6
  82. package/packages/core/dev-delivery-warrant-state.js +3 -4
  83. package/packages/core/dev-delivery-warrant.js +12 -2
  84. package/packages/core/github-governance-authority.js +4 -4
  85. package/packages/core/kfd-adopter-manifest.js +46 -47
  86. package/packages/core/next-development-projection.js +2 -2
  87. package/packages/core/paper-agent-entry.js +30 -4
  88. package/packages/core/paper-fleet.js +1 -1
  89. package/packages/core/paper-runtime-channels.js +348 -0
  90. package/packages/core/paper-scaffold-content.js +10 -0
  91. package/packages/core/paper.js +37 -71
  92. package/packages/core/release-line-dry-run.js +1 -1
  93. package/packages/core/release-passport-contract.js +5 -5
  94. package/packages/core/release-passport.js +5 -4
  95. package/packages/core/release-tail-provider-plane.js +68 -1048
  96. package/packages/core/v4-canonical-contracts.js +10 -75
  97. package/packages/core/v4-domain-wasm-artifact.js +7 -0
  98. package/packages/core/v4-domain-wasm.js +216 -0
  99. package/packages/core/v4-floating-consumer-evidence.js +1 -1
  100. package/packages/core/v4-floating-consumer-policy.js +1 -1
  101. package/packages/core/v4-partial-mutation-recovery-qualification.js +9 -386
  102. package/packages/core/v4-product-publication.js +19 -349
  103. package/packages/core/v4-protected-publication-source.js +19 -21
  104. package/packages/core/v4-provider-operation-journal.js +18 -487
  105. package/packages/core/v4-provider-readback-idempotency.js +12 -97
  106. package/packages/core/v4-release-activation-shadow.js +13 -500
  107. package/packages/core/v4-release-invocation.js +28 -389
  108. package/packages/core/v4-stable-publication-fence.js +13 -342
  109. package/packages/core/v4-universal-workflow-bootstrap.js +586 -0
  110. package/scripts/binary-publication-evidence.mjs +135 -0
  111. package/scripts/build-contract-core.mjs +1 -14
  112. package/scripts/build-v4-domain-wasm.mjs +189 -0
  113. package/scripts/check-action-bundles.mjs +12 -2
  114. package/scripts/check-ci-lane-change-budget.mjs +4 -1
  115. package/scripts/check-core-mechanism-inventory.mjs +4 -3
  116. package/scripts/check-inventory.mjs +35 -44
  117. package/scripts/check-maintainability.mjs +16 -113
  118. package/scripts/check-v4-floating-consumer-policy-contract.mjs +2 -2
  119. package/scripts/check-v4-public-dogfood-contract.mjs +22 -9
  120. package/scripts/check-v4-release-topology.mjs +90 -33
  121. package/scripts/check-v4-runtime-semantic-closure.mjs +4 -1
  122. package/scripts/check-v4-universal-workflow-bootstrap.mjs +266 -0
  123. package/scripts/check-workflow-taxonomy.mjs +6 -0
  124. package/scripts/copy-v4-domain-wasm.mjs +14 -0
  125. package/scripts/dev-delivery-authority-command-adapters.mjs +1 -1
  126. package/scripts/dev-delivery-authority.mjs +8 -8
  127. package/scripts/dev-delivery-source-proof-reuse.mjs +2 -1
  128. package/scripts/dev-delivery-warrant-options.mjs +14 -9
  129. package/scripts/dev-delivery-warrant-store.mjs +73 -7
  130. package/scripts/dev-delivery-warrant-transition.mjs +109 -0
  131. package/scripts/dev-delivery-warrant.mjs +76 -99
  132. package/scripts/dev-pr-auto-merge.mjs +15 -15
  133. package/scripts/generate-channel-build-workflow.mjs +7 -2
  134. package/scripts/generate-channel-promotion-workflow.mjs +7 -5
  135. package/scripts/generate-site-bundle.mjs +11 -11
  136. package/scripts/generate-v4-universal-workflow-facades.mjs +458 -0
  137. package/scripts/generate-workflow-taxonomy.mjs +25 -0
  138. package/scripts/github-output.mjs +31 -0
  139. package/scripts/maintainability-metrics.mjs +16 -5
  140. package/scripts/maintainability-public-surface.mjs +115 -0
  141. package/scripts/next-development-review.mjs +307 -0
  142. package/scripts/paper-work-fleet-cli.mjs +2 -0
  143. package/scripts/release-asset-client.mjs +91 -0
  144. package/scripts/release-candidate-resolver.mjs +9 -9
  145. package/scripts/source-verification-evidence.mjs +344 -0
  146. package/scripts/stable-candidate-qualification.mjs +1 -1
  147. package/scripts/universal-facade-maintainability.mjs +82 -0
  148. package/scripts/v4-product-publication-intent.mjs +13 -6
  149. package/scripts/v4-publication-settlement.mjs +211 -0
  150. package/scripts/v4-universal-workflow-backflow.mjs +212 -0
  151. package/scripts/v4-universal-workflow-engine.mjs +618 -0
  152. package/scripts/v4-universal-workflow-self-dogfood.mjs +205 -0
  153. package/scripts/verify-version-state-delta.mjs +173 -0
  154. package/scripts/workflow-taxonomy.mjs +507 -0
  155. package/templates/native-dev-delivery.yml +4 -7
  156. package/templates/universal-buildchain-bootstrap-recovery.yml +282 -0
  157. package/templates/universal-buildchain-bootstrap.yml +28 -0
@@ -1,9 +1,5 @@
1
- import {
2
- V4ContractFault,
3
- v4CanonicalBytes,
4
- v4ContentRoot,
5
- validateV4Root,
6
- } from "./v4-canonical-contracts.js";
1
+ import { V4ContractFault } from "./v4-canonical-contracts.js";
2
+ import { V4DomainWasmFault, invokeV4DomainWasm } from "./v4-domain-wasm.js";
7
3
 
8
4
  export const V4_RELEASE_INVOCATION_CONTRACT =
9
5
  "kungfu-buildchain-v4-release-invocation/v1";
@@ -16,235 +12,25 @@ export const V4_RELEASE_RECEIPT_CONTRACT =
16
12
  export const V4_RELEASE_PROVIDER_CONTRACT =
17
13
  "kungfu-buildchain-release-tail-provider/v1";
18
14
 
19
- const SHA_PATTERN = /^[0-9a-f]{40}$/u;
20
- const TAG_PATTERN = /^v[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/u;
21
- const ROUTE_SURFACES = new Set([
22
- "alpha",
23
- "stable",
24
- "public",
25
- "private",
26
- "declarative",
27
- "legacy-compatible",
28
- ]);
29
- const EXECUTION_MODES = new Set(["fresh", "resume"]);
30
- const COMPARISON_STATES = new Set(["identical", "ahead", "behind", "diverged"]);
31
-
32
- function fault(code, path, message) {
33
- throw new V4ContractFault(code, path, message);
34
- }
35
-
36
- function exactKeys(value, keys, path) {
37
- if (!value || typeof value !== "object" || Array.isArray(value))
38
- fault("invalid-release-invocation", path, `${path} must be an object`);
39
- const actual = Object.keys(value).sort();
40
- const expected = [...keys].sort();
41
- if (
42
- actual.length !== expected.length ||
43
- actual.some((key, index) => key !== expected[index])
44
- )
45
- fault(
46
- "invalid-release-invocation-shape",
47
- path,
48
- `${path} keys are not canonical`,
49
- );
50
- }
51
-
52
- function sha(value, path, nullable = false) {
53
- if (nullable && value === null) return value;
54
- if (typeof value !== "string" || !SHA_PATTERN.test(value))
55
- fault("invalid-release-sha", path, `${path} must be an exact Git SHA`);
56
- return value;
57
- }
58
-
59
- function text(value, path) {
60
- if (
61
- typeof value !== "string" ||
62
- value.length === 0 ||
63
- /[^\x20-\x7e]/u.test(value)
64
- )
65
- fault("invalid-release-text", path, `${path} must be printable ASCII`);
66
- return value;
67
- }
68
-
69
- function validatePublisher(value) {
70
- exactKeys(
71
- value,
72
- ["repository", "workflow", "workflowSha", "job"],
73
- "$/publisher",
74
- );
75
- if (
76
- value.repository !== "kungfu-systems/buildchain" ||
77
- value.workflow !== ".github/workflows/.release-candidate-promote.yml" ||
78
- value.job !== "apply"
79
- )
80
- fault(
81
- "invalid-publisher-identity",
82
- "$/publisher",
83
- "publisher identity is not the canonical v4 APPLY job",
84
- );
85
- sha(value.workflowSha, "$/publisher/workflowSha");
86
- }
87
-
88
- function validateRuntime(value) {
89
- exactKeys(value, ["repository", "commit", "tree"], "$/runtime");
90
- if (value.repository !== "kungfu-systems/buildchain")
91
- fault(
92
- "invalid-runtime-identity",
93
- "$/runtime/repository",
94
- "runtime repository is not canonical",
95
- );
96
- sha(value.commit, "$/runtime/commit");
97
- sha(value.tree, "$/runtime/tree");
98
- }
99
-
100
- function validateCandidate(value) {
101
- exactKeys(value, ["repository", "commit", "tree", "version"], "$/candidate");
102
- text(value.repository, "$/candidate/repository");
103
- sha(value.commit, "$/candidate/commit");
104
- sha(value.tree, "$/candidate/tree");
105
- text(value.version, "$/candidate/version");
106
- }
107
-
108
- function validateTarget(value) {
109
- exactKeys(value, ["channel", "tag", "expectedOldSha"], "$/target");
110
- if (
111
- !["alpha", "stable"].includes(value.channel) ||
112
- !TAG_PATTERN.test(value.tag)
113
- )
114
- fault(
115
- "invalid-release-target",
116
- "$/target",
117
- "release channel and exact tag are not canonical",
118
- );
119
- sha(value.expectedOldSha, "$/target/expectedOldSha", true);
120
- }
121
-
122
- function validateAuthority(value) {
123
- exactKeys(
124
- value,
125
- ["policyRoot", "qualificationRoot", "warrantRoot"],
126
- "$/authority",
127
- );
128
- for (const name of ["policyRoot", "qualificationRoot", "warrantRoot"])
129
- validateV4Root(value[name], `$/authority/${name}`);
130
- }
131
-
132
- function validateProvider(value, candidate) {
133
- exactKeys(value, ["adapter", "contract", "repository"], "$/provider");
134
- if (
135
- value.adapter !== "built-in-provider-plane" ||
136
- value.contract !== V4_RELEASE_PROVIDER_CONTRACT ||
137
- value.repository !== candidate.repository
138
- )
139
- fault(
140
- "invalid-release-provider",
141
- "$/provider",
142
- "provider identity must bind the built-in Provider Plane and candidate repository",
143
- );
144
- }
145
-
146
- function validateParent(value) {
147
- exactKeys(
148
- value,
149
- ["invocationRoot", "transactionRoot", "receiptRoot"],
150
- "$/parent",
151
- );
152
- const roots = [
153
- value.invocationRoot,
154
- value.transactionRoot,
155
- value.receiptRoot,
156
- ];
157
- if (roots.every((root) => root === null)) return;
158
- if (roots.some((root) => root === null))
159
- fault(
160
- "invalid-release-parent-lineage",
161
- "$/parent",
162
- "parent lineage roots must be either all null or all present",
163
- );
164
- roots.forEach((root, index) =>
165
- validateV4Root(
166
- root,
167
- `$/parent/${["invocationRoot", "transactionRoot", "receiptRoot"][index]}`,
168
- ),
169
- );
15
+ function invoke(operation, payload) {
16
+ try {
17
+ return invokeV4DomainWasm(operation, payload);
18
+ } catch (error) {
19
+ if (error instanceof V4DomainWasmFault) {
20
+ throw new V4ContractFault(error.code, error.path, error.message);
21
+ }
22
+ throw error;
23
+ }
170
24
  }
171
25
 
172
26
  export function createV4ReleaseInvocation(value) {
173
- exactKeys(
174
- value,
175
- [
176
- "schema",
177
- "publisher",
178
- "runtime",
179
- "candidate",
180
- "target",
181
- "authority",
182
- "provider",
183
- "parent",
184
- ],
185
- "$",
186
- );
187
- if (value.schema !== V4_RELEASE_INVOCATION_CONTRACT)
188
- fault(
189
- "invalid-release-invocation",
190
- "$/schema",
191
- "unsupported invocation schema",
192
- );
193
- validatePublisher(value.publisher);
194
- validateRuntime(value.runtime);
195
- validateCandidate(value.candidate);
196
- validateTarget(value.target);
197
- validateAuthority(value.authority);
198
- validateProvider(value.provider, value.candidate);
199
- validateParent(value.parent);
200
- v4CanonicalBytes(value);
201
- const roots = {
202
- publisherRoot: v4ContentRoot(
203
- "release-invocation-publisher",
204
- value.publisher,
205
- ),
206
- runtimeRoot: v4ContentRoot("release-invocation-runtime", value.runtime),
207
- candidateRoot: v4ContentRoot(
208
- "release-invocation-candidate",
209
- value.candidate,
210
- ),
211
- targetRoot: v4ContentRoot("release-invocation-target", value.target),
212
- authorityRoot: v4ContentRoot(
213
- "release-invocation-authority",
214
- value.authority,
215
- ),
216
- providerRoot: v4ContentRoot("release-invocation-provider", value.provider),
217
- parentRoot: v4ContentRoot("release-invocation-parent", value.parent),
218
- };
219
- const invocationRoot = v4ContentRoot("release-invocation", {
220
- schema: V4_RELEASE_INVOCATION_CONTRACT,
221
- ...roots,
222
- });
223
- return { invocation: value, roots: { ...roots, invocationRoot } };
27
+ const projected = invoke("release-invocation", value);
28
+ return { ...projected, invocation: value };
224
29
  }
225
30
 
226
31
  export function adaptV4ReleaseInvocation(value) {
227
- exactKeys(value, ["schema", "route", "invocation"], "$adapter");
228
- if (value.schema !== V4_RELEASE_INVOCATION_ADAPTER_CONTRACT)
229
- fault(
230
- "invalid-release-adapter",
231
- "$adapter/schema",
232
- "unsupported adapter schema",
233
- );
234
- exactKeys(value.route, ["surface", "execution"], "$adapter/route");
235
- if (!ROUTE_SURFACES.has(value.route.surface))
236
- fault(
237
- "invalid-release-adapter",
238
- "$adapter/route/surface",
239
- "unsupported route surface",
240
- );
241
- if (!EXECUTION_MODES.has(value.route.execution))
242
- fault(
243
- "invalid-release-adapter",
244
- "$adapter/route/execution",
245
- "unsupported execution mode",
246
- );
247
- return createV4ReleaseInvocation(value.invocation);
32
+ const projected = invoke("release-invocation-adapter", value);
33
+ return { ...projected, invocation: value.invocation };
248
34
  }
249
35
 
250
36
  export function planV4ReleaseRoute({
@@ -256,170 +42,23 @@ export function planV4ReleaseRoute({
256
42
  dryRun = false,
257
43
  resume = false,
258
44
  }) {
259
- sha(requestedSha, "$route/requestedSha");
260
- sha(observedSha, "$route/observedSha");
261
- if (!COMPARISON_STATES.has(comparisonStatus))
262
- fault(
263
- "invalid-release-route",
264
- "$route/comparisonStatus",
265
- "unsupported source comparison state",
266
- );
267
- text(targetRef, "$route/targetRef");
268
- const alphaLane = /^alpha\/v[0-9]+\/v[0-9]+\.[0-9]+$/u.test(targetRef);
269
- const stableLane =
270
- /^release\/v[0-9]+\/v[0-9]+\.[0-9]+$/u.test(targetRef) ||
271
- ["publish-gate/major", "major-gate"].includes(targetRef);
272
- if (!alphaLane && !stableLane)
273
- fault(
274
- "invalid-release-route",
275
- "$route/targetRef",
276
- "source lane is not a supported v4 release lane",
277
- );
278
- const derivedChannel = alphaLane ? "alpha" : "stable";
279
- const normalizedRequested =
280
- requestedChannel === "alpha"
281
- ? "alpha"
282
- : ["release", "stable", "major"].includes(requestedChannel)
283
- ? "stable"
284
- : requestedChannel === ""
285
- ? derivedChannel
286
- : "";
287
- if (!normalizedRequested || normalizedRequested !== derivedChannel)
288
- fault(
289
- "invalid-release-route",
290
- "$route/channel",
291
- "requested channel does not match the source lane",
292
- );
293
- let decision = resume ? "Resume" : "Fresh";
294
- let reason = resume ? "resume" : "fresh";
295
- if (comparisonStatus === "ahead" && !resume && !dryRun) {
296
- decision = "NoOp";
297
- reason = "source-advanced";
298
- } else if (
299
- requestedSha !== observedSha &&
300
- !(resume && comparisonStatus === "ahead") &&
301
- !(dryRun && comparisonStatus === "ahead")
302
- ) {
303
- decision = "Blocked";
304
- reason = `source-${comparisonStatus}`;
305
- }
306
- return Object.freeze({
307
- decision,
308
- reason,
309
- channel: normalizedRequested,
310
- targetRef,
311
- requestedSha,
312
- observedSha,
313
- });
45
+ return Object.freeze(
46
+ invoke("release-route", {
47
+ requestedSha,
48
+ observedSha,
49
+ comparisonStatus,
50
+ requestedChannel,
51
+ targetRef,
52
+ dryRun,
53
+ resume,
54
+ }),
55
+ );
314
56
  }
315
57
 
316
58
  export function createV4ReleaseTransaction(value) {
317
- exactKeys(
318
- value,
319
- [
320
- "invocationRoot",
321
- "publisherRoot",
322
- "runtimeRoot",
323
- "providerRoot",
324
- "parentRoot",
325
- ],
326
- "$transaction",
327
- );
328
- for (const name of [
329
- "invocationRoot",
330
- "publisherRoot",
331
- "runtimeRoot",
332
- "providerRoot",
333
- "parentRoot",
334
- ])
335
- validateV4Root(value[name], `$transaction/${name}`);
336
- const transaction = {
337
- schema: V4_RELEASE_TRANSACTION_CONTRACT,
338
- invocationRoot: value.invocationRoot,
339
- publisherRoot: value.publisherRoot,
340
- runtimeRoot: value.runtimeRoot,
341
- providerRoot: value.providerRoot,
342
- parentRoot: value.parentRoot,
343
- phases: ["QUALIFY", "APPLY", "SETTLE"],
344
- writer: "canonical-v4-apply",
345
- };
346
- return {
347
- transaction,
348
- transactionRoot: v4ContentRoot("release-transaction", transaction),
349
- };
59
+ return invoke("release-transaction", value);
350
60
  }
351
61
 
352
62
  export function createV4ReleaseReceipt(value) {
353
- exactKeys(
354
- value,
355
- [
356
- "schema",
357
- "transactionRoot",
358
- "outcome",
359
- "releasePassportRoot",
360
- "providerTransactionRoot",
361
- "providerStateRoot",
362
- "providerReceiptRoots",
363
- ],
364
- "$receipt",
365
- );
366
- if (value.schema !== V4_RELEASE_RECEIPT_CONTRACT)
367
- fault(
368
- "invalid-release-receipt",
369
- "$receipt/schema",
370
- "unsupported receipt schema",
371
- );
372
- validateV4Root(value.transactionRoot, "$receipt/transactionRoot");
373
- if (!["complete", "blocked"].includes(value.outcome))
374
- fault(
375
- "invalid-release-receipt",
376
- "$receipt/outcome",
377
- "unsupported receipt outcome",
378
- );
379
- for (const name of [
380
- "releasePassportRoot",
381
- "providerTransactionRoot",
382
- "providerStateRoot",
383
- ]) {
384
- if (value[name] !== null) validateV4Root(value[name], `$receipt/${name}`);
385
- }
386
- if (!Array.isArray(value.providerReceiptRoots))
387
- fault(
388
- "invalid-release-receipt",
389
- "$receipt/providerReceiptRoots",
390
- "receipt roots must be an array",
391
- );
392
- value.providerReceiptRoots.forEach((root, index) =>
393
- validateV4Root(root, `$receipt/providerReceiptRoots/${index}`),
394
- );
395
- const canonicalRoots = [...new Set(value.providerReceiptRoots)].sort();
396
- if (
397
- canonicalRoots.length !== value.providerReceiptRoots.length ||
398
- canonicalRoots.some(
399
- (root, index) => root !== value.providerReceiptRoots[index],
400
- )
401
- )
402
- fault(
403
- "invalid-release-receipt",
404
- "$receipt/providerReceiptRoots",
405
- "provider receipt roots must be sorted and unique",
406
- );
407
- if (
408
- value.outcome === "complete" &&
409
- [
410
- value.releasePassportRoot,
411
- value.providerTransactionRoot,
412
- value.providerStateRoot,
413
- ].some((root) => root === null)
414
- )
415
- fault(
416
- "invalid-release-receipt",
417
- "$receipt/outcome",
418
- "complete receipt requires every terminal root",
419
- );
420
- v4CanonicalBytes(value);
421
- return {
422
- receipt: value,
423
- receiptRoot: v4ContentRoot("release-receipt", value),
424
- };
63
+ return invoke("release-receipt", value);
425
64
  }