@kungfu-tech/buildchain 4.1.0-alpha.0 → 4.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) 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 +111 -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 +1 -5
  160. package/packages/core/publication/authority/assembly.js +1 -6
  161. package/packages/core/publication/authority/governance.js +2 -9
  162. package/packages/core/publication/authority/verification.js +2 -17
  163. package/packages/core/publication/binary/action.js +5 -7
  164. package/packages/core/publication/candidate/qualification-action.js +1 -6
  165. package/packages/core/publication/candidate/stage-capsules.js +1 -1
  166. package/packages/core/publication/npm/preview-action.js +9 -15
  167. package/packages/core/publication/oci/preview-actions.js +1 -10
  168. package/packages/core/publication/publication-artifact-candidate.js +2 -2
  169. package/packages/core/publication/publication-authority.js +2 -2
  170. package/packages/core/publication/publication-rehearsal-projection.js +3 -3
  171. package/packages/core/publication/settlement/actions.js +2 -11
  172. package/packages/core/release/binary/coordinates-action.js +0 -13
  173. package/packages/core/release/binary/coordinates.js +2 -19
  174. package/packages/core/release/commands/promotion-channel-router.mjs +12 -56
  175. package/packages/core/release/commands/resume-from-candidate-run.mjs +2 -3
  176. package/packages/core/release/dev-alpha-active-release-train.js +0 -5
  177. package/packages/core/release/line/action.js +2 -13
  178. package/packages/core/release/next-development/actions.js +2 -5
  179. package/packages/core/release/passport/consumer-validation.js +1 -28
  180. package/packages/core/release/promote-candidate/development-source.js +7 -8
  181. package/packages/core/release/promotion/actions.js +7 -38
  182. package/packages/core/release/promotion/admission.js +3 -50
  183. package/packages/core/release/promotion/candidate.js +2 -4
  184. package/packages/core/release/promotion/channel.js +13 -101
  185. package/packages/core/release/promotion/qualification-action.js +2 -13
  186. package/packages/core/release/promotion/routing.js +16 -81
  187. package/packages/core/release/promotion/selection.js +1 -9
  188. package/packages/core/release/promotion-request.js +1 -40
  189. package/packages/core/release/qualification/actions.js +0 -8
  190. package/packages/core/release/qualification/public-build.js +1 -1
  191. package/packages/core/release/recovery/candidate.js +15 -21
  192. package/packages/core/release/recovery/capsules.js +2 -10
  193. package/packages/core/release/recovery/lineage.js +305 -0
  194. package/packages/core/release/recovery/provenance.js +1 -2
  195. package/packages/core/release/recovery/publication.js +4 -14
  196. package/packages/core/release/recovery/readback.js +19 -32
  197. package/packages/core/release/recovery/runtime.js +4 -95
  198. package/packages/core/release/release-candidate-recovery.js +4 -9
  199. package/packages/core/release/release-candidate.js +2 -5
  200. package/packages/core/release/reseal/actions.js +3 -22
  201. package/packages/core/release/reseal/admission.js +0 -2
  202. package/packages/core/release/reseal/finalize-platform.js +0 -2
  203. package/packages/core/release/tail-reseal-github.js +1 -2
  204. package/packages/core/release/tail-reseal-receipt.js +0 -1
  205. package/packages/core/release/tail-reseal.js +2 -20
  206. package/packages/core/release/version-state.js +4 -13
  207. package/packages/core/runtime/buildchain-domain.wasm +0 -0
  208. package/packages/core/runtime/checkout-identity.js +0 -13
  209. package/packages/core/runtime/domain-wasm-artifact.js +2 -2
  210. package/packages/core/runtime/entry/actions.js +121 -0
  211. package/packages/core/runtime/entry/activation.js +86 -0
  212. package/packages/core/runtime/entry/github.js +52 -0
  213. package/packages/core/runtime/entry/recovery.js +37 -0
  214. package/packages/core/runtime/entry/selection.js +110 -0
  215. package/packages/core/web/controller.js +1 -1
  216. package/packages/core/web/publication-admission-action.js +1 -8
  217. package/packages/core/web/web-surface-publication-candidate.js +2 -5
  218. package/packages/core/workflow/admission/actions.js +6 -26
  219. package/packages/core/workflow/admission/recovery.js +3 -43
  220. package/packages/core/workflow/admission/transactions.js +8 -24
  221. package/packages/core/workflow/commands/buildchain-cli-help.mjs +1 -1
  222. package/packages/core/workflow/commands/universal-workflow-engine.mjs +2 -7
  223. package/packages/core/workflow/dogfood/actions.js +0 -17
  224. package/packages/core/workflow/engine/action.js +0 -5
  225. package/packages/core/workflow/engine/conformance.js +1 -1
  226. package/packages/core/workflow/engine/execution.js +2 -6
  227. package/packages/core/workflow/engine/identity.js +1 -6
  228. package/packages/core/workflow/engine/release-environment.js +11 -35
  229. package/packages/core/workflow/engine/release-promotion.js +2 -2
  230. package/packages/core/workflow/settlement/actions.js +0 -12
  231. package/packages/core/workflow/universal-self-dogfood.js +2 -16
  232. package/packages/core/workflow/universal-workflow-bootstrap.js +16 -241
  233. package/packages/core/workflow/workflow-taxonomy.mjs +2 -2
  234. package/scripts/check-dev-delivery-actions.mjs +17 -8
  235. package/scripts/check-floating-consumer-policy-contract.mjs +6 -6
  236. package/scripts/check-inventory.mjs +1 -10
  237. package/scripts/check-public-dogfood-contract.mjs +34 -21
  238. package/scripts/check-release-topology.mjs +2 -6
  239. package/scripts/check-runtime-entry.mjs +133 -0
  240. package/scripts/check-universal-workflow-bootstrap.mjs +45 -281
  241. package/scripts/check-workflows.sh +0 -7
  242. package/scripts/generate-bootstrap-admission.mjs +1 -1
  243. package/scripts/generate-channel-promotion-workflow.mjs +4 -4
  244. package/scripts/inventory/binary.mjs +4 -4
  245. package/scripts/inventory/promotion.mjs +5 -3
  246. package/scripts/runtime-source-boundaries.mjs +70 -0
  247. package/scripts/site-capability-metadata.mjs +2 -2
  248. package/scripts/workflow-action-graph.mjs +5 -18
  249. package/scripts/workflow-self-reference.mjs +20 -0
  250. package/templates/native-dev-delivery.yml +4 -4
  251. package/templates/universal-buildchain-bootstrap.yml +12 -2
  252. package/architecture/runtime-ref-resume-authority.json +0 -64
  253. package/architecture/universal-workflow-train-admission.json +0 -76
  254. package/contracts/v4-runtime-ref-resume-authority-v1.schema.json +0 -235
  255. package/docs/v4-runtime-ref-resume-authority.md +0 -69
  256. package/packages/core/consumer/channel-selection.js +0 -211
  257. package/packages/core/consumer/commands/buildchain-channel-router.mjs +0 -81
  258. package/packages/core/consumer/invocation-selector.js +0 -4
  259. package/packages/core/consumer/runtime-ref-resume-authority.js +0 -621
  260. package/packages/core/consumer/workflow-definition-authority.js +0 -64
  261. package/packages/core/contracts/runtime-contract-action.js +0 -48
  262. package/packages/core/release/commands/promotion-identity-resolver.mjs +0 -77
  263. package/packages/core/release/commands/verify-promotion-router-binding.sh +0 -36
  264. package/packages/core/release/promotion/identities.js +0 -56
  265. package/packages/core/release/runtime-override-authorization.js +0 -242
  266. package/packages/core/runtime/commands/runtime-ref-core.mjs +0 -171
  267. package/packages/core/runtime/provider-closure.js +0 -60
  268. package/packages/core/runtime/runtime-selection-action.js +0 -34
  269. package/packages/core/runtime/runtime-selection.js +0 -136
  270. package/packages/core/runtime/workflow-runtime.js +0 -11
  271. package/packages/core/workflow/admission/review.js +0 -188
  272. package/packages/core/workflow/commands/universal-workflow-backflow.mjs +0 -26
  273. package/packages/core/workflow/installation.js +0 -33
  274. package/packages/core/workflow/settlement/backflow.js +0 -187
  275. package/scripts/generate-bootstrap-recovery.mjs +0 -94
  276. package/templates/bootstrap-recovery/actions/build/source/admit/action.yml +0 -17
  277. package/templates/bootstrap-recovery/actions/build/source/admit/dist/index.js +0 -63
  278. package/templates/bootstrap-recovery/actions/runtime/dependencies/install/action.yml +0 -18
  279. package/templates/bootstrap-recovery/actions/runtime/dependencies/install/dist/index.js +0 -63
  280. package/templates/bootstrap-recovery/actions/runtime/environment/prepare/action.yml +0 -21
  281. package/templates/bootstrap-recovery/actions/workflow/admission/inspect/action.yml +0 -27
  282. package/templates/bootstrap-recovery/actions/workflow/admission/inspect/dist/index.js +0 -64
  283. package/templates/bootstrap-recovery/actions/workflow/admission/review/action.yml +0 -15
  284. package/templates/bootstrap-recovery/actions/workflow/admission/review/dist/index.js +0 -65
  285. package/templates/bootstrap-recovery/actions/workflow/recovery/admit/action.yml +0 -47
  286. package/templates/bootstrap-recovery/actions/workflow/recovery/execute/action.yml +0 -48
  287. package/templates/bootstrap-recovery/actions/workflow/recovery/settle/action.yml +0 -54
  288. package/templates/bootstrap-recovery/actions/workflow/settlement/seal/action.yml +0 -17
  289. package/templates/bootstrap-recovery/actions/workflow/settlement/seal/dist/index.js +0 -65
  290. package/templates/bootstrap-recovery/manifest.json +0 -68
  291. package/templates/bootstrap-recovery/package.json +0 -9
  292. package/templates/universal-buildchain-bootstrap-recovery.yml +0 -115
@@ -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 || "";