@kungfu-tech/buildchain 4.0.1-alpha.2 → 4.0.1-alpha.21

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 (203) hide show
  1. package/actions/release-tail/README.md +8 -0
  2. package/architecture/ci-lane-change-budget.json +187 -0
  3. package/architecture/decisions/0002-next-development-transition.md +101 -0
  4. package/architecture/decisions/0003-two-phase-delivery-warrant.md +152 -0
  5. package/architecture/internal-capabilities.json +211 -8
  6. package/architecture/maintainability-policy.json +113 -28
  7. package/architecture/release-tail-contract-inventory.json +5 -2
  8. package/architecture/v3-core-mechanism-inventory.json +91 -0
  9. package/architecture/v4-adopter-delivery-parity.json +32 -5
  10. package/architecture/v4-capability-state-machine-manifest.json +73 -0
  11. package/architecture/v4-compatibility-facts-parity.json +77 -0
  12. package/architecture/v4-delivery-authority-parity.json +250 -0
  13. package/architecture/v4-delivery-warrant-shadow-fixtures.json +41 -9
  14. package/architecture/v4-floating-consumer-policy.json +6 -0
  15. package/architecture/v4-next-development-parity.json +192 -0
  16. package/architecture/v4-publication-rehearsal-parity.json +84 -0
  17. package/architecture/v4-release-train-parity.json +1 -0
  18. package/architecture/v4-tail-reseal-parity.json +150 -0
  19. package/bin/buildchain.mjs +32 -3
  20. package/bin/internal/adopter-delivery-cli.mjs +70 -0
  21. package/bin/internal/command-registry.mjs +3 -0
  22. package/bin/internal/compatibility-facts-cli.mjs +101 -0
  23. package/contracts/dev-delivery-authority-v2.schema.json +662 -0
  24. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
  25. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
  26. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
  27. package/contracts/fixtures/v4-adopter-delivery-v1/archive-template.json +19 -0
  28. package/contracts/fixtures/v4-adopter-delivery-v1/bootstrap-positive.json +93 -0
  29. package/contracts/fixtures/v4-adopter-delivery-v1/gate-positive.json +29 -0
  30. package/contracts/fixtures/v4-adopter-delivery-v1/gate-unknown-selector.json +26 -0
  31. package/contracts/fixtures/v4-adopter-delivery-v1/offline-vectors.json +50 -0
  32. package/contracts/fixtures/v4-compatibility-facts-v1/shared.json +1129 -0
  33. package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +7 -1
  34. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/artifacts/product.bin +1 -0
  35. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/config/buildchain.toml +5 -0
  36. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/release-activation.json +1 -0
  37. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/signed-channel.json +1 -0
  38. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/evidence/qualification.json +1 -0
  39. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/candidate.json +5 -0
  40. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/release-passport.json +1 -0
  41. package/contracts/fixtures/v4-publication-rehearsal-v1/capsule.json +707 -0
  42. package/contracts/fixtures/v4-publication-rehearsal-v1/offline-vectors.json +27 -0
  43. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +229 -0
  44. package/contracts/next-development-request-v1.schema.json +66 -0
  45. package/contracts/next-development-transition-v1.schema.json +292 -0
  46. package/contracts/v4-adopter-delivery-v1.schema.json +81 -0
  47. package/contracts/v4-compatibility-facts-v1.schema.json +230 -0
  48. package/contracts/v4-floating-consumer-policy-receipt-v1.schema.json +4 -2
  49. package/contracts/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  50. package/contracts/v4-tail-reseal-v1.schema.json +276 -0
  51. package/dist/site/agent-index.json +5 -0
  52. package/dist/site/artifact-schemas.json +10 -0
  53. package/dist/site/buildchain-contract.json +1475 -27
  54. package/dist/site/buildchain-site.json +627 -31
  55. package/dist/site/capability-registry.json +17 -14
  56. package/dist/site/cli-registry.json +205 -3
  57. package/dist/site/kfd-claims.json +490 -16
  58. package/dist/site/kfd-upstream-aggregate.json +1 -1
  59. package/dist/site/manual-registry.json +52 -6
  60. package/dist/site/node-api-registry.json +14736 -8851
  61. package/dist/site/page-registry.json +593 -21
  62. package/dist/site/public-surface-audit.json +837 -48
  63. package/dist/site/publication-authority-registry.json +44 -8
  64. package/dist/site/publication-registry.json +4 -4
  65. package/dist/site/release-provenance.json +24 -0
  66. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +662 -0
  67. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +199 -0
  68. package/dist/site/schemas/v4-adopter-delivery-v1.schema.json +81 -0
  69. package/dist/site/schemas/v4-compatibility-facts-v1.schema.json +230 -0
  70. package/dist/site/schemas/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  71. package/dist/site/site-manifest.json +34 -10
  72. package/dist/site/workflow-registry.json +160 -10
  73. package/docs/MAP.md +8 -2
  74. package/docs/cli-reference.md +404 -13
  75. package/docs/cli.md +8 -0
  76. package/docs/dev-alpha-candidate-patrol.md +8 -0
  77. package/docs/dev-delivery-qualification-landing-adr.md +251 -0
  78. package/docs/dev-delivery-warrant.md +351 -38
  79. package/docs/next-development-transition.md +118 -0
  80. package/docs/node-api-reference.md +646 -293
  81. package/docs/release-tail-provider-plane.md +30 -0
  82. package/docs/v4-adopter-delivery.md +133 -0
  83. package/docs/v4-compatibility-facts.md +91 -0
  84. package/docs/v4-publication-rehearsal.md +130 -0
  85. package/docs/v4-tail-reseal.md +73 -0
  86. package/docs/versioning.md +4 -3
  87. package/package.json +34 -6
  88. package/packages/core/adopter-delivery-passport.js +259 -0
  89. package/packages/core/adopter-delivery-vectors.js +158 -0
  90. package/packages/core/adopter-delivery-vectors.json +77 -0
  91. package/packages/core/buildchain-agent-manuals.js +3 -0
  92. package/packages/core/buildchain-compatibility-authority.js +336 -0
  93. package/packages/core/buildchain-compatibility-fact.js +394 -0
  94. package/packages/core/buildchain-compatibility-facts.json +217 -0
  95. package/packages/core/buildchain-compatibility-proof.js +566 -0
  96. package/packages/core/buildchain-config.js +84 -0
  97. package/packages/core/buildchain-contract.js +96 -143
  98. package/packages/core/buildchain-delivery-bootstrap.js +240 -0
  99. package/packages/core/buildchain-delivery-infrastructure.js +164 -0
  100. package/packages/core/buildchain-delivery-self-dogfood.js +395 -0
  101. package/packages/core/buildchain-publication-authority.js +1 -0
  102. package/packages/core/channel-candidate.js +8 -0
  103. package/packages/core/channel-promotion-baseline.js +55 -0
  104. package/packages/core/ci-lane-change-budget.js +247 -0
  105. package/packages/core/dev-alpha-candidate-selection.js +10 -2
  106. package/packages/core/dev-delivery-authority-candidate.js +270 -0
  107. package/packages/core/dev-delivery-authority-evidence.js +146 -0
  108. package/packages/core/dev-delivery-authority-landing.js +461 -0
  109. package/packages/core/dev-delivery-authority-observation.js +48 -0
  110. package/packages/core/dev-delivery-authority-qualification.js +591 -0
  111. package/packages/core/dev-delivery-authority-settlement.js +213 -0
  112. package/packages/core/dev-delivery-authority-state.js +583 -0
  113. package/packages/core/dev-delivery-candidate-identity.js +13 -0
  114. package/packages/core/dev-delivery-contract-surface.js +76 -0
  115. package/packages/core/dev-delivery-execution-failure.js +133 -0
  116. package/packages/core/dev-delivery-execution-transfer.js +592 -0
  117. package/packages/core/dev-delivery-landing-admission-core.js +119 -0
  118. package/packages/core/dev-delivery-landing-readback.js +598 -0
  119. package/packages/core/dev-delivery-landing-terminal-evidence.js +271 -0
  120. package/packages/core/dev-delivery-landing-testing-port.js +6 -0
  121. package/packages/core/dev-delivery-native-execution.js +110 -0
  122. package/packages/core/dev-delivery-native-proof.js +562 -0
  123. package/packages/core/dev-delivery-process-boundary.js +563 -0
  124. package/packages/core/dev-delivery-provider-attempt.js +127 -0
  125. package/packages/core/dev-delivery-provider-heartbeat.js +382 -0
  126. package/packages/core/dev-delivery-warrant-cancellation.js +1 -0
  127. package/packages/core/dev-delivery-warrant-qualification.js +145 -0
  128. package/packages/core/dev-delivery-warrant-settlement.js +237 -36
  129. package/packages/core/dev-delivery-warrant-state.js +587 -0
  130. package/packages/core/dev-delivery-warrant.js +328 -370
  131. package/packages/core/github-governance-authority.js +1 -0
  132. package/packages/core/index.js +5 -0
  133. package/packages/core/kungfu-temporal-fact.js +557 -0
  134. package/packages/core/legacy-kfd-adopter-driver.js +167 -0
  135. package/packages/core/next-development-candidate-reservation.js +186 -0
  136. package/packages/core/next-development-controller.js +728 -0
  137. package/packages/core/next-development-projection.js +287 -0
  138. package/packages/core/next-development-transition.js +738 -0
  139. package/packages/core/paper-agent-entry.js +11 -5
  140. package/packages/core/paper.js +16 -5
  141. package/packages/core/published-delivery-authority.js +266 -0
  142. package/packages/core/release-candidate-recovery.js +70 -15
  143. package/packages/core/release-candidate.js +2 -2
  144. package/packages/core/release-passport.js +36 -9
  145. package/packages/core/v4-adopter-delivery-parity.js +3 -3
  146. package/packages/core/v4-adopter-delivery.js +359 -0
  147. package/packages/core/v4-canonical-contracts.js +5 -0
  148. package/packages/core/v4-delivery-warrant-read-candidate.js +10 -3
  149. package/packages/core/v4-floating-consumer-evidence.js +18 -4
  150. package/packages/core/v4-floating-consumer-policy.js +143 -20
  151. package/packages/core/v4-floating-consumer-release-passport.js +32 -5
  152. package/packages/core/v4-publication-rehearsal-capsule.js +468 -0
  153. package/packages/core/v4-publication-rehearsal-provider-bindings.js +212 -0
  154. package/packages/core/v4-publication-rehearsal.js +481 -0
  155. package/packages/core/v4-tail-reseal-contract.js +26 -0
  156. package/packages/core/v4-tail-reseal-github.js +178 -0
  157. package/packages/core/v4-tail-reseal-receipt.js +225 -0
  158. package/packages/core/v4-tail-reseal.js +594 -0
  159. package/packages/core/workflow-yaml-contract.js +24 -2
  160. package/scripts/buildchain-cli-help.mjs +41 -2
  161. package/scripts/check-ci-lane-change-budget.mjs +100 -0
  162. package/scripts/check-inventory.mjs +14 -3
  163. package/scripts/check-v4-floating-consumer-policy-contract.mjs +23 -4
  164. package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
  165. package/scripts/dev-delivery-authority-command-adapters.mjs +206 -0
  166. package/scripts/dev-delivery-authority-provider.mjs +28 -0
  167. package/scripts/dev-delivery-authority.mjs +490 -0
  168. package/scripts/dev-delivery-native-run.mjs +177 -0
  169. package/scripts/dev-delivery-process-boundary.mjs +260 -0
  170. package/scripts/dev-delivery-proof.mjs +67 -2
  171. package/scripts/dev-delivery-provider-heartbeat.mjs +215 -0
  172. package/scripts/dev-delivery-source-proof-replay.mjs +153 -0
  173. package/scripts/dev-delivery-source-proof-reuse.mjs +13 -97
  174. package/scripts/dev-delivery-two-phase-resume.mjs +345 -0
  175. package/scripts/dev-delivery-two-phase.mjs +573 -0
  176. package/scripts/dev-delivery-warrant-options.mjs +266 -0
  177. package/scripts/dev-delivery-warrant-store.mjs +231 -0
  178. package/scripts/dev-delivery-warrant.mjs +232 -194
  179. package/scripts/dev-pr-auto-merge.mjs +1 -1
  180. package/scripts/dev-pr-delivery-warrant.mjs +11 -0
  181. package/scripts/dev-qualification-patrol.mjs +9 -9
  182. package/scripts/dispatch-artifact-signing-authority.mjs +1 -1
  183. package/scripts/generate-channel-promotion-workflow.mjs +2 -2
  184. package/scripts/generate-next-development-guidance.mjs +49 -0
  185. package/scripts/generate-release-candidate-passport.mjs +152 -0
  186. package/scripts/generate-site-bundle.mjs +69 -4
  187. package/scripts/init-repo.mjs +22 -4
  188. package/scripts/next-development-self-dogfood-harness.mjs +460 -0
  189. package/scripts/next-development-self-dogfood.mjs +597 -0
  190. package/scripts/next-development-transition.mjs +47 -0
  191. package/scripts/npm-publish-transaction.mjs +2 -2
  192. package/scripts/promotion-channel-router.mjs +4 -4
  193. package/scripts/release-candidate-anchor-provenance.mjs +99 -0
  194. package/scripts/release-tail.mjs +51 -3
  195. package/scripts/release-train-self-dogfood.mjs +94 -92
  196. package/scripts/resume-from-candidate-run.mjs +557 -30
  197. package/scripts/site-capability-metadata.mjs +41 -0
  198. package/scripts/stable-candidate-qualification.mjs +9 -10
  199. package/scripts/v4-consumer-policy.mjs +5 -5
  200. package/scripts/v4-publication-rehearsal-fixture.mjs +144 -0
  201. package/scripts/v4-tail-reseal-macos-rehearsal.mjs +134 -0
  202. package/scripts/v4-tail-reseal.mjs +416 -0
  203. package/templates/native-dev-delivery.yml +143 -0
