@kungfu-tech/buildchain 4.1.0-alpha.0 → 4.1.0-alpha.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 (295) hide show
  1. package/AGENTS.md +30 -41
  2. package/CONTRIBUTING.md +6 -7
  3. package/architecture/action-taxonomy.json +5 -21
  4. package/architecture/agent-change-map.md +74 -56
  5. package/architecture/build-orchestration.json +8 -1
  6. package/architecture/ci-lane-change-budget.json +179 -69
  7. package/architecture/floating-consumer-policy.json +7 -17
  8. package/architecture/internal-capabilities.json +58 -72
  9. package/architecture/maintainability-debt.json +138 -52
  10. package/architecture/maintainability-policy.json +6 -15
  11. package/architecture/promotion-job-topology.json +39 -20
  12. package/architecture/release-topology.json +26 -37
  13. package/architecture/runtime-entry.json +26 -0
  14. package/architecture/runtime-resume-lineage.json +23 -0
  15. package/architecture/stage-capsule-qualification.json +2 -2
  16. package/architecture/universal-workflow-bootstrap.json +10 -25
  17. package/architecture/universal-workflow-capability-policy.json +61 -0
  18. package/architecture/universal-workflow-fault-campaign.json +18 -24
  19. package/architecture/workflow-taxonomy.json +0 -11
  20. package/contracts/fixtures/{v4-runtime-ref-resume-authority-v1 → runtime-resume-lineage-v2}/scenario.json +2 -3
  21. package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +2 -2
  22. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
  23. package/contracts/promotion-invocation-v1.schema.json +0 -44
  24. package/contracts/promotion-request-v1.schema.json +0 -39
  25. package/contracts/runtime-resume-lineage-v2.schema.json +182 -0
  26. package/dist/site/buildchain-contract.json +472 -361
  27. package/dist/site/buildchain-site.json +99 -99
  28. package/dist/site/capability-registry.json +3 -3
  29. package/dist/site/cli-registry.json +4 -4
  30. package/dist/site/controller-registry.json +94 -78
  31. package/dist/site/kfd-claims.json +224 -343
  32. package/dist/site/kfd-upstream-aggregate.json +1 -1
  33. package/dist/site/manual-registry.json +15 -15
  34. package/dist/site/node-api-registry.json +239 -354
  35. package/dist/site/page-registry.json +80 -80
  36. package/dist/site/public-surface-audit.json +203 -254
  37. package/dist/site/publication-authority-registry.json +1 -24
  38. package/dist/site/publication-registry.json +4 -4
  39. package/dist/site/release-provenance.json +1 -1
  40. package/dist/site/site-manifest.json +19 -19
  41. package/dist/site/workflow-registry.json +197 -357
  42. package/docs/MAP.md +3 -3
  43. package/docs/auditable-demo.md +4 -4
  44. package/docs/cli-reference.md +2 -2
  45. package/docs/code-organization.md +5 -4
  46. package/docs/controller-evidence.md +2 -2
  47. package/docs/dev-alpha-candidate-patrol.md +5 -5
  48. package/docs/dev-delivery-warrant.md +14 -24
  49. package/docs/engineering-housekeeper.md +3 -3
  50. package/docs/github-artifact-attestation.md +9 -12
  51. package/docs/github-governance-authority.md +4 -4
  52. package/docs/node-api-reference.md +153 -167
  53. package/docs/publication-artifacts.md +3 -4
  54. package/docs/publication-authority.md +2 -2
  55. package/docs/release-candidate.md +21 -27
  56. package/docs/release-governance.md +10 -10
  57. package/docs/release-promotion-request.md +11 -18
  58. package/docs/release-propagation.md +5 -6
  59. package/docs/release-tail-provider-plane.md +2 -3
  60. package/docs/reusable-build-surface.md +13 -7
  61. package/docs/runtime-entry.md +122 -0
  62. package/docs/runtime-train-validation.md +30 -41
  63. package/docs/v4-publication-rehearsal.md +5 -5
  64. package/docs/v4-stage-capsule.md +9 -10
  65. package/docs/web-surface-deployments.md +16 -20
  66. package/docs/workflow-catalog.md +0 -1
  67. package/package.json +6 -6
  68. package/packages/core/adoption/commands/init-repo.mjs +2 -2
  69. package/packages/core/adoption/cross-platform-adopter-qualification.js +2 -13
  70. package/packages/core/adoption/qualification/actions.js +3 -5
  71. package/packages/core/adoption/qualification/admission.js +2 -3
  72. package/packages/core/build/artifact/attestation.js +0 -1
  73. package/packages/core/build/artifact/contracts.js +1 -4
  74. package/packages/core/build/artifact/store.js +6 -5
  75. package/packages/core/build/artifact-signing.js +4 -10
  76. package/packages/core/build/binary/actions.js +15 -9
  77. package/packages/core/build/binary-publication-dispatch.js +2 -6
  78. package/packages/core/build/demo/action-context.js +2 -11
  79. package/packages/core/build/demo/binary-action.js +8 -10
  80. package/packages/core/build/gate/controller.js +0 -2
  81. package/packages/core/build/github-attestation/action.js +2 -7
  82. package/packages/core/build/github-attestation/admission.js +0 -8
  83. package/packages/core/build/github-attestation/transaction.js +1 -2
  84. package/packages/core/build/lifecycle/stage-action.js +2 -0
  85. package/packages/core/build/lifecycle/stage.js +6 -3
  86. package/packages/core/build/macos-credential-island/dmg-assembly.js +0 -2
  87. package/packages/core/build/macos-credential-island/lib.js +2 -6
  88. package/packages/core/build/plan/action-context.js +0 -7
  89. package/packages/core/build/plan/action.js +7 -11
  90. package/packages/core/build/plan/admission.js +6 -73
  91. package/packages/core/build/plan/configuration.js +1 -1
  92. package/packages/core/build/plan/environment.js +1 -1
  93. package/packages/core/build/plan/identity.js +1 -5
  94. package/packages/core/build/plan/resolve.js +7 -1
  95. package/packages/core/build/recovery/checkpoint.js +158 -0
  96. package/packages/core/build/recovery/transaction.js +51 -0
  97. package/packages/core/build/signing/authority-actions.js +2 -11
  98. package/packages/core/build/signing/control.js +0 -5
  99. package/packages/core/build/signing/controller-transaction.js +0 -1
  100. package/packages/core/build/signing/delegation.js +2 -4
  101. package/packages/core/build/signing/dispatch.js +10 -56
  102. package/packages/core/build/signing/intake.js +0 -4
  103. package/packages/core/build/signing/prepare.js +1 -1
  104. package/packages/core/build/signing/request.js +3 -8
  105. package/packages/core/build/source/checkout-action.js +6 -10
  106. package/packages/core/build/source/controller.js +1 -4
  107. package/packages/core/build/source/lifecycle.js +3 -13
  108. package/packages/core/build/stage-capsule/actions.js +3 -13
  109. package/packages/core/build/stage-capsule/campaign/resume.js +10 -5
  110. package/packages/core/build/stage-capsule/rehearsal/verify.js +3 -4
  111. package/packages/core/build/stage-capsule-resume-planner.js +0 -1
  112. package/packages/core/build/summary/aggregation.js +5 -5
  113. package/packages/core/build/summary/finalization.js +1 -1
  114. package/packages/core/build/verification/actions.js +3 -12
  115. package/packages/core/build/verification/runner.js +22 -20
  116. package/packages/core/consumer/floating-consumer-evidence.js +3 -21
  117. package/packages/core/consumer/floating-consumer-policy.js +2 -93
  118. package/packages/core/consumer/floating-consumer-release-passport.js +1 -34
  119. package/packages/core/consumer/policy-admission.js +1 -3
  120. package/packages/core/contracts/buildchain-contract.js +12 -146
  121. package/packages/core/contracts/workflow-yaml-contract.js +11 -1
  122. package/packages/core/dev-delivery/candidate/admission.js +3 -4
  123. package/packages/core/dev-delivery/candidate/coordinates.js +0 -8
  124. package/packages/core/dev-delivery/commands/dev-delivery-request.sh +5 -13
  125. package/packages/core/dev-delivery/commands/dev-delivery-source-proof-reuse.mjs +0 -3
  126. package/packages/core/dev-delivery/dev-delivery-contract-surface.js +4 -52
  127. package/packages/core/dev-delivery/dev-delivery-execution-transfer.js +2 -15
  128. package/packages/core/dev-delivery/native/action-context.js +4 -32
  129. package/packages/core/dev-delivery/native/provider-boundary.js +0 -2
  130. package/packages/core/dev-delivery/native/transactions.js +1 -2
  131. package/packages/core/dev-delivery/queue/reconciliation-action.js +6 -10
  132. package/packages/core/dev-delivery/source-proof/predicates.js +0 -6
  133. package/packages/core/dev-delivery/source-proof/reuse.js +0 -2
  134. package/packages/core/dev-delivery/source-proof/seal.js +0 -2
  135. package/packages/core/governance/alpha-candidate/action.js +1 -10
  136. package/packages/core/governance/audit/actions.js +1 -3
  137. package/packages/core/governance/audit/collection.js +1 -3
  138. package/packages/core/governance/audit/identity.js +3 -31
  139. package/packages/core/governance/audit/transactions.js +2 -4
  140. package/packages/core/governance/buildchain-publication-authority.js +0 -1
  141. package/packages/core/governance/commands/audit-github-governance.mjs +3 -2
  142. package/packages/core/governance/github-governance-authority.js +0 -5
  143. package/packages/core/governance/receipt-admission.js +0 -15
  144. package/packages/core/index.js +1 -1
  145. package/packages/core/observability/controller/identity.js +4 -5
  146. package/packages/core/observability/controller-evidence.js +5 -10
  147. package/packages/core/paper/commands/paper.mjs +6 -6
  148. package/packages/core/paper/operations/plans.js +2 -2
  149. package/packages/core/paper/operations/provisioning-validation.js +1 -1
  150. package/packages/core/paper/operations/scaffold-workflows.js +29 -12
  151. package/packages/core/paper/operations/scaffold.js +97 -69
  152. package/packages/core/paper/paper-agent-entry.js +0 -11
  153. package/packages/core/paper/paper-runtime-channels.js +21 -66
  154. package/packages/core/paper/paper-scaffold-content.js +1 -1
  155. package/packages/core/paper/paper.js +9 -5
  156. package/packages/core/paper/publication/candidate.js +0 -9
  157. package/packages/core/paper/publication-controller.js +2 -4
  158. package/packages/core/providers/github/artifact-attestation.js +1 -1
  159. package/packages/core/publication/authority/actions.js +9 -8
  160. package/packages/core/publication/authority/admission.js +0 -11
  161. package/packages/core/publication/authority/assembly.js +2 -7
  162. package/packages/core/publication/authority/control-plane.js +2 -2
  163. package/packages/core/publication/authority/governance.js +2 -9
  164. package/packages/core/publication/authority/request.js +7 -2
  165. package/packages/core/publication/authority/verification.js +3 -18
  166. package/packages/core/publication/binary/action.js +5 -7
  167. package/packages/core/publication/candidate/qualification-action.js +1 -6
  168. package/packages/core/publication/candidate/stage-capsules.js +1 -1
  169. package/packages/core/publication/npm/preview-action.js +9 -15
  170. package/packages/core/publication/oci/preview-actions.js +1 -10
  171. package/packages/core/publication/publication-artifact-candidate.js +2 -2
  172. package/packages/core/publication/publication-authority.js +2 -2
  173. package/packages/core/publication/publication-rehearsal-projection.js +3 -3
  174. package/packages/core/publication/settlement/actions.js +2 -11
  175. package/packages/core/release/binary/coordinates-action.js +0 -13
  176. package/packages/core/release/binary/coordinates.js +2 -19
  177. package/packages/core/release/commands/promotion-channel-router.mjs +12 -56
  178. package/packages/core/release/commands/resume-from-candidate-run.mjs +2 -3
  179. package/packages/core/release/dev-alpha-active-release-train.js +0 -5
  180. package/packages/core/release/line/action.js +2 -13
  181. package/packages/core/release/next-development/actions.js +2 -5
  182. package/packages/core/release/passport/consumer-validation.js +1 -28
  183. package/packages/core/release/promote-candidate/development-source.js +7 -8
  184. package/packages/core/release/promotion/actions.js +7 -38
  185. package/packages/core/release/promotion/admission.js +3 -50
  186. package/packages/core/release/promotion/candidate.js +2 -4
  187. package/packages/core/release/promotion/channel.js +13 -101
  188. package/packages/core/release/promotion/qualification-action.js +2 -13
  189. package/packages/core/release/promotion/routing.js +16 -81
  190. package/packages/core/release/promotion/selection.js +1 -9
  191. package/packages/core/release/promotion-request.js +1 -40
  192. package/packages/core/release/qualification/actions.js +0 -8
  193. package/packages/core/release/qualification/public-build.js +1 -1
  194. package/packages/core/release/recovery/candidate.js +15 -21
  195. package/packages/core/release/recovery/capsules.js +2 -10
  196. package/packages/core/release/recovery/lineage.js +305 -0
  197. package/packages/core/release/recovery/provenance.js +1 -2
  198. package/packages/core/release/recovery/publication.js +4 -14
  199. package/packages/core/release/recovery/readback.js +19 -32
  200. package/packages/core/release/recovery/runtime.js +4 -95
  201. package/packages/core/release/release-candidate-recovery.js +4 -9
  202. package/packages/core/release/release-candidate.js +2 -5
  203. package/packages/core/release/reseal/actions.js +3 -22
  204. package/packages/core/release/reseal/admission.js +0 -2
  205. package/packages/core/release/reseal/finalize-platform.js +0 -2
  206. package/packages/core/release/tail-reseal-github.js +1 -2
  207. package/packages/core/release/tail-reseal-receipt.js +0 -1
  208. package/packages/core/release/tail-reseal.js +2 -20
  209. package/packages/core/release/version-state.js +16 -13
  210. package/packages/core/runtime/buildchain-domain.wasm +0 -0
  211. package/packages/core/runtime/checkout-identity.js +0 -13
  212. package/packages/core/runtime/domain-wasm-artifact.js +2 -2
  213. package/packages/core/runtime/entry/actions.js +121 -0
  214. package/packages/core/runtime/entry/activation.js +86 -0
  215. package/packages/core/runtime/entry/github.js +55 -0
  216. package/packages/core/runtime/entry/recovery.js +37 -0
  217. package/packages/core/runtime/entry/selection.js +110 -0
  218. package/packages/core/web/controller.js +1 -1
  219. package/packages/core/web/publication-admission-action.js +1 -8
  220. package/packages/core/web/web-surface-publication-candidate.js +2 -5
  221. package/packages/core/workflow/admission/actions.js +6 -26
  222. package/packages/core/workflow/admission/recovery.js +3 -43
  223. package/packages/core/workflow/admission/transactions.js +8 -24
  224. package/packages/core/workflow/commands/buildchain-cli-help.mjs +1 -1
  225. package/packages/core/workflow/commands/universal-workflow-engine.mjs +2 -7
  226. package/packages/core/workflow/dogfood/actions.js +0 -17
  227. package/packages/core/workflow/engine/action.js +0 -5
  228. package/packages/core/workflow/engine/conformance.js +1 -1
  229. package/packages/core/workflow/engine/execution.js +2 -6
  230. package/packages/core/workflow/engine/identity.js +1 -6
  231. package/packages/core/workflow/engine/release-environment.js +11 -35
  232. package/packages/core/workflow/engine/release-promotion.js +2 -2
  233. package/packages/core/workflow/settlement/actions.js +0 -12
  234. package/packages/core/workflow/universal-self-dogfood.js +2 -16
  235. package/packages/core/workflow/universal-workflow-bootstrap.js +16 -241
  236. package/packages/core/workflow/workflow-taxonomy.mjs +2 -2
  237. package/scripts/check-dev-delivery-actions.mjs +17 -8
  238. package/scripts/check-floating-consumer-policy-contract.mjs +6 -6
  239. package/scripts/check-inventory.mjs +1 -10
  240. package/scripts/check-public-dogfood-contract.mjs +34 -21
  241. package/scripts/check-release-topology.mjs +2 -6
  242. package/scripts/check-runtime-entry.mjs +133 -0
  243. package/scripts/check-universal-workflow-bootstrap.mjs +45 -281
  244. package/scripts/check-workflows.sh +0 -7
  245. package/scripts/generate-bootstrap-admission.mjs +1 -1
  246. package/scripts/generate-channel-promotion-workflow.mjs +4 -4
  247. package/scripts/inventory/binary.mjs +4 -4
  248. package/scripts/inventory/promotion.mjs +5 -3
  249. package/scripts/runtime-source-boundaries.mjs +70 -0
  250. package/scripts/site-capability-metadata.mjs +2 -2
  251. package/scripts/workflow-action-graph.mjs +5 -18
  252. package/scripts/workflow-self-reference.mjs +20 -0
  253. package/templates/native-dev-delivery.yml +4 -4
  254. package/templates/universal-buildchain-bootstrap.yml +12 -2
  255. package/architecture/runtime-ref-resume-authority.json +0 -64
  256. package/architecture/universal-workflow-train-admission.json +0 -76
  257. package/contracts/v4-runtime-ref-resume-authority-v1.schema.json +0 -235
  258. package/docs/v4-runtime-ref-resume-authority.md +0 -69
  259. package/packages/core/consumer/channel-selection.js +0 -211
  260. package/packages/core/consumer/commands/buildchain-channel-router.mjs +0 -81
  261. package/packages/core/consumer/invocation-selector.js +0 -4
  262. package/packages/core/consumer/runtime-ref-resume-authority.js +0 -621
  263. package/packages/core/consumer/workflow-definition-authority.js +0 -64
  264. package/packages/core/contracts/runtime-contract-action.js +0 -48
  265. package/packages/core/release/commands/promotion-identity-resolver.mjs +0 -77
  266. package/packages/core/release/commands/verify-promotion-router-binding.sh +0 -36
  267. package/packages/core/release/promotion/identities.js +0 -56
  268. package/packages/core/release/runtime-override-authorization.js +0 -242
  269. package/packages/core/runtime/commands/runtime-ref-core.mjs +0 -171
  270. package/packages/core/runtime/provider-closure.js +0 -60
  271. package/packages/core/runtime/runtime-selection-action.js +0 -34
  272. package/packages/core/runtime/runtime-selection.js +0 -136
  273. package/packages/core/runtime/workflow-runtime.js +0 -11
  274. package/packages/core/workflow/admission/review.js +0 -188
  275. package/packages/core/workflow/commands/universal-workflow-backflow.mjs +0 -26
  276. package/packages/core/workflow/installation.js +0 -33
  277. package/packages/core/workflow/settlement/backflow.js +0 -187
  278. package/scripts/generate-bootstrap-recovery.mjs +0 -94
  279. package/templates/bootstrap-recovery/actions/build/source/admit/action.yml +0 -17
  280. package/templates/bootstrap-recovery/actions/build/source/admit/dist/index.js +0 -63
  281. package/templates/bootstrap-recovery/actions/runtime/dependencies/install/action.yml +0 -18
  282. package/templates/bootstrap-recovery/actions/runtime/dependencies/install/dist/index.js +0 -63
  283. package/templates/bootstrap-recovery/actions/runtime/environment/prepare/action.yml +0 -21
  284. package/templates/bootstrap-recovery/actions/workflow/admission/inspect/action.yml +0 -27
  285. package/templates/bootstrap-recovery/actions/workflow/admission/inspect/dist/index.js +0 -64
  286. package/templates/bootstrap-recovery/actions/workflow/admission/review/action.yml +0 -15
  287. package/templates/bootstrap-recovery/actions/workflow/admission/review/dist/index.js +0 -65
  288. package/templates/bootstrap-recovery/actions/workflow/recovery/admit/action.yml +0 -47
  289. package/templates/bootstrap-recovery/actions/workflow/recovery/execute/action.yml +0 -48
  290. package/templates/bootstrap-recovery/actions/workflow/recovery/settle/action.yml +0 -54
  291. package/templates/bootstrap-recovery/actions/workflow/settlement/seal/action.yml +0 -17
  292. package/templates/bootstrap-recovery/actions/workflow/settlement/seal/dist/index.js +0 -65
  293. package/templates/bootstrap-recovery/manifest.json +0 -68
  294. package/templates/bootstrap-recovery/package.json +0 -9
  295. package/templates/universal-buildchain-bootstrap-recovery.yml +0 -115
