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

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 (281) hide show
  1. package/AGENTS.md +14 -5
  2. package/CONTRIBUTING.md +58 -0
  3. package/README.md +3 -3
  4. package/actions/promote-buildchain-ref/README.md +1 -1
  5. package/actions/release-candidate-promote/README.md +31 -0
  6. package/architecture/agent-change-map.md +190 -126
  7. package/architecture/{v4-architecture-constitution.md → architecture-constitution.md} +33 -30
  8. package/architecture/{v3-core-mechanism-inventory.md → baseline-core-mechanism-inventory.md} +1 -1
  9. package/architecture/{v4-bootstrap-authority.json → bootstrap-authority.json} +3 -3
  10. package/architecture/{v3-v4-capability-closure.md → capability-parity-closure.md} +3 -3
  11. package/architecture/{v3-v4-live-capability-inventory.json → capability-parity-live-capability-inventory.json} +4 -4
  12. package/architecture/{v4-capability-state-machine-manifest.json → capability-state-machine-manifest.json} +2 -2
  13. package/architecture/{v4-capability-state-machine-manifest.schema.json → capability-state-machine-manifest.schema.json} +2 -2
  14. package/architecture/ci-lane-change-budget.json +384 -0
  15. package/architecture/{v4-cross-platform-adopter-qualification.json → cross-platform-adopter-qualification.json} +4 -4
  16. package/architecture/{v4-delivery-authority-parity.json → delivery-authority-parity.json} +17 -17
  17. package/architecture/{v4-delivery-warrant-shadow-bootstrap-plan.json → delivery-warrant-shadow-bootstrap-plan.json} +4 -4
  18. package/architecture/{v4-delivery-warrant-shadow-bootstrap-plan.md → delivery-warrant-shadow-bootstrap-plan.md} +7 -7
  19. package/architecture/{v4-floating-consumer-policy.json → floating-consumer-policy.json} +2 -2
  20. package/architecture/{v4-floating-consumer-policy.md → floating-consumer-policy.md} +1 -1
  21. package/architecture/implementation-naming.json +1273 -0
  22. package/architecture/internal-capabilities.json +201 -154
  23. package/architecture/maintainability-debt.json +205 -146
  24. package/architecture/maintainability-policy.json +37 -33
  25. package/architecture/{v4-next-development-parity.json → next-development-parity.json} +12 -12
  26. package/architecture/{v4-partial-mutation-recovery-qualification.json → partial-mutation-recovery-qualification.json} +8 -5
  27. package/architecture/{v4-platform-stage-checkpoints.json → platform-stage-checkpoints.json} +3 -3
  28. package/architecture/{v4-provider-operation-journal-contract.json → provider-operation-journal-contract.json} +10 -7
  29. package/architecture/publication-facade-patches.json +64 -0
  30. package/architecture/{v4-publication-rehearsal-parity.json → publication-rehearsal-parity.json} +4 -4
  31. package/architecture/{v4-release-activation-shadow-domain.json → release-activation-shadow-domain.json} +9 -6
  32. package/architecture/release-tail-contract-inventory.json +6 -6
  33. package/architecture/{v4-release-topology.json → release-topology.json} +163 -72
  34. package/architecture/{v4-release-train-parity.json → release-train-parity.json} +2 -2
  35. package/architecture/{v4-runtime-ref-resume-authority.json → runtime-ref-resume-authority.json} +1 -1
  36. package/architecture/{v4-runtime-semantic-closure.json → runtime-semantic-closure.json} +2 -2
  37. package/architecture/{v4-rust-libnode-bridge-evaluation.json → rust-libnode-bridge-evaluation.json} +3 -3
  38. package/architecture/{v4-rust-libnode-bridge-spike.md → rust-libnode-bridge-spike.md} +6 -6
  39. package/architecture/rust-wasm-production-authority.json +58 -0
  40. package/architecture/{v4-stable-publication-fence.json → stable-publication-fence.json} +7 -4
  41. package/architecture/{v4-stage-capsule-contract.json → stage-capsule-contract.json} +1 -1
  42. package/architecture/{v4-stage-capsule-qualification.json → stage-capsule-qualification.json} +8 -8
  43. package/architecture/{v4-stage-capsule-resume-planner.json → stage-capsule-resume-planner.json} +2 -2
  44. package/architecture/{v4-stage-capsule-store-contract.json → stage-capsule-store-contract.json} +4 -4
  45. package/architecture/{v4-tail-reseal-parity.json → tail-reseal-parity.json} +35 -33
  46. package/architecture/universal-workflow-bootstrap.json +176 -0
  47. package/architecture/universal-workflow-fault-campaign.json +72 -0
  48. package/architecture/universal-workflow-train-admission.json +40 -0
  49. package/architecture/workflow-taxonomy.json +1462 -0
  50. package/bin/buildchain.mjs +10 -10
  51. package/bin/internal/adopter-delivery-cli.mjs +9 -9
  52. package/contracts/buildchain-v2-residuals-v1.json +57 -48
  53. package/contracts/dev-delivery-authority-v2.schema.json +16 -2
  54. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
  55. package/contracts/v4-canonical-contracts-v1.schema.json +1 -0
  56. package/crates/{buildchain-v4-bridge → buildchain-host-bridge}/Cargo.lock +1 -1
  57. package/crates/{buildchain-v4-bridge → buildchain-host-bridge}/Cargo.toml +1 -1
  58. package/crates/{buildchain-v4-bridge → buildchain-host-bridge}/src/main.rs +3 -3
  59. package/dist/site/buildchain-contract.json +98 -53
  60. package/dist/site/buildchain-site.json +351 -102
  61. package/dist/site/capability-registry.json +7 -7
  62. package/dist/site/controller-registry.json +50 -13
  63. package/dist/site/kfd-claims.json +2773 -1052
  64. package/dist/site/kfd-upstream-aggregate.json +1 -1
  65. package/dist/site/manual-registry.json +14 -14
  66. package/dist/site/node-api-registry.json +13176 -10733
  67. package/dist/site/page-registry.json +332 -83
  68. package/dist/site/public-surface-audit.json +3227 -1222
  69. package/dist/site/publication-authority-registry.json +1135 -363
  70. package/dist/site/publication-registry.json +4 -4
  71. package/dist/site/release-provenance.json +18 -9
  72. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +16 -2
  73. package/dist/site/site-manifest.json +18 -18
  74. package/dist/site/workflow-registry.json +5367 -1931
  75. package/docs/MAP.md +5 -3
  76. package/docs/auditable-demo.md +1 -1
  77. package/docs/cli.md +21 -8
  78. package/docs/dev-delivery-warrant.md +1 -1
  79. package/docs/engineering-housekeeper.md +3 -3
  80. package/docs/kfd-support.md +26 -2
  81. package/docs/next-development-transition.md +26 -3
  82. package/docs/node-api-reference.md +618 -358
  83. package/docs/oci-publication.md +173 -0
  84. package/docs/publication-authority.md +2 -2
  85. package/docs/publish-transaction.md +36 -3
  86. package/docs/release-candidate.md +3 -3
  87. package/docs/release-flow.md +67 -19
  88. package/docs/release-governance.md +8 -8
  89. package/docs/release-passport.md +27 -2
  90. package/docs/reusable-build-surface.md +17 -1
  91. package/docs/v4-adopter-delivery.md +4 -4
  92. package/docs/v4-canonical-contracts.md +7 -7
  93. package/docs/v4-delivery-warrant-read-candidate.md +3 -3
  94. package/docs/v4-delivery-warrant-semantic-diff.md +3 -3
  95. package/docs/v4-production-release.md +77 -8
  96. package/docs/v4-publication-rehearsal.md +3 -3
  97. package/docs/v4-runtime-ref-resume-authority.md +2 -2
  98. package/docs/v4-rust-wasm-production-authority.md +58 -0
  99. package/docs/v4-stage-capsule.md +9 -9
  100. package/docs/v4-tail-reseal.md +2 -2
  101. package/docs/workflow-catalog.md +155 -0
  102. package/docs/workflow-path-migration.md +109 -0
  103. package/package.json +39 -24
  104. package/packages/compatibility/adopter-delivery.js +16 -0
  105. package/packages/compatibility/cross-platform-adopter-qualification.js +12 -0
  106. package/packages/compatibility/floating-consumer-policy.js +14 -0
  107. package/packages/compatibility/publication-qualification.js +11 -0
  108. package/packages/compatibility/publication-rehearsal.js +18 -0
  109. package/packages/compatibility/runtime-ref-resume-authority.js +13 -0
  110. package/packages/compatibility/tail-reseal-receipt.js +7 -0
  111. package/packages/compatibility/tail-reseal.js +11 -0
  112. package/packages/core/{v4-adopter-delivery-parity.js → adopter-delivery-parity.js} +12 -12
  113. package/packages/core/{v4-adopter-delivery.js → adopter-delivery.js} +24 -24
  114. package/packages/core/artifact-verification-envelope.js +5 -5
  115. package/packages/core/buildchain-contract.js +6 -6
  116. package/packages/core/buildchain-domain.wasm +0 -0
  117. package/packages/core/buildchain-kfd-claims.js +2 -2
  118. package/packages/core/buildchain-publication-authority.js +43 -26
  119. package/packages/core/{v4-canonical-contracts.js → canonical-contracts.js} +39 -103
  120. package/packages/core/ci-lane-change-budget.js +14 -1
  121. package/packages/core/controller-evidence.js +4 -1
  122. package/packages/core/{v4-cross-platform-adopter-qualification.js → cross-platform-adopter-qualification.js} +19 -19
  123. package/packages/core/{v4-delivery-warrant-fixture-runner.js → delivery-warrant-fixture-runner.js} +36 -32
  124. package/packages/core/{v4-delivery-warrant-read-candidate.js → delivery-warrant-read-candidate.js} +40 -40
  125. package/packages/core/{v4-delivery-warrant-semantic-diff-gate.js → delivery-warrant-semantic-diff-gate.js} +58 -59
  126. package/packages/core/{v4-delivery-warrant-shadow-adapter.js → delivery-warrant-shadow-adapter.js} +15 -15
  127. package/packages/core/dev-delivery-candidate-identity.js +40 -6
  128. package/packages/core/dev-delivery-execution-transfer.js +6 -6
  129. package/packages/core/dev-delivery-native-proof.js +12 -8
  130. package/packages/core/dev-delivery-warrant-legacy-recovery.js +1 -1
  131. package/packages/core/dev-delivery-warrant-native-compatibility.js +4 -4
  132. package/packages/core/dev-delivery-warrant-state.js +14 -15
  133. package/packages/core/dev-delivery-warrant.js +15 -5
  134. package/packages/core/domain-wasm-artifact.js +7 -0
  135. package/packages/core/domain-wasm.js +216 -0
  136. package/packages/core/{v4-floating-consumer-evidence.js → floating-consumer-evidence.js} +14 -14
  137. package/packages/core/{v4-floating-consumer-policy.js → floating-consumer-policy.js} +28 -30
  138. package/packages/core/{v4-floating-consumer-release-passport.js → floating-consumer-release-passport.js} +25 -25
  139. package/packages/core/github-governance-authority.js +4 -4
  140. package/packages/core/index.js +4 -8
  141. package/packages/core/kfd-adopter-manifest.js +46 -47
  142. package/packages/core/next-development-projection.js +26 -3
  143. package/packages/core/next-development-transition.js +5 -6
  144. package/packages/core/oci-compose-qualification.js +143 -0
  145. package/packages/core/oci-publication-bundle.js +281 -0
  146. package/packages/core/oci-publication-graph.js +206 -0
  147. package/packages/core/paper-agent-entry.js +30 -4
  148. package/packages/core/paper-fleet.js +1 -1
  149. package/packages/core/paper-runtime-channels.js +348 -0
  150. package/packages/core/paper-scaffold-content.js +10 -0
  151. package/packages/core/paper.js +37 -71
  152. package/packages/core/partial-mutation-recovery-qualification.js +18 -0
  153. package/packages/core/{v4-platform-stage-checkpoints.js → platform-stage-checkpoints.js} +37 -37
  154. package/packages/core/product-publication.js +59 -0
  155. package/packages/core/{v4-protected-publication-source.js → protected-publication-source.js} +22 -24
  156. package/packages/core/provider-operation-journal.js +62 -0
  157. package/packages/core/{v4-provider-readback-idempotency.js → provider-readback-idempotency.js} +40 -125
  158. package/packages/core/public-export-compatibility.js +33 -0
  159. package/packages/core/publication-development.js +72 -0
  160. package/packages/core/{v4-publication-qualification.js → publication-qualification.js} +17 -17
  161. package/packages/core/{v4-publication-rehearsal-capsule.js → publication-rehearsal-capsule.js} +23 -23
  162. package/packages/core/publication-rehearsal-projection.js +2 -2
  163. package/packages/core/{v4-publication-rehearsal-provider-bindings.js → publication-rehearsal-provider-bindings.js} +4 -4
  164. package/packages/core/publication-rehearsal-runtime.js +21 -21
  165. package/packages/core/{v4-publication-rehearsal.js → publication-rehearsal.js} +33 -33
  166. package/packages/core/publication-sealed-bundle.js +78 -13
  167. package/packages/core/release-activation-shadow.js +32 -0
  168. package/packages/core/release-candidate.js +6 -6
  169. package/packages/core/release-invocation.js +64 -0
  170. package/packages/core/release-line-dry-run.js +1 -1
  171. package/packages/core/release-passport-contract.js +5 -5
  172. package/packages/core/release-passport.js +41 -40
  173. package/packages/core/release-tail-product-capabilities.js +9 -0
  174. package/packages/core/release-tail-provider-plane.js +68 -1048
  175. package/packages/core/{v4-runtime-ref-resume-authority.js → runtime-ref-resume-authority.js} +36 -40
  176. package/packages/core/{v4-runtime-selector-persistence.js → runtime-selector-persistence.js} +7 -7
  177. package/packages/core/stable-publication-fence.js +28 -0
  178. package/packages/core/{v4-stage-capsule-local-store.js → stage-capsule-local-store.js} +56 -54
  179. package/packages/core/{v4-stage-capsule-qualification-campaign.js → stage-capsule-qualification-campaign.js} +37 -38
  180. package/packages/core/{v4-stage-capsule-qualification.js → stage-capsule-qualification.js} +28 -29
  181. package/packages/core/{v4-stage-capsule-resume-planner.js → stage-capsule-resume-planner.js} +29 -29
  182. package/packages/core/{v4-stage-capsule-store.js → stage-capsule-store.js} +59 -56
  183. package/packages/core/{v4-stage-capsule.js → stage-capsule.js} +45 -45
  184. package/packages/core/{v4-tail-reseal-contract.js → tail-reseal-contract.js} +6 -6
  185. package/packages/core/{v4-tail-reseal-github.js → tail-reseal-github.js} +12 -12
  186. package/packages/core/{v4-tail-reseal-receipt.js → tail-reseal-receipt.js} +22 -22
  187. package/packages/core/{v4-tail-reseal.js → tail-reseal.js} +29 -29
  188. package/packages/core/universal-workflow-bootstrap.js +586 -0
  189. package/scripts/{v4-architecture.mjs → architecture.mjs} +6 -6
  190. package/scripts/binary-publication-evidence.mjs +135 -0
  191. package/scripts/{v4-bridge-bootstrap.mjs → bridge-bootstrap.mjs} +14 -18
  192. package/scripts/{v4-bridge-evidence.mjs → bridge-evidence.mjs} +8 -8
  193. package/scripts/build-contract-core.mjs +1 -14
  194. package/scripts/build-domain-wasm.mjs +177 -0
  195. package/scripts/{v3-v4-capability-catalog.mjs → capability-parity-catalog.mjs} +19 -19
  196. package/scripts/check-action-bundles.mjs +12 -2
  197. package/scripts/{check-v3-v4-capability-inventory.mjs → check-capability-parity-inventory.mjs} +42 -42
  198. package/scripts/check-ci-lane-change-budget.mjs +4 -1
  199. package/scripts/check-core-mechanism-inventory.mjs +8 -4
  200. package/scripts/{check-v4-floating-consumer-policy-contract.mjs → check-floating-consumer-policy-contract.mjs} +10 -10
  201. package/scripts/check-implementation-naming.mjs +135 -0
  202. package/scripts/check-inventory.mjs +39 -47
  203. package/scripts/check-maintainability.mjs +25 -115
  204. package/scripts/{check-v4-public-dogfood-contract.mjs → check-public-dogfood-contract.mjs} +37 -24
  205. package/scripts/{check-v4-release-topology.mjs → check-release-topology.mjs} +131 -52
  206. package/scripts/{check-v4-runtime-semantic-closure.mjs → check-runtime-semantic-closure.mjs} +23 -17
  207. package/scripts/check-universal-workflow-bootstrap.mjs +266 -0
  208. package/scripts/check-workflow-taxonomy.mjs +6 -0
  209. package/scripts/{v4-consumer-policy.mjs → consumer-policy.mjs} +15 -15
  210. package/scripts/copy-domain-wasm.mjs +14 -0
  211. package/scripts/{v4-cross-platform-adopter-qualification.mjs → cross-platform-adopter-qualification.mjs} +9 -9
  212. package/scripts/{v4-declarative-promotion-admission.mjs → declarative-promotion-admission.mjs} +4 -4
  213. package/scripts/dev-delivery-authority-command-adapters.mjs +1 -1
  214. package/scripts/dev-delivery-authority.mjs +8 -8
  215. package/scripts/dev-delivery-source-proof-reuse.mjs +2 -1
  216. package/scripts/dev-delivery-warrant-options.mjs +15 -10
  217. package/scripts/dev-delivery-warrant-store.mjs +98 -13
  218. package/scripts/dev-delivery-warrant-transition.mjs +109 -0
  219. package/scripts/dev-delivery-warrant.mjs +80 -103
  220. package/scripts/dev-pr-auto-merge.mjs +15 -15
  221. package/scripts/dev-pr-delivery-warrant.mjs +1 -1
  222. package/scripts/generate-channel-build-workflow.mjs +7 -2
  223. package/scripts/generate-channel-promotion-workflow.mjs +19 -34
  224. package/scripts/generate-release-candidate-passport.mjs +23 -23
  225. package/scripts/generate-site-bundle.mjs +28 -28
  226. package/scripts/generate-universal-workflow-facades.mjs +498 -0
  227. package/scripts/generate-workflow-taxonomy.mjs +25 -0
  228. package/scripts/github-output.mjs +31 -0
  229. package/scripts/{v4-host-adapter.mjs → host-adapter.mjs} +1 -1
  230. package/scripts/implementation-references.mjs +25 -0
  231. package/scripts/init-repo.mjs +1 -1
  232. package/scripts/maintainability-metrics.mjs +16 -5
  233. package/scripts/maintainability-public-surface.mjs +115 -0
  234. package/scripts/next-development-review.mjs +313 -0
  235. package/scripts/oci-compose-preview.mjs +261 -0
  236. package/scripts/paper-work-fleet-cli.mjs +2 -0
  237. package/scripts/{v4-platform-stage-checkpoint-rehearsal.mjs → platform-stage-checkpoint-rehearsal.mjs} +17 -17
  238. package/scripts/{v4-product-publication-intent.mjs → product-publication-intent.mjs} +28 -13
  239. package/scripts/publication-candidate-kind.mjs +93 -0
  240. package/scripts/publication-candidate-sealer.mjs +16 -1
  241. package/scripts/{v4-publication-rehearsal-fixture.mjs → publication-rehearsal-fixture.mjs} +5 -5
  242. package/scripts/publication-settlement.mjs +211 -0
  243. package/scripts/release-asset-client.mjs +91 -0
  244. package/scripts/{v4-release-candidate-adapter.mjs → release-candidate-adapter.mjs} +4 -4
  245. package/scripts/release-candidate-resolver.mjs +24 -35
  246. package/scripts/release-tail.mjs +5 -5
  247. package/scripts/resume-from-candidate-run.mjs +35 -42
  248. package/scripts/site-capability-metadata.mjs +9 -0
  249. package/scripts/source-verification-evidence.mjs +344 -0
  250. package/scripts/stable-candidate-qualification.mjs +1 -1
  251. package/scripts/{v4-stage-capsule-qualification.mjs → stage-capsule-qualification.mjs} +62 -62
  252. package/scripts/{v4-stage-capsule-resume-rehearsal.mjs → stage-capsule-resume-rehearsal.mjs} +6 -6
  253. package/scripts/{v4-tail-reseal-macos-rehearsal.mjs → tail-reseal-macos-rehearsal.mjs} +9 -9
  254. package/scripts/{v4-tail-reseal.mjs → tail-reseal.mjs} +19 -19
  255. package/scripts/universal-facade-maintainability.mjs +91 -0
  256. package/scripts/universal-workflow-backflow.mjs +212 -0
  257. package/scripts/universal-workflow-engine.mjs +620 -0
  258. package/scripts/universal-workflow-self-dogfood.mjs +205 -0
  259. package/scripts/verify-version-state-delta.mjs +175 -0
  260. package/scripts/{v4-warrant-shadow-plan.mjs → warrant-shadow-plan.mjs} +6 -6
  261. package/scripts/workflow-taxonomy.mjs +507 -0
  262. package/templates/native-dev-delivery.yml +4 -7
  263. package/templates/universal-buildchain-bootstrap-recovery.yml +282 -0
  264. package/templates/universal-buildchain-bootstrap.yml +28 -0
  265. package/actions/v4-release-candidate-promote/README.md +0 -3
  266. package/packages/core/v4-partial-mutation-recovery-qualification.js +0 -395
  267. package/packages/core/v4-product-publication.js +0 -387
  268. package/packages/core/v4-provider-operation-journal.js +0 -531
  269. package/packages/core/v4-release-activation-shadow.js +0 -519
  270. package/packages/core/v4-release-invocation.js +0 -425
  271. package/packages/core/v4-stable-publication-fence.js +0 -357
  272. /package/architecture/{v4-adopter-delivery-parity.json → adopter-delivery-parity.json} +0 -0
  273. /package/architecture/{v3-core-mechanism-inventory.json → baseline-core-mechanism-inventory.json} +0 -0
  274. /package/architecture/{v4-canonical-contract-fixtures.json → canonical-contract-fixtures.json} +0 -0
  275. /package/architecture/{v4-compatibility-facts-parity.json → compatibility-facts-parity.json} +0 -0
  276. /package/architecture/{v4-delivery-warrant-shadow-bootstrap-plan.schema.json → delivery-warrant-shadow-bootstrap-plan.schema.json} +0 -0
  277. /package/architecture/{v4-delivery-warrant-shadow-fixtures.json → delivery-warrant-shadow-fixtures.json} +0 -0
  278. /package/architecture/{v4-delivery-warrant-shadow-fixtures.schema.json → delivery-warrant-shadow-fixtures.schema.json} +0 -0
  279. /package/architecture/{v4-exception-ledger.json → exception-ledger.json} +0 -0
  280. /package/architecture/{v4-exception-ledger.schema.json → exception-ledger.schema.json} +0 -0
  281. /package/architecture/{v4-release-invocation-fixtures.json → release-invocation-fixtures.json} +0 -0