@@ -0,0 +1,271 @@
1
+ import {
2
+ devDeliveryContentRoot,
3
+ devDeliveryExactRoot as exactRoot,
4
+ devDeliveryExactSha as exactSha,
5
+ devDeliveryPositiveInteger as positiveInteger,
6
+ devDeliveryProtectedBase as protectedBase,
7
+ devDeliveryRepository as repository,
8
+ devDeliveryText as text,
9
+ devDeliveryTimestamp as timestamp,
10
+ } from "./dev-delivery-common.js";
11
+ import { normalizeDevDeliveryProviderAttempt } from "./dev-delivery-provider-attempt.js";
12
+
13
+ export const DEV_DELIVERY_LANDING_TERMINAL_READBACK_SCHEMA =
14
+ "kungfu.buildchain.github-landing-terminal-readback/v2";
15
+
16
+ const sealedReadbacks = new WeakSet();
17
+ const COMPLETED_PROVIDER_STATES = new Set(["completed"]);
18
+ const PROVIDER_PULL_REQUEST_STATES = new Set(["open", "closed"]);
19
+ const TERMINAL_OUTCOMES = new Set([
20
+ "merged",
21
+ "terminal-failure",
22
+ "dequeued",
23
+ "cancelled",
24
+ ]);
25
+ const TERMINAL_JOB_CONCLUSIONS = new Set([
26
+ "cancelled",
27
+ "failure",
28
+ "action_required",
29
+ "skipped",
30
+ "stale",
31
+ "startup_failure",
32
+ "success",
33
+ "timed_out",
34
+ ]);
35
+
36
+ function requiredText(value, label) {
37
+ if (value === null || value === undefined || value === "") {
38
+ throw new Error(`${label} is required`);
39
+ }
40
+ if (typeof value !== "string") {
41
+ throw new Error(`${label} must be a string`);
42
+ }
43
+ const normalized = text(value);
44
+ if (!normalized) throw new Error(`${label} is required`);
45
+ return normalized;
46
+ }
47
+
48
+ function exactInteger(value, label) {
49
+ if (!Number.isInteger(value)) {
50
+ throw new Error(`${label} must be an integer`);
51
+ }
52
+ return positiveInteger(value, label);
53
+ }
54
+
55
+ function exactBoolean(value, label) {
56
+ if (typeof value !== "boolean") {
57
+ throw new Error(`${label} must be a boolean`);
58
+ }
59
+ return value;
60
+ }
61
+
62
+ function exactValue(value, allowed, label) {
63
+ const normalized = requiredText(value, label);
64
+ if (!allowed.has(normalized)) {
65
+ throw new Error(`${label} is unsupported: ${normalized}`);
66
+ }
67
+ return normalized;
68
+ }
69
+
70
+ function readbackBody(input) {
71
+ return {
72
+ schema: DEV_DELIVERY_LANDING_TERMINAL_READBACK_SCHEMA,
73
+ verifier: "buildchain-github-provider-live-readback",
74
+ terminal: true,
75
+ repository: repository(requiredText(input.repository, "repository")),
76
+ protectedBase: protectedBase(
77
+ requiredText(input.protectedBase, "protected base"),
78
+ ),
79
+ stateRoot: exactRoot(
80
+ requiredText(input.stateRoot, "provider readback stateRoot"),
81
+ "provider readback stateRoot",
82
+ ),
83
+ candidateId: exactRoot(
84
+ requiredText(input.candidateId, "provider readback candidateId"),
85
+ "provider readback candidateId",
86
+ ),
87
+ pullRequestNumber: exactInteger(
88
+ input.pullRequestNumber,
89
+ "provider readback pull request",
90
+ ),
91
+ sourceHead: exactSha(
92
+ requiredText(input.sourceHead, "provider readback sourceHead"),
93
+ "provider readback sourceHead",
94
+ ),
95
+ landingWarrantToken: exactRoot(
96
+ requiredText(input.landingWarrantToken, "provider readback fence"),
97
+ "provider readback fence",
98
+ ),
99
+ landingWarrantGeneration: exactInteger(
100
+ input.landingWarrantGeneration,
101
+ "provider readback generation",
102
+ ),
103
+ providerRunId: exactInteger(
104
+ input.providerRunId,
105
+ "provider readback run id",
106
+ ),
107
+ providerRunAttempt: exactInteger(
108
+ input.providerRunAttempt,
109
+ "provider readback run attempt",
110
+ ),
111
+ providerRunState: exactValue(
112
+ input.providerRunState,
113
+ COMPLETED_PROVIDER_STATES,
114
+ "provider run state",
115
+ ),
116
+ providerRunConclusion: requiredText(
117
+ input.providerRunConclusion,
118
+ "provider run conclusion",
119
+ ),
120
+ providerRunHead: exactSha(
121
+ requiredText(input.providerRunHead, "provider run head"),
122
+ "provider run head",
123
+ ),
124
+ providerJobId: exactInteger(
125
+ input.providerJobId,
126
+ "provider readback job id",
127
+ ),
128
+ providerJobState: exactValue(
129
+ input.providerJobState,
130
+ COMPLETED_PROVIDER_STATES,
131
+ "provider job state",
132
+ ),
133
+ providerJobConclusion: exactValue(
134
+ input.providerJobConclusion,
135
+ TERMINAL_JOB_CONCLUSIONS,
136
+ "provider job conclusion",
137
+ ),
138
+ providerJobStartedAt: timestamp(
139
+ requiredText(input.providerJobStartedAt, "provider job start"),
140
+ "provider job start",
141
+ ),
142
+ providerJobCompletedAt: timestamp(
143
+ requiredText(input.providerJobCompletedAt, "provider job completion"),
144
+ "provider job completion",
145
+ ),
146
+ providerAttempt: normalizeDevDeliveryProviderAttempt(input.providerAttempt),
147
+ admissionRoot: exactRoot(
148
+ requiredText(input.admissionRoot, "provider readback admission root"),
149
+ "provider readback admission root",
150
+ ),
151
+ pullRequestState: exactValue(
152
+ input.pullRequestState,
153
+ PROVIDER_PULL_REQUEST_STATES,
154
+ "provider pull request state",
155
+ ),
156
+ pullRequestMerged: exactBoolean(
157
+ input.pullRequestMerged,
158
+ "provider pull request merged",
159
+ ),
160
+ protectedBaseHead: exactSha(
161
+ requiredText(input.protectedBaseHead, "provider protected base head"),
162
+ "provider protected base head",
163
+ ),
164
+ providerRunHeadInProtectedBase: exactBoolean(
165
+ input.providerRunHeadInProtectedBase,
166
+ "provider run head in protected base",
167
+ ),
168
+ outcome: exactValue(input.outcome, TERMINAL_OUTCOMES, "provider outcome"),
169
+ reason: requiredText(input.reason, "provider reason"),
170
+ observedAt: timestamp(
171
+ requiredText(input.observedAt, "provider readback observedAt"),
172
+ "provider readback observedAt",
173
+ ),
174
+ };
175
+ }
176
+
177
+ export function sealLandingTerminalReadback(input) {
178
+ const body = readbackBody(input);
179
+ if (
180
+ (body.outcome === "merged") !==
181
+ (body.pullRequestMerged && body.providerRunHeadInProtectedBase)
182
+ ) {
183
+ throw new Error(
184
+ "merged provider outcome requires the exact admitted run head in the protected base",
185
+ );
186
+ }
187
+ const evidence = {
188
+ schema: "kungfu.buildchain.github-landing-terminal-evidence/v1",
189
+ repository: body.repository,
190
+ stateRoot: body.stateRoot,
191
+ candidateId: body.candidateId,
192
+ sourceHead: body.sourceHead,
193
+ landingWarrantToken: body.landingWarrantToken,
194
+ landingWarrantGeneration: body.landingWarrantGeneration,
195
+ providerRunId: body.providerRunId,
196
+ providerRunAttempt: body.providerRunAttempt,
197
+ providerJobId: body.providerJobId,
198
+ admissionRoot: body.admissionRoot,
199
+ providerAttempt: body.providerAttempt,
200
+ providerJobConclusion: body.providerJobConclusion,
201
+ protectedBaseHead: body.protectedBaseHead,
202
+ providerRunHeadInProtectedBase: body.providerRunHeadInProtectedBase,
203
+ outcome: body.outcome,
204
+ observedAt: body.observedAt,
205
+ };
206
+ const readback = {
207
+ ...body,
208
+ evidenceRoot: devDeliveryContentRoot(evidence),
209
+ };
210
+ const sealed = {
211
+ ...readback,
212
+ readbackRoot: devDeliveryContentRoot(readback),
213
+ };
214
+ sealedReadbacks.add(sealed);
215
+ return sealed;
216
+ }
217
+
218
+ export function sealLandingTerminalReadbackForTesting(input) {
219
+ return sealLandingTerminalReadback(input);
220
+ }
221
+
222
+ export function verifyLandingSettlementReadback({
223
+ state,
224
+ candidate,
225
+ warrant,
226
+ sealedProviderReadback,
227
+ }) {
228
+ if (!sealedReadbacks.has(sealedProviderReadback)) {
229
+ throw new Error(
230
+ "Landing settlement requires product-owned GitHub live readback",
231
+ );
232
+ }
233
+ const readback = sealedProviderReadback;
234
+ const bindings = [
235
+ [readback.repository, state.repository, "repository"],
236
+ [readback.protectedBase, state.protectedBase, "protected base"],
237
+ [readback.stateRoot, state.stateRoot, "state root"],
238
+ [readback.candidateId, candidate.candidateId, "candidate"],
239
+ [readback.pullRequestNumber, candidate.pullRequestNumber, "pull request"],
240
+ [readback.sourceHead, candidate.sourceHead, "source head"],
241
+ [readback.landingWarrantToken, warrant.token, "fence"],
242
+ [readback.landingWarrantGeneration, warrant.generation, "generation"],
243
+ [readback.providerRunId, warrant.providerAttempt.runId, "provider run"],
244
+ [
245
+ readback.providerRunAttempt,
246
+ warrant.providerAttempt.runAttempt,
247
+ "provider run attempt",
248
+ ],
249
+ [readback.providerJobId, warrant.providerAttempt.jobId, "provider job"],
250
+ [readback.admissionRoot, warrant.mergeGroupAdmissionRoot, "admission root"],
251
+ ];
252
+ for (const [actual, expected, label] of bindings) {
253
+ if (actual !== expected)
254
+ throw new Error(`provider terminal readback ${label} mismatch`);
255
+ }
256
+ if (
257
+ JSON.stringify(readback.providerAttempt) !==
258
+ JSON.stringify(warrant.providerAttempt)
259
+ ) {
260
+ throw new Error("provider terminal readback exact attempt mismatch");
261
+ }
262
+ if (Date.parse(readback.observedAt) < Date.parse(warrant.issuedAt)) {
263
+ throw new Error(
264
+ "provider terminal readback is stale for this Landing Warrant",
265
+ );
266
+ }
267
+ return readback;
268
+ }
269
+
270
+ export const verifyExpiredLandingSettlementReadback =
271
+ verifyLandingSettlementReadback;
@@ -0,0 +1,6 @@
1
+ export const DEV_DELIVERY_TESTING_PROVIDER_READBACK = Symbol(
2
+ "Buildchain dev delivery testing provider readback",
3
+ );
4
+
5
+ export { sealLandingTerminalReadbackForTesting } from "./dev-delivery-landing-terminal-evidence.js";
6
+ export { admitDevDeliveryMergeGroupWithVerifiedProviderAttempt as admitDevDeliveryMergeGroupForTesting } from "./dev-delivery-landing-admission-core.js";
@@ -0,0 +1,110 @@
1
+ import {
2
+ devDeliveryClone as clone,
3
+ devDeliveryContentRoot,
4
+ devDeliveryExactRoot as exactRoot,
5
+ devDeliveryExactSha as exactSha,
6
+ devDeliveryProtectedBase as protectedBase,
7
+ devDeliveryRepository as repository,
8
+ devDeliveryText as text,
9
+ devDeliveryTimestamp as timestamp,
10
+ } from "./dev-delivery-common.js";
11
+
12
+ export const NATIVE_EXECUTION_BINDING_SCHEMA =
13
+ "kungfu.buildchain.native-execution-binding/v2";
14
+ export const NATIVE_COMMAND_CONTRACT_SCHEMA =
15
+ "kungfu.buildchain.native-command-contract/v1";
16
+ export const NATIVE_EXECUTION_RECEIPT_SCHEMA =
17
+ "kungfu.buildchain.native-heartbeat-run-receipt/v3";
18
+
19
+ export function createNativeCommandContract(commandInput) {
20
+ const command = text(commandInput);
21
+ if (!command) throw new Error("native command is required");
22
+ const contract = {
23
+ schema: NATIVE_COMMAND_CONTRACT_SCHEMA,
24
+ runner: "bash-lc",
25
+ command,
26
+ };
27
+ return { ...contract, commandRoot: devDeliveryContentRoot(contract) };
28
+ }
29
+
30
+ export function normalizeNativeCommandContract(input = {}) {
31
+ const contract = createNativeCommandContract(input.command);
32
+ if (input.schema && input.schema !== contract.schema) {
33
+ throw new Error("native command contract schema is unsupported");
34
+ }
35
+ if (input.runner && input.runner !== contract.runner) {
36
+ throw new Error("native command contract runner is unsupported");
37
+ }
38
+ if (input.commandRoot && input.commandRoot !== contract.commandRoot) {
39
+ throw new Error("native command contract root drift");
40
+ }
41
+ return contract;
42
+ }
43
+
44
+ export function createNativeExecutionBinding(input = {}) {
45
+ return {
46
+ schema: NATIVE_EXECUTION_BINDING_SCHEMA,
47
+ repository: repository(input.repository),
48
+ protectedBase: protectedBase(input.protectedBase),
49
+ sourceHead: exactSha(input.sourceHead, "sourceHead"),
50
+ qualifiedBase: exactSha(input.qualifiedBase, "qualifiedBase"),
51
+ nativeCommandRoot: exactRoot(input.nativeCommandRoot, "nativeCommandRoot"),
52
+ toolchainRoot: exactRoot(input.toolchainRoot, "toolchainRoot"),
53
+ environmentRoot: exactRoot(input.environmentRoot, "environmentRoot"),
54
+ };
55
+ }
56
+
57
+ export function createNativeExecutionReceipt(input = {}) {
58
+ const executionBinding = createNativeExecutionBinding(input.executionBinding);
59
+ const receipt = {
60
+ schema: NATIVE_EXECUTION_RECEIPT_SCHEMA,
61
+ outcome: input.outcome === "succeeded" ? "succeeded" : text(input.outcome),
62
+ commandRoot: exactRoot(input.commandRoot, "commandRoot"),
63
+ executionBinding,
64
+ executionBindingRoot: devDeliveryContentRoot(executionBinding),
65
+ startedAt: timestamp(input.startedAt, "startedAt"),
66
+ completedAt: timestamp(input.completedAt, "completedAt"),
67
+ heartbeatCount: Number(input.heartbeatCount),
68
+ };
69
+ if (receipt.outcome !== "succeeded")
70
+ throw new Error("native execution receipt must record succeeded outcome");
71
+ if (receipt.commandRoot !== receipt.executionBinding.nativeCommandRoot) {
72
+ throw new Error("native execution receipt command root is not authorized");
73
+ }
74
+ if (!Number.isInteger(receipt.heartbeatCount) || receipt.heartbeatCount < 1)
75
+ throw new Error("heartbeatCount must be a positive integer");
76
+ if (Date.parse(receipt.completedAt) < Date.parse(receipt.startedAt))
77
+ throw new Error("native execution receipt completedAt precedes startedAt");
78
+ return { ...receipt, receiptRoot: devDeliveryContentRoot(receipt) };
79
+ }
80
+
81
+ export function verifyNativeExecutionReceipt(receiptInput, expected = {}) {
82
+ try {
83
+ const receipt = clone(receiptInput || {});
84
+ if (receipt.schema !== NATIVE_EXECUTION_RECEIPT_SCHEMA)
85
+ return { ok: false, reason: "unsupported-schema" };
86
+ const receiptRoot = receipt.receiptRoot;
87
+ delete receipt.receiptRoot;
88
+ if (devDeliveryContentRoot(receipt) !== receiptRoot)
89
+ return { ok: false, reason: "receipt-root-drift" };
90
+ const normalized = createNativeExecutionReceipt({
91
+ ...receipt,
92
+ executionBinding: receipt.executionBinding,
93
+ });
94
+ if (normalized.receiptRoot !== receiptRoot)
95
+ return { ok: false, reason: "receipt-input-drift" };
96
+ for (const [field, value] of Object.entries(expected)) {
97
+ if (value !== undefined && receipt.executionBinding?.[field] !== value)
98
+ return { ok: false, reason: `${field}-mismatch` };
99
+ }
100
+ return {
101
+ ok: true,
102
+ reason: "exact-native-execution-receipt",
103
+ receiptRoot,
104
+ executionBindingRoot: receipt.executionBindingRoot,
105
+ receipt: normalized,
106
+ };
107
+ } catch (error) {
108
+ return { ok: false, reason: "invalid-receipt", error: error.message };
109
+ }
110
+ }