@@ -54,9 +54,9 @@ function materializeRecoveryEvidence({
54
54
  runtimeRoot,
55
55
  recoveryRunId,
56
56
  recoveryRunAttempt,
57
- authorizationPath,
58
- authorizationJson,
59
- authorizationRoot,
57
+
58
+
59
+
60
60
  runId,
61
61
  run,
62
62
  selected,
@@ -104,9 +104,9 @@ function materializeRecoveryEvidence({
104
104
  runtimeRoot,
105
105
  recoveryRunId,
106
106
  recoveryRunAttempt,
107
- authorizationPath,
108
- authorizationJson,
109
- authorizationRoot,
107
+
108
+
109
+
110
110
  })
111
111
  : "";
112
112
  const tarballs = publication.npmArtifacts.map((entry) =>
@@ -219,7 +219,6 @@ async function qualifyRecoveredCandidate({
219
219
  publicationNames,
220
220
  bundleRoot,
221
221
  repoInfo,
222
- candidateRuntimeSha,
223
222
  publishArtifactKind,
224
223
  publishPackageMain,
225
224
  releasePatterns,
@@ -262,8 +261,7 @@ async function qualifyRecoveredCandidate({
262
261
  bundleRoot,
263
262
  repository: repoInfo.fullName,
264
263
  passport,
265
- candidateRuntimeSha,
266
- publishArtifactKind,
264
+ publishArtifactKind,
267
265
  publishPackageMain,
268
266
  releasePatterns,
269
267
  platformManifests: platformManifestEvidence.manifests,
@@ -273,8 +271,7 @@ async function qualifyRecoveredCandidate({
273
271
  rematerializeOnResume,
274
272
  });
275
273
  const stageCapsules = resolveRecoveredStageCapsules({
276
- candidateRuntimeSha,
277
- runtimeSha,
274
+ runtimeSha,
278
275
  sidecar: stageCapsuleSidecar,
279
276
  passport,
280
277
  downloads,
@@ -318,7 +315,6 @@ async function qualifyRecoveredCandidate({
318
315
  targetTree: targetCommit.tree?.sha,
319
316
  expectedSourceTree,
320
317
  expectedCandidateRoot,
321
- expectedRuntimeSha: candidateRuntimeSha,
322
318
  expectedTransactionId: transactionId,
323
319
  existingTransaction,
324
320
  run: normalizeCandidateRun(run, repoInfo.fullName),
@@ -371,7 +367,6 @@ export async function resumeFromCandidateRun({
371
367
  targetSha,
372
368
  expectedSourceTree = "",
373
369
  expectedCandidateRoot = "",
374
- candidateRuntimeSha,
375
370
  runtimeSha,
376
371
  transactionId = "",
377
372
  artifactName = "",
@@ -387,9 +382,9 @@ export async function resumeFromCandidateRun({
387
382
  recoveryRunId,
388
383
  recoveryRunAttempt = "1",
389
384
  runtimeRoot = installationRoot(import.meta.url),
390
- authorizationPath,
391
- authorizationJson,
392
- authorizationRoot,
385
+
386
+
387
+
393
388
  fetchImpl = globalThis.fetch,
394
389
  } = {}) {
395
390
  const repoInfo = splitRepository(repository);
@@ -466,8 +461,7 @@ export async function resumeFromCandidateRun({
466
461
  publicationNames,
467
462
  bundleRoot,
468
463
  repoInfo,
469
- candidateRuntimeSha,
470
- publishArtifactKind,
464
+ publishArtifactKind,
471
465
  publishPackageMain,
472
466
  releasePatterns,
473
467
  channel,
@@ -510,9 +504,9 @@ export async function resumeFromCandidateRun({
510
504
  runtimeRoot,
511
505
  recoveryRunId,
512
506
  recoveryRunAttempt,
513
- authorizationPath,
514
- authorizationJson,
515
- authorizationRoot,
507
+
508
+
509
+
516
510
  runId,
517
511
  run,
518
512
  selected,
@@ -1,6 +1,6 @@
1
1
  import { domainContentRoot } from "../../contracts/canonical-contracts.js";
2
2
  import { validateStageCapsule } from "../../build/stage-capsule.js";
3
- import { runtimeResumeDocumentRoot } from "../../consumer/runtime-ref-resume-authority.js";
3
+ import { runtimeResumeDocumentRoot } from "./lineage.js";
4
4
  export function verifyReleaseCandidateStageCapsules({
5
5
  sidecar,
6
6
  passport,
@@ -25,7 +25,6 @@ export function verifyReleaseCandidateStageCapsules({
25
25
  sidecar.source?.sha !== passport.source.headSha ||
26
26
  sidecar.source?.treeSha !== passport.source.treeHash ||
27
27
  sidecar.buildAttempt?.id !== expectedAttempt ||
28
- sidecar.buildAttempt?.runtimeSha !== passport.buildchain.sha ||
29
28
  sidecar.consumerPolicyReceiptRoot !== passport.consumerPolicy?.receiptRoot
30
29
  ) {
31
30
  throw new Error(
@@ -66,11 +65,7 @@ export function verifyReleaseCandidateStageCapsules({
66
65
  new Date(download.artifact.expires_at).toISOString() ||
67
66
  entry.capsule.identity.policyRoot !== sidecar.consumerPolicyReceiptRoot ||
68
67
  entry.capsule.identity.sourceRoot !==
69
- domainContentRoot("candidate-identity", passport.source) ||
70
- entry.capsule.identity.runtimeRoot !==
71
- domainContentRoot("candidate-identity", {
72
- sha: passport.buildchain.sha,
73
- })
68
+ domainContentRoot("candidate-identity", passport.source)
74
69
  ) {
75
70
  throw new Error(
76
71
  `Stage Capsule ${entry.platform} does not bind the verified provider artifact`,
@@ -91,12 +86,9 @@ export function verifyReleaseCandidateStageCapsules({
91
86
  }
92
87
 
93
88
  export function resolveRecoveredStageCapsules({
94
- candidateRuntimeSha,
95
- runtimeSha,
96
89
  sidecar,
97
90
  passport,
98
91
  downloads,
99
92
  }) {
100
- if (candidateRuntimeSha === runtimeSha) return [];
101
93
  return verifyReleaseCandidateStageCapsules({ sidecar, passport, downloads });
102
94
  }
@@ -0,0 +1,305 @@
1
+ import crypto from "node:crypto";
2
+ export const RUNTIME_RESUME_LINEAGE_CONTRACT =
3
+ "buildchain.runtime-resume-lineage/v2";
4
+ const EXACT_SHA = /^[0-9a-f]{40}$/u;
5
+ const SHA256_ROOT = /^sha256:[0-9a-f]{64}$/u;
6
+ const TOKEN = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/u;
7
+ function stableJson(value) {
8
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
9
+ if (value && typeof value === "object") {
10
+ return `{${Object.keys(value)
11
+ .sort()
12
+ .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`)
13
+ .join(",")}}`;
14
+ }
15
+ return JSON.stringify(value);
16
+ }
17
+
18
+ export function runtimeResumeDocumentRoot(value) {
19
+ return `sha256:${crypto.createHash("sha256").update(stableJson(value)).digest("hex")}`;
20
+ }
21
+
22
+ function exactSha(value, label) {
23
+ const normalized = String(value || "")
24
+ .trim()
25
+ .toLowerCase();
26
+ if (!EXACT_SHA.test(normalized)) {
27
+ throw new Error(`${label} must be an exact 40-character Git SHA`);
28
+ }
29
+ return normalized;
30
+ }
31
+
32
+ function root(value, label) {
33
+ const normalized = String(value || "")
34
+ .trim()
35
+ .toLowerCase();
36
+ if (!SHA256_ROOT.test(normalized)) {
37
+ throw new Error(`${label} must be a sha256 content root`);
38
+ }
39
+ return normalized;
40
+ }
41
+
42
+ function nonEmpty(value, label) {
43
+ const normalized = String(value || "").trim();
44
+ if (!normalized) throw new Error(`${label} must be non-empty`);
45
+ return normalized;
46
+ }
47
+
48
+ function token(value, label) {
49
+ const normalized = nonEmpty(value, label);
50
+ if (!TOKEN.test(normalized)) {
51
+ throw new Error(`${label} must be an ASCII identity token`);
52
+ }
53
+ return normalized;
54
+ }
55
+
56
+ function exactKeys(value, expected, label) {
57
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
58
+ throw new Error(`${label} must be an object`);
59
+ }
60
+ const actual = Object.keys(value).sort();
61
+ const canonical = [...expected].sort();
62
+ if (
63
+ actual.length !== canonical.length ||
64
+ actual.some((key, index) => key !== canonical[index])
65
+ ) {
66
+ throw new Error(`${label} has an invalid field set`);
67
+ }
68
+ }
69
+
70
+ function sortedUnique(values, label) {
71
+ if (!Array.isArray(values) || values.length === 0) {
72
+ throw new Error(`${label} must be a non-empty array`);
73
+ }
74
+ const normalized = values.map((value, index) =>
75
+ token(value, `${label}[${index}]`),
76
+ );
77
+ const expected = [...new Set(normalized)].sort((left, right) =>
78
+ Buffer.from(left).compare(Buffer.from(right)),
79
+ );
80
+ if (
81
+ normalized.length !== expected.length ||
82
+ normalized.some((value, index) => value !== expected[index])
83
+ ) {
84
+ throw new Error(`${label} must be byte-sorted and duplicate-free`);
85
+ }
86
+ return normalized;
87
+ }
88
+
89
+ export function createRuntimeResumeLineage({
90
+ repository,
91
+ buildAttempt,
92
+ resumeAttempt,
93
+ source,
94
+ consumerPolicyReceiptRoot,
95
+ requiredPlatforms,
96
+ stageCapsules,
97
+ resumePlanRoot,
98
+ finalPublicReadbackRoot,
99
+ } = {}) {
100
+ const buildId = token(buildAttempt?.id, "buildAttempt.id");
101
+ const resumeId = token(resumeAttempt?.id, "resumeAttempt.id");
102
+ if (buildId === resumeId) {
103
+ throw new Error("resume must create a new governed attempt");
104
+ }
105
+ const buildRuntimeSha = buildAttempt?.runtimeSha;
106
+ const resumeRuntimeSha = resumeAttempt?.runtimeSha;
107
+ const sourceIdentity = {
108
+ sha: exactSha(source?.sha, "source.sha"),
109
+ treeSha: exactSha(source?.treeSha, "source.treeSha"),
110
+ };
111
+ const policyRoot = root(
112
+ consumerPolicyReceiptRoot,
113
+ "consumerPolicyReceiptRoot",
114
+ );
115
+ const platforms = sortedUnique(requiredPlatforms, "requiredPlatforms");
116
+ if (!Array.isArray(stageCapsules))
117
+ throw new Error("stageCapsules must be an array");
118
+ const capsuleByPlatform = new Map();
119
+ for (const [index, capsule] of stageCapsules.entries()) {
120
+ exactKeys(
121
+ capsule,
122
+ [
123
+ "platform",
124
+ "capsuleRoot",
125
+ "identityRoot",
126
+ "artifactDigest",
127
+ "sourceSha",
128
+ "sourceTreeSha",
129
+ "policyRoot",
130
+ "buildRuntimeSha",
131
+ "sealed",
132
+ ],
133
+ `stageCapsules[${index}]`,
134
+ );
135
+ const platform = token(
136
+ capsule.platform,
137
+ `stageCapsules[${index}].platform`,
138
+ );
139
+ if (!platforms.includes(platform)) {
140
+ throw new Error(`stageCapsules[${index}] names an undeclared platform`);
141
+ }
142
+ if (capsuleByPlatform.has(platform)) {
143
+ throw new Error(`duplicate Stage Capsule for ${platform}`);
144
+ }
145
+ if (capsule.sealed !== true)
146
+ throw new Error(`Stage Capsule ${platform} is not sealed`);
147
+ if (
148
+ exactSha(capsule.sourceSha, `${platform}.sourceSha`) !==
149
+ sourceIdentity.sha ||
150
+ exactSha(capsule.sourceTreeSha, `${platform}.sourceTreeSha`) !==
151
+ sourceIdentity.treeSha ||
152
+ root(capsule.policyRoot, `${platform}.policyRoot`) !== policyRoot
153
+ ) {
154
+ throw new Error(
155
+ `Stage Capsule ${platform} identity is stale or ambiguous`,
156
+ );
157
+ }
158
+ capsuleByPlatform.set(platform, {
159
+ platform,
160
+ capsuleRoot: root(capsule.capsuleRoot, `${platform}.capsuleRoot`),
161
+ identityRoot: root(capsule.identityRoot, `${platform}.identityRoot`),
162
+ artifactDigest: root(
163
+ capsule.artifactDigest,
164
+ `${platform}.artifactDigest`,
165
+ ),
166
+ });
167
+ }
168
+ const reusedCapsules = platforms
169
+ .filter((platform) => capsuleByPlatform.has(platform))
170
+ .map((platform) => capsuleByPlatform.get(platform));
171
+ const rebuildPlatforms = platforms.filter(
172
+ (platform) => !capsuleByPlatform.has(platform),
173
+ );
174
+ const lineage = {
175
+ schemaVersion: 2,
176
+ contract: RUNTIME_RESUME_LINEAGE_CONTRACT,
177
+ status: "qualified",
178
+ repository: nonEmpty(repository, "repository"),
179
+ source: sourceIdentity,
180
+ consumerPolicyReceiptRoot: policyRoot,
181
+ attempts: {
182
+ build: { id: buildId, runtimeSha: buildRuntimeSha },
183
+ resume: { id: resumeId, runtimeSha: resumeRuntimeSha },
184
+ },
185
+
186
+ continuation: {
187
+ mechanism: "new-governed-attempt",
188
+ rerunFailedJobs: false,
189
+ resumePlanRoot: root(resumePlanRoot, "resumePlanRoot"),
190
+ },
191
+ stageCapsules: {
192
+ requiredPlatforms: platforms,
193
+ reused: reusedCapsules,
194
+ rebuildPlatforms,
195
+ },
196
+ finalPublicReadbackRoot: root(
197
+ finalPublicReadbackRoot,
198
+ "finalPublicReadbackRoot",
199
+ ),
200
+ };
201
+ return { lineage, lineageRoot: runtimeResumeDocumentRoot(lineage) };
202
+ }
203
+
204
+ function validSourceIdentity(source) {
205
+ return (
206
+ EXACT_SHA.test(String(source?.sha || "")) &&
207
+ EXACT_SHA.test(String(source?.treeSha || ""))
208
+ );
209
+ }
210
+
211
+ function platformLineageFailures(stageCapsules) {
212
+ const failures = [];
213
+ const required = stageCapsules?.requiredPlatforms || [];
214
+ const reused = stageCapsules?.reused || [];
215
+ const rebuilt = stageCapsules?.rebuildPlatforms || [];
216
+ const requiredCanonical = [...new Set(required)].sort();
217
+ const reusedPlatforms = reused.map((entry) => entry.platform);
218
+ const rebuiltCanonical = [...new Set(rebuilt)].sort();
219
+ if (
220
+ required.length === 0 ||
221
+ required.length !== requiredCanonical.length ||
222
+ !required.every((platform, index) => platform === requiredCanonical[index])
223
+ ) {
224
+ failures.push("required-platforms-invalid");
225
+ }
226
+ if (
227
+ reusedPlatforms.length !== new Set(reusedPlatforms).size ||
228
+ rebuilt.length !== rebuiltCanonical.length ||
229
+ !reusedPlatforms.every((platform) => !rebuilt.includes(platform))
230
+ ) {
231
+ failures.push("platform-lineage-ambiguous");
232
+ }
233
+ if (
234
+ [...reusedPlatforms, ...rebuilt].sort().join("\0") !==
235
+ [...required].sort().join("\0")
236
+ ) {
237
+ failures.push("platform-lineage-incomplete");
238
+ }
239
+ if (
240
+ !reused.every((entry) =>
241
+ [entry.capsuleRoot, entry.identityRoot, entry.artifactDigest].every(
242
+ (value) => SHA256_ROOT.test(String(value || "")),
243
+ ),
244
+ )
245
+ ) {
246
+ failures.push("capsule-root-invalid");
247
+ }
248
+ return failures;
249
+ }
250
+
251
+ export function verifyRuntimeResumeLineage({
252
+ lineage,
253
+ lineageRoot,
254
+ repository = "",
255
+ sourceSha = "",
256
+ consumerPolicyReceiptRoot = "",
257
+ } = {}) {
258
+ const failures = [];
259
+ const check = (condition, code) => {
260
+ if (!condition) failures.push(code);
261
+ };
262
+ check(
263
+ lineage?.contract === RUNTIME_RESUME_LINEAGE_CONTRACT,
264
+ "contract-invalid",
265
+ );
266
+ check(lineage?.status === "qualified", "status-not-qualified");
267
+ check(
268
+ SHA256_ROOT.test(String(lineageRoot || "")) &&
269
+ lineageRoot === runtimeResumeDocumentRoot(lineage),
270
+ "lineage-root-mismatch",
271
+ );
272
+ check(
273
+ lineage?.attempts?.build?.id &&
274
+ lineage?.attempts?.resume?.id &&
275
+ lineage.attempts.build.id !== lineage.attempts.resume.id,
276
+ "attempt-not-fresh",
277
+ );
278
+ check(validSourceIdentity(lineage?.source), "source-identity-invalid");
279
+ check(
280
+ lineage?.continuation?.mechanism === "new-governed-attempt" &&
281
+ lineage?.continuation?.rerunFailedJobs === false,
282
+ "continuation-mechanism-invalid",
283
+ );
284
+ failures.push(...platformLineageFailures(lineage?.stageCapsules));
285
+ check(
286
+ [
287
+ lineage?.consumerPolicyReceiptRoot,
288
+ lineage?.continuation?.resumePlanRoot,
289
+ lineage?.finalPublicReadbackRoot,
290
+ ].every((value) => SHA256_ROOT.test(String(value || ""))),
291
+ "evidence-root-invalid",
292
+ );
293
+ if (sourceSha)
294
+ check(lineage?.source?.sha === sourceSha, "source-sha-mismatch");
295
+ if (consumerPolicyReceiptRoot) {
296
+ check(
297
+ lineage?.consumerPolicyReceiptRoot === consumerPolicyReceiptRoot,
298
+ "consumer-policy-root-mismatch",
299
+ );
300
+ }
301
+ if (repository) {
302
+ check(lineage?.repository === repository, "repository-mismatch");
303
+ }
304
+ return { ok: failures.length === 0, failures };
305
+ }
@@ -36,8 +36,7 @@ export function resolveAnchorRecoveryRequest({
36
36
  !/^[0-9a-f]{40}$/u.test(String(request.supersededCandidate?.sha || "")) ||
37
37
  !/^sha256:[0-9a-f]{64}$/u.test(
38
38
  String(request.supersededCandidate?.root || ""),
39
- ) ||
40
- request.runtime?.sha !== passport.buildchain?.sha
39
+ )
41
40
  ) {
42
41
  throw new Error(
43
42
  "anchored candidate request does not bind the sealed recovery identity",
@@ -13,20 +13,14 @@ export function createRecoveredPublicationCandidate({
13
13
  allFiles,
14
14
  repository,
15
15
  passport,
16
- candidateRuntimeSha,
17
16
  }) {
18
- if (passport.buildchain?.sha !== candidateRuntimeSha) {
19
- throw new Error(
20
- `recovered publication candidate runtime mismatch: passport=${passport.buildchain?.sha || "<empty>"} expected=${candidateRuntimeSha || "<empty>"}`,
21
- );
22
- }
23
17
  const payload = {
24
18
  schemaVersion: 1,
25
19
  contract: PUBLICATION_ARTIFACT_CANDIDATE_CONTRACT,
26
20
  repository,
27
21
  sourceSha: passport.source.headSha,
28
22
  sourceTreeSha: passport.source.treeHash,
29
- runtimeSha: candidateRuntimeSha,
23
+ runtimeSha: passport.buildchain?.sha,
30
24
  releaseCandidateRoot: `sha256:${passport.candidateHash}`,
31
25
  files: allFiles.map(({ path: filePath, size, sha256 }) => ({
32
26
  path: filePath,
@@ -45,7 +39,6 @@ export function createRecoveredPublication({
45
39
  bundleRoot,
46
40
  repository,
47
41
  passport,
48
- candidateRuntimeSha,
49
42
  publishArtifactKind,
50
43
  publishPackageMain,
51
44
  releasePatterns,
@@ -78,8 +71,7 @@ export function createRecoveredPublication({
78
71
  allFiles,
79
72
  repository,
80
73
  passport,
81
- candidateRuntimeSha,
82
- });
74
+ });
83
75
  const sealed = resolveOciCandidate({ payloadRoot: bundleRoot, passport });
84
76
  return {
85
77
  manifest: sealed.manifest,
@@ -97,8 +89,7 @@ export function createRecoveredPublication({
97
89
  allFiles,
98
90
  repository,
99
91
  passport,
100
- candidateRuntimeSha,
101
- });
92
+ });
102
93
  const version = String(passport.target?.version || "").trim();
103
94
  if (!version)
104
95
  throw new Error(
@@ -163,8 +154,7 @@ export function createRecoveredPublication({
163
154
  allFiles,
164
155
  repository,
165
156
  passport,
166
- candidateRuntimeSha,
167
- });
157
+ });
168
158
  const manifest = createPublicationSealedBundle({
169
159
  candidate,
170
160
  packageName: main.metadata.name,
@@ -1,23 +1,22 @@
1
1
  import path from "node:path";
2
2
  import { compareSemver } from "../../publication/candidate/registry-hydration.js";
3
3
  import { githubJson } from "./../candidate/transport.js";
4
- import { runtimeResumeDocumentRoot } from "../../consumer/runtime-ref-resume-authority.js";
4
+ import { runtimeResumeDocumentRoot } from "./lineage.js";
5
5
  export function validateRuntimeResumePublicReadback({
6
6
  targetRef,
7
7
  targetSha,
8
8
  targetVersion,
9
- alphaSha,
9
+ floatingSha,
10
10
  exactTagSha,
11
11
  tagLineage,
12
- runtimeLineage,
13
12
  floatingTargetLineage,
14
- runtimeSha,
15
13
  version,
16
14
  transaction,
17
15
  main,
18
16
  npm,
19
17
  }) {
20
- const channelVersion = npm["dist-tags"]?.alpha;
18
+ const distTag = version.includes("-") ? "alpha" : "latest";
19
+ const channelVersion = npm["dist-tags"]?.[distTag];
21
20
  let channelDidNotRegress = false;
22
21
  try {
23
22
  channelDidNotRegress = compareSemver(channelVersion, version) >= 0;
@@ -29,18 +28,16 @@ export function validateRuntimeResumePublicReadback({
29
28
  transaction?.version !== version ||
30
29
  exactTagSha !== transaction?.source_sha ||
31
30
  !["ahead", "identical"].includes(tagLineage?.status) ||
32
- !["ahead", "identical"].includes(runtimeLineage?.status) ||
33
31
  !["ahead", "identical"].includes(floatingTargetLineage?.status) ||
34
- !alphaSha ||
32
+ !floatingSha ||
35
33
  !targetSha ||
36
- !runtimeSha ||
37
34
  channelVersion !== targetVersion ||
38
35
  !channelDidNotRegress ||
39
36
  !npm.versions?.[channelVersion]?.dist?.integrity ||
40
37
  npm.versions?.[version]?.dist?.integrity !== main.digest
41
38
  ) {
42
39
  throw new Error(
43
- "cross-runtime final public readback does not match durable publication bytes and runtime",
40
+ "cross-runtime final public readback does not match durable publication bytes",
44
41
  );
45
42
  }
46
43
  }
@@ -48,7 +45,6 @@ export function validateRuntimeResumePublicReadback({
48
45
  export async function readPublicResumeState({
49
46
  repoInfo,
50
47
  targetRef,
51
- runtimeSha,
52
48
  version,
53
49
  transaction,
54
50
  token,
@@ -73,9 +69,11 @@ export async function readPublicResumeState({
73
69
  );
74
70
  const packageUrl = `https://registry.npmjs.org/${encodeURIComponent(main.name)}`;
75
71
  const exactTag = transaction.exact_tag || `v${version}`;
76
- const [targetSha, alphaSha, exactTagSha, npmResponse] = await Promise.all([
72
+ const floatingRef = `v${version.split(".")[0]}${version.includes("-") ? "-alpha" : ""}`;
73
+ const distTag = version.includes("-") ? "alpha" : "latest";
74
+ const [targetSha, floatingSha, exactTagSha, npmResponse] = await Promise.all([
77
75
  readRef(`heads/${targetRef}`),
78
- readRef("tags/v4-alpha"),
76
+ readRef(`tags/${floatingRef}`),
79
77
  readRef(`tags/${exactTag}`),
80
78
  fetchImpl(packageUrl),
81
79
  ]);
@@ -85,7 +83,7 @@ export async function readPublicResumeState({
85
83
  );
86
84
  }
87
85
  const npm = await npmResponse.json();
88
- const [tagLineage, runtimeLineage, floatingTargetLineage, targetPackageFile] =
86
+ const [tagLineage, floatingTargetLineage, targetPackageFile] =
89
87
  await Promise.all([
90
88
  githubJson({
91
89
  apiUrl,
@@ -97,13 +95,7 @@ export async function readPublicResumeState({
97
95
  apiUrl,
98
96
  token,
99
97
  fetchImpl,
100
- path: `/repos/${repoInfo.owner}/${repoInfo.repo}/compare/${runtimeSha}...${alphaSha}`,
101
- }),
102
- githubJson({
103
- apiUrl,
104
- token,
105
- fetchImpl,
106
- path: `/repos/${repoInfo.owner}/${repoInfo.repo}/compare/${alphaSha}...${targetSha}`,
98
+ path: `/repos/${repoInfo.owner}/${repoInfo.repo}/compare/${floatingSha}...${targetSha}`,
107
99
  }),
108
100
  githubJson({
109
101
  apiUrl,
@@ -130,13 +122,11 @@ export async function readPublicResumeState({
130
122
  targetRef,
131
123
  targetSha,
132
124
  targetVersion,
133
- alphaSha,
125
+ floatingSha,
134
126
  exactTagSha,
135
127
  tagLineage,
136
- runtimeLineage,
137
- floatingTargetLineage,
138
- runtimeSha,
139
- version,
128
+ floatingTargetLineage,
129
+ version,
140
130
  transaction,
141
131
  main,
142
132
  npm,
@@ -149,21 +139,18 @@ export async function readPublicResumeState({
149
139
  version,
150
140
  refs: {
151
141
  target: { ref: targetRef, sha: targetSha },
152
- floating: { ref: "v4-alpha", sha: alphaSha },
142
+ floating: { ref: floatingRef, sha: floatingSha },
153
143
  exactTag: { ref: exactTag, sha: exactTagSha },
154
144
  },
155
145
  npm: {
156
146
  package: main.name,
157
147
  version,
158
- distTag: "alpha",
148
+ distTag,
159
149
  integrity: npm.versions[version].dist.integrity,
160
150
  targetVersion,
161
- distTagVersion: npm["dist-tags"].alpha,
162
- distTagIntegrity: npm.versions[npm["dist-tags"].alpha].dist.integrity,
151
+ distTagVersion: npm["dist-tags"][distTag],
152
+ distTagIntegrity: npm.versions[npm["dist-tags"][distTag]].dist.integrity,
163
153
  },
164
154
  };
165
155
  return { ...body, root: runtimeResumeDocumentRoot(body) };
166
156
  }
167
-
168
- export const resolveRuntimeResumePublicRuntimeSha = (material) =>
169
- material?.buildAttempt?.runtimeSha || "";