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