@@ -5,14 +5,14 @@ import path from "node:path";
5
5
  import { spawnSync } from "node:child_process";
6
6
  import { fileURLToPath } from "node:url";
7
7
 
8
- import { v4CanonicalBytes } from "../packages/core/v4-canonical-contracts.js";
9
- import { V4StageCapsuleLocalStore } from "../packages/core/v4-stage-capsule-local-store.js";
10
- import { v4StageCapsuleBlobRoot } from "../packages/core/v4-stage-capsule-store.js";
8
+ import { domainCanonicalBytes } from "../packages/core/canonical-contracts.js";
9
+ import { StageCapsuleLocalStore } from "../packages/core/stage-capsule-local-store.js";
10
+ import { stageCapsuleBlobRoot } from "../packages/core/stage-capsule-store.js";
11
11
  import {
12
- emitV4PlatformStageCheckpoint,
13
- restoreV4PlatformStageCheckpoint,
14
- validateV4PlatformStageCheckpointDeclaration,
15
- } from "../packages/core/v4-platform-stage-checkpoints.js";
12
+ emitPlatformStageCheckpoint,
13
+ restorePlatformStageCheckpoint,
14
+ validatePlatformStageCheckpointDeclaration,
15
+ } from "../packages/core/platform-stage-checkpoints.js";
16
16
 
