@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,577 +0,0 @@
1
- #!/usr/bin/env node
2
- import { execFileSync } from "node:child_process";
3
- import fs from "node:fs";
4
- import path from "node:path";
5
-
6
- import {
7
- createNativeQualificationProof,
8
- devDeliveryContentRoot,
9
- } from "../packages/core/dev-delivery-warrant.js";
10
- import { runNativeWithHeartbeat } from "./dev-delivery-native-run.mjs";
11
- import {
12
- attributedGitHubBaseDelta,
13
- classifyNativeProofAgainstCurrent,
14
- replayQualifiedNativeWarrant,
15
- } from "./dev-delivery-two-phase-resume.mjs";
16
- import { runDevDeliveryCommand } from "./dev-delivery-warrant.mjs";
17
-
18
- function flag(args, name, fallback = "") {
19
- const index = args.indexOf(`--${name}`);
20
- return index === -1 ? fallback : args[index + 1] || "";
21
- }
22
-
23
- function positiveInteger(value, label, fallback = 0) {
24
- const parsed = Number(value || fallback);
25
- if (!Number.isInteger(parsed) || parsed < 1) {
26
- throw new Error(`${label} must be a positive integer`);
27
- }
28
- return parsed;
29
- }
30
-
31
- function jsonList(value, label) {
32
- let parsed;
33
- try {
34
- parsed = JSON.parse(value || "[]");
35
- } catch (cause) {
36
- throw new Error(`${label} must be a JSON array: ${cause.message}`);
37
- }
38
- if (!Array.isArray(parsed)) throw new Error(`${label} must be a JSON array`);
39
- return parsed;
40
- }
41
-
42
- function exactSha(value, label) {
43
- const normalized = String(value || "")
44
- .trim()
45
- .toLowerCase();
46
- if (!/^[0-9a-f]{40}$/u.test(normalized)) {
47
- throw new Error(`${label} must be an exact lowercase Git SHA`);
48
- }
49
- return normalized;
50
- }
51
-
52
- function readJson(file, label) {
53
- if (!file) throw new Error(`${label} is required`);
54
- return JSON.parse(fs.readFileSync(file, "utf8"));
55
- }
56
-
57
- function writeJson(file, value) {
58
- fs.mkdirSync(path.dirname(file), { recursive: true });
59
- fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
60
- }
61
-
62
- export class GitHubTwoPhaseClient {
63
- constructor({
64
- repository,
65
- token,
66
- apiUrl = "https://api.github.com",
67
- fetchImpl = globalThis.fetch,
68
- } = {}) {
69
- if (!token) throw new Error("GITHUB_TOKEN is required");
70
- this.repository = repository;
71
- this.token = token;
72
- this.apiUrl = apiUrl.replace(/\/+$/u, "");
73
- this.fetch = fetchImpl;
74
- }
75
-
76
- async request(requestPath, { method = "GET", body } = {}) {
77
- const response = await this.fetch(`${this.apiUrl}${requestPath}`, {
78
- method,
79
- headers: {
80
- accept: "application/vnd.github+json",
81
- authorization: `Bearer ${this.token}`,
82
- "content-type": "application/json",
83
- "x-github-api-version": "2022-11-28",
84
- },
85
- body: body === undefined ? undefined : JSON.stringify(body),
86
- });
87
- const raw = await response.text();
88
- const data = raw ? JSON.parse(raw) : null;
89
- if (!response.ok) throw new Error(data?.message || `${requestPath} failed`);
90
- return data;
91
- }
92
-
93
- async baseSha(branch) {
94
- const data = await this.request(
95
- `/repos/${this.repository}/git/ref/heads/${branch
96
- .split("/")
97
- .map(encodeURIComponent)
98
- .join("/")}`,
99
- );
100
- return exactSha(data?.object?.sha, "protected base SHA");
101
- }
102
-
103
- async exactPullRequestHead(pullRequestNumber, expectedHead) {
104
- const data = await this.request(
105
- `/repos/${this.repository}/pulls/${pullRequestNumber}`,
106
- );
107
- const observed = exactSha(data?.head?.sha, "observed PR head");
108
- if (observed !== expectedHead) {
109
- throw new Error(
110
- `semantic source head changed: ${observed} != ${expectedHead}`,
111
- );
112
- }
113
- return observed;
114
- }
115
-
116
- async baseDelta(previousBase, currentBase) {
117
- if (previousBase === currentBase) {
118
- return {
119
- graphKnown: true,
120
- attributionComplete: true,
121
- changedPaths: [],
122
- renames: [],
123
- };
124
- }
125
- const data = await this.request(
126
- `/repos/${this.repository}/compare/${previousBase}...${currentBase}`,
127
- );
128
- return attributedGitHubBaseDelta(data, previousBase);
129
- }
130
-
131
- async wake(eventType, candidate) {
132
- await this.request(`/repos/${this.repository}/dispatches`, {
133
- method: "POST",
134
- body: {
135
- event_type: eventType,
136
- // Preserve every binding in one property under GitHub's ten-property limit.
137
- client_payload: { candidate },
138
- },
139
- });
140
- }
141
- }
142
-
143
- export function composeCandidate(candidateDirectory, expectedHead, baseSha) {
144
- try {
145
- execFileSync("git", ["-C", candidateDirectory, "merge", "--abort"], {
146
- stdio: "ignore",
147
- });
148
- } catch {
149
- // No merge was active.
150
- }
151
- execFileSync(
152
- "git",
153
- ["-C", candidateDirectory, "reset", "--hard", expectedHead],
154
- {
155
- stdio: "ignore",
156
- },
157
- );
158
- execFileSync(
159
- "git",
160
- ["-C", candidateDirectory, "merge", "--no-commit", "--no-ff", baseSha],
161
- {
162
- stdio: "pipe",
163
- env: {
164
- ...process.env,
165
- GIT_COMMITTER_NAME: "Buildchain Delivery Warrant",
166
- GIT_COMMITTER_EMAIL:
167
- "buildchain-delivery-warrant@users.noreply.github.com",
168
- },
169
- },
170
- );
171
- }
172
-
173
- async function releaseFailedAttempt({
174
- error,
175
- options,
176
- warrant,
177
- nativeAttempts,
178
- evidenceDirectory,
179
- runCommand,
180
- client,
181
- }) {
182
- const failure = {
183
- schema: "kungfu.buildchain.two-phase-delivery-failure/v1",
184
- pullRequestNumber: options.pullRequestNumber,
185
- expectedHead: options.expectedHead,
186
- fencingToken: warrant.fencingToken,
187
- leaseGeneration: warrant.generation,
188
- nativeAttempts,
189
- reason: error.message,
190
- };
191
- const evidenceRoot = devDeliveryContentRoot(failure);
192
- writeJson(path.join(evidenceDirectory, "failure.json"), {
193
- ...failure,
194
- evidenceRoot,
195
- });
196
- try {
197
- const closed = await runCommand({
198
- command: "close",
199
- repository: options.repository,
200
- branch: options.branch,
201
- fencingToken: warrant.fencingToken,
202
- leaseGeneration: warrant.generation,
203
- outcome: "terminal-failure",
204
- evidenceRoot,
205
- reason: error.message,
206
- execute: true,
207
- token: options.token,
208
- apiUrl: options.apiUrl,
209
- });
210
- writeJson(path.join(evidenceDirectory, "failure-close.json"), closed);
211
- const nextCandidate = closed.observation?.queued?.[0] || null;
212
- if (nextCandidate && options.wakeEventType) {
213
- try {
214
- await client.wake(options.wakeEventType, {
215
- schema: "kungfu.buildchain.dev-delivery-wake/v1",
216
- targetBranch: options.branch,
217
- ...nextCandidate,
218
- });
219
- writeJson(path.join(evidenceDirectory, "wake-next.json"), {
220
- schema: "kungfu.buildchain.dev-delivery-wake-receipt/v1",
221
- eventType: options.wakeEventType,
222
- candidateId: nextCandidate.candidateId,
223
- pullRequestNumber: nextCandidate.pullRequestNumber,
224
- sourceHead: nextCandidate.sourceHead,
225
- action: "repository-dispatch-sent",
226
- });
227
- } catch (wakeError) {
228
- writeJson(path.join(evidenceDirectory, "wake-next-error.json"), {
229
- schema: "kungfu.buildchain.dev-delivery-wake-error/v1",
230
- reason: wakeError.message,
231
- candidateId: nextCandidate.candidateId,
232
- nextAction:
233
- "A later candidate submission or lease recovery will retry deterministic selection.",
234
- });
235
- }
236
- }
237
- } catch (closeError) {
238
- writeJson(path.join(evidenceDirectory, "failure-close-error.json"), {
239
- schema: "kungfu.buildchain.two-phase-delivery-close-error/v1",
240
- reason: closeError.message,
241
- nextAction:
242
- "Recover the expired lease or close the current fenced generation; no merge admission was attempted.",
243
- });
244
- }
245
- }
246
-
247
- export async function runTwoPhaseDelivery(options, dependencies = {}) {
248
- const client =
249
- dependencies.client ||
250
- new GitHubTwoPhaseClient({
251
- repository: options.repository,
252
- token: options.token,
253
- apiUrl: options.apiUrl,
254
- });
255
- const runCommand = dependencies.runCommand || runDevDeliveryCommand;
256
- const runNative = dependencies.runNative || runNativeWithHeartbeat;
257
- const warrantResult = readJson(options.warrantResultPath, "Warrant result");
258
- const warrant =
259
- warrantResult.observation?.activeWarrant || warrantResult.warrant;
260
- if (!warrant || !["provisional", "qualified"].includes(warrant.phase)) {
261
- throw new Error(
262
- "two-phase delivery requires an active provisional or qualified Warrant",
263
- );
264
- }
265
- if (
266
- Number(warrant.pullRequestNumber) !== options.pullRequestNumber ||
267
- warrant.sourceHead !== options.expectedHead
268
- ) {
269
- throw new Error("provisional Warrant does not match the exact PR head");
270
- }
271
- const evidenceDirectory = path.resolve(options.evidenceDirectory);
272
- fs.mkdirSync(evidenceDirectory, { recursive: true });
273
- const qualifiedReplay = await replayQualifiedNativeWarrant({ warrant, pullRequestNumber: options.pullRequestNumber, expectedHead: options.expectedHead, exactPullRequestHead: (...args) => client.exactPullRequestHead(...args) });
274
- if (qualifiedReplay) return qualifiedReplay;
275
- let proof = options.nativeProofPath
276
- ? readJson(options.nativeProofPath, "native proof")
277
- : null;
278
- let classified = proof
279
- ? await classifyNativeProofAgainstCurrent(proof, options, client)
280
- : null;
281
- let nativeAttempts = 0;
282
-
283
- try {
284
- while (true) {
285
- if (classified?.decision.reusable) {
286
- await client.exactPullRequestHead(
287
- options.pullRequestNumber,
288
- options.expectedHead,
289
- );
290
- classified = await classifyNativeProofAgainstCurrent(proof, options, client);
291
- if (classified.decision.reusable) break;
292
- }
293
- if (nativeAttempts >= 2) break;
294
- if (!String(options.nativeCommand || "").trim()) {
295
- throw new Error(
296
- `native proof cannot be reused (${classified?.decision.reason || "not-supplied"}) and native-command is empty`,
297
- );
298
- }
299
- await client.exactPullRequestHead(
300
- options.pullRequestNumber,
301
- options.expectedHead,
302
- );
303
- const qualifiedBase = await client.baseSha(options.branch);
304
- composeCandidate(
305
- options.candidateDirectory,
306
- options.expectedHead,
307
- qualifiedBase,
308
- );
309
- nativeAttempts += 1;
310
- const heartbeatReceipt = await runNative({
311
- command: options.nativeCommand,
312
- cwd: options.candidateDirectory,
313
- intervalMs: options.heartbeatSeconds * 1000,
314
- executionBinding: {
315
- repository: options.repository,
316
- protectedBase: options.branch,
317
- sourceHead: options.expectedHead,
318
- qualifiedBase,
319
- toolchainRoot: options.toolchainRoot,
320
- },
321
- heartbeat: async () => {
322
- await runCommand({
323
- command: "heartbeat",
324
- repository: options.repository,
325
- branch: options.branch,
326
- fencingToken: warrant.fencingToken,
327
- leaseGeneration: warrant.generation,
328
- leaseSeconds: options.leaseSeconds,
329
- execute: true,
330
- token: options.token,
331
- apiUrl: options.apiUrl,
332
- });
333
- },
334
- });
335
- writeJson(
336
- path.join(
337
- evidenceDirectory,
338
- `native-heartbeat-attempt-${nativeAttempts}.json`,
339
- ),
340
- heartbeatReceipt,
341
- );
342
- await client.exactPullRequestHead(
343
- options.pullRequestNumber,
344
- options.expectedHead,
345
- );
346
- proof = createNativeQualificationProof({
347
- repository: options.repository,
348
- protectedBase: options.branch,
349
- sourceIdentityRoot: options.sourceIdentityRoot,
350
- sourcePatchRoot: options.sourcePatchRoot,
351
- planRoot: options.planRoot,
352
- closureRoot: options.closureRoot,
353
- dependencyRoot: options.dependencyRoot,
354
- toolchainRoot: options.toolchainRoot,
355
- environmentRoot: options.environmentRoot,
356
- qualifiedBase,
357
- affectedPaths: options.affectedPaths,
358
- shardEvidenceRoots: [
359
- ...options.shardEvidenceRoots,
360
- heartbeatReceipt.receiptRoot,
361
- ],
362
- qualifiedAt: new Date().toISOString(),
363
- });
364
- writeJson(path.join(evidenceDirectory, "native-proof.json"), proof);
365
- classified = await classifyNativeProofAgainstCurrent(proof, options, client);
366
- }
367
-
368
- if (!classified?.decision.reusable) {
369
- throw new Error(
370
- `native proof remains non-reusable after ${nativeAttempts} attempt(s): ${classified?.decision.reason || "unknown"}`,
371
- );
372
- }
373
- writeJson(path.join(evidenceDirectory, "native-proof.json"), proof);
374
- writeJson(
375
- path.join(evidenceDirectory, "native-reuse-decision.json"),
376
- classified.decision,
377
- );
378
- const qualified = await runCommand({
379
- command: "qualify",
380
- repository: options.repository,
381
- branch: options.branch,
382
- fencingToken: warrant.fencingToken,
383
- leaseGeneration: warrant.generation,
384
- nativeProofPath: path.join(evidenceDirectory, "native-proof.json"),
385
- nativeReuseDecisionPath: path.join(
386
- evidenceDirectory,
387
- "native-reuse-decision.json",
388
- ),
389
- currentBase: classified.current.currentBase,
390
- graphKnown: classified.current.graphKnown,
391
- attributionComplete: classified.current.attributionComplete,
392
- changedPaths: JSON.stringify(classified.current.changedPaths),
393
- renames: JSON.stringify(classified.current.renames),
394
- execute: true,
395
- token: options.token,
396
- apiUrl: options.apiUrl,
397
- });
398
- writeJson(
399
- path.join(evidenceDirectory, "qualified-warrant.json"),
400
- qualified,
401
- );
402
- return {
403
- schema: "kungfu.buildchain.two-phase-delivery-result/v1",
404
- ok: true,
405
- outcome: "qualified-warrant",
406
- nativeAttempts,
407
- nativeProofRoot: proof.proofRoot,
408
- nativeReuseDecisionRoot: classified.decision.decisionRoot,
409
- qualificationReceiptRoot: qualified.receiptRoot,
410
- landingAuthority: false,
411
- qualifiedWarrant: qualified.observation.activeWarrant,
412
- };
413
- } catch (error) {
414
- await releaseFailedAttempt({
415
- error,
416
- options,
417
- warrant,
418
- nativeAttempts,
419
- evidenceDirectory,
420
- runCommand,
421
- client,
422
- });
423
- throw error;
424
- }
425
- }
426
-
427
- function cliOptions(args, environment = process.env) {
428
- const leaseSeconds = positiveInteger(
429
- flag(
430
- args,
431
- "lease-seconds",
432
- environment.BUILDCHAIN_DEV_DELIVERY_LEASE_SECONDS,
433
- ),
434
- "leaseSeconds",
435
- 3600,
436
- );
437
- const heartbeatSeconds = positiveInteger(
438
- flag(
439
- args,
440
- "heartbeat-seconds",
441
- environment.BUILDCHAIN_DEV_DELIVERY_HEARTBEAT_SECONDS,
442
- ),
443
- "heartbeatSeconds",
444
- Math.max(15, Math.floor(leaseSeconds / 3)),
445
- );
446
- if (heartbeatSeconds >= leaseSeconds) {
447
- throw new Error("heartbeatSeconds must be less than leaseSeconds");
448
- }
449
- return {
450
- repository: flag(args, "repository", environment.GITHUB_REPOSITORY),
451
- branch: flag(
452
- args,
453
- "branch",
454
- environment.BUILDCHAIN_DEV_DELIVERY_BRANCH || environment.GITHUB_BASE_REF,
455
- ),
456
- pullRequestNumber: positiveInteger(
457
- flag(args, "pull-request", environment.BUILDCHAIN_DEV_DELIVERY_PR_NUMBER),
458
- "pullRequestNumber",
459
- ),
460
- expectedHead: exactSha(
461
- flag(
462
- args,
463
- "expected-head",
464
- environment.BUILDCHAIN_DEV_DELIVERY_SOURCE_HEAD,
465
- ),
466
- "expectedHead",
467
- ),
468
- sourceIdentityRoot: flag(
469
- args,
470
- "source-identity-root",
471
- environment.BUILDCHAIN_DEV_DELIVERY_SOURCE_IDENTITY_ROOT,
472
- ),
473
- sourcePatchRoot: flag(
474
- args,
475
- "source-patch-root",
476
- environment.BUILDCHAIN_DEV_DELIVERY_SOURCE_PATCH_ROOT,
477
- ),
478
- planRoot: flag(
479
- args,
480
- "plan-root",
481
- environment.BUILDCHAIN_DEV_DELIVERY_PLAN_ROOT,
482
- ),
483
- closureRoot: flag(
484
- args,
485
- "closure-root",
486
- environment.BUILDCHAIN_DEV_DELIVERY_CLOSURE_ROOT,
487
- ),
488
- dependencyRoot: flag(
489
- args,
490
- "dependency-root",
491
- environment.BUILDCHAIN_DEV_DELIVERY_DEPENDENCY_ROOT,
492
- ),
493
- toolchainRoot: flag(
494
- args,
495
- "toolchain-root",
496
- environment.BUILDCHAIN_DEV_DELIVERY_TOOLCHAIN_ROOT,
497
- ),
498
- environmentRoot: flag(
499
- args,
500
- "environment-root",
501
- environment.BUILDCHAIN_DEV_DELIVERY_ENVIRONMENT_ROOT,
502
- ),
503
- affectedPaths: jsonList(
504
- flag(
505
- args,
506
- "affected-paths-json",
507
- environment.BUILDCHAIN_DEV_DELIVERY_AFFECTED_PATHS,
508
- ),
509
- "affectedPaths",
510
- ),
511
- shardEvidenceRoots: jsonList(
512
- flag(
513
- args,
514
- "shard-evidence-roots-json",
515
- environment.BUILDCHAIN_DEV_DELIVERY_SHARD_EVIDENCE_ROOTS,
516
- ),
517
- "shardEvidenceRoots",
518
- ),
519
- nativeCommand: flag(
520
- args,
521
- "native-command",
522
- environment.BUILDCHAIN_DEV_DELIVERY_NATIVE_COMMAND,
523
- ),
524
- nativeProofPath: flag(
525
- args,
526
- "native-proof",
527
- environment.BUILDCHAIN_DEV_DELIVERY_NATIVE_PROOF,
528
- ),
529
- warrantResultPath: flag(
530
- args,
531
- "warrant-result",
532
- environment.BUILDCHAIN_DEV_DELIVERY_WARRANT_RESULT,
533
- ),
534
- candidateDirectory: path.resolve(
535
- flag(args, "candidate-directory", ".buildchain/candidate"),
536
- ),
537
- evidenceDirectory: path.resolve(
538
- flag(args, "evidence-directory", ".buildchain/dev-delivery"),
539
- ),
540
- leaseSeconds,
541
- heartbeatSeconds,
542
- token: environment.GITHUB_TOKEN,
543
- apiUrl: environment.GITHUB_API_URL || "https://api.github.com",
544
- wakeEventType: flag(
545
- args,
546
- "wake-event-type",
547
- environment.BUILDCHAIN_DEV_DELIVERY_WAKE_EVENT_TYPE ||
548
- "buildchain-dev-delivery-wake",
549
- ),
550
- };
551
- }
552
-
553
- async function main() {
554
- const args = process.argv.slice(2);
555
- if (args.length === 0 || args.includes("--help")) {
556
- process.stdout.write(
557
- "Usage: buildchain dev two-phase --repository owner/repo --branch dev/vN/vN.M --pull-request N --expected-head SHA --warrant-result FILE [--native-proof FILE] [--native-command COMMAND]\n",
558
- );
559
- return;
560
- }
561
- const options = cliOptions(args);
562
- const result = await runTwoPhaseDelivery(options);
563
- writeJson(
564
- path.join(options.evidenceDirectory, "two-phase-result.json"),
565
- result,
566
- );
567
- process.stdout.write(
568
- `Two-phase Delivery Warrant: ${result.qualificationReceiptRoot}\n`,
569
- );
570
- }
571
-
572
- if (import.meta.url === `file://${process.argv[1]}`) {
573
- main().catch((error) => {
574
- console.error(`buildchain dev two-phase: ${error.message}`);
575
- process.exit(1);
576
- });
577
- }
@@ -1,49 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import fs from "node:fs";
4
- import path from "node:path";
5
- import { pathToFileURL } from "node:url";
6
-
7
- import { nextDevelopmentManual } from "../packages/core/next-development-projection.js";
8
-
9
- export const NEXT_DEVELOPMENT_MANUAL_PATH =
10
- "docs/next-development-transition.md";
11
-
12
- export function generateNextDevelopmentGuidance({
13
- cwd = process.cwd(),
14
- check = false,
15
- } = {}) {
16
- const target = path.resolve(cwd, NEXT_DEVELOPMENT_MANUAL_PATH);
17
- const expected = nextDevelopmentManual();
18
- const current = fs.existsSync(target) ? fs.readFileSync(target, "utf8") : "";
19
- if (check) {
20
- if (current !== expected) {
21
- throw new Error(
22
- `${NEXT_DEVELOPMENT_MANUAL_PATH} drifted from its contract source`,
23
- );
24
- }
25
- return { ok: true, changed: false, path: NEXT_DEVELOPMENT_MANUAL_PATH };
26
- }
27
- fs.mkdirSync(path.dirname(target), { recursive: true });
28
- if (current !== expected) fs.writeFileSync(target, expected);
29
- return {
30
- ok: true,
31
- changed: current !== expected,
32
- path: NEXT_DEVELOPMENT_MANUAL_PATH,
33
- };
34
- }
35
-
36
- if (
37
- process.argv[1] &&
38
- import.meta.url === pathToFileURL(process.argv[1]).href
39
- ) {
40
- try {
41
- const result = generateNextDevelopmentGuidance({
42
- check: process.argv.includes("--check"),
43
- });
44
- process.stdout.write(`${JSON.stringify(result)}\n`);
45
- } catch (error) {
46
- process.stderr.write(`next-development guidance: ${error.message}\n`);
47
- process.exitCode = 1;
48
- }
49
- }