@kungfu-tech/buildchain 4.0.1-alpha.0 → 4.0.1-alpha.3

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 (121) hide show
  1. package/AGENTS.md +13 -5
  2. package/actions/promote-buildchain-ref/README.md +11 -6
  3. package/architecture/decisions/0003-two-phase-delivery-warrant.md +152 -0
  4. package/architecture/internal-capabilities.json +105 -2
  5. package/architecture/maintainability-policy.json +218 -19
  6. package/architecture/v3-core-mechanism-inventory.json +2 -0
  7. package/architecture/v4-delivery-authority-parity.json +250 -0
  8. package/architecture/v4-delivery-warrant-shadow-fixtures.json +29 -6
  9. package/architecture/v4-floating-consumer-policy.json +75 -0
  10. package/architecture/v4-floating-consumer-policy.md +32 -0
  11. package/architecture/v4-runtime-ref-resume-authority.json +64 -0
  12. package/architecture/v4-stage-capsule-qualification.json +2 -2
  13. package/bin/buildchain.mjs +9 -1
  14. package/bin/internal/trust-release-release-handlers.mjs +5 -0
  15. package/contracts/dev-delivery-authority-v2.schema.json +662 -0
  16. package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +53 -0
  17. package/contracts/fixtures/v4-runtime-ref-resume-authority-v1/scenario.json +15 -0
  18. package/contracts/v4-floating-consumer-policy-receipt-v1.schema.json +105 -0
  19. package/contracts/v4-runtime-ref-resume-authority-v1.schema.json +235 -0
  20. package/dist/site/agent-index.json +1 -0
  21. package/dist/site/artifact-schemas.json +2 -0
  22. package/dist/site/buildchain-contract.json +186 -33
  23. package/dist/site/buildchain-site.json +229 -32
  24. package/dist/site/capability-registry.json +3 -3
  25. package/dist/site/cli-registry.json +46 -2
  26. package/dist/site/controller-registry.json +62 -6
  27. package/dist/site/kfd-claims.json +105 -16
  28. package/dist/site/kfd-upstream-aggregate.json +1 -1
  29. package/dist/site/manual-registry.json +7 -7
  30. package/dist/site/node-api-registry.json +7491 -5290
  31. package/dist/site/page-registry.json +218 -21
  32. package/dist/site/public-surface-audit.json +412 -20
  33. package/dist/site/publication-registry.json +4 -4
  34. package/dist/site/release-provenance.json +4 -0
  35. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +662 -0
  36. package/dist/site/site-manifest.json +11 -11
  37. package/dist/site/workflow-registry.json +63 -19
  38. package/docs/MAP.md +3 -0
  39. package/docs/cli-reference.md +211 -13
  40. package/docs/dev-delivery-qualification-landing-adr.md +251 -0
  41. package/docs/dev-delivery-warrant.md +336 -30
  42. package/docs/lifecycle-protocol.md +41 -0
  43. package/docs/node-api-reference.md +319 -186
  44. package/docs/reusable-build-surface.md +41 -0
  45. package/docs/runtime-train-validation.md +10 -0
  46. package/docs/v4-runtime-ref-resume-authority.md +69 -0
  47. package/docs/versioning.md +1 -0
  48. package/package.json +10 -4
  49. package/packages/core/artifact-signing.js +61 -0
  50. package/packages/core/buildchain-config.js +66 -1
  51. package/packages/core/buildchain-contract.js +3 -2
  52. package/packages/core/dev-delivery-authority-candidate.js +270 -0
  53. package/packages/core/dev-delivery-authority-evidence.js +146 -0
  54. package/packages/core/dev-delivery-authority-landing.js +461 -0
  55. package/packages/core/dev-delivery-authority-observation.js +48 -0
  56. package/packages/core/dev-delivery-authority-qualification.js +591 -0
  57. package/packages/core/dev-delivery-authority-settlement.js +213 -0
  58. package/packages/core/dev-delivery-authority-state.js +583 -0
  59. package/packages/core/dev-delivery-candidate-identity.js +13 -0
  60. package/packages/core/dev-delivery-contract-surface.js +76 -0
  61. package/packages/core/dev-delivery-execution-failure.js +133 -0
  62. package/packages/core/dev-delivery-execution-transfer.js +572 -0
  63. package/packages/core/dev-delivery-landing-admission-core.js +119 -0
  64. package/packages/core/dev-delivery-landing-readback.js +598 -0
  65. package/packages/core/dev-delivery-landing-terminal-evidence.js +271 -0
  66. package/packages/core/dev-delivery-landing-testing-port.js +6 -0
  67. package/packages/core/dev-delivery-native-execution.js +110 -0
  68. package/packages/core/dev-delivery-native-proof.js +546 -0
  69. package/packages/core/dev-delivery-process-boundary.js +551 -0
  70. package/packages/core/dev-delivery-proof.js +37 -3
  71. package/packages/core/dev-delivery-provider-attempt.js +127 -0
  72. package/packages/core/dev-delivery-provider-heartbeat.js +370 -0
  73. package/packages/core/dev-delivery-warrant-cancellation.js +1 -0
  74. package/packages/core/dev-delivery-warrant-qualification.js +145 -0
  75. package/packages/core/dev-delivery-warrant-settlement.js +237 -36
  76. package/packages/core/dev-delivery-warrant-state.js +565 -0
  77. package/packages/core/dev-delivery-warrant.js +320 -368
  78. package/packages/core/index.js +2 -0
  79. package/packages/core/publication-authority.js +5 -5
  80. package/packages/core/release-candidate.js +79 -19
  81. package/packages/core/release-passport.js +239 -33
  82. package/packages/core/v4-floating-consumer-evidence.js +324 -0
  83. package/packages/core/v4-floating-consumer-policy.js +446 -0
  84. package/packages/core/v4-floating-consumer-release-passport.js +126 -0
  85. package/packages/core/v4-runtime-ref-resume-authority.js +625 -0
  86. package/packages/core/v4-runtime-selector-persistence.js +228 -0
  87. package/packages/core/workflow-yaml-contract.js +48 -0
  88. package/scripts/audit-publication-control-plane.mjs +31 -31
  89. package/scripts/buildchain-cli-help.mjs +11 -2
  90. package/scripts/check-inventory.mjs +1 -1
  91. package/scripts/check-v4-floating-consumer-policy-contract.mjs +198 -0
  92. package/scripts/check-v4-public-dogfood-contract.mjs +6 -11
  93. package/scripts/dev-delivery-authority-command-adapters.mjs +206 -0
  94. package/scripts/dev-delivery-authority-provider.mjs +28 -0
  95. package/scripts/dev-delivery-authority.mjs +490 -0
  96. package/scripts/dev-delivery-native-run.mjs +177 -0
  97. package/scripts/dev-delivery-process-boundary.mjs +260 -0
  98. package/scripts/dev-delivery-proof.mjs +67 -2
  99. package/scripts/dev-delivery-provider-heartbeat.mjs +215 -0
  100. package/scripts/dev-delivery-source-proof-reuse.mjs +631 -0
  101. package/scripts/dev-delivery-two-phase-resume.mjs +345 -0
  102. package/scripts/dev-delivery-two-phase.mjs +573 -0
  103. package/scripts/dev-delivery-warrant-options.mjs +266 -0
  104. package/scripts/dev-delivery-warrant-store.mjs +227 -0
  105. package/scripts/dev-delivery-warrant.mjs +227 -193
  106. package/scripts/dev-pr-auto-merge.mjs +37 -48
  107. package/scripts/dev-pr-delivery-warrant.mjs +215 -2
  108. package/scripts/dev-pr-prequeue-guard.mjs +399 -0
  109. package/scripts/ensure-github-release.mjs +3 -3
  110. package/scripts/generate-channel-build-workflow.mjs +3 -0
  111. package/scripts/generate-channel-promotion-workflow.mjs +112 -12
  112. package/scripts/generate-release-candidate-passport.mjs +41 -33
  113. package/scripts/generate-site-bundle.mjs +26 -4
  114. package/scripts/init-repo.mjs +5 -1
  115. package/scripts/inspect-artifact-signing-requests.mjs +6 -0
  116. package/scripts/npm-publish-transaction.mjs +103 -91
  117. package/scripts/resume-from-candidate-run.mjs +11 -14
  118. package/scripts/seal-artifact-signing-requests.mjs +6 -0
  119. package/scripts/site-capability-metadata.mjs +14 -0
  120. package/scripts/v4-consumer-policy.mjs +231 -0
  121. package/templates/native-dev-delivery.yml +141 -0
@@ -0,0 +1,270 @@
1
+ import {
2
+ devDeliveryExactRoot as exactRoot,
3
+ devDeliveryExactSha as exactSha,
4
+ devDeliveryText as text,
5
+ devDeliveryTimestamp as timestamp,
6
+ } from "./dev-delivery-common.js";
7
+ import { createDevDeliveryCandidateIdentity } from "./dev-delivery-candidate-identity.js";
8
+ import { normalizeNativeCommandContract } from "./dev-delivery-native-proof.js";
9
+ import { normalizeDevDeliveryTerminalProviderEvidence } from "./dev-delivery-provider-attempt.js";
10
+ import { normalizeProviderFailureAuthorityBinding } from "./dev-delivery-warrant-settlement.js";
11
+
12
+ export const TERMINAL_STATES = new Set([
13
+ "merged",
14
+ "terminal-failure",
15
+ "dequeued",
16
+ "cancelled",
17
+ ]);
18
+ const DELIVERY_CLASSES = new Set([
19
+ "non-native-fast",
20
+ "native-proof-required",
21
+ "cross-platform",
22
+ "release",
23
+ ]);
24
+ export const DEV_DELIVERY_COMPATIBILITY_QUALIFICATION_SCHEMA =
25
+ "kungfu.buildchain.dev-delivery-compatibility-qualification/v1";
26
+ export const DEV_DELIVERY_NATIVE_QUALIFICATION_SCHEMA =
27
+ "kungfu.buildchain.dev-delivery-native-qualification/v1";
28
+
29
+ function nonNegativeInteger(value, label, fallback = 0) {
30
+ const parsed = Number(value ?? fallback);
31
+ if (!Number.isInteger(parsed) || parsed < 0) {
32
+ throw new Error(`${label} must be a non-negative integer`);
33
+ }
34
+ return parsed;
35
+ }
36
+
37
+ function normalizedDomains(input = []) {
38
+ if (!Array.isArray(input))
39
+ throw new Error(
40
+ "qualificationDomains must be an array of rooted safety domains",
41
+ );
42
+ return [
43
+ ...new Set(input.map((value) => exactRoot(value, "qualification domain"))),
44
+ ].sort();
45
+ }
46
+
47
+ function candidateIdentity(input, expected) {
48
+ return createDevDeliveryCandidateIdentity(input, expected, (value) => {
49
+ const normalized = text(value);
50
+ if (!DELIVERY_CLASSES.has(normalized))
51
+ throw new Error(`unsupported deliveryClass ${normalized}`);
52
+ return normalized;
53
+ });
54
+ }
55
+
56
+ function nullableRoot(value, label) {
57
+ return value === null ? null : exactRoot(value, label);
58
+ }
59
+
60
+ function normalizeQualification(input) {
61
+ if (!input) return null;
62
+ if (input.schema === DEV_DELIVERY_COMPATIBILITY_QUALIFICATION_SCHEMA) {
63
+ if (input.authority !== "legacy-compatibility-only")
64
+ throw new Error(
65
+ "compatibility qualification cannot claim native authority",
66
+ );
67
+ if (input.nativeProofAuthority !== false)
68
+ throw new Error(
69
+ "compatibility qualification must deny native proof authority",
70
+ );
71
+ if (!["phase-less", "qualified"].includes(input.legacyWarrantPhase))
72
+ throw new Error(
73
+ "compatibility qualification legacy phase is unsupported",
74
+ );
75
+ return {
76
+ schema: input.schema,
77
+ authority: input.authority,
78
+ nativeProofAuthority: false,
79
+ legacyStateRoot: exactRoot(
80
+ input.legacyStateRoot,
81
+ "compatibility qualification legacyStateRoot",
82
+ ),
83
+ legacyWarrantPhase: input.legacyWarrantPhase,
84
+ legacyFencingToken: exactRoot(
85
+ input.legacyFencingToken,
86
+ "compatibility qualification legacyFencingToken",
87
+ ),
88
+ legacyGeneration: nonNegativeInteger(
89
+ input.legacyGeneration,
90
+ "compatibility qualification legacyGeneration",
91
+ ),
92
+ qualificationReceiptRoot: nullableRoot(
93
+ input.qualificationReceiptRoot,
94
+ "compatibility qualification receiptRoot",
95
+ ),
96
+ sourceProofRoot: exactRoot(
97
+ input.sourceProofRoot,
98
+ "compatibility qualification sourceProofRoot",
99
+ ),
100
+ nativeProofRoot: nullableRoot(
101
+ input.nativeProofRoot,
102
+ "compatibility qualification nativeProofRoot",
103
+ ),
104
+ nativeExecutionBindingRoot: nullableRoot(
105
+ input.nativeExecutionBindingRoot,
106
+ "compatibility qualification nativeExecutionBindingRoot",
107
+ ),
108
+ nativeExecutionReceiptRoot: nullableRoot(
109
+ input.nativeExecutionReceiptRoot,
110
+ "compatibility qualification nativeExecutionReceiptRoot",
111
+ ),
112
+ nativeCommandRoot: nullableRoot(
113
+ input.nativeCommandRoot,
114
+ "compatibility qualification nativeCommandRoot",
115
+ ),
116
+ qualificationContractRoot: nullableRoot(
117
+ input.qualificationContractRoot,
118
+ "compatibility qualification contractRoot",
119
+ ),
120
+ qualifiedAt:
121
+ input.qualifiedAt === null
122
+ ? null
123
+ : timestamp(
124
+ input.qualifiedAt,
125
+ "compatibility qualification qualifiedAt",
126
+ ),
127
+ };
128
+ }
129
+ if (input.schema !== DEV_DELIVERY_NATIVE_QUALIFICATION_SCHEMA)
130
+ throw new Error("native qualification schema is unsupported");
131
+ if (
132
+ input.authority !== "verified-native-qualification" ||
133
+ input.nativeProofAuthority !== true
134
+ )
135
+ throw new Error("native qualification must carry verified proof authority");
136
+ return {
137
+ schema: input.schema,
138
+ authority: input.authority,
139
+ nativeProofAuthority: true,
140
+ ...(input.evidenceRoot
141
+ ? {
142
+ evidenceRoot: exactRoot(
143
+ input.evidenceRoot,
144
+ "qualification evidenceRoot",
145
+ ),
146
+ }
147
+ : {}),
148
+ qualificationReceiptRoot: exactRoot(
149
+ input.qualificationReceiptRoot,
150
+ "qualification receiptRoot",
151
+ ),
152
+ sourceProofRoot: exactRoot(
153
+ input.sourceProofRoot,
154
+ "qualification sourceProofRoot",
155
+ ),
156
+ nativeProofRoot: exactRoot(
157
+ input.nativeProofRoot,
158
+ "qualification nativeProofRoot",
159
+ ),
160
+ nativeExecutionBindingRoot: exactRoot(
161
+ input.nativeExecutionBindingRoot,
162
+ "qualification nativeExecutionBindingRoot",
163
+ ),
164
+ nativeExecutionReceiptRoot: exactRoot(
165
+ input.nativeExecutionReceiptRoot,
166
+ "qualification nativeExecutionReceiptRoot",
167
+ ),
168
+ nativeCommandRoot: exactRoot(
169
+ input.nativeCommandRoot,
170
+ "qualification nativeCommandRoot",
171
+ ),
172
+ qualificationContractRoot: exactRoot(
173
+ input.qualificationContractRoot,
174
+ "qualification contractRoot",
175
+ ),
176
+ qualifiedAt: timestamp(input.qualifiedAt, "qualification qualifiedAt"),
177
+ };
178
+ }
179
+
180
+ export function normalizeDevDeliveryAuthorityCandidate(input, expected) {
181
+ const identity = candidateIdentity(input, expected);
182
+ if (input.candidateId && input.candidateId !== identity.candidateId)
183
+ throw new Error(
184
+ `candidateId mismatch for PR #${identity.pullRequestNumber}`,
185
+ );
186
+ const status = text(input.status || "queued");
187
+ if (
188
+ ![
189
+ "queued",
190
+ "qualifying",
191
+ "qualified",
192
+ "landing",
193
+ ...TERMINAL_STATES,
194
+ ].includes(status)
195
+ )
196
+ throw new Error(`unsupported candidate status ${status || "<empty>"}`);
197
+ const candidate = {
198
+ ...identity,
199
+ sourceHead: exactSha(input.sourceHead, "sourceHead"),
200
+ sourcePatchRoot: exactRoot(input.sourcePatchRoot, "sourcePatchRoot"),
201
+ sourceProofRoot: exactRoot(input.sourceProofRoot, "sourceProofRoot"),
202
+ planRoot: exactRoot(input.planRoot, "planRoot"),
203
+ closureRoot: exactRoot(input.closureRoot, "closureRoot"),
204
+ dependencyRoot: exactRoot(input.dependencyRoot, "dependencyRoot"),
205
+ toolchainRoot: exactRoot(input.toolchainRoot, "toolchainRoot"),
206
+ enqueuedAt: timestamp(input.enqueuedAt, "candidate enqueuedAt"),
207
+ updatedAt: timestamp(
208
+ input.updatedAt || input.enqueuedAt,
209
+ "candidate updatedAt",
210
+ ),
211
+ status,
212
+ qualification: normalizeQualification(input.qualification),
213
+ terminal: input.terminal
214
+ ? {
215
+ outcome: text(input.terminal.outcome),
216
+ evidenceRoot: exactRoot(
217
+ input.terminal.evidenceRoot,
218
+ "terminal evidenceRoot",
219
+ ),
220
+ reason: text(input.terminal.reason),
221
+ settledAt: timestamp(input.terminal.settledAt, "terminal settledAt"),
222
+ ...(normalizeProviderFailureAuthorityBinding(input.terminal) || {}),
223
+ ...normalizeDevDeliveryTerminalProviderEvidence(input.terminal),
224
+ }
225
+ : null,
226
+ };
227
+ if (Object.hasOwn(input, "environmentRoot"))
228
+ candidate.environmentRoot = exactRoot(
229
+ input.environmentRoot,
230
+ "environmentRoot",
231
+ );
232
+ if (Object.hasOwn(input, "nativeCommandContract")) {
233
+ candidate.nativeCommandContract = normalizeNativeCommandContract(
234
+ input.nativeCommandContract,
235
+ );
236
+ }
237
+ if (Object.hasOwn(input, "affectedPaths")) {
238
+ if (!Array.isArray(input.affectedPaths))
239
+ throw new Error("candidate affectedPaths must be an array");
240
+ candidate.affectedPaths = [
241
+ ...new Set(input.affectedPaths.map(text).filter(Boolean)),
242
+ ].sort();
243
+ }
244
+ if (Object.hasOwn(input, "shardEvidenceRoots")) {
245
+ if (!Array.isArray(input.shardEvidenceRoots))
246
+ throw new Error("candidate shardEvidenceRoots must be an array");
247
+ candidate.shardEvidenceRoots = [
248
+ ...new Set(
249
+ input.shardEvidenceRoots.map((value) =>
250
+ exactRoot(value, "candidate shardEvidenceRoot"),
251
+ ),
252
+ ),
253
+ ].sort();
254
+ }
255
+ if (Object.hasOwn(input, "qualificationDomains"))
256
+ candidate.qualificationDomains = normalizedDomains(
257
+ input.qualificationDomains,
258
+ );
259
+ if (Object.hasOwn(input, "qualificationAttempts"))
260
+ candidate.qualificationAttempts = nonNegativeInteger(
261
+ input.qualificationAttempts,
262
+ "candidate qualificationAttempts",
263
+ );
264
+ if (Object.hasOwn(input, "landingOvertakes"))
265
+ candidate.landingOvertakes = nonNegativeInteger(
266
+ input.landingOvertakes,
267
+ "candidate landingOvertakes",
268
+ );
269
+ return candidate;
270
+ }
@@ -0,0 +1,146 @@
1
+ import {
2
+ devDeliveryClone as clone,
3
+ devDeliveryContentRoot,
4
+ } from "./dev-delivery-common.js";
5
+ import { verifySourceQualificationProof } from "./dev-delivery-proof.js";
6
+ import { verifyNativeQualificationProof } from "./dev-delivery-native-proof.js";
7
+
8
+ export const DEV_DELIVERY_BOUNDED_QUALIFICATION_CONTRACT_SCHEMA =
9
+ "kungfu.buildchain.dev-delivery-bounded-qualification-contract/v1";
10
+ export const DEV_DELIVERY_BOUNDED_QUALIFICATION_RECEIPT_SCHEMA =
11
+ "kungfu.buildchain.dev-delivery-bounded-qualification-receipt/v1";
12
+
13
+ function contractBody({ state, candidate, lease, sourceProof, nativeProof }) {
14
+ return {
15
+ schema: DEV_DELIVERY_BOUNDED_QUALIFICATION_CONTRACT_SCHEMA,
16
+ authority: "qualification-only",
17
+ mergeGroupAdmission: false,
18
+ repository: state.repository,
19
+ protectedBase: state.protectedBase,
20
+ candidateId: candidate.candidateId,
21
+ qualificationLeaseToken: lease.token,
22
+ qualificationLeaseGeneration: lease.generation,
23
+ sourceHead: candidate.sourceHead,
24
+ sourceProofRoot: sourceProof.proofRoot,
25
+ nativeProofRoot: nativeProof.proofRoot,
26
+ nativeExecutionBindingRoot: nativeProof.nativeExecutionBindingRoot,
27
+ nativeExecutionReceiptRoot: nativeProof.nativeExecutionReceiptRoot,
28
+ nativeCommandRoot: candidate.nativeCommandContract.commandRoot,
29
+ planRoot: candidate.planRoot,
30
+ closureRoot: candidate.closureRoot,
31
+ dependencyRoot: candidate.dependencyRoot,
32
+ toolchainRoot: candidate.toolchainRoot,
33
+ environmentRoot: candidate.environmentRoot,
34
+ qualificationDomains: candidate.qualificationDomains || [],
35
+ shardEvidenceRoots: candidate.shardEvidenceRoots || [],
36
+ };
37
+ }
38
+
39
+ export function createDevDeliveryQualificationContract(input = {}) {
40
+ const body = contractBody(input);
41
+ return { ...body, contractRoot: devDeliveryContentRoot(body) };
42
+ }
43
+
44
+ export function verifyDevDeliveryQualificationEvidence({
45
+ state,
46
+ candidate,
47
+ lease,
48
+ sourceProof,
49
+ nativeProof,
50
+ qualificationContract,
51
+ }) {
52
+ const source = verifySourceQualificationProof(sourceProof, {
53
+ repository: state.repository,
54
+ protectedBase: state.protectedBase,
55
+ sourceHead: candidate.sourceHead,
56
+ sourceIdentityRoot: candidate.sourceIdentityRoot,
57
+ sourcePatchRoot: candidate.sourcePatchRoot,
58
+ planRoot: candidate.planRoot,
59
+ closureRoot: candidate.closureRoot,
60
+ dependencyRoot: candidate.dependencyRoot,
61
+ toolchainRoot: candidate.toolchainRoot,
62
+ });
63
+ if (!source.ok) {
64
+ throw new Error(`source qualification proof rejected: ${source.reason}`);
65
+ }
66
+ if (source.proofRoot !== candidate.sourceProofRoot) {
67
+ throw new Error("source qualification proof root does not match candidate");
68
+ }
69
+ const native = verifyNativeQualificationProof(nativeProof, {
70
+ repository: state.repository,
71
+ protectedBase: state.protectedBase,
72
+ sourceHead: candidate.sourceHead,
73
+ sourceIdentityRoot: candidate.sourceIdentityRoot,
74
+ sourcePatchRoot: candidate.sourcePatchRoot,
75
+ planRoot: candidate.planRoot,
76
+ closureRoot: candidate.closureRoot,
77
+ dependencyRoot: candidate.dependencyRoot,
78
+ toolchainRoot: candidate.toolchainRoot,
79
+ environmentRoot: candidate.environmentRoot,
80
+ nativeCommandRoot: candidate.nativeCommandContract?.commandRoot,
81
+ });
82
+ if (!native.ok) {
83
+ throw new Error(`native qualification proof rejected: ${native.reason}`);
84
+ }
85
+ const expectedShards = [
86
+ ...(candidate.shardEvidenceRoots || []),
87
+ nativeProof.nativeExecutionReceiptRoot,
88
+ ].sort();
89
+ if (
90
+ JSON.stringify(nativeProof.shardEvidenceRoots) !==
91
+ JSON.stringify([...new Set(expectedShards)])
92
+ ) {
93
+ throw new Error(
94
+ "native qualification shard evidence does not match candidate",
95
+ );
96
+ }
97
+ const expected = createDevDeliveryQualificationContract({
98
+ state,
99
+ candidate,
100
+ lease,
101
+ sourceProof,
102
+ nativeProof,
103
+ });
104
+ const observed = clone(qualificationContract || {});
105
+ if (
106
+ JSON.stringify(observed) !== JSON.stringify(expected) ||
107
+ observed.contractRoot !== expected.contractRoot
108
+ ) {
109
+ throw new Error(
110
+ "bounded qualification contract does not match exact evidence",
111
+ );
112
+ }
113
+ return {
114
+ sourceProofRoot: source.proofRoot,
115
+ nativeProofRoot: native.proofRoot,
116
+ nativeExecutionBindingRoot: nativeProof.nativeExecutionBindingRoot,
117
+ nativeExecutionReceiptRoot: nativeProof.nativeExecutionReceiptRoot,
118
+ nativeCommandRoot: candidate.nativeCommandContract.commandRoot,
119
+ qualificationContractRoot: expected.contractRoot,
120
+ };
121
+ }
122
+
123
+ export function createDevDeliveryBoundedQualificationReceipt({
124
+ state,
125
+ candidate,
126
+ lease,
127
+ evidence,
128
+ qualifiedAt,
129
+ }) {
130
+ const receipt = {
131
+ schema: DEV_DELIVERY_BOUNDED_QUALIFICATION_RECEIPT_SCHEMA,
132
+ action: "qualification-completed-lease-released",
133
+ authority: "qualification-only",
134
+ mergeGroupAdmission: false,
135
+ repository: state.repository,
136
+ protectedBase: state.protectedBase,
137
+ candidateId: candidate.candidateId,
138
+ qualificationLeaseToken: lease.token,
139
+ qualificationLeaseGeneration: lease.generation,
140
+ ...evidence,
141
+ qualifiedAt,
142
+ expectedOldStateRoot: state.stateRoot,
143
+ nextAction: "Wait for the single exclusive Landing Warrant.",
144
+ };
145
+ return { receipt, receiptRoot: devDeliveryContentRoot(receipt) };
146
+ }