17
17
  const repoRoot = path.resolve(
18
18
  path.dirname(fileURLToPath(import.meta.url)),
@@ -32,10 +32,10 @@ function required(name) {
32
32
  }
33
33
 
34
34
  function readDeclaration() {
35
- return validateV4PlatformStageCheckpointDeclaration(
35
+ return validatePlatformStageCheckpointDeclaration(
36
36
  JSON.parse(
37
37
  fs.readFileSync(
38
- path.join(repoRoot, "architecture/v4-platform-stage-checkpoints.json"),
38
+ path.join(repoRoot, "architecture/platform-stage-checkpoints.json"),
39
39
  "utf8",
40
40
  ),
41
41
  ),
@@ -49,12 +49,12 @@ function stageFor(declaration, stageId) {
49
49
  }
50
50
 
51
51
  function rooted(label) {
52
- return v4StageCapsuleBlobRoot(Buffer.from(`${label}\n`, "utf8"));
52
+ return stageCapsuleBlobRoot(Buffer.from(`${label}\n`, "utf8"));
53
53
  }
54
54
 
55
55
  function writeJson(file, value) {
56
56
  fs.mkdirSync(path.dirname(file), { recursive: true });
57
- fs.writeFileSync(file, v4CanonicalBytes(value), { flag: "wx" });
57
+ fs.writeFileSync(file, domainCanonicalBytes(value), { flag: "wx" });
58
58
  }
59
59
 
60
60
  function emit({ workRoot, platformId, stageId, recordedAt }) {
@@ -87,11 +87,11 @@ function emit({ workRoot, platformId, stageId, recordedAt }) {
87
87
  const productionOutputRoots = Object.fromEntries(
88
88
  Object.entries(outputs).map(([name, bytes]) => [
89
89
  name,
90
- v4StageCapsuleBlobRoot(bytes),
90
+ stageCapsuleBlobRoot(bytes),
91
91
  ]),
92
92
  );
93
- const store = new V4StageCapsuleLocalStore(path.join(workRoot, "store"));
94
- const result = emitV4PlatformStageCheckpoint({
93
+ const store = new StageCapsuleLocalStore(path.join(workRoot, "store"));
94
+ const result = emitPlatformStageCheckpoint({
95
95
  declaration,
96
96
  platformId,
97
97
  stageId,
@@ -131,8 +131,8 @@ function restore({ workRoot, platformId, stageId, recordedAt }) {
131
131
  );
132
132
  if (emission.platform !== platformId || emission.stage !== stageId)
133
133
  throw new Error("emission identity does not match restore request");
134
- const store = new V4StageCapsuleLocalStore(path.join(workRoot, "store"));
135
- const result = restoreV4PlatformStageCheckpoint({
134
+ const store = new StageCapsuleLocalStore(path.join(workRoot, "store"));
135
+ const result = restorePlatformStageCheckpoint({
136
136
  declaration,
137
137
  expectedPlatform: platformId,
138
138
  expectedStage: stageId,
@@ -201,7 +201,7 @@ else if (action === "rehearse") {
201
201
  providerCredentialsUsed: restored.providerCredentialsUsed,
202
202
  };
203
203
  writeJson(path.join(common.workRoot, "evidence.json"), evidence);
204
- process.stdout.write(v4CanonicalBytes(evidence));
204
+ process.stdout.write(domainCanonicalBytes(evidence));
205
205
  } else {
206
206
  throw new Error("action must be emit, restore, or rehearse");
207
207
  }
@@ -5,8 +5,8 @@ import path from "node:path";
5
5
  import { pathToFileURL } from "node:url";
6
6
 
7
7
  import { spawnSyncCommand } from "../packages/core/spawn-command.js";
8
- import { selectV4ProductPublicationIntent } from "../packages/core/v4-product-publication.js";
9
- import { v4ContentRoot } from "../packages/core/v4-canonical-contracts.js";
8
+ import { selectProductPublicationIntent } from "../packages/core/product-publication.js";
9
+ import { domainContentRoot } from "../packages/core/canonical-contracts.js";
10
10
 
11
11
  function env(name, required = false) {
12
12
  const value = String(process.env[name] || "").trim();
@@ -18,7 +18,8 @@ function readJson(file) {
18
18
  return JSON.parse(fs.readFileSync(path.resolve(file), "utf8"));
19
19
  }
20
20
 
21
- function packageName() {
21
+ function packageName(artifactKind) {
22
+ if (artifactKind !== "npm") return "";
22
23
  const declared = env("BUILDCHAIN_PUBLISH_PACKAGE_MAIN");
23
24
  if (declared) return declared;
24
25
  const manifestPath = env("BUILDCHAIN_SEALED_BUNDLE_MANIFEST", true);
@@ -58,36 +59,50 @@ function writeOutput(name, value) {
58
59
  fs.appendFileSync(output, `${name}=${String(value)}\n`);
59
60
  }
60
61
 
61
- export function resolveV4ProductPublicationIntent() {
62
- const name = packageName();
62
+ export function resolveProductPublicationIntent() {
63
+ const artifactKind = env("BUILDCHAIN_PUBLISH_ARTIFACT_KIND") || "npm";
64
+ const name = packageName(artifactKind);
63
65
  const sourceSha = env("BUILDCHAIN_SOURCE_SHA", true);
64
- const manifest = readJson(env("BUILDCHAIN_SEALED_BUNDLE_MANIFEST", true));
66
+ const manifestPath = env(
67
+ "BUILDCHAIN_SEALED_BUNDLE_MANIFEST",
68
+ artifactKind !== "custom",
69
+ );
70
+ const manifest = manifestPath ? readJson(manifestPath) : null;
65
71
  const requiredArtifacts = readJson(
66
72
  env("BUILDCHAIN_REQUIRED_ARTIFACTS_PATH", true),
67
73
  );
68
74
  const channel = env("BUILDCHAIN_CHANNEL", true);
69
- const intent = selectV4ProductPublicationIntent({
75
+ const intent = selectProductPublicationIntent({
70
76
  channel,
71
77
  targetRef: env("BUILDCHAIN_TARGET_REF", true),
72
78
  sourceSha,
73
79
  sourceTimestamp: env("BUILDCHAIN_SOURCE_TIMESTAMP", true),
74
80
  repository: env("BUILDCHAIN_REPOSITORY", true),
81
+ artifactKind,
75
82
  packageName: name,
83
+ ...(manifest?.npmPackages
84
+ ? {
85
+ npmPackages: manifest.npmPackages.map((entry) => ({
86
+ ...entry,
87
+ sha256: `sha256:${entry.sha256}`,
88
+ })),
89
+ }
90
+ : {}),
76
91
  distTag:
77
92
  env("BUILDCHAIN_PUBLISH_DIST_TAG") ||
78
93
  (channel === "alpha" ? "alpha" : "latest"),
79
- sealedBundleRoot: manifest.root,
80
- requiredArtifactsRoot: v4ContentRoot(
94
+ sealedBundleRoot: manifest?.root,
95
+ requiredArtifactsRoot: domainContentRoot(
81
96
  "v4-product-required-artifacts",
82
97
  requiredArtifacts,
83
98
  ),
84
99
  candidateVersion: env("BUILDCHAIN_CANDIDATE_VERSION", true),
85
100
  recoveredVersion: env("BUILDCHAIN_RECOVERED_PUBLICATION_VERSION"),
86
- observedVersions: observedVersions(name),
101
+ observedVersions: artifactKind === "npm" ? observedVersions(name) : [],
87
102
  });
88
103
  const outputPath = path.resolve(
89
104
  env("BUILDCHAIN_PRODUCT_PUBLICATION_INTENT_PATH") ||
90
- ".buildchain/release-candidate/v4-product-publication-intent.json",
105
+ ".buildchain/release-candidate/product-publication-intent.json",
91
106
  );
92
107
  fs.mkdirSync(path.dirname(outputPath), { recursive: true });
93
108
  fs.writeFileSync(outputPath, `${JSON.stringify(intent, null, 2)}\n`);
@@ -95,7 +110,7 @@ export function resolveV4ProductPublicationIntent() {
95
110
  writeOutput("exact-tag", intent.exactTag);
96
111
  writeOutput("intent-path", outputPath);
97
112
  writeOutput("intent-root", intent.intentRoot);
98
- return { name, intent, outputPath };
113
+ return { name: name || artifactKind, intent, outputPath };
99
114
  }
100
115
 
101
116
  if (
@@ -103,7 +118,7 @@ if (
103
118
  import.meta.url === pathToFileURL(process.argv[1]).href
104
119
  ) {
105
120
  try {
106
- const result = resolveV4ProductPublicationIntent();
121
+ const result = resolveProductPublicationIntent();
107
122
  process.stdout.write(
108
123
  `v4 product publication intent: ${result.name}@${result.intent.version} (${result.intent.mode})\n`,
109
124
  );
@@ -0,0 +1,93 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { ociPublicationTag } from "../packages/core/oci-publication-graph.js";
4
+ import { verifyOciPublicationBundle } from "../packages/core/oci-publication-bundle.js";
5
+
6
+ export function resolveOciCandidate({ payloadRoot, passport }) {
7
+ const matches = [];
8
+ function visit(directory) {
9
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
10
+ if (entry.isSymbolicLink())
11
+ throw new Error("OCI candidate cannot contain symlinks");
12
+ const file = path.join(directory, entry.name);
13
+ if (entry.isDirectory()) visit(file);
14
+ else if (entry.name === "oci-family.json") matches.push(file);
15
+ }
16
+ }
17
+ visit(payloadRoot);
18
+ if (matches.length !== 1)
19
+ throw new Error("OCI candidate requires exactly one sealed image family");
20
+ const manifest = JSON.parse(fs.readFileSync(matches[0]));
21
+ const bundleRoot = path.dirname(matches[0]);
22
+ const verified = verifyOciPublicationBundle({
23
+ bundleRoot,
24
+ manifest,
25
+ repository: passport.repository,
26
+ sourceSha: passport.source.headSha,
27
+ version: passport.target.version,
28
+ });
29
+ return {
30
+ root: bundleRoot,
31
+ manifest: verified.manifest,
32
+ requiredArtifacts: manifest.images.map((image) => ({
33
+ kind: "oci",
34
+ name: image.repository,
35
+ ref: ociPublicationTag(image, manifest.version),
36
+ digest: image.digest,
37
+ platform: image.platform,
38
+ required: true,
39
+ })),
40
+ };
41
+ }
42
+
43
+ export function resolveRecoveredPublicationVersion({
44
+ artifactVersion,
45
+ channel,
46
+ rematerializeOnResume = false,
47
+ } = {}) {
48
+ const version = String(artifactVersion || "").trim(),
49
+ match = version.match(
50
+ /^(\d+\.\d+\.\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u,
51
+ );
52
+ if (!match)
53
+ throw new Error(
54
+ `recovered npm artifact has invalid publication version: ${version || "<empty>"}`,
55
+ );
56
+ return channel === "release" && rematerializeOnResume ? match[1] : version;
57
+ }
58
+ export function resolveRecoveredCandidateVersion({
59
+ artifactVersion,
60
+ publicationVersion,
61
+ channel,
62
+ rematerializeOnResume = false,
63
+ targetRef = "",
64
+ candidateRef = "",
65
+ } = {}) {
66
+ const version = String(artifactVersion || "").trim(),
67
+ target = String(targetRef || "").replace(/^refs\/heads\//u, ""),
68
+ candidate = String(candidateRef || "").replace(/^refs\/heads\//u, "");
69
+ if (channel !== "release" || !rematerializeOnResume) return version;
70
+ const prefix = `publish-gate/${target}/`;
71
+ if (!target || !candidate.startsWith(prefix))
72
+ throw new Error(
73
+ `stable recovery candidate ref must descend from ${prefix || "publish-gate/<target>/"}`,
74
+ );
75
+ const candidateVersion = candidate.slice(prefix.length);
76
+ if (!/^\d+\.\d+\.\d+-alpha\.\d+$/u.test(candidateVersion))
77
+ throw new Error(
78
+ `stable recovery candidate ref must bind an exact alpha version, got ${candidateVersion || "<empty>"}`,
79
+ );
80
+ if (candidateVersion.replace(/-alpha\.\d+$/u, "") !== publicationVersion)
81
+ throw new Error(
82
+ `stable recovery candidate ${candidateVersion} does not match publication ${publicationVersion || "<empty>"}`,
83
+ );
84
+ if (
85
+ (version.match(
86
+ /^(\d+\.\d+\.\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u,
87
+ )?.[1] || "") !== publicationVersion
88
+ )
89
+ throw new Error(
90
+ `recovered npm artifact version ${version || "<empty>"} does not match publication ${publicationVersion}`,
91
+ );
92
+ return candidateVersion;
93
+ }
@@ -1,3 +1,4 @@
1
+ import { resolveOciCandidate } from "./publication-candidate-kind.mjs";
1
2
  import crypto from "node:crypto";
2
3
  import fs from "node:fs";
3
4
  import path from "node:path";
@@ -69,7 +70,7 @@ export function createResolvedPublicationSealedBundle({
69
70
  });
70
71
  const main = resolvedNpmArtifacts.find((entry) => entry.metadata.role === "main")
71
72
  || (resolvedNpmArtifacts.length === 1 ? resolvedNpmArtifacts[0] : undefined);
72
- if (!main) throw new Error("candidate npm payload set has no unique main package tarball");
73
+ if (!main || resolvedNpmArtifacts.filter((entry) => entry.metadata.role === "main").length > 1) throw new Error("candidate npm payload set has no unique main package tarball");
73
74
  const selectedReleaseAssets = (releaseAssetPaths.length > 0
74
75
  ? releaseAssetPaths
75
76
  : resolvedNpmArtifacts.map((entry) => entry.file.absolutePath))
@@ -88,6 +89,12 @@ export function createResolvedPublicationSealedBundle({
88
89
  releaseCandidateRoot: `sha256:${normalizeSha256(releaseCandidateRoot, "releaseCandidateRoot")}`,
89
90
  files: files.map(({ path: filePath, size, sha256 }) => ({ path: filePath, size, sha256 })),
90
91
  };
92
+ if (resolvedNpmArtifacts.length > 1) {
93
+ candidatePayload.npmPackages = resolvedNpmArtifacts.map(({file, metadata}) => ({
94
+ name: metadata.name, version: metadata.ref, role: metadata.role,
95
+ path: file.path, size: file.size, sha256: file.sha256, integrity: metadata.integrity,
96
+ }));
97
+ }
91
98
  const candidate = {
92
99
  ...candidatePayload,
93
100
  candidateDigest: publicationArtifactCandidateDigest(candidatePayload),
@@ -102,3 +109,11 @@ export function createResolvedPublicationSealedBundle({
102
109
  });
103
110
  return { root: resolvedRoot, manifest, npmArtifacts: resolvedNpmArtifacts, files };
104
111
  }
112
+
113
+ export function resolveCandidatePublicationBundle({ kind, payloadDir, passport, runtimeSha, npmArtifacts, releaseAssetPaths }) {
114
+ if (kind === "oci") return resolveOciCandidate({ payloadRoot: payloadDir, passport });
115
+ if (kind !== "npm") return undefined;
116
+ return createResolvedPublicationSealedBundle({ bundleRoot: payloadDir, repository: passport.repository,
117
+ sourceSha: passport.source?.headSha, sourceTreeSha: passport.source?.treeHash,
118
+ runtimeSha, releaseCandidateRoot: passport.candidateHash, npmArtifacts, releaseAssetPaths });
119
+ }
@@ -6,9 +6,9 @@ import path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
 
8
8
  import {
9
- createV4PublicationRehearsalCapsule,
10
- executeV4PublicationRehearsal,
11
- } from "../packages/core/v4-publication-rehearsal.js";
9
+ createDomainPublicationRehearsalCapsule,
10
+ executeDomainPublicationRehearsal,
11
+ } from "../packages/core/publication-rehearsal.js";
12
12
 
13
13
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
14
14
  const fixtureRoot = path.join(
@@ -61,7 +61,7 @@ async function generated() {
61
61
  path: relative,
62
62
  root: files.find((entry) => entry.path === relative).root,
63
63
  });
64
- const capsule = createV4PublicationRehearsalCapsule({
64
+ const capsule = createDomainPublicationRehearsalCapsule({
65
65
  source: {
66
66
  repository: "kungfu-systems/buildchain",
67
67
  revision: "bc12cd0ff18a7e1d918777ea093c169349952d34",
@@ -100,7 +100,7 @@ async function generated() {
100
100
  });
101
101
  const vectors = [];
102
102
  for (const platform of ["linux", "macos", "windows"]) {
103
- const result = await executeV4PublicationRehearsal({
103
+ const result = await executeDomainPublicationRehearsal({
104
104
  capsule,
105
105
  candidateRoot,
106
106
  mode: "simulate",
@@ -0,0 +1,211 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import {
5
+ createReleaseInvocation,
6
+ createReleaseReceipt,
7
+ createDomainReleaseTransaction,
8
+ } from "../packages/core/release-invocation.js";
9
+ import {
10
+ releaseTailRoot,
11
+ validateReleaseTailTransaction,
12
+ } from "../packages/core/release-tail-provider-plane.js";
13
+
14
+ export const SETTLEMENT_ASSET = "buildchain-publication-settlement.json";
15
+
16
+ export function verifyPublicationSettlement(
17
+ documents,
18
+ { repository, tag, sourceSha, publicPassport, candidateSha } = {},
19
+ ) {
20
+ const {
21
+ invocation,
22
+ transaction,
23
+ receipt,
24
+ passport,
25
+ product,
26
+ providerState,
27
+ productState,
28
+ } = documents;
29
+ const projected = createReleaseInvocation(invocation);
30
+ const roots = createDomainReleaseTransaction({
31
+ invocationRoot: projected.roots.invocationRoot,
32
+ publisherRoot: projected.roots.publisherRoot,
33
+ runtimeRoot: projected.roots.runtimeRoot,
34
+ providerRoot: projected.roots.providerRoot,
35
+ parentRoot: projected.roots.parentRoot,
36
+ });
37
+ const { receiptRoot, ...receiptBody } = receipt;
38
+ const { passportRoot, ...passportBody } = passport;
39
+ const { root: productRoot, ...productBody } = product;
40
+ if (
41
+ !validateReleaseTailTransaction(providerState).valid ||
42
+ !validateReleaseTailTransaction(productState).valid
43
+ )
44
+ throw new Error("invalid provider transaction state");
45
+ if (
46
+ releaseTailRoot(transaction) !==
47
+ releaseTailRoot({
48
+ ...roots.transaction,
49
+ transactionRoot: roots.transactionRoot,
50
+ }) ||
51
+ createReleaseReceipt(receiptBody).receiptRoot !== receiptRoot ||
52
+ receipt.transactionRoot !== roots.transactionRoot ||
53
+ receipt.outcome !== "complete" ||
54
+ passportRoot !== releaseTailRoot(passportBody) ||
55
+ receipt.releasePassportRoot !== passportRoot ||
56
+ productRoot !== releaseTailRoot(productBody) ||
57
+ !receipt.providerReceiptRoots.includes(productRoot) ||
58
+ receipt.providerTransactionRoot !== providerState.transactionRoot ||
59
+ receipt.providerStateRoot !== providerState.stateRoot ||
60
+ providerState.state !== "complete" ||
61
+ productState.state !== "complete" ||
62
+ product.transaction.stateRoot !== productState.stateRoot ||
63
+ product.transaction.transactionRoot !== productState.transactionRoot ||
64
+ productState.transactionRoot !== roots.transactionRoot ||
65
+ providerState.receipts.some(
66
+ ({ receiptRoot: root }) => !receipt.providerReceiptRoots.includes(root),
67
+ )
68
+ )
69
+ throw new Error("terminal publication receipt lineage does not verify");
70
+ verifyPublicationCoordinates(documents, {
71
+ repository,
72
+ tag,
73
+ sourceSha,
74
+ publicPassport,
75
+ candidateSha,
76
+ });
77
+ return { publication: "complete", receiptRoot, sourceSha, tag, repository };
78
+ }
79
+
80
+ function verifyPublicationCoordinates(
81
+ { invocation, passport, product },
82
+ { repository, tag, sourceSha, publicPassport, candidateSha },
83
+ ) {
84
+ if (
85
+ invocation.candidate.repository !== repository ||
86
+ (candidateSha && invocation.candidate.commit !== candidateSha) ||
87
+ passport.repository !== repository ||
88
+ invocation.provider.repository !== repository ||
89
+ invocation.target.tag !== tag ||
90
+ passport.release.tag !== tag ||
91
+ passport.release.version !== tag.replace(/^v/u, "") ||
92
+ product.publication.exactTag !== tag ||
93
+ product.publication.version !== passport.release.version ||
94
+ product.publication.releaseSha !== sourceSha ||
95
+ product.publication.state !== "complete" ||
96
+ product.publication.finalizationNeeded ||
97
+ passport.source.headSha !== invocation.candidate.commit ||
98
+ passport.source.treeHash !== invocation.candidate.tree ||
99
+ passport.policyDigest !== invocation.authority.policyRoot ||
100
+ passport.publicationQualificationRoot !==
101
+ invocation.authority.qualificationRoot ||
102
+ (publicPassport &&
103
+ releaseTailRoot(publicPassport) !== releaseTailRoot(passport))
104
+ )
105
+ throw new Error(
106
+ "publication evidence does not match exact provider release coordinates",
107
+ );
108
+ }
109
+
110
+ export function readApplyDocuments(base) {
111
+ const read = (relative) =>
112
+ JSON.parse(fs.readFileSync(path.join(base, relative)));
113
+ return {
114
+ invocation: read("release-tail/release-invocation.json"),
115
+ transaction: read("release-tail/release-transaction.json"),
116
+ receipt: read("release-tail/release-receipt.json"),
117
+ product: read("release-tail/product-provider-result.json"),
118
+ providerState: read("release-tail/state.json"),
119
+ productState: read("release-tail/product-provider-transaction.json"),
120
+ passport: read("release-passport/buildchain.release.json"),
121
+ };
122
+ }
123
+
124
+ export async function settlePublication({
125
+ base,
126
+ client,
127
+ applyOutcome,
128
+ repository,
129
+ candidateSha,
130
+ }) {
131
+ const documents = readApplyDocuments(base);
132
+ if (
133
+ documents.invocation.candidate.repository !== repository ||
134
+ (candidateSha && documents.invocation.candidate.commit !== candidateSha)
135
+ )
136
+ throw new Error(
137
+ "publication settlement does not match the admitted repository and candidate",
138
+ );
139
+ const tag = documents.invocation.target.tag;
140
+ const release = client.release(tag);
141
+ const sourceSha = client.json(
142
+ `repos/${repository}/commits/${encodeURIComponent(tag)}`,
143
+ ).sha;
144
+ const matches = release.assets.filter(
145
+ ({ name }) => name === "buildchain.release.json",
146
+ );
147
+ if (matches.length !== 1)
148
+ throw new Error(
149
+ "exact public publication passport is missing or ambiguous",
150
+ );
151
+ const publicPassport = JSON.parse(client.assetBytes(matches[0]));
152
+ const status = verifyPublicationSettlement(documents, {
153
+ repository,
154
+ tag,
155
+ sourceSha,
156
+ publicPassport,
157
+ });
158
+ // Publication completion is immutable; next-development and distribution progress stay separate.
159
+ const settlement = {
160
+ schemaVersion: 1,
161
+ contract: "buildchain-v4-publication-settlement/v1",
162
+ id: "v4-publication",
163
+ release: { sourceSha, tag, channel: documents.invocation.target.channel },
164
+ documents,
165
+ };
166
+ const file = path.join(base, "release-tail", SETTLEMENT_ASSET);
167
+ client.write(file, settlement);
168
+ await client.publish(release, [file]);
169
+ const summary = {
170
+ ...status,
171
+ nextDevelopment: applyOutcome === "success" ? "advanced" : "incomplete",
172
+ binaryDistribution: "pending-provider-readback",
173
+ };
174
+ client.write(
175
+ path.join(base, "release-tail", "delivery-summary.json"),
176
+ summary,
177
+ );
178
+ return { summary, receipt: documents.receipt };
179
+ }
180
+
181
+ async function main() {
182
+ const { releaseAssetClient } = await import("./release-asset-client.mjs");
183
+ const repository = process.env.GITHUB_REPOSITORY;
184
+ const result = await settlePublication({
185
+ base: process.argv[2],
186
+ client: releaseAssetClient(repository),
187
+ repository,
188
+ candidateSha: process.env.CANDIDATE_SHA,
189
+ applyOutcome: process.env.APPLY_OUTCOME,
190
+ });
191
+ if (process.env.GITHUB_OUTPUT)
192
+ fs.appendFileSync(
193
+ process.env.GITHUB_OUTPUT,
194
+ `receipt-json=${JSON.stringify(result.receipt)}\nreceipt-root=${result.receipt.receiptRoot}\nstatus=complete\n`,
195
+ );
196
+ if (process.env.GITHUB_STEP_SUMMARY)
197
+ fs.appendFileSync(
198
+ process.env.GITHUB_STEP_SUMMARY,
199
+ `Publication: **complete**, receipt \`${result.receipt.receiptRoot}\`. Next development: **${result.summary.nextDevelopment}**. Binary distribution: **pending provider readback**.\n`,
200
+ );
201
+ }
202
+
203
+ if (
204
+ process.argv[1] &&
205
+ path.basename(process.argv[1]) === "publication-settlement.mjs" &&
206
+ import.meta.url === pathToFileURL(process.argv[1]).href
207
+ )
208
+ main().catch((error) => {
209
+ console.error(error.message);
210
+ process.exitCode = 1;
211
+ });
@@ -0,0 +1,91 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import {
5
+ reconcileImmutableReleaseAssets,
6
+ uniqueReleaseAssets,
7
+ } from "../actions/promote-buildchain-ref/reuse-complete-release.js";
8
+
9
+ export function releaseAssetClient(
10
+ repository,
11
+ { execute = execFileSync, token } = {},
12
+ ) {
13
+ if (!/^[\w.-]+\/[\w.-]+$/u.test(repository))
14
+ throw new Error("exact repository required");
15
+ const [owner, repo] = repository.split("/");
16
+ const raw = (endpoint, args = []) =>
17
+ execute("gh", ["api", endpoint, ...args], {
18
+ maxBuffer: 128 * 1024 * 1024,
19
+ stdio: ["ignore", "pipe", "pipe"],
20
+ ...(token ? { env: { ...process.env, GH_TOKEN: token } } : {}),
21
+ });
22
+ const json = (endpoint) => JSON.parse(raw(endpoint));
23
+ const assetBytes = (asset) =>
24
+ raw(`repos/${repository}/releases/assets/${asset.id}`, [
25
+ "-H",
26
+ "Accept: application/octet-stream",
27
+ ]);
28
+ return {
29
+ json,
30
+ assetBytes,
31
+ release: (tag) =>
32
+ json(`repos/${repository}/releases/tags/${encodeURIComponent(tag)}`),
33
+ async publish(release, files) {
34
+ const octokit = {
35
+ rest: {
36
+ repos: {
37
+ getReleaseAsset: async ({ asset_id }) => ({
38
+ data: assetBytes({ id: asset_id }),
39
+ }),
40
+ },
41
+ },
42
+ };
43
+ const result = await reconcileImmutableReleaseAssets({
44
+ octokit,
45
+ owner,
46
+ repo,
47
+ releaseId: release.id,
48
+ remoteAssets: uniqueReleaseAssets(release.assets || []),
49
+ assetPaths: files,
50
+ uploadReleaseAsset: async ({ name }) => {
51
+ const file = files.find((file) => path.basename(file) === name);
52
+ return JSON.parse(
53
+ raw(
54
+ `https://uploads.github.com/repos/${repository}/releases/${release.id}/assets?name=${encodeURIComponent(name)}`,
55
+ [
56
+ "--method",
57
+ "POST",
58
+ "--input",
59
+ file,
60
+ "-H",
61
+ "Content-Type: application/octet-stream",
62
+ ],
63
+ ),
64
+ );
65
+ },
66
+ });
67
+ // A successful upload response alone is not the provider readback.
68
+ const observed = this.release(release.tag_name);
69
+ await reconcileImmutableReleaseAssets({
70
+ octokit,
71
+ owner,
72
+ repo,
73
+ releaseId: release.id,
74
+ remoteAssets: uniqueReleaseAssets(observed.assets || []),
75
+ assetPaths: files,
76
+ uploadReleaseAsset: async () => {
77
+ throw new Error("uploaded release asset missing on readback");
78
+ },
79
+ });
80
+ return result.map(({ action, name, digest }) => ({
81
+ action,
82
+ name,
83
+ digest,
84
+ }));
85
+ },
86
+ write(file, value) {
87
+ fs.mkdirSync(path.dirname(file), { recursive: true });
88
+ fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
89
+ },
90
+ };
91
+ }
@@ -6,7 +6,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
6
6
 
7
7
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
8
8
 
9
- export function resolveV4ReleaseCandidateAdapter({
9
+ export function resolveReleaseCandidateAdapter({
10
10
  resumeCandidateRunId = "",
11
11
  } = {}) {
12
12
  const mode = String(resumeCandidateRunId || "").trim() ? "recovery" : "fresh";
@@ -19,11 +19,11 @@ export function resolveV4ReleaseCandidateAdapter({
19
19
  });
20
20
  }
21
21
 
22
- export function runV4ReleaseCandidateAdapter({
22
+ export function runReleaseCandidateAdapter({
23
23
  env = process.env,
24
24
  exec = execFileSync,
25
25
  } = {}) {
26
- const route = resolveV4ReleaseCandidateAdapter({
26
+ const route = resolveReleaseCandidateAdapter({
27
27
  resumeCandidateRunId: env.BUILDCHAIN_RESUME_CANDIDATE_RUN_ID,
28
28
  });
29
29
  exec(process.execPath, [path.join(root, route.script)], {
@@ -37,5 +37,5 @@ if (
37
37
  process.argv[1] &&
38
38
  import.meta.url === pathToFileURL(process.argv[1]).href
39
39
  ) {
40
- runV4ReleaseCandidateAdapter();
40
+ runReleaseCandidateAdapter();
41
41
  }