@kungfu-tech/buildchain 3.0.9-alpha.9 → 4.0.0-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 (262) hide show
  1. package/AGENTS.md +39 -0
  2. package/README.md +17 -13
  3. package/actions/promote-buildchain-ref/README.md +0 -10
  4. package/actions/release-tail/README.md +6 -10
  5. package/architecture/internal-capabilities.json +502 -0
  6. package/architecture/maintainability-baseline.json +59 -0
  7. package/architecture/maintainability-policy.json +1384 -0
  8. package/architecture/release-tail-contract-inventory.json +587 -0
  9. package/architecture/v3-core-mechanism-inventory.json +1043 -0
  10. package/architecture/v3-core-mechanism-inventory.md +67 -0
  11. package/architecture/v4-adopter-delivery-parity.json +47 -0
  12. package/architecture/v4-architecture-constitution.md +210 -0
  13. package/architecture/v4-bootstrap-authority.json +56 -0
  14. package/architecture/v4-canonical-contract-fixtures.json +105 -0
  15. package/architecture/v4-capability-state-machine-manifest.json +480 -0
  16. package/architecture/v4-capability-state-machine-manifest.schema.json +202 -0
  17. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +830 -0
  18. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.md +223 -0
  19. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.schema.json +318 -0
  20. package/architecture/v4-delivery-warrant-shadow-fixtures.json +227 -0
  21. package/architecture/v4-delivery-warrant-shadow-fixtures.schema.json +67 -0
  22. package/architecture/v4-exception-ledger.json +5 -0
  23. package/architecture/v4-exception-ledger.schema.json +56 -0
  24. package/architecture/v4-partial-mutation-recovery-qualification.json +65 -0
  25. package/architecture/v4-platform-stage-checkpoints.json +97 -0
  26. package/architecture/v4-provider-operation-journal-contract.json +113 -0
  27. package/architecture/v4-release-activation-shadow-domain.json +61 -0
  28. package/architecture/v4-release-train-parity.json +68 -0
  29. package/architecture/v4-rust-libnode-bridge-evaluation.json +107 -0
  30. package/architecture/v4-rust-libnode-bridge-spike.md +85 -0
  31. package/architecture/v4-stable-publication-fence.json +66 -0
  32. package/architecture/v4-stage-capsule-contract.json +90 -0
  33. package/architecture/v4-stage-capsule-qualification.json +99 -0
  34. package/architecture/v4-stage-capsule-resume-planner.json +52 -0
  35. package/architecture/v4-stage-capsule-store-contract.json +72 -0
  36. package/bin/buildchain.mjs +15 -10
  37. package/contracts/auditable-demo-scenario-v1.schema.json +1 -1
  38. package/contracts/buildchain-v2-residuals-v1.json +2 -2
  39. package/contracts/fixtures/v4-delivery-warrant-trace-v1/golden.json +158 -0
  40. package/contracts/fixtures/v4-delivery-warrant-trace-v1/property.json +380 -0
  41. package/contracts/fixtures/v4-delivery-warrant-trace-v1/replay.json +163 -0
  42. package/contracts/fixtures/v4-partial-mutation-recovery-v1/shared.json +155 -0
  43. package/contracts/fixtures/v4-provider-operation-journal-v1/shared.json +457 -0
  44. package/contracts/fixtures/v4-provider-readback-idempotency-v1/shared.json +682 -0
  45. package/contracts/fixtures/v4-release-activation-shadow-v1/shared.json +53 -0
  46. package/contracts/fixtures/v4-stable-publication-fence-v1/shared.json +56 -0
  47. package/contracts/fixtures/v4-stage-capsule-resume-v1/late-platform-failure.json +176 -0
  48. package/contracts/fixtures/v4-stage-capsule-store-v1/shared.json +132 -0
  49. package/contracts/fixtures/v4-stage-capsule-v1/shared.json +111 -0
  50. package/contracts/v4-canonical-contracts-v1.schema.json +182 -0
  51. package/contracts/v4-delivery-warrant-semantic-diff-report-v1.schema.json +284 -0
  52. package/contracts/v4-delivery-warrant-trace-v1.schema.json +215 -0
  53. package/contracts/v4-host-contract-v1.schema.json +135 -0
  54. package/contracts/v4-partial-mutation-recovery-v1.schema.json +168 -0
  55. package/contracts/v4-provider-operation-journal-v1.schema.json +381 -0
  56. package/contracts/v4-release-activation-shadow-v1.schema.json +186 -0
  57. package/contracts/v4-stable-publication-fence-v1.schema.json +125 -0
  58. package/contracts/v4-stage-capsule-resume-v1.schema.json +225 -0
  59. package/contracts/v4-stage-capsule-store-v1.schema.json +154 -0
  60. package/contracts/v4-stage-capsule-v1.schema.json +178 -0
  61. package/crates/buildchain-v4-bridge/Cargo.lock +213 -0
  62. package/crates/buildchain-v4-bridge/Cargo.toml +12 -0
  63. package/crates/buildchain-v4-bridge/src/main.rs +495 -0
  64. package/dist/site/agent-index.json +0 -4
  65. package/dist/site/artifact-schemas.json +0 -8
  66. package/dist/site/buildchain-contract.json +103 -397
  67. package/dist/site/buildchain-site.json +302 -386
  68. package/dist/site/capability-registry.json +9 -11
  69. package/dist/site/cli-registry.json +8 -53
  70. package/dist/site/controller-registry.json +48 -8
  71. package/dist/site/kfd-claims.json +129 -167
  72. package/dist/site/kfd-upstream-aggregate.json +9 -9
  73. package/dist/site/manual-registry.json +18 -49
  74. package/dist/site/node-api-registry.json +4345 -7345
  75. package/dist/site/page-registry.json +278 -346
  76. package/dist/site/public-surface-audit.json +85 -404
  77. package/dist/site/publication-authority-registry.json +11 -1
  78. package/dist/site/publication-registry.json +4 -4
  79. package/dist/site/release-provenance.json +3 -9
  80. package/dist/site/schemas/kfd-support-projection-v1.schema.json +106 -0
  81. package/dist/site/site-manifest.json +22 -38
  82. package/dist/site/workflow-registry.json +78 -35
  83. package/docs/MAP.md +8 -5
  84. package/docs/auditable-demo.md +2 -2
  85. package/docs/aws-us-elastic-runner-burst-plane.md +7 -59
  86. package/docs/cli-reference.md +15 -213
  87. package/docs/cli.md +14 -14
  88. package/docs/dev-alpha-candidate-patrol.md +3 -11
  89. package/docs/dev-delivery-warrant.md +29 -194
  90. package/docs/engineering-housekeeper.md +12 -4
  91. package/docs/getting-started.md +1 -1
  92. package/docs/install.md +5 -5
  93. package/docs/kfd-support.md +2 -7
  94. package/docs/lifecycle-protocol.md +2 -4
  95. package/docs/node-api-reference.md +414 -554
  96. package/docs/release-flow.md +31 -31
  97. package/docs/release-governance.md +16 -28
  98. package/docs/release-passport.md +2 -15
  99. package/docs/release-tail-contract.md +13 -6
  100. package/docs/release-tail-provider-plane.md +13 -19
  101. package/docs/release-train.md +4 -4
  102. package/docs/reusable-build-surface.md +14 -27
  103. package/docs/site-bundle-contract.md +1 -5
  104. package/docs/stable-candidate-patrol.md +7 -7
  105. package/docs/v4-canonical-contracts.md +92 -0
  106. package/docs/v4-delivery-warrant-read-candidate.md +73 -0
  107. package/docs/v4-delivery-warrant-semantic-diff.md +75 -0
  108. package/docs/v4-production-release.md +63 -0
  109. package/docs/v4-stage-capsule.md +193 -0
  110. package/docs/versioning.md +3 -5
  111. package/package.json +19 -19
  112. package/packages/core/adopter-delivery-gate.js +576 -0
  113. package/packages/core/adopter-delivery-json.js +66 -0
  114. package/packages/core/artifact-signing.js +0 -61
  115. package/packages/core/artifact-verification-envelope.js +5 -5
  116. package/packages/core/build-facts.js +12 -4
  117. package/packages/core/buildchain-agent-manuals.js +0 -2
  118. package/packages/core/buildchain-channel-identity.js +3 -2
  119. package/packages/core/buildchain-config.js +4 -69
  120. package/packages/core/buildchain-contract.js +232 -46
  121. package/packages/core/buildchain-kfd-claims.js +1 -1
  122. package/packages/core/channel-candidate.js +0 -8
  123. package/packages/core/channel-promotion-baseline.js +0 -52
  124. package/packages/core/controller-evidence.js +3 -4
  125. package/packages/core/dev-alpha-candidate-selection.js +2 -10
  126. package/packages/core/dev-delivery-warrant-cancellation.js +0 -1
  127. package/packages/core/dev-delivery-warrant-settlement.js +20 -67
  128. package/packages/core/dev-delivery-warrant.js +50 -138
  129. package/packages/core/diagnostics.js +3 -8
  130. package/packages/core/github-governance-authority.js +3 -1
  131. package/packages/core/kfd-adopter-category-driver.js +167 -0
  132. package/packages/core/kfd-adopter-manifest.js +47 -46
  133. package/packages/core/kfd-gate.js +15 -45
  134. package/packages/core/paper-agent-entry.js +7 -16
  135. package/packages/core/paper-fleet.js +2 -2
  136. package/packages/core/paper-repository.js +2 -3
  137. package/packages/core/paper-scaffold-content.js +2 -23
  138. package/packages/core/paper.js +11 -43
  139. package/packages/core/publication-reproducibility.js +4 -4
  140. package/packages/core/release-line-bootstrap.js +21 -8
  141. package/packages/core/release-passport-contract.js +5 -5
  142. package/packages/core/release-passport.js +20 -131
  143. package/packages/core/self-dogfood-version.js +48 -35
  144. package/packages/core/spawn-command.js +232 -8
  145. package/packages/core/v4-adopter-delivery-parity.js +219 -0
  146. package/packages/core/v4-canonical-contracts.js +284 -0
  147. package/packages/core/v4-delivery-warrant-fixture-runner.js +371 -0
  148. package/packages/core/v4-delivery-warrant-read-candidate.js +279 -0
  149. package/packages/core/v4-delivery-warrant-semantic-diff-gate.js +352 -0
  150. package/packages/core/v4-delivery-warrant-shadow-adapter.js +447 -0
  151. package/packages/core/v4-partial-mutation-recovery-qualification.js +395 -0
  152. package/packages/core/v4-platform-stage-checkpoints.js +471 -0
  153. package/packages/core/v4-provider-operation-journal.js +531 -0
  154. package/packages/core/v4-provider-readback-idempotency.js +394 -0
  155. package/packages/core/v4-release-activation-shadow.js +519 -0
  156. package/packages/core/v4-stable-publication-fence.js +357 -0
  157. package/packages/core/v4-stage-capsule-local-store.js +426 -0
  158. package/packages/core/v4-stage-capsule-qualification-campaign.js +512 -0
  159. package/packages/core/v4-stage-capsule-qualification.js +456 -0
  160. package/packages/core/v4-stage-capsule-resume-planner.js +397 -0
  161. package/packages/core/v4-stage-capsule-store.js +401 -0
  162. package/packages/core/v4-stage-capsule.js +319 -0
  163. package/scripts/assemble-self-publication-admission.mjs +1 -1
  164. package/scripts/audit-publication-control-plane.mjs +5 -5
  165. package/scripts/auditable-demo-bundle-verification.mjs +3 -2
  166. package/scripts/auditable-demo-platform.mjs +2 -2
  167. package/scripts/auditable-demo-renditions.mjs +1 -1
  168. package/scripts/auditable-demo.mjs +2 -2
  169. package/scripts/aws-macos-jit-controller-core.mjs +13 -346
  170. package/scripts/aws-macos-jit-controller-runtime.mjs +2 -210
  171. package/scripts/aws-macos-jit-controller.mjs +37 -275
  172. package/scripts/aws-macos-jit-core.mjs +3 -41
  173. package/scripts/aws-macos-jit.mjs +0 -12
  174. package/scripts/aws-windows-jit-campaign.mjs +2 -2
  175. package/scripts/aws-windows-jit-controller-core.mjs +1 -1
  176. package/scripts/aws-windows-jit-controller.mjs +3 -3
  177. package/scripts/build-contract-core.mjs +3 -8
  178. package/scripts/build-standalone-binary.mjs +3 -14
  179. package/scripts/buildchain-channel-router.mjs +4 -0
  180. package/scripts/buildchain-cli-help.mjs +7 -16
  181. package/scripts/buildchain-contract-lock.mjs +0 -6
  182. package/scripts/check-action-bundles.mjs +3 -4
  183. package/scripts/check-internal-architecture.mjs +7 -6
  184. package/scripts/check-inventory.mjs +30 -25
  185. package/scripts/check-v4-public-dogfood-contract.mjs +270 -0
  186. package/scripts/create-release-bundle.mjs +8 -4
  187. package/scripts/dev-alpha-candidate-patrol.mjs +1 -22
  188. package/scripts/dev-delivery-proof.mjs +2 -64
  189. package/scripts/dev-delivery-warrant.mjs +61 -86
  190. package/scripts/dev-pr-auto-merge.mjs +4 -30
  191. package/scripts/dev-pr-delivery-warrant.mjs +0 -55
  192. package/scripts/dispatch-artifact-signing-authority.mjs +7 -4
  193. package/scripts/generate-buildchain-kfd-witnesses.mjs +94 -88
  194. package/scripts/generate-channel-build-workflow.mjs +54 -24
  195. package/scripts/generate-channel-promotion-workflow.mjs +15 -6
  196. package/scripts/generate-site-bundle.mjs +8 -27
  197. package/scripts/git-fetch-process-tree.mjs +34 -1
  198. package/scripts/init-repo.mjs +64 -159
  199. package/scripts/inspect-artifact-signing-requests.mjs +0 -6
  200. package/scripts/locked-source-checkout.mjs +3 -4
  201. package/scripts/maintainability-metrics.mjs +8 -2
  202. package/scripts/npm-publish-dry-run.mjs +2 -2
  203. package/scripts/npm-publish-transaction.mjs +2 -2
  204. package/scripts/publication-commit-evidence.mjs +23 -69
  205. package/scripts/release-candidate-resolver.mjs +11 -17
  206. package/scripts/release-tail.mjs +3 -49
  207. package/scripts/resume-from-candidate-run.mjs +9 -123
  208. package/scripts/run-lifecycle-core.mjs +12 -13
  209. package/scripts/seal-artifact-signing-requests.mjs +17 -21
  210. package/scripts/site-capability-metadata.mjs +3 -20
  211. package/scripts/stable-candidate-qualification.mjs +10 -10
  212. package/scripts/v4-architecture.mjs +12 -2
  213. package/scripts/v4-bridge-bootstrap.mjs +141 -0
  214. package/scripts/v4-bridge-evidence.mjs +141 -0
  215. package/scripts/v4-host-adapter.mjs +182 -0
  216. package/scripts/v4-platform-stage-checkpoint-rehearsal.mjs +207 -0
  217. package/scripts/v4-stage-capsule-qualification.mjs +528 -0
  218. package/scripts/v4-stage-capsule-resume-rehearsal.mjs +57 -0
  219. package/scripts/v4-warrant-shadow-plan.mjs +601 -0
  220. package/scripts/verify-golden-path.mjs +5 -5
  221. package/scripts/web-surface-cloudfront-rewrite.mjs +15 -15
  222. package/scripts/web-surface-core.mjs +2 -8
  223. package/scripts/workflow-call-contract.mjs +5 -184
  224. package/contracts/dev-delivery-authority-v2.schema.json +0 -253
  225. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json +0 -16
  226. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json +0 -57
  227. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +0 -47
  228. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +0 -47
  229. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +0 -40
  230. package/contracts/next-development-request-v1.schema.json +0 -66
  231. package/contracts/next-development-transition-v1.schema.json +0 -292
  232. package/contracts/publication-rehearsal-capsule-v1.schema.json +0 -173
  233. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +0 -442
  234. package/dist/site/schemas/publication-rehearsal-capsule-v1.schema.json +0 -269
  235. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +0 -353
  236. package/dist/site/schemas/release-tail-provider-bindings-v1.schema.json +0 -94
  237. package/docs/dev-delivery-qualification-landing-adr.md +0 -137
  238. package/docs/next-development-transition.md +0 -119
  239. package/docs/publication-rehearsal.md +0 -94
  240. package/packages/core/buildchain-compatibility-proof.js +0 -631
  241. package/packages/core/dev-delivery-authority.js +0 -996
  242. package/packages/core/dev-delivery-native-proof.js +0 -418
  243. package/packages/core/dev-delivery-warrant-shadow.js +0 -502
  244. package/packages/core/next-development-candidate-reservation.js +0 -186
  245. package/packages/core/next-development-controller.js +0 -726
  246. package/packages/core/next-development-projection.js +0 -288
  247. package/packages/core/next-development-transition.js +0 -738
  248. package/packages/core/publication-rehearsal-projection.js +0 -173
  249. package/packages/core/publication-rehearsal-runtime.js +0 -921
  250. package/scripts/aws-macos-jit-instance-rehydrate.mjs +0 -260
  251. package/scripts/aws-macos-jit-source-rebind.mjs +0 -724
  252. package/scripts/dev-delivery-authority.mjs +0 -368
  253. package/scripts/dev-delivery-native-run.mjs +0 -235
  254. package/scripts/dev-delivery-two-phase-resume.mjs +0 -90
  255. package/scripts/dev-delivery-two-phase.mjs +0 -577
  256. package/scripts/generate-next-development-guidance.mjs +0 -49
  257. package/scripts/materialize-self-release-candidate-version.mjs +0 -137
  258. package/scripts/next-development-self-dogfood-harness.mjs +0 -409
  259. package/scripts/next-development-self-dogfood.mjs +0 -532
  260. package/scripts/next-development-transition.mjs +0 -47
  261. package/scripts/release-candidate-tail-reseal.mjs +0 -426
  262. package/templates/native-dev-delivery.yml +0 -86
@@ -1,115 +1,121 @@
1
1
  #!/usr/bin/env node
2
- import crypto from "node:crypto";
3
2
  import fs from "node:fs";
4
- import { execFileSync } from "node:child_process";
5
- import { createRequire } from "node:module";
6
3
  import path from "node:path";
4
+ import { execFileSync } from "node:child_process";
7
5
  import { pathToFileURL } from "node:url";
8
- import { addAdopterWitness, initAdopterManifest } from "@kungfu-tech/kfd/adopter-conformance/toolchain";
9
- import kfdStandards from "@kungfu-tech/kfd/standards.json" with { type: "json" };
10
- import { installedKfdPackageArtifactRoot } from "../packages/core/artifact-verification-envelope.js";
11
- import { createKfdAdopterManifestGate, createKfdLegacySupportMatrixProjection, validateKfdAdopterManifestGate, validateKfdLegacySupportMatrixProjection } from "../packages/core/kfd-adopter-manifest.js";
12
- import { KFD_PRODUCT_GATE_INPUT_CONTRACT, evaluateKfdProductGate, kfdProductGateDigest, validateKfdProductGateResult } from "../packages/core/kfd-product-gates.js";
13
- import { createBuildchainKfd1Witness, createBuildchainKfd2Claims, createBuildchainKfd3ArtifactWitness, createBuildchainKfd3PrebuildWitness } from "../packages/core/buildchain-kfd-claims.js";
14
- import { BUILDCHAIN_KFD1_CONTRACT_WORLD_WITNESS_PATH, BUILDCHAIN_KFD2_CLAIMS_DIR, BUILDCHAIN_KFD3_ARTIFACT_WITNESS_PATH, BUILDCHAIN_KFD3_PREBUILD_WITNESS_PATH } from "../packages/core/buildchain-layout.js";
6
+ import {
7
+ createBuildchainKfd1Witness,
8
+ createBuildchainKfd2Claims,
9
+ createBuildchainKfd3ArtifactWitness,
10
+ createBuildchainKfd3PrebuildWitness,
11
+ } from "../packages/core/buildchain-kfd-claims.js";
12
+ import {
13
+ BUILDCHAIN_KFD1_CONTRACT_WORLD_WITNESS_PATH,
14
+ BUILDCHAIN_KFD2_CLAIMS_DIR,
15
+ BUILDCHAIN_KFD3_ARTIFACT_WITNESS_PATH,
16
+ BUILDCHAIN_KFD3_PREBUILD_WITNESS_PATH,
17
+ } from "../packages/core/buildchain-layout.js";
15
18
  import { writeGitHubOutputs } from "./build-contract-core.mjs";
16
- const REPOSITORY = "kungfu-systems/buildchain", require = createRequire(import.meta.url), kfdRoot = path.dirname(require.resolve("@kungfu-tech/kfd/package.json"));
17
- const evidenceSources = { "KFD-1": "dist/site/release-passport-check-manifest.json", "KFD-2": "dist/site/kfd-claims.json", "KFD-3": "dist/site/public-surface-audit.json", "KFD-4": "packages/core/kfd-product-gates.js", "KFD-5": "packages/core/kfd-product-gates.js", "KFD-7": "packages/core/kfd-product-gates.js", "KFD-10": "packages/core/dev-delivery-warrant.js" };
19
+
18
20
  function parseArgs(argv = process.argv.slice(2)) {
19
- const args = { cwd: process.cwd(), outputDir: ".buildchain/kfd", sourceSha: process.env.BUILDCHAIN_SOURCE_SHA || "" };
21
+ const args = {
22
+ cwd: process.cwd(),
23
+ outputDir: ".buildchain/kfd",
24
+ sourceSha: process.env.BUILDCHAIN_SOURCE_SHA || "",
25
+ };
20
26
  for (let index = 0; index < argv.length; index += 1) {
21
27
  const arg = argv[index];
22
- if (arg === "--cwd") args.cwd = argv[++index] || args.cwd;
23
- else if (arg === "--output-dir") args.outputDir = argv[++index] || args.outputDir;
24
- else if (arg === "--source-sha") args.sourceSha = argv[++index] || args.sourceSha;
25
- else if (arg === "--help") args.help = true;
26
- else throw new Error(`unknown argument: ${arg}`);
28
+ if (arg === "--cwd") {
29
+ args.cwd = argv[++index] || args.cwd;
30
+ } else if (arg === "--output-dir") {
31
+ args.outputDir = argv[++index] || args.outputDir;
32
+ } else if (arg === "--source-sha") {
33
+ args.sourceSha = argv[++index] || args.sourceSha;
34
+ } else if (arg === "--help") {
35
+ args.help = true;
36
+ } else {
37
+ throw new Error(`unknown argument: ${arg}`);
38
+ }
27
39
  }
28
40
  return args;
29
41
  }
42
+
30
43
  function gitSha(cwd) {
31
- try { return execFileSync("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8" }).trim(); } catch { return ""; }
44
+ try {
45
+ return execFileSync("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8" }).trim();
46
+ } catch {
47
+ return "";
48
+ }
32
49
  }
33
- function digest(bytes) { return `sha256:${crypto.createHash("sha256").update(bytes).digest("hex")}`; }
34
- function fileDigest(filePath) { return digest(fs.readFileSync(filePath)); }
35
- function relative(root, filePath) { return path.relative(root, filePath).replace(/\\/g, "/"); }
36
- function writeJson(root, relativePath, value) {
37
- const filePath = path.join(root, relativePath);
50
+
51
+ function writeJson(filePath, value) {
38
52
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
39
53
  fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
40
- return { path: relativePath, sha256: fileDigest(filePath), filePath };
41
54
  }
42
- function readJson(filePath, sourceSha = "") { return JSON.parse(fs.readFileSync(filePath, "utf8").replaceAll("{{SOURCE_SHA}}", sourceSha)); }
43
- export function generateBuildchainKfdWitnesses({ cwd = process.cwd(), outputDir = ".buildchain/kfd", sourceSha = "", emitOutputs = true } = {}) {
44
- const root = path.resolve(cwd), outDir = path.resolve(root, outputDir), resolvedSourceSha = sourceSha || gitSha(root);
55
+
56
+ function toRepoRelative(cwd, filePath) {
57
+ return path.relative(cwd, filePath).replace(/\\/g, "/");
58
+ }
59
+
60
+ export function generateBuildchainKfdWitnesses({
61
+ cwd = process.cwd(),
62
+ outputDir = ".buildchain/kfd",
63
+ sourceSha = "",
64
+ emitOutputs = true,
65
+ } = {}) {
66
+ const root = path.resolve(cwd);
67
+ const outDir = path.resolve(root, outputDir);
68
+ const resolvedSourceSha = sourceSha || gitSha(root);
45
69
  const outputPath = (canonicalPath) => path.join(outDir, path.relative(".buildchain/kfd", canonicalPath));
46
- const paths = { kfd1Witness: outputPath(BUILDCHAIN_KFD1_CONTRACT_WORLD_WITNESS_PATH), kfd3PrebuildWitness: outputPath(BUILDCHAIN_KFD3_PREBUILD_WITNESS_PATH), kfd3ArtifactWitness: outputPath(BUILDCHAIN_KFD3_ARTIFACT_WITNESS_PATH), kfd2ClaimsDir: outputPath(BUILDCHAIN_KFD2_CLAIMS_DIR) };
47
- writeJson(path.dirname(paths.kfd1Witness), path.basename(paths.kfd1Witness), createBuildchainKfd1Witness({ root, sourceSha: resolvedSourceSha }));
48
- writeJson(path.dirname(paths.kfd3PrebuildWitness), path.basename(paths.kfd3PrebuildWitness), createBuildchainKfd3PrebuildWitness({ root, sourceSha: resolvedSourceSha }));
49
- writeJson(path.dirname(paths.kfd3ArtifactWitness), path.basename(paths.kfd3ArtifactWitness), createBuildchainKfd3ArtifactWitness({ root, sourceSha: resolvedSourceSha }));
50
- const witnessFiles = { "kfd-1-witness": relative(root, paths.kfd1Witness), "kfd-3-prebuild-witness": relative(root, paths.kfd3PrebuildWitness), "kfd-3-artifact-witness": relative(root, paths.kfd3ArtifactWitness) };
70
+ const paths = {
71
+ kfd1Witness: outputPath(BUILDCHAIN_KFD1_CONTRACT_WORLD_WITNESS_PATH),
72
+ kfd3PrebuildWitness: outputPath(BUILDCHAIN_KFD3_PREBUILD_WITNESS_PATH),
73
+ kfd3ArtifactWitness: outputPath(BUILDCHAIN_KFD3_ARTIFACT_WITNESS_PATH),
74
+ kfd2ClaimsDir: outputPath(BUILDCHAIN_KFD2_CLAIMS_DIR),
75
+ };
76
+ writeJson(paths.kfd1Witness, createBuildchainKfd1Witness({ root, sourceSha: resolvedSourceSha }));
77
+ writeJson(paths.kfd3PrebuildWitness, createBuildchainKfd3PrebuildWitness({ root, sourceSha: resolvedSourceSha }));
78
+ writeJson(paths.kfd3ArtifactWitness, createBuildchainKfd3ArtifactWitness({ root, sourceSha: resolvedSourceSha }));
79
+ const witnessFiles = {
80
+ "kfd-1-witness": toRepoRelative(root, paths.kfd1Witness),
81
+ "kfd-3-prebuild-witness": toRepoRelative(root, paths.kfd3PrebuildWitness),
82
+ "kfd-3-artifact-witness": toRepoRelative(root, paths.kfd3ArtifactWitness),
83
+ };
51
84
  const kfd2ClaimPaths = createBuildchainKfd2Claims({ root, witnessFiles }).map((claim) => {
52
- const slug = String(claim.id || "claim").replace(/^claim:/, "").replace(/[^0-9A-Za-z._-]+/g, "-").replace(/^-+|-+$/g, "") || "claim";
53
- return writeJson(paths.kfd2ClaimsDir, `${slug}.json`, claim).filePath;
85
+ const slug = String(claim.id || "claim")
86
+ .replace(/^claim:/, "")
87
+ .replace(/[^0-9A-Za-z._-]+/g, "-")
88
+ .replace(/^-+|-+$/g, "") || "claim";
89
+ const claimPath = path.join(paths.kfd2ClaimsDir, `${slug}.json`);
90
+ writeJson(claimPath, claim);
91
+ return claimPath;
54
92
  });
55
- const outputs = { "kfd-1-witness-jsons": relative(root, paths.kfd1Witness), "kfd-2-claim-jsons": kfd2ClaimPaths.map((filePath) => relative(root, filePath)).join(","), "kfd-3-prebuild-witness-jsons": relative(root, paths.kfd3PrebuildWitness), "kfd-3-artifact-witness-jsons": relative(root, paths.kfd3ArtifactWitness), "source-sha": resolvedSourceSha, "output-dir": relative(root, outDir) };
56
- if (emitOutputs) writeGitHubOutputs(outputs);
57
- return { schemaVersion: 1, contract: "kungfu-buildchain-self-kfd-witness-generation", outputs };
58
- }
59
- function productRecords(root, standard, sourceSha) {
60
- if (standard === "kfd-4") return [
61
- ["observer-perspective", readJson(path.join(root, "contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json"), sourceSha)],
62
- ["perspective-replay", readJson(path.join(root, "contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json"), sourceSha)],
63
- ];
64
- if (standard === "kfd-5") return [["primitive-discovery", readJson(path.join(kfdRoot, "cases/live/software-work-perspective-settlement/cuts/0001-assignment.json"))]];
65
- const profile = readJson(path.join(kfdRoot, "verifier/fixtures/kfd-7/valid-domain-profile.json"));
66
- profile.evidenceObligations = profile.evidenceObligations.map((entry) => ({ ...entry, status: "passed", artifactRefs: ["qualification-proof"], residualRisk: "Bound to the retained Buildchain product gate cut; independent certification remains external." }));
67
- profile.activation = { decision: "activate", evidenceCut: `git://${REPOSITORY}@${sourceSha}`, independentReview: "review://protected-release-review", productWitnesses: ["qualification-proof"], residualRisk: "The product gate is non-qualifying and non-self-certifying." };
68
- profile.domainProfile = { ...profile.domainProfile, product: "Buildchain", implementation: `git+https://github.com/${REPOSITORY}@${sourceSha}`, qualificationStatus: "qualified" };
69
- return [["domain-profile", profile]];
70
- }
71
- async function generateProductGate(root, outDir, standard, sourceSha, checkedAt) {
72
- const records = productRecords(root, standard, sourceSha).map(([role, value], index) => ({ role, ...writeJson(outDir, `records/${standard}-${index}.json`, value) }));
73
- const kinds = standard === "kfd-4" ? [["projection-fsck", "projection-fsck"], ["negative", "negative-fixture"]] : standard === "kfd-5" ? [["negative", "negative-fixture"]] : [["qualification-proof", "qualification-proof"], ["independent-review", "independent-review"], ["negative", "negative-fixture"]];
74
- const evidence = kinds.map(([id, kind]) => ({ id, kind, ...writeJson(outDir, `evidence/${standard}-${id}.json`, { schemaVersion: 1, contract: "kungfu-buildchain-kfd-adopter-evidence-reference", id, kind, source: { repository: REPOSITORY, sha: sourceSha }, observedAt: checkedAt, status: "retained", nonClaim: "This product-owned reference does not independently qualify or certify KFD adoption." }) }));
75
- const input = { schemaVersion: 1, contract: KFD_PRODUCT_GATE_INPUT_CONTRACT, standard, standardRevision: kfdStandards.standards[standard].revision, source: { repository: REPOSITORY, sha: sourceSha }, evidenceCut: { generatedAt: checkedAt, expiresAt: new Date(Date.parse(checkedAt) + 86400000).toISOString() }, records: records.map(({ role, path, sha256 }) => ({ role, path, sha256 })), evidence: evidence.map(({ id, kind, path, sha256 }) => ({ id, kind, path, sha256 })), responsibility: { owner: REPOSITORY, evidenceOwner: "Buildchain maintainers", proofOwner: "Buildchain release gate" }, nonClaims: ["A passed product gate does not qualify, certify, activate, or independently approve KFD adoption."] };
76
- const gate = await evaluateKfdProductGate({ cwd: outDir, input, expectedSourceSha: sourceSha, checkedAt });
77
- if (gate.status !== "passed" || !validateKfdProductGateResult(gate, { expectedSourceSha: sourceSha, checkedAt }).valid) throw new Error(`${standard} product gate failed: ${JSON.stringify(gate.issues)}`);
78
- writeJson(outDir, `${standard}/product-gate.json`, gate);
79
- return gate;
80
- }
81
- export async function generateBuildchainKfdAdopterRelease({ cwd = process.cwd(), outputDir = ".buildchain/kfd/adopter-release", sourceSha = "", checkedAt = new Date().toISOString(), emitOutputs = true } = {}) {
82
- const root = path.resolve(cwd), outDir = path.resolve(root, outputDir);
83
- if (!/^[0-9a-f]{40}$/.test(sourceSha) || !Number.isFinite(Date.parse(checkedAt))) throw new Error("source SHA and checked-at must be exact");
84
- for (const sourcePath of Object.values(evidenceSources)) if (!fs.statSync(path.join(root, sourcePath)).isFile()) throw new Error(`required Buildchain evidence source is missing: ${sourcePath}`);
85
- const packageArtifactRoot = installedKfdPackageArtifactRoot(), gates = [];
86
- for (const standard of ["kfd-4", "kfd-5", "kfd-7"]) gates.push(await generateProductGate(root, outDir, standard, sourceSha, checkedAt));
87
- const sourceRoot = kfdProductGateDigest({ repository: REPOSITORY, sourceSha, files: [...new Set(Object.values(evidenceSources))].sort().map((sourcePath) => ({ path: sourcePath, sha256: fileDigest(path.join(root, sourcePath)) })) });
88
- let manifest = initAdopterManifest({ manifestId: "buildchain-v3-full-cut", adopterId: REPOSITORY, artifactKind: "git-commit", artifactCoordinate: `${REPOSITORY}@${sourceSha}`, artifactRoot: sourceRoot, scope: "Buildchain v3 release and protected delivery authority", packageArtifactRoot, verifiedAt: checkedAt, maxAgeSeconds: 86400, packageRoot: kfdRoot });
89
- const gateById = new Map(gates.map((gate) => [gate.standard.toUpperCase(), gate]));
90
- for (const id of ["KFD-1", "KFD-2", "KFD-3", "KFD-4", "KFD-5", "KFD-7"]) {
91
- const row = manifest.decisions.find((entry) => entry.id === id);
92
- const sourcePath = evidenceSources[id];
93
- const sourceEvidence = (kind, rootValue = fileDigest(path.join(root, sourcePath))) => ({ kind, coordinate: `git+https://github.com/${REPOSITORY}@${sourceSha}#${sourcePath}`, root: rootValue, observedAt: checkedAt, kfdPackageRoot: packageArtifactRoot });
94
- row.state = "candidate"; row.usage = "used"; row.implementationEvidence = [sourceEvidence("implementation")]; row.verificationEvidence = [sourceEvidence("verification", gateById.get(id)?.gateRoot)]; row.gaps = ["Independent decision-specific assessment and certification remain external."];
93
+ const outputs = {
94
+ "kfd-1-witness-jsons": toRepoRelative(root, paths.kfd1Witness),
95
+ "kfd-2-claim-jsons": kfd2ClaimPaths.map((claimPath) => toRepoRelative(root, claimPath)).join(","),
96
+ "kfd-3-prebuild-witness-jsons": toRepoRelative(root, paths.kfd3PrebuildWitness),
97
+ "kfd-3-artifact-witness-jsons": toRepoRelative(root, paths.kfd3ArtifactWitness),
98
+ "source-sha": resolvedSourceSha,
99
+ "output-dir": toRepoRelative(root, outDir),
100
+ };
101
+ if (emitOutputs) {
102
+ writeGitHubOutputs(outputs);
95
103
  }
96
- const kfd6 = manifest.decisions.find((entry) => entry.id === "KFD-6");
97
- kfd6.state = "unsupported"; kfd6.usage = "unused"; kfd6.gaps = ["Buildchain does not claim KFD-6 support in this cut."];
98
- manifest = addAdopterWitness(manifest, { decisionId: "KFD-10", profileId: "kfd-warrant-evidence", witnessCoordinate: `git+https://github.com/${REPOSITORY}@${sourceSha}#${evidenceSources["KFD-10"]}`, witnessRoot: fileDigest(path.join(root, evidenceSources["KFD-10"])), packageArtifactRoot, verifiedAt: checkedAt, maxAgeSeconds: 86400, packageRoot: kfdRoot });
99
- const manifestPath = writeJson(outDir, "kfd-adopter-manifest.json", manifest).filePath, manifestGate = createKfdAdopterManifestGate({ manifest, packageArtifactRoot, gateResults: gates, authorityPath: "kfd-adopter-manifest.json", expectedSourceSha: sourceSha, checkedAt });
100
- if (!validateKfdAdopterManifestGate(manifestGate, { expectedSourceSha: sourceSha, checkedAt }).valid) throw new Error(`generated adopter manifest gate failed: ${JSON.stringify(manifestGate.issues)}`);
101
- const gatePath = writeJson(outDir, "kfd-adopter-manifest-gate.json", manifestGate).filePath, support = createKfdLegacySupportMatrixProjection({ manifest, manifestGate });
102
- if (!validateKfdLegacySupportMatrixProjection(support, { manifest, manifestGate }).valid) throw new Error("generated KFD support projection failed");
103
- const supportPath = writeJson(outDir, "kfd-support.json", support).filePath;
104
- const outputs = { "kfd-adopter-manifest-json": relative(root, manifestPath), "kfd-adopter-manifest-gate-json": relative(root, gatePath), "kfd-support-matrix-json": relative(root, supportPath), "kfd-product-gate-jsons": gates.map((gate) => relative(root, path.join(outDir, gate.standard, "product-gate.json"))).join(","), "kfd-adopter-manifest-root": manifestGate.authority.manifestRoot, "kfd-adopter-gate-root": manifestGate.gateRoot, "kfd-package-artifact-root": packageArtifactRoot, "source-sha": sourceSha };
105
- if (emitOutputs) writeGitHubOutputs(outputs);
106
- return { schemaVersion: 1, contract: "kungfu-buildchain-kfd-adopter-release-generation", status: "passed", qualifying: false, selfCertified: false, outputs };
104
+ return {
105
+ schemaVersion: 1,
106
+ contract: "kungfu-buildchain-self-kfd-witness-generation",
107
+ outputs,
108
+ };
107
109
  }
110
+
108
111
  if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
109
112
  try {
110
113
  const args = parseArgs();
111
- if (args.help) process.stdout.write("Usage: generate-buildchain-kfd-witnesses [--cwd <repo>] [--output-dir <dir>] [--source-sha <sha>]\n");
112
- else process.stdout.write(`${JSON.stringify(generateBuildchainKfdWitnesses(args), null, 2)}\n`);
114
+ if (args.help) {
115
+ process.stdout.write("Usage: generate-buildchain-kfd-witnesses [--cwd <repo>] [--output-dir <dir>] [--source-sha <sha>]\n");
116
+ process.exit(0);
117
+ }
118
+ process.stdout.write(`${JSON.stringify(generateBuildchainKfdWitnesses(args), null, 2)}\n`);
113
119
  } catch (error) {
114
120
  console.error(`buildchain self KFD witnesses: ${error.message}`);
115
121
  process.exitCode = 1;
@@ -46,26 +46,22 @@ function routerInputs(inputBlock) {
46
46
 
47
47
  function routerOutputs(outputBlock) {
48
48
  const forwarded = outputBlock
49
- .replace(
50
- /^ value: \$\{\{ jobs\.[^.]+\.outputs\.([a-z0-9-]+) \|\| jobs\.[^.]+\.outputs\.\1 \}\}$/gm,
51
- " value: ${{ jobs.alpha.outputs.$1 || jobs.stable.outputs.$1 }}",
52
- )
53
- .replace(/^ value: \$\{\{ jobs\.[^.]+\.outputs\.([^ }]+) \}\}$/gm, " value: ${{ jobs.alpha.outputs.$1 || jobs.stable.outputs.$1 }}")
49
+ .replace(/^ value: \$\{\{ jobs\.[^.]+\.outputs\.([^ }]+) \}\}$/gm, " value: ${{ jobs.override.outputs.$1 || jobs.alpha.outputs.$1 || jobs.stable.outputs.$1 }}")
54
50
  .replaceAll("build-lifecycle", "build-channel-router")
55
- .replace("value: ${{ jobs.alpha.outputs.controller-plan-artifact || jobs.stable.outputs.controller-plan-artifact }}", "value: ${{ jobs.controller-plan.outputs.controller-plan-artifact }}")
56
- .replace("value: ${{ jobs.alpha.outputs.controller-plan-json || jobs.stable.outputs.controller-plan-json }}", "value: ${{ jobs.controller-plan.outputs.controller-plan-json }}")
57
- .replace("value: ${{ jobs.alpha.outputs.controller-plan-digest || jobs.stable.outputs.controller-plan-digest }}", "value: ${{ jobs.controller-plan.outputs.controller-plan-digest }}")
58
- .replace("value: ${{ jobs.alpha.outputs.controller-receipt-artifact || jobs.stable.outputs.controller-receipt-artifact }}", "value: ${{ jobs.controller-receipt.outputs.controller-receipt-artifact }}")
59
- .replace("value: ${{ jobs.alpha.outputs.controller-receipt-json || jobs.stable.outputs.controller-receipt-json }}", "value: ${{ jobs.controller-receipt.outputs.controller-receipt-json }}")
60
- .replace("value: ${{ jobs.alpha.outputs.controller-receipt-digest || jobs.stable.outputs.controller-receipt-digest }}", "value: ${{ jobs.controller-receipt.outputs.controller-receipt-digest }}")
61
- .replace("value: ${{ jobs.alpha.outputs.controller-receipt-status || jobs.stable.outputs.controller-receipt-status }}", "value: ${{ jobs.controller-receipt.outputs.controller-receipt-status }}")
51
+ .replace("value: ${{ jobs.override.outputs.controller-plan-artifact || jobs.alpha.outputs.controller-plan-artifact || jobs.stable.outputs.controller-plan-artifact }}", "value: ${{ jobs.controller-plan.outputs.controller-plan-artifact }}")
52
+ .replace("value: ${{ jobs.override.outputs.controller-plan-json || jobs.alpha.outputs.controller-plan-json || jobs.stable.outputs.controller-plan-json }}", "value: ${{ jobs.controller-plan.outputs.controller-plan-json }}")
53
+ .replace("value: ${{ jobs.override.outputs.controller-plan-digest || jobs.alpha.outputs.controller-plan-digest || jobs.stable.outputs.controller-plan-digest }}", "value: ${{ jobs.controller-plan.outputs.controller-plan-digest }}")
54
+ .replace("value: ${{ jobs.override.outputs.controller-receipt-artifact || jobs.alpha.outputs.controller-receipt-artifact || jobs.stable.outputs.controller-receipt-artifact }}", "value: ${{ jobs.controller-receipt.outputs.controller-receipt-artifact }}")
55
+ .replace("value: ${{ jobs.override.outputs.controller-receipt-json || jobs.alpha.outputs.controller-receipt-json || jobs.stable.outputs.controller-receipt-json }}", "value: ${{ jobs.controller-receipt.outputs.controller-receipt-json }}")
56
+ .replace("value: ${{ jobs.override.outputs.controller-receipt-digest || jobs.alpha.outputs.controller-receipt-digest || jobs.stable.outputs.controller-receipt-digest }}", "value: ${{ jobs.controller-receipt.outputs.controller-receipt-digest }}")
57
+ .replace("value: ${{ jobs.override.outputs.controller-receipt-status || jobs.alpha.outputs.controller-receipt-status || jobs.stable.outputs.controller-receipt-status }}", "value: ${{ jobs.controller-receipt.outputs.controller-receipt-status }}")
62
58
  .replace(
63
- /( credential-island-macos-artifact:\n(?: .*\n)*? value:) \$\{\{ jobs\.alpha\.outputs\.artifact-name \|\| jobs\.stable\.outputs\.artifact-name \}\}/,
64
- "$1 ${{ jobs.alpha.outputs.credential-island-macos-artifact || jobs.stable.outputs.credential-island-macos-artifact }}",
59
+ /( credential-island-macos-artifact:\n(?: .*\n)*? value:) \$\{\{ jobs\.override\.outputs\.artifact-name \|\| jobs\.alpha\.outputs\.artifact-name \|\| jobs\.stable\.outputs\.artifact-name \}\}/,
60
+ "$1 ${{ jobs.override.outputs.credential-island-macos-artifact || jobs.alpha.outputs.credential-island-macos-artifact || jobs.stable.outputs.credential-island-macos-artifact }}",
65
61
  )
66
62
  .replace(
67
- /( credential-island-macos-manifest-artifact:\n(?: .*\n)*? value:) \$\{\{ jobs\.alpha\.outputs\.manifest-artifact-name \|\| jobs\.stable\.outputs\.manifest-artifact-name \}\}/,
68
- "$1 ${{ jobs.alpha.outputs.credential-island-macos-manifest-artifact || jobs.stable.outputs.credential-island-macos-manifest-artifact }}",
63
+ /( credential-island-macos-manifest-artifact:\n(?: .*\n)*? value:) \$\{\{ jobs\.override\.outputs\.manifest-artifact-name \|\| jobs\.alpha\.outputs\.manifest-artifact-name \|\| jobs\.stable\.outputs\.manifest-artifact-name \}\}/,
64
+ "$1 ${{ jobs.override.outputs.credential-island-macos-manifest-artifact || jobs.alpha.outputs.credential-island-macos-manifest-artifact || jobs.stable.outputs.credential-island-macos-manifest-artifact }}",
69
65
  );
70
66
  return [
71
67
  " buildchain-channel:",
@@ -85,6 +81,12 @@ function forwardedInputs(names) {
85
81
  return names
86
82
  .map((name) => {
87
83
  if (name === "buildchain-ref") return ` buildchain-ref: \${{ needs.resolve-channel.outputs.buildchain-ref }}`;
84
+ if (name === "buildchain-expected-channel") {
85
+ return " buildchain-expected-channel: ${{ needs.resolve-channel.outputs.channel }}";
86
+ }
87
+ if (name === "buildchain-expected-major") {
88
+ return " buildchain-expected-major: ${{ needs.resolve-channel.outputs.major }}";
89
+ }
88
90
  if (name === "buildchain-contract-lock-path") {
89
91
  return " buildchain-contract-lock-path: ${{ needs.resolve-channel.outputs.contract-lock-path }}";
90
92
  }
@@ -158,6 +160,7 @@ function routerControllerReceiptJob() {
158
160
  needs:
159
161
  - resolve-channel
160
162
  - controller-plan
163
+ - override
161
164
  - alpha
162
165
  - stable
163
166
  if: \${{ always() && needs.controller-plan.result == 'success' }}
@@ -188,9 +191,9 @@ function routerControllerReceiptJob() {
188
191
  env:
189
192
  BUILDCHAIN_CONTROLLER_PLAN_PATH: .buildchain/controller/plan.json
190
193
  BUILDCHAIN_CONTROLLER_STAGES_JSON: >-
191
- [{"id":"resolve-channel","status":"\${{ needs.resolve-channel.result }}"},{"id":"alpha","status":"\${{ needs.alpha.result }}"},{"id":"stable","status":"\${{ needs.stable.result }}"},{"id":"aggregate","status":"\${{ needs.resolve-channel.outputs.channel == 'alpha' && needs.alpha.result || needs.stable.result }}"}]
192
- BUILDCHAIN_CONTROLLER_EVIDENCE_JSON: \${{ (needs.alpha.outputs.controller-receipt-digest != '' || needs.stable.outputs.controller-receipt-digest != '') && format('[{{"kind":"nested-controller-receipt","digest":"{0}"}}]', needs.alpha.outputs.controller-receipt-digest || needs.stable.outputs.controller-receipt-digest) || '[]' }}
193
- BUILDCHAIN_CONTROLLER_REASON_CODE: \${{ ((needs.resolve-channel.outputs.channel == 'alpha' && needs.alpha.result == 'success') || (needs.resolve-channel.outputs.channel == 'stable' && needs.stable.result == 'success')) && '' || 'nested-build-incomplete' }}
194
+ [{"id":"resolve-channel","status":"\${{ needs.resolve-channel.result }}"},{"id":"override","status":"\${{ needs.override.result }}"},{"id":"alpha","status":"\${{ needs.alpha.result }}"},{"id":"stable","status":"\${{ needs.stable.result }}"},{"id":"aggregate","status":"\${{ needs.resolve-channel.outputs.runtime-override == 'true' && needs.override.result || needs.resolve-channel.outputs.channel == 'alpha' && needs.alpha.result || needs.stable.result }}"}]
195
+ BUILDCHAIN_CONTROLLER_EVIDENCE_JSON: \${{ (needs.override.outputs.controller-receipt-digest != '' || needs.alpha.outputs.controller-receipt-digest != '' || needs.stable.outputs.controller-receipt-digest != '') && format('[{{"kind":"nested-controller-receipt","digest":"{0}"}}]', needs.override.outputs.controller-receipt-digest || needs.alpha.outputs.controller-receipt-digest || needs.stable.outputs.controller-receipt-digest) || '[]' }}
196
+ BUILDCHAIN_CONTROLLER_REASON_CODE: \${{ ((needs.resolve-channel.outputs.runtime-override == 'true' && needs.override.result == 'success') || (needs.resolve-channel.outputs.runtime-override != 'true' && needs.resolve-channel.outputs.channel == 'alpha' && needs.alpha.result == 'success') || (needs.resolve-channel.outputs.runtime-override != 'true' && needs.resolve-channel.outputs.channel == 'stable' && needs.stable.result == 'success')) && '' || 'nested-build-incomplete' }}
194
197
  BUILDCHAIN_CONTROLLER_REASON_SUMMARY: Nested build controller did not complete successfully
195
198
  BUILDCHAIN_CONTROLLER_RECEIPT_ARTIFACT: buildchain-channel-controller-receipt-\${{ github.sha }}
196
199
  BUILDCHAIN_CONTROLLER_RECEIPT_PATH: .buildchain/controller/receipt.json
@@ -221,6 +224,7 @@ function routerAggregateJob() {
221
224
  name: Summarize build contract
222
225
  needs:
223
226
  - resolve-channel
227
+ - override
224
228
  - alpha
225
229
  - stable
226
230
  - controller-receipt
@@ -231,13 +235,19 @@ function routerAggregateJob() {
231
235
  shell: bash
232
236
  env:
233
237
  CHANNEL: \${{ needs.resolve-channel.outputs.channel }}
238
+ RUNTIME_OVERRIDE: \${{ needs.resolve-channel.outputs.runtime-override }}
239
+ OVERRIDE_RESULT: \${{ needs.override.result }}
234
240
  ALPHA_RESULT: \${{ needs.alpha.result }}
235
241
  STABLE_RESULT: \${{ needs.stable.result }}
236
242
  CONTROLLER_RECEIPT_RESULT: \${{ needs.controller-receipt.result }}
237
243
  run: |
238
244
  set -euo pipefail
239
245
  selected_result="\${STABLE_RESULT}"
240
- if [[ "\${CHANNEL}" = "alpha" ]]; then selected_result="\${ALPHA_RESULT}"; fi
246
+ if [[ "\${RUNTIME_OVERRIDE}" = "true" ]]; then
247
+ selected_result="\${OVERRIDE_RESULT}"
248
+ elif [[ "\${CHANNEL}" = "alpha" ]]; then
249
+ selected_result="\${ALPHA_RESULT}"
250
+ fi
241
251
  if [[ "\${selected_result}" != "success" || "\${CONTROLLER_RECEIPT_RESULT}" != "success" ]]; then
242
252
  echo "::error::Buildchain channel router did not qualify: channel=\${CHANNEL} selected=\${selected_result} controller-receipt=\${CONTROLLER_RECEIPT_RESULT}"
243
253
  exit 1
@@ -262,13 +272,29 @@ function splitBuildJobsByChannel(workflow, names, major) {
262
272
  if (index < 0) throw new Error("generated workflow is missing the build job");
263
273
  const inputs = forwardedInputs(names);
264
274
  const jobs = `
275
+ override:
276
+ name: Build trusted runtime override
277
+ needs:
278
+ - resolve-channel
279
+ - controller-plan
280
+ if: \${{ needs.resolve-channel.outputs.runtime-override == 'true' }}
281
+ uses: ./.github/workflows/.build.yml
282
+ permissions:
283
+ actions: read
284
+ contents: read
285
+ issues: write
286
+ id-token: write
287
+ with:
288
+ ${inputs}
289
+ secrets: inherit
290
+
265
291
  alpha:
266
292
  name: Build alpha channel
267
293
  needs:
268
294
  - resolve-channel
269
295
  - controller-plan
270
- if: \${{ needs.resolve-channel.outputs.channel == 'alpha' }}
271
- uses: kungfu-systems/buildchain/.github/workflows/.build.yml@v${major}-alpha
296
+ if: \${{ needs.resolve-channel.outputs.runtime-override != 'true' && needs.resolve-channel.outputs.channel == 'alpha' }}
297
+ uses: ./.github/workflows/.build.yml
272
298
  permissions:
273
299
  actions: read
274
300
  contents: read
@@ -283,8 +309,8 @@ ${inputs}
283
309
  needs:
284
310
  - resolve-channel
285
311
  - controller-plan
286
- if: \${{ needs.resolve-channel.outputs.channel == 'stable' }}
287
- uses: kungfu-systems/buildchain/.github/workflows/.build.yml@v${major}
312
+ if: \${{ needs.resolve-channel.outputs.runtime-override != 'true' && needs.resolve-channel.outputs.channel == 'stable' }}
313
+ uses: ./.github/workflows/.build.yml
288
314
  permissions:
289
315
  actions: read
290
316
  contents: read
@@ -355,6 +381,10 @@ export function generateChannelBuildWorkflow(source) {
355
381
  splitBuildJobsByChannel(generateChannelBuildWorkflowBase(source), names, major),
356
382
  )
357
383
  .replaceAll("runs-on: ubuntu-24.04", "runs-on: ${{ fromJSON(inputs.control-runner-json) }}")
384
+ .replace(
385
+ " buildchain-ref: ${{ steps.channel.outputs.buildchain-ref }}\n",
386
+ " buildchain-ref: ${{ steps.channel.outputs.buildchain-ref }}\n major: ${{ steps.channel.outputs.major }}\n runtime-override: ${{ steps.channel.outputs.runtime-override }}\n",
387
+ )
358
388
  .replace(
359
389
  "\npermissions:\n contents: read\n",
360
390
  "\npermissions:\n actions: read\n contents: read\n",
@@ -21,6 +21,8 @@ const internalInputs = new Set([
21
21
  "promotion-target-ref",
22
22
  "promotion-override-used",
23
23
  "publication-authority-workflow-path",
24
+ "buildchain-expected-channel",
25
+ "buildchain-expected-major",
24
26
  ]);
25
27
 
26
28
  function blockBetween(source, start, end) {
@@ -91,7 +93,7 @@ function publicOutputs(outputBlock) {
91
93
  return [...routed, ...forwarded].join("\n");
92
94
  }
93
95
 
94
- function forwardedInputs(inputNames, { includeInternal = true, unsupportedInputs = [] } = {}) {
96
+ function forwardedInputs(inputNames, { includeInternal = true, major = 2, unsupportedInputs = [], workflowPath = ".github/workflows/.release-candidate-promote.yml" } = {}) {
95
97
  const unsupported = new Set(unsupportedInputs);
96
98
  return inputNames
97
99
  .filter((name) => includeInternal || !internalInputs.has(name))
@@ -100,6 +102,7 @@ function forwardedInputs(inputNames, { includeInternal = true, unsupportedInputs
100
102
  const routed = {
101
103
  "buildchain-ref": "runtime-sha",
102
104
  "buildchain-contract-lock-path": "contract-lock-path",
105
+ "buildchain-expected-channel": "channel",
103
106
  channel: "publication-channel",
104
107
  "target-ref": "target-ref",
105
108
  "promotion-router-ref": "router-ref",
@@ -117,8 +120,11 @@ function forwardedInputs(inputNames, { includeInternal = true, unsupportedInputs
117
120
  if (name === "promotion-override-used") {
118
121
  return ` ${name}: \${{ needs.resolve-promotion.outputs.override-used == 'true' }}`;
119
122
  }
123
+ if (name === "buildchain-expected-major") {
124
+ return ` buildchain-expected-major: "${major}"`;
125
+ }
120
126
  if (name === "publication-authority-workflow-path") {
121
- return " publication-authority-workflow-path: .github/workflows/.release-candidate-promote.yml";
127
+ return ` publication-authority-workflow-path: ${workflowPath}`;
122
128
  }
123
129
  return routed
124
130
  ? ` ${name}: \${{ needs.resolve-promotion.outputs.${routed} }}`
@@ -189,11 +195,13 @@ export function generateChannelPromotionWorkflow(source, { major = 2, shellRouti
189
195
  }
190
196
  const alphaForwarded = forwardedInputs(inputNames, {
191
197
  includeInternal: alphaRoute.forwardInternalInputs,
192
- unsupportedInputs: alphaRoute.unsupportedInputs,
198
+ major,
199
+ unsupportedInputs: alphaRoute.unsupportedInputs, workflowPath: alphaRoute.workflowPath,
193
200
  });
194
201
  const stableForwarded = forwardedInputs(inputNames, {
195
202
  includeInternal: stableRoute.forwardInternalInputs,
196
- unsupportedInputs: stableRoute.unsupportedInputs,
203
+ major,
204
+ unsupportedInputs: stableRoute.unsupportedInputs, workflowPath: stableRoute.workflowPath,
197
205
  });
198
206
  return `# Generated by scripts/generate-channel-promotion-workflow.mjs. Do not edit directly.
199
207
  name: Release Candidate Promote
@@ -259,8 +267,9 @@ jobs:
259
267
  exit 1
260
268
  fi
261
269
 
262
- if [[ "\${ref}" =~ ^[0-9A-Fa-f]{40}$ ]]; then sha="\${ref,,}"; else
263
- remote_url="https://github.com/\${repository}.git"; refs="$(git ls-remote "\${remote_url}" "refs/heads/\${ref}" "refs/tags/\${ref}" "refs/tags/\${ref}^{}")"
270
+ if [[ "\${ref}" =~ ^[0-9a-fA-F]{40}$ ]]; then sha="\${ref,,}"; else
271
+ remote_url="https://github.com/\${repository}.git"
272
+ refs="$(git ls-remote "\${remote_url}" "refs/heads/\${ref}" "refs/tags/\${ref}" "refs/tags/\${ref}^{}")"
264
273
  head_sha="$(printf '%s\\n' "\${refs}" | awk -v name="refs/heads/\${ref}" '$2 == name { print tolower($1) }')"
265
274
  tag_sha="$(printf '%s\\n' "\${refs}" | awk -v peeled="refs/tags/\${ref}^{}" -v name="refs/tags/\${ref}" '$2 == peeled { print tolower($1); found=1 } $2 == name && !found { fallback=tolower($1) } END { if (!found && fallback != "") print fallback }')"
266
275
  if [[ -n "\${head_sha}" && -n "\${tag_sha}" && "\${head_sha}" != "\${tag_sha}" ]]; then echo "::error::Promotion router ref is ambiguous between branch and tag"; exit 1; fi
@@ -364,14 +364,13 @@ const manualMetaById = new Map(Object.entries({
364
364
  "publish-transaction": { capabilityGroup: "release-passport-trust", audience: ["release-operator"], maturity: "stable", order: 120 },
365
365
  "release-tail-contract": { capabilityGroup: "release-passport-trust", audience: ["release-operator", "agent", "maintainer"], maturity: "draft", order: 122 },
366
366
  "release-tail-provider-plane": { capabilityGroup: "release-passport-trust", audience: ["release-operator", "agent", "maintainer"], maturity: "preview", order: 123 },
367
- "publication-rehearsal": { capabilityGroup: "release-passport-trust", audience: ["release-operator", "agent", "maintainer"], maturity: "preview", order: 124 },
368
367
  "release-activation-transaction": { capabilityGroup: "release-passport-trust", audience: ["release-operator", "agent"], maturity: "preview", order: 125 },
369
368
  "release-candidate": { capabilityGroup: "reusable-build", audience: ["release-operator", "consumer"], maturity: "stable", order: 130 },
370
369
  "release-train": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 132 },
371
- "next-development-transition": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 133 },
372
370
  "stable-candidate-patrol": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer"], maturity: "preview", order: 135 },
373
371
  "dev-qualification-patrol": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 136 },
374
372
  "dev-alpha-candidate-patrol": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 137 },
373
+ "v4-canonical-contracts": { capabilityGroup: "governance-versioning", audience: ["developer", "maintainer", "agent"], maturity: "preview", order: 138 },
375
374
  "observed-evidence-patrol": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 140 },
376
375
  "engineering-housekeeper": { capabilityGroup: "governance-versioning", audience: ["maintainer", "consumer", "agent"], maturity: "preview", order: 145 },
377
376
  "reusable-build-surface": { capabilityGroup: "reusable-build", audience: ["consumer", "release-operator"], maturity: "stable", order: 200 },
@@ -412,6 +411,10 @@ function pageCapabilityMeta(relPath, category) {
412
411
  if (manual) {
413
412
  return manualMeta(manual.id);
414
413
  }
414
+ const docMeta = category === "manual" ? manualMetaById.get(path.basename(relPath, ".md")) : null;
415
+ if (docMeta) {
416
+ return docMeta;
417
+ }
415
418
  if (category === "action") {
416
419
  return { capabilityGroup: capabilityGroup("api-cli-reference"), audience: ["developer", "agent"], maturity: "stable" };
417
420
  }
@@ -734,7 +737,6 @@ function buildSiteBundle() {
734
737
  "docs/reusable-build-surface.md",
735
738
  "docs/release-candidate.md",
736
739
  "docs/release-train.md",
737
- "docs/next-development-transition.md",
738
740
  "docs/stable-candidate-patrol.md",
739
741
  "docs/dev-qualification-patrol.md",
740
742
  "docs/dev-alpha-candidate-patrol.md",
@@ -927,11 +929,8 @@ function buildSiteBundle() {
927
929
  "buildchain.release.json",
928
930
  "release-passport-check-manifest.json",
929
931
  "schemas/release-passport-v1.schema.json",
930
- "schemas/publication-rehearsal-capsule-v1.schema.json",
931
- "schemas/release-tail-capabilities-v1.schema.json",
932
- "schemas/release-tail-provider-bindings-v1.schema.json",
933
932
  "schemas/kfd-agent-hub-adoption.schema.json",
934
- "schemas/kfd-product-gate-input-v1.schema.json", "schemas/dev-delivery-authority-v2.schema.json",
933
+ "schemas/kfd-product-gate-input-v1.schema.json",
935
934
  "kfd-support.json",
936
935
  "artifact-evidence.json",
937
936
  "product-mechanism.json",
@@ -964,11 +963,8 @@ function buildSiteBundle() {
964
963
  "artifact-schemas.json",
965
964
  "release-passport-check-manifest.json",
966
965
  "schemas/release-passport-v1.schema.json",
967
- "schemas/publication-rehearsal-capsule-v1.schema.json",
968
- "schemas/release-tail-capabilities-v1.schema.json",
969
- "schemas/release-tail-provider-bindings-v1.schema.json",
970
966
  "schemas/kfd-agent-hub-adoption.schema.json",
971
- "schemas/kfd-product-gate-input-v1.schema.json", "schemas/dev-delivery-authority-v2.schema.json",
967
+ "schemas/kfd-product-gate-input-v1.schema.json",
972
968
  "buildchain-contract.json",
973
969
  "kfd-claims.json",
974
970
  "product-mechanism.json",
@@ -1097,11 +1093,8 @@ function buildSiteBundle() {
1097
1093
  "artifact-schemas.json",
1098
1094
  "release-passport-check-manifest.json",
1099
1095
  "schemas/release-passport-v1.schema.json",
1100
- "schemas/publication-rehearsal-capsule-v1.schema.json",
1101
- "schemas/release-tail-capabilities-v1.schema.json",
1102
- "schemas/release-tail-provider-bindings-v1.schema.json",
1103
1096
  "schemas/kfd-agent-hub-adoption.schema.json",
1104
- "schemas/kfd-product-gate-input-v1.schema.json", "schemas/dev-delivery-authority-v2.schema.json",
1097
+ "schemas/kfd-product-gate-input-v1.schema.json",
1105
1098
  "buildchain-contract.json",
1106
1099
  "kfd-upstream-aggregate.json",
1107
1100
  "kfd-claims.json",
@@ -1274,20 +1267,8 @@ function buildSiteBundle() {
1274
1267
  "artifact-schemas.json": artifactSchemas,
1275
1268
  "release-passport-check-manifest.json": createReleasePassportCheckManifest(),
1276
1269
  "schemas/release-passport-v1.schema.json": RELEASE_PASSPORT_SCHEMA,
1277
- "schemas/publication-rehearsal-capsule-v1.schema.json": readJson(
1278
- "contracts/publication-rehearsal-capsule-v1.schema.json",
1279
- ),
1280
- "schemas/release-tail-capabilities-v1.schema.json": readJson(
1281
- "contracts/release-tail-capabilities-v1.schema.json",
1282
- ),
1283
- "schemas/release-tail-provider-bindings-v1.schema.json": readJson(
1284
- "contracts/release-tail-provider-bindings-v1.schema.json",
1285
- ),
1286
1270
  "schemas/kfd-agent-hub-adoption.schema.json": KFD_AGENT_HUB_ADOPTION_SCHEMA,
1287
1271
  "schemas/kfd-product-gate-input-v1.schema.json": KFD_PRODUCT_GATE_INPUT_SCHEMA,
1288
- "schemas/dev-delivery-authority-v2.schema.json": readJson(
1289
- "contracts/dev-delivery-authority-v2.schema.json",
1290
- ),
1291
1272
  "badge-endpoint-registry.json": badgeEndpointRegistry,
1292
1273
  "publication-registry.json": publicationRegistry,
1293
1274
  "buildchain-contract.json": createBuildchainContractWorld({ root, controllerRegistry }),
@@ -1,12 +1,43 @@
1
1
  #!/usr/bin/env node
2
2
  import { execFileSync, spawn } from "node:child_process";
3
3
  import fs from "node:fs";
4
+ import path from "node:path";
4
5
  import { fileURLToPath, pathToFileURL } from "node:url";
5
6
 
6
7
  const INTERNAL_COMMAND = "--buildchain-internal-git-fetch";
8
+ const CMD_META_CHARACTERS = /([()\][%!^`"<>&|;, *?])/g;
7
9
  const TIMEOUT_EXIT_CODE = 124;
8
10
  const scriptPath = fileURLToPath(import.meta.url);
9
11
 
12
+ function cmdEscapeCommand(value) {
13
+ return String(value).replace(CMD_META_CHARACTERS, "^$1");
14
+ }
15
+
16
+ function cmdEscapeArgument(value) {
17
+ let text = String(value);
18
+ text = text.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"');
19
+ text = text.replace(/(?=(\\+?)?)\1$/g, "$1$1");
20
+ return `"${text}"`.replace(CMD_META_CHARACTERS, "^$1");
21
+ }
22
+
23
+ function resolveGitInvocation(args, env = process.env) {
24
+ if (process.platform !== "win32") return { command: "git", args };
25
+ const gitShim = String(env.PATH || "")
26
+ .split(path.delimiter)
27
+ .map((directory) => path.join(directory, "git.cmd"))
28
+ .find((candidate) => fs.existsSync(candidate));
29
+ if (!gitShim) return { command: "git", args };
30
+ const shellCommand = [
31
+ cmdEscapeCommand(gitShim),
32
+ ...args.map(cmdEscapeArgument),
33
+ ].join(" ");
34
+ return {
35
+ command: env.ComSpec || env.comspec || process.env.ComSpec || process.env.comspec || "cmd.exe",
36
+ args: ["/d", "/s", "/c", `"${shellCommand}"`],
37
+ windowsVerbatimArguments: true,
38
+ };
39
+ }
40
+
10
41
  async function terminateProcessTree(child, graceMs) {
11
42
  if (!child?.pid) return;
12
43
  if (process.platform === "win32") {
@@ -63,12 +94,14 @@ async function runInternalGitFetch() {
63
94
  50,
64
95
  Number(process.env.BUILDCHAIN_GIT_TIMEOUT_GRACE_MS || 2000),
65
96
  );
66
- const child = spawn("git", payload.args, {
97
+ const invocation = resolveGitInvocation(payload.args);
98
+ const child = spawn(invocation.command, invocation.args, {
67
99
  cwd: payload.cwd,
68
100
  env: process.env,
69
101
  detached: process.platform !== "win32",
70
102
  stdio: ["ignore", "pipe", "pipe"],
71
103
  windowsHide: true,
104
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments,
72
105
  });
73
106
  const stdout = [];
74
107
  const stderr = [];