@kungfu-tech/buildchain 4.0.1-alpha.4 → 4.0.1-alpha.5

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 (87) hide show
  1. package/architecture/decisions/0002-next-development-transition.md +101 -0
  2. package/architecture/internal-capabilities.json +52 -3
  3. package/architecture/maintainability-policy.json +22 -10
  4. package/architecture/v3-core-mechanism-inventory.json +89 -0
  5. package/architecture/v4-capability-state-machine-manifest.json +73 -0
  6. package/architecture/v4-compatibility-facts-parity.json +77 -0
  7. package/architecture/v4-next-development-parity.json +192 -0
  8. package/architecture/v4-release-train-parity.json +1 -0
  9. package/architecture/v4-tail-reseal-parity.json +150 -0
  10. package/bin/buildchain.mjs +16 -1
  11. package/bin/internal/command-registry.mjs +2 -0
  12. package/bin/internal/compatibility-facts-cli.mjs +101 -0
  13. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
  14. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
  15. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
  16. package/contracts/fixtures/v4-compatibility-facts-v1/shared.json +1129 -0
  17. package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +7 -1
  18. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +229 -0
  19. package/contracts/next-development-request-v1.schema.json +66 -0
  20. package/contracts/next-development-transition-v1.schema.json +292 -0
  21. package/contracts/v4-compatibility-facts-v1.schema.json +230 -0
  22. package/contracts/v4-tail-reseal-v1.schema.json +276 -0
  23. package/dist/site/agent-index.json +1 -0
  24. package/dist/site/artifact-schemas.json +2 -0
  25. package/dist/site/buildchain-contract.json +1388 -23
  26. package/dist/site/buildchain-site.json +257 -19
  27. package/dist/site/capability-registry.json +10 -8
  28. package/dist/site/cli-registry.json +106 -0
  29. package/dist/site/kfd-claims.json +187 -12
  30. package/dist/site/kfd-upstream-aggregate.json +1 -1
  31. package/dist/site/manual-registry.json +35 -4
  32. package/dist/site/node-api-registry.json +6579 -4493
  33. package/dist/site/page-registry.json +233 -11
  34. package/dist/site/public-surface-audit.json +241 -7
  35. package/dist/site/publication-authority-registry.json +6 -1
  36. package/dist/site/publication-registry.json +4 -4
  37. package/dist/site/release-provenance.json +7 -0
  38. package/dist/site/schemas/v4-compatibility-facts-v1.schema.json +230 -0
  39. package/dist/site/site-manifest.json +24 -8
  40. package/dist/site/workflow-registry.json +36 -4
  41. package/docs/MAP.md +4 -1
  42. package/docs/cli-reference.md +125 -0
  43. package/docs/dev-alpha-candidate-patrol.md +8 -0
  44. package/docs/next-development-transition.md +118 -0
  45. package/docs/node-api-reference.md +250 -117
  46. package/docs/v4-compatibility-facts.md +91 -0
  47. package/docs/v4-tail-reseal.md +73 -0
  48. package/docs/versioning.md +4 -3
  49. package/package.json +14 -5
  50. package/packages/core/buildchain-agent-manuals.js +2 -0
  51. package/packages/core/buildchain-compatibility-authority.js +336 -0
  52. package/packages/core/buildchain-compatibility-fact.js +394 -0
  53. package/packages/core/buildchain-compatibility-facts.json +217 -0
  54. package/packages/core/buildchain-compatibility-proof.js +566 -0
  55. package/packages/core/buildchain-contract.js +93 -141
  56. package/packages/core/channel-candidate.js +8 -0
  57. package/packages/core/channel-promotion-baseline.js +55 -0
  58. package/packages/core/dev-alpha-candidate-selection.js +10 -2
  59. package/packages/core/dev-delivery-execution-transfer.js +21 -1
  60. package/packages/core/dev-delivery-process-boundary.js +19 -6
  61. package/packages/core/dev-delivery-provider-heartbeat.js +18 -6
  62. package/packages/core/kungfu-temporal-fact.js +557 -0
  63. package/packages/core/next-development-candidate-reservation.js +186 -0
  64. package/packages/core/next-development-controller.js +728 -0
  65. package/packages/core/next-development-projection.js +287 -0
  66. package/packages/core/next-development-transition.js +738 -0
  67. package/packages/core/paper-agent-entry.js +11 -5
  68. package/packages/core/paper.js +16 -5
  69. package/packages/core/v4-canonical-contracts.js +5 -0
  70. package/packages/core/v4-floating-consumer-policy.js +29 -9
  71. package/packages/core/v4-tail-reseal-contract.js +26 -0
  72. package/packages/core/v4-tail-reseal-github.js +178 -0
  73. package/packages/core/v4-tail-reseal-receipt.js +225 -0
  74. package/packages/core/v4-tail-reseal.js +594 -0
  75. package/scripts/buildchain-cli-help.mjs +20 -0
  76. package/scripts/check-inventory.mjs +11 -0
  77. package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
  78. package/scripts/generate-next-development-guidance.mjs +49 -0
  79. package/scripts/generate-site-bundle.mjs +16 -3
  80. package/scripts/init-repo.mjs +22 -4
  81. package/scripts/next-development-self-dogfood-harness.mjs +460 -0
  82. package/scripts/next-development-self-dogfood.mjs +597 -0
  83. package/scripts/next-development-transition.mjs +47 -0
  84. package/scripts/site-capability-metadata.mjs +12 -0
  85. package/scripts/v4-consumer-policy.mjs +1 -5
  86. package/scripts/v4-tail-reseal-macos-rehearsal.mjs +134 -0
  87. package/scripts/v4-tail-reseal.mjs +416 -0
@@ -0,0 +1,597 @@
1
+ #!/usr/bin/env node
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { pathToFileURL } from "node:url";
7
+
8
+ import {
9
+ runNextDevelopmentController,
10
+ validateNextDevelopmentController,
11
+ } from "../packages/core/next-development-controller.js";
12
+ import {
13
+ NEXT_DEVELOPMENT_TRANSITION_CONTRACT,
14
+ nextDevelopmentRoot,
15
+ } from "../packages/core/next-development-transition.js";
16
+ import {
17
+ DurableStore,
18
+ HOSTED_READBACK_PATHS,
19
+ PROTECTED_DEV_BRANCH,
20
+ RECORDED_AT,
21
+ VersionStateAdapterHarness,
22
+ adapterTransition,
23
+ anchorInput,
24
+ exactRoot,
25
+ exactSha,
26
+ fixtureSha,
27
+ repository,
28
+ required,
29
+ validateAdapterEvidence,
30
+ validateAdapterOperation,
31
+ validateRecoveryEvidence,
32
+ validateSelfDogfoodRoute,
33
+ } from "./next-development-self-dogfood-harness.mjs";
34
+
35
+ export const NEXT_DEVELOPMENT_SELF_DOGFOOD_CHECKPOINT =
36
+ "kungfu-buildchain-next-development-self-dogfood-checkpoint/v1";
37
+ export const NEXT_DEVELOPMENT_SELF_DOGFOOD_EVIDENCE =
38
+ "kungfu-buildchain-next-development-self-dogfood/v1";
39
+ export const HOSTED_SELF_DOGFOOD_EVIDENCE =
40
+ "kungfu-buildchain-alpha-self-dogfood";
41
+
42
+ function checkpointBody(checkpoint) {
43
+ const body = structuredClone(checkpoint);
44
+ delete body.checkpointRoot;
45
+ return body;
46
+ }
47
+
48
+ function evidenceBody(evidence) {
49
+ const body = structuredClone(evidence);
50
+ delete body.evidenceRoot;
51
+ return body;
52
+ }
53
+
54
+ export function validateSelfDogfoodCheckpoint(checkpoint) {
55
+ if (checkpoint?.contract !== NEXT_DEVELOPMENT_SELF_DOGFOOD_CHECKPOINT) {
56
+ throw new Error(
57
+ "next-development self-dogfood checkpoint contract mismatch",
58
+ );
59
+ }
60
+ const runtimeSha = exactSha(checkpoint.route?.runtimeSha, "route.runtimeSha");
61
+ exactRoot(checkpoint.route?.contractRoot, "route.contractRoot");
62
+ const targetRepository = repository(
63
+ checkpoint.route?.repository,
64
+ "route.repository",
65
+ );
66
+ if (
67
+ checkpoint.route.runtimeRef !== "v4-alpha" ||
68
+ checkpoint.route.publicWorkflow !==
69
+ `${targetRepository}/.github/workflows/build.yml@v4-alpha` ||
70
+ targetRepository !== "kungfu-systems/buildchain"
71
+ ) {
72
+ throw new Error("checkpoint requires the public owner/repo v4-alpha route");
73
+ }
74
+ if (runtimeSha !== checkpoint.route.runtimeSha) {
75
+ throw new Error("checkpoint runtime SHA is not canonical");
76
+ }
77
+ required(checkpoint.faultRunnerId, "faultRunnerId");
78
+ const semver = validateNextDevelopmentController(
79
+ checkpoint.semver.controller,
80
+ );
81
+ const anchored = validateNextDevelopmentController(
82
+ checkpoint.anchored.controller,
83
+ );
84
+ if (
85
+ semver.transition.state.status !== "planned" ||
86
+ semver.activeAttempt !== null ||
87
+ checkpoint.semver.materializations !== 1 ||
88
+ checkpoint.semver.adapterOperations?.length !== 1 ||
89
+ checkpoint.semver.durableStateFailures !== 1
90
+ ) {
91
+ throw new Error(
92
+ "semver checkpoint must prove one transient durable-state failure",
93
+ );
94
+ }
95
+ checkpoint.semver.adapterOperations.forEach(validateAdapterOperation);
96
+ if (
97
+ anchored.transition.state.status !== "waiting-anchor" ||
98
+ anchored.transition.target.version !== null ||
99
+ checkpoint.anchored.materializations !== 0
100
+ ) {
101
+ throw new Error("anchored checkpoint must persist manual waiting");
102
+ }
103
+ if (checkpoint.alphaCandidateRebuilds !== 0) {
104
+ throw new Error("post-Alpha proof must not rebuild the Alpha candidate");
105
+ }
106
+ if (
107
+ checkpoint.checkpointRoot !==
108
+ nextDevelopmentRoot(checkpointBody(checkpoint))
109
+ ) {
110
+ throw new Error("next-development self-dogfood checkpoint root drifted");
111
+ }
112
+ return structuredClone(checkpoint);
113
+ }
114
+
115
+ export async function createSelfDogfoodCheckpoint({
116
+ repository: targetRepository,
117
+ runtimeRef,
118
+ runtimeSha,
119
+ contractRoot,
120
+ runnerId,
121
+ } = {}) {
122
+ const routeRepository = repository(targetRepository);
123
+ const route = {
124
+ repository: routeRepository,
125
+ publicWorkflow: `${routeRepository}/.github/workflows/build.yml@v4-alpha`,
126
+ runtimeRef: required(runtimeRef, "runtimeRef"),
127
+ runtimeSha: exactSha(runtimeSha, "runtimeSha"),
128
+ contractRoot: exactRoot(contractRoot, "contractRoot"),
129
+ protectedDevBranch: PROTECTED_DEV_BRANCH,
130
+ hostedReadbackPaths: HOSTED_READBACK_PATHS,
131
+ };
132
+ if (
133
+ route.repository !== "kungfu-systems/buildchain" ||
134
+ route.runtimeRef !== "v4-alpha"
135
+ ) {
136
+ throw new Error(
137
+ "self-dogfood checkpoint requires the public kungfu-systems/buildchain v4-alpha route",
138
+ );
139
+ }
140
+
141
+ const semverStore = new DurableStore([], { transientFailures: 1 });
142
+ const semverExecutor = new VersionStateAdapterHarness({ route });
143
+ await runNextDevelopmentController(
144
+ {
145
+ transition: adapterTransition(route, "semver"),
146
+ protectedDevBranch: PROTECTED_DEV_BRANCH,
147
+ recordedAt: RECORDED_AT,
148
+ },
149
+ { store: semverStore, executor: semverExecutor },
150
+ ).then(
151
+ () => {
152
+ throw new Error("transient durable-state fault injection did not run");
153
+ },
154
+ (error) => {
155
+ if (
156
+ !/injected transient durable-state write failure/u.test(error.message)
157
+ ) {
158
+ throw error;
159
+ }
160
+ },
161
+ );
162
+
163
+ const anchoredStore = new DurableStore();
164
+ const anchoredExecutor = new VersionStateAdapterHarness({ route });
165
+ await runNextDevelopmentController(
166
+ {
167
+ transition: adapterTransition(route, "anchored"),
168
+ protectedDevBranch: PROTECTED_DEV_BRANCH,
169
+ recordedAt: RECORDED_AT,
170
+ },
171
+ { store: anchoredStore, executor: anchoredExecutor },
172
+ );
173
+
174
+ const checkpoint = {
175
+ schemaVersion: 1,
176
+ contract: NEXT_DEVELOPMENT_SELF_DOGFOOD_CHECKPOINT,
177
+ route,
178
+ faultRunnerId: required(runnerId, "runnerId"),
179
+ alphaCandidateRebuilds: 0,
180
+ semver: {
181
+ controller: semverStore.only(),
182
+ materializations: semverExecutor.materializations,
183
+ adapterOperations: semverExecutor.operationRecords(),
184
+ durableStateFailures: semverStore.transientFailures,
185
+ },
186
+ anchored: {
187
+ controller: anchoredStore.only(),
188
+ materializations: anchoredExecutor.materializations,
189
+ },
190
+ };
191
+ checkpoint.checkpointRoot = nextDevelopmentRoot(checkpoint);
192
+ return validateSelfDogfoodCheckpoint(checkpoint);
193
+ }
194
+
195
+ function assertVerifiedModel(model, label) {
196
+ const controller = validateNextDevelopmentController(model?.controller);
197
+ if (
198
+ model.status !== "verified" ||
199
+ controller.transition.state.status !== "verified" ||
200
+ model.controllerRoot !== controller.controllerRoot ||
201
+ model.readbackRoot !== nextDevelopmentRoot(controller.readback)
202
+ ) {
203
+ throw new Error(
204
+ `${label} does not bind its verified controller and readback`,
205
+ );
206
+ }
207
+ return controller;
208
+ }
209
+
210
+ export function validateSelfDogfoodEvidence(evidence) {
211
+ if (evidence?.contract !== NEXT_DEVELOPMENT_SELF_DOGFOOD_EVIDENCE) {
212
+ throw new Error("next-development self-dogfood evidence contract mismatch");
213
+ }
214
+ exactRoot(evidence.checkpointRoot, "checkpointRoot");
215
+ exactRoot(evidence.transactionRoot, "transactionRoot");
216
+ exactRoot(evidence.protectedDevReadbackRoot, "protectedDevReadbackRoot");
217
+ validateSelfDogfoodRoute(evidence.route);
218
+ const semver = assertVerifiedModel(
219
+ evidence.models?.semverAuto,
220
+ "semver/auto",
221
+ );
222
+ const anchored = assertVerifiedModel(
223
+ evidence.models?.anchoredManual,
224
+ "anchored/manual",
225
+ );
226
+ if (evidence.status !== "passed")
227
+ throw new Error("self-dogfood evidence did not pass");
228
+ validateRecoveryEvidence(evidence.recovery);
229
+ if (
230
+ semver.controllerRoot !== evidence.transactionRoot ||
231
+ nextDevelopmentRoot(semver.readback) !==
232
+ evidence.protectedDevReadbackRoot ||
233
+ evidence.models.anchoredManual.waitingStatus !== "waiting-anchor" ||
234
+ evidence.models.anchoredManual.waitingControllerRoot ===
235
+ anchored.controllerRoot
236
+ ) {
237
+ throw new Error("both legal next-development models must be proved");
238
+ }
239
+ validateAdapterEvidence(evidence.adapter, semver, anchored);
240
+ if (
241
+ evidence.adoption?.coordinate !==
242
+ "kungfu-systems/buildchain/.github/workflows/build.yml@v4" ||
243
+ evidence.adoption?.exactShaProductionPin !== false
244
+ ) {
245
+ throw new Error("Kungfu adoption must use the floating v4 coordinate");
246
+ }
247
+ if (evidence.evidenceRoot !== nextDevelopmentRoot(evidenceBody(evidence))) {
248
+ throw new Error("next-development self-dogfood evidence root drifted");
249
+ }
250
+ return structuredClone(evidence);
251
+ }
252
+
253
+ export async function resumeSelfDogfoodCheckpoint(
254
+ checkpointInput,
255
+ { runnerId } = {},
256
+ ) {
257
+ const checkpoint = validateSelfDogfoodCheckpoint(checkpointInput);
258
+ const resumeRunnerId = required(runnerId, "runnerId");
259
+ if (resumeRunnerId === checkpoint.faultRunnerId) {
260
+ throw new Error("post-Alpha recovery must run on a fresh runner identity");
261
+ }
262
+
263
+ const initialDevSha = fixtureSha("protected-dev:initial");
264
+ const movedDevSha = fixtureSha("protected-dev:moved-during-recovery");
265
+ const semverStore = new DurableStore([checkpoint.semver.controller]);
266
+ const semverExecutor = new VersionStateAdapterHarness({
267
+ route: checkpoint.route,
268
+ operations: checkpoint.semver.adapterOperations,
269
+ devSha: initialDevSha,
270
+ movedDevSha,
271
+ moveAfterRecoveredOperation: true,
272
+ pullRequestReadsBeforeMerge: 2,
273
+ });
274
+ const input = {
275
+ transition: adapterTransition(checkpoint.route, "semver"),
276
+ protectedDevBranch: PROTECTED_DEV_BRANCH,
277
+ recordedAt: RECORDED_AT,
278
+ };
279
+ const superseded = await runNextDevelopmentController(input, {
280
+ store: semverStore,
281
+ executor: semverExecutor,
282
+ });
283
+ const pending = await runNextDevelopmentController(input, {
284
+ store: semverStore,
285
+ executor: semverExecutor,
286
+ });
287
+ const delayed = await runNextDevelopmentController(input, {
288
+ store: semverStore,
289
+ executor: semverExecutor,
290
+ });
291
+ const semver = await runNextDevelopmentController(input, {
292
+ store: semverStore,
293
+ executor: semverExecutor,
294
+ });
295
+
296
+ const anchoredStore = new DurableStore([checkpoint.anchored.controller]);
297
+ const anchoredExecutor = new VersionStateAdapterHarness({
298
+ route: checkpoint.route,
299
+ });
300
+ const anchored = await runNextDevelopmentController(
301
+ {
302
+ transition: adapterTransition(checkpoint.route, "anchored"),
303
+ protectedDevBranch: PROTECTED_DEV_BRANCH,
304
+ reviewedInput: anchorInput(),
305
+ recordedAt: RECORDED_AT,
306
+ },
307
+ { store: anchoredStore, executor: anchoredExecutor },
308
+ );
309
+
310
+ const semverReadbackRoot = nextDevelopmentRoot(semver.readback);
311
+ const anchoredReadbackRoot = nextDevelopmentRoot(anchored.readback);
312
+ const evidence = {
313
+ schemaVersion: 1,
314
+ contract: NEXT_DEVELOPMENT_SELF_DOGFOOD_EVIDENCE,
315
+ status: "passed",
316
+ route: checkpoint.route,
317
+ checkpointRoot: checkpoint.checkpointRoot,
318
+ transactionRoot: semver.controllerRoot,
319
+ protectedDevReadbackRoot: semverReadbackRoot,
320
+ recovery: {
321
+ faultRunnerId: checkpoint.faultRunnerId,
322
+ resumeRunnerId,
323
+ freshRunner: true,
324
+ transientDurableStateFailures: checkpoint.semver.durableStateFailures,
325
+ recoveredAdapterOperations: semverExecutor.recoveredOperations,
326
+ alphaCandidateRebuilds: 0,
327
+ devMaterializationsBefore: checkpoint.semver.materializations,
328
+ devMaterializationsAfter: semverExecutor.materializations,
329
+ protectedDevMovement: {
330
+ initialSha: initialDevSha,
331
+ movedSha: movedDevSha,
332
+ supersededAttempts: superseded.attempts.filter(
333
+ (attempt) => attempt.status === "superseded",
334
+ ).length,
335
+ },
336
+ protectedPrDelay: {
337
+ status: pending.transition.state.status,
338
+ delayedStatus: delayed.transition.state.status,
339
+ unchangedControllerRoot:
340
+ pending.controllerRoot === delayed.controllerRoot,
341
+ },
342
+ },
343
+ adapter: {
344
+ boundary: "materializeNextDevelopmentTransition",
345
+ contract: NEXT_DEVELOPMENT_TRANSITION_CONTRACT,
346
+ operations: [
347
+ ...semverExecutor.operationRecords(),
348
+ ...anchoredExecutor.operationRecords(),
349
+ ],
350
+ },
351
+ models: {
352
+ semverAuto: {
353
+ status: semver.transition.state.status,
354
+ targetVersion: semver.transition.target.version,
355
+ controllerRoot: semver.controllerRoot,
356
+ readbackRoot: semverReadbackRoot,
357
+ controller: semver,
358
+ },
359
+ anchoredManual: {
360
+ waitingStatus: checkpoint.anchored.controller.transition.state.status,
361
+ waitingControllerRoot: checkpoint.anchored.controller.controllerRoot,
362
+ status: anchored.transition.state.status,
363
+ targetVersion: anchored.transition.target.version,
364
+ controllerRoot: anchored.controllerRoot,
365
+ readbackRoot: anchoredReadbackRoot,
366
+ controller: anchored,
367
+ },
368
+ },
369
+ adoption: {
370
+ coordinate: "kungfu-systems/buildchain/.github/workflows/build.yml@v4",
371
+ runtimeRef: "v4",
372
+ exactShaProductionPin: false,
373
+ },
374
+ };
375
+ evidence.evidenceRoot = nextDevelopmentRoot(evidence);
376
+ return validateSelfDogfoodEvidence(evidence);
377
+ }
378
+
379
+ function normalizeHostedReadback(value, route) {
380
+ const paths = (value?.versionRoots || [])
381
+ .map((entry, index) => ({
382
+ path: required(entry?.path, `hosted versionRoots[${index}].path`),
383
+ gitBlobSha: exactSha(
384
+ entry?.gitBlobSha,
385
+ `hosted versionRoots[${index}].gitBlobSha`,
386
+ ),
387
+ }))
388
+ .sort((left, right) => left.path.localeCompare(right.path));
389
+ if (
390
+ JSON.stringify(paths.map((entry) => entry.path)) !==
391
+ JSON.stringify(route.hostedReadbackPaths)
392
+ ) {
393
+ throw new Error(
394
+ "hosted protected Dev readback must exactly cover declared paths",
395
+ );
396
+ }
397
+ const body = {
398
+ repository: repository(value?.repository, "hosted readback repository"),
399
+ branch: required(value?.branch, "hosted readback branch"),
400
+ commitSha: exactSha(value?.commitSha, "hosted readback commitSha"),
401
+ treeSha: exactSha(value?.treeSha, "hosted readback treeSha"),
402
+ versionRoots: paths,
403
+ };
404
+ if (
405
+ body.repository !== route.repository ||
406
+ body.branch !== route.protectedDevBranch
407
+ ) {
408
+ throw new Error("hosted protected Dev readback route drifted");
409
+ }
410
+ return { ...body, evidenceRoot: nextDevelopmentRoot(body) };
411
+ }
412
+
413
+ export function createHostedSelfDogfoodEvidence({
414
+ nextDevelopment,
415
+ observation,
416
+ } = {}) {
417
+ const proof = validateSelfDogfoodEvidence(nextDevelopment);
418
+ const hostedProtectedDevReadback = normalizeHostedReadback(
419
+ observation?.protectedDevReadback,
420
+ proof.route,
421
+ );
422
+ const observed = structuredClone(observation?.observed || {});
423
+ const failures = [];
424
+ if (observed.alpha?.ref !== "v4-alpha")
425
+ failures.push("alpha runtime ref mismatch");
426
+ if (observed.alpha?.class !== "alpha")
427
+ failures.push("alpha runtime class mismatch");
428
+ if (observed.alpha?.sha !== observed.alpha?.expectedSha)
429
+ failures.push("alpha runtime SHA mismatch");
430
+ if (observed.alpha?.sha !== proof.route.runtimeSha)
431
+ failures.push("next-development runtime SHA mismatch");
432
+ if (observed.stable?.ref !== "v4")
433
+ failures.push("stable runtime ref mismatch");
434
+ if (observed.stable?.class !== "stable")
435
+ failures.push("stable runtime class mismatch");
436
+ if (observed.stable?.sha !== observed.stable?.expectedSha)
437
+ failures.push("stable runtime SHA mismatch");
438
+ for (const [lane, item] of Object.entries(observed)) {
439
+ exactSha(item?.sha, `observed ${lane} SHA`);
440
+ exactSha(item?.expectedSha, `expected ${lane} SHA`);
441
+ }
442
+ const evidence = {
443
+ schemaVersion: 1,
444
+ contract: HOSTED_SELF_DOGFOOD_EVIDENCE,
445
+ repository: repository(observation?.repository),
446
+ callerSha: exactSha(observation?.callerSha, "callerSha"),
447
+ checkedAt: required(observation?.checkedAt, "checkedAt"),
448
+ status: failures.length === 0 ? "passed" : "failed",
449
+ observed,
450
+ nextDevelopment: proof,
451
+ hostedProtectedDevReadback,
452
+ failures,
453
+ };
454
+ if (evidence.repository !== proof.route.repository) {
455
+ throw new Error("hosted evidence repository differs from the public route");
456
+ }
457
+ evidence.evidenceRoot = nextDevelopmentRoot(evidence);
458
+ return evidence;
459
+ }
460
+
461
+ export function validateHostedSelfDogfoodEvidence(evidence) {
462
+ if (evidence?.contract !== HOSTED_SELF_DOGFOOD_EVIDENCE) {
463
+ throw new Error("hosted self-dogfood evidence contract mismatch");
464
+ }
465
+ const proof = validateSelfDogfoodEvidence(evidence.nextDevelopment);
466
+ repository(evidence.repository);
467
+ exactSha(evidence.callerSha, "callerSha");
468
+ required(evidence.checkedAt, "checkedAt");
469
+ for (const [lane, item] of Object.entries(evidence.observed || {})) {
470
+ exactSha(item?.sha, `observed ${lane} SHA`);
471
+ exactSha(item?.expectedSha, `expected ${lane} SHA`);
472
+ }
473
+ const readback = normalizeHostedReadback(
474
+ evidence.hostedProtectedDevReadback,
475
+ proof.route,
476
+ );
477
+ if (
478
+ readback.evidenceRoot !==
479
+ evidence.hostedProtectedDevReadback?.evidenceRoot ||
480
+ evidence.evidenceRoot !== nextDevelopmentRoot(evidenceBody(evidence))
481
+ ) {
482
+ throw new Error("hosted self-dogfood evidence root drifted");
483
+ }
484
+ if (
485
+ evidence.status !== "passed" ||
486
+ evidence.failures?.length !== 0 ||
487
+ evidence.repository !== proof.route.repository ||
488
+ evidence.observed?.alpha?.ref !== "v4-alpha" ||
489
+ evidence.observed?.alpha?.class !== "alpha" ||
490
+ evidence.observed?.alpha?.sha !== evidence.observed?.alpha?.expectedSha ||
491
+ evidence.observed?.alpha?.sha !== proof.route.runtimeSha ||
492
+ evidence.observed?.stable?.ref !== "v4" ||
493
+ evidence.observed?.stable?.class !== "stable" ||
494
+ evidence.observed?.stable?.sha !== evidence.observed?.stable?.expectedSha
495
+ ) {
496
+ throw new Error(
497
+ "hosted self-dogfood evidence is not a passing exact readback",
498
+ );
499
+ }
500
+ return structuredClone(evidence);
501
+ }
502
+
503
+ function parseArgs(argv) {
504
+ const options = {};
505
+ for (let index = 0; index < argv.length; index += 1) {
506
+ const name = argv[index];
507
+ if (!name.startsWith("--") || index + 1 >= argv.length) {
508
+ throw new Error(`invalid argument: ${name}`);
509
+ }
510
+ options[
511
+ name.slice(2).replace(/-([a-z])/gu, (_, letter) => letter.toUpperCase())
512
+ ] = argv[index + 1];
513
+ index += 1;
514
+ }
515
+ return options;
516
+ }
517
+
518
+ function readJson(filePath) {
519
+ return JSON.parse(fs.readFileSync(path.resolve(filePath), "utf8"));
520
+ }
521
+
522
+ function writeJson(filePath, value) {
523
+ const output = path.resolve(filePath);
524
+ fs.mkdirSync(path.dirname(output), { recursive: true });
525
+ fs.writeFileSync(output, `${JSON.stringify(value, null, 2)}\n`);
526
+ }
527
+
528
+ function writeActionsOutputs(value) {
529
+ const output = process.env.GITHUB_OUTPUT;
530
+ if (!output) return;
531
+ fs.appendFileSync(
532
+ output,
533
+ [
534
+ `transaction-root=${value.transactionRoot || value.nextDevelopment?.transactionRoot || ""}`,
535
+ `protected-dev-readback-root=${value.protectedDevReadbackRoot || value.hostedProtectedDevReadback?.evidenceRoot || ""}`,
536
+ `evidence-root=${value.evidenceRoot || value.checkpointRoot || ""}`,
537
+ ].join("\n") + "\n",
538
+ );
539
+ }
540
+
541
+ async function main(argv = process.argv.slice(2)) {
542
+ const command = argv.shift();
543
+ const options = parseArgs(argv);
544
+ if (command === "checkpoint") {
545
+ const checkpoint = await createSelfDogfoodCheckpoint({
546
+ repository: options.repository,
547
+ runtimeRef: options.runtimeRef,
548
+ runtimeSha: options.runtimeSha,
549
+ contractRoot: options.contractRoot,
550
+ runnerId: options.runnerId,
551
+ });
552
+ writeJson(required(options.output, "output"), checkpoint);
553
+ writeActionsOutputs(checkpoint);
554
+ return checkpoint;
555
+ }
556
+ if (command === "resume") {
557
+ const evidence = await resumeSelfDogfoodCheckpoint(
558
+ readJson(required(options.input, "input")),
559
+ { runnerId: options.runnerId },
560
+ );
561
+ writeJson(required(options.output, "output"), evidence);
562
+ writeActionsOutputs(evidence);
563
+ return evidence;
564
+ }
565
+ if (command === "attest-hosted") {
566
+ const evidence = createHostedSelfDogfoodEvidence({
567
+ nextDevelopment: readJson(required(options.input, "input")),
568
+ observation: readJson(required(options.observation, "observation")),
569
+ });
570
+ writeJson(required(options.output, "output"), evidence);
571
+ writeActionsOutputs(evidence);
572
+ return evidence;
573
+ }
574
+ if (command === "verify") {
575
+ return validateSelfDogfoodEvidence(
576
+ readJson(required(options.input, "input")),
577
+ );
578
+ }
579
+ if (command === "verify-hosted") {
580
+ return validateHostedSelfDogfoodEvidence(
581
+ readJson(required(options.input, "input")),
582
+ );
583
+ }
584
+ throw new Error(
585
+ "usage: next-development-self-dogfood.mjs checkpoint|resume|attest-hosted|verify|verify-hosted ...",
586
+ );
587
+ }
588
+
589
+ if (
590
+ process.argv[1] &&
591
+ import.meta.url === pathToFileURL(process.argv[1]).href
592
+ ) {
593
+ main().catch((error) => {
594
+ process.stderr.write(`next-development self-dogfood: ${error.message}\n`);
595
+ process.exitCode = 1;
596
+ });
597
+ }
@@ -0,0 +1,47 @@
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 { materializeNextDevelopmentTransition } from "../packages/core/next-development-transition.js";
8
+
9
+ function flag(args, name, fallback = "") {
10
+ const index = args.indexOf(`--${name}`);
11
+ return index === -1 ? fallback : String(args[index + 1] || "");
12
+ }
13
+
14
+ function usage() {
15
+ return `usage: node scripts/next-development-transition.mjs materialize --input <request.json> [--cwd <checkout>] [--write]\n`;
16
+ }
17
+
18
+ export function runNextDevelopmentAdapter(args = process.argv.slice(2)) {
19
+ const [command] = args;
20
+ if (command !== "materialize") throw new Error(usage().trim());
21
+ const inputPath = flag(args, "input");
22
+ if (!inputPath)
23
+ throw new Error(
24
+ "next-development materialize requires --input <request.json>",
25
+ );
26
+ const cwd = path.resolve(flag(args, "cwd", process.cwd()));
27
+ const request = JSON.parse(fs.readFileSync(path.resolve(inputPath), "utf8"));
28
+ return materializeNextDevelopmentTransition({
29
+ cwd,
30
+ request,
31
+ write: args.includes("--write"),
32
+ });
33
+ }
34
+
35
+ if (
36
+ process.argv[1] &&
37
+ import.meta.url === pathToFileURL(process.argv[1]).href
38
+ ) {
39
+ try {
40
+ process.stdout.write(
41
+ `${JSON.stringify(runNextDevelopmentAdapter(), null, 2)}\n`,
42
+ );
43
+ } catch (error) {
44
+ process.stderr.write(`next-development transition: ${error.message}\n`);
45
+ process.exitCode = 1;
46
+ }
47
+ }
@@ -39,6 +39,10 @@ export function cliCommandMeta(id) {
39
39
  "explain-artifact": { group: "release-passport-trust", purpose: "Explain artifact evidence for humans or agents." },
40
40
  "explain-release": { group: "release-passport-trust", purpose: "Explain a release passport for humans or agents." },
41
41
  facts: { group: "observability-diagnostics", purpose: "Inspect build facts command families." },
42
+ "facts-compatibility-project": { group: "governance-versioning", purpose: "Project legacy digest and proof views from the current Cut-bound compatibility Fact registry." },
43
+ "facts-compatibility-query": { group: "governance-versioning", purpose: "Verify one explicit directional compatibility path and emit a rooted receipt." },
44
+ "facts-compatibility-query-template": { group: "governance-versioning", purpose: "Create a direct query template for one current compatibility Fact." },
45
+ "facts-compatibility-verify": { group: "governance-versioning", purpose: "Verify the exact append-only compatibility Fact registry and current Cut." },
42
46
  help: { group: "getting-started", purpose: "Print Buildchain CLI help." },
43
47
  homebrew: { group: "distribution-indexes", purpose: "Inspect Homebrew distribution-index command families." },
44
48
  "homebrew-check": { group: "distribution-indexes", purpose: "Verify Homebrew tap metadata against upstream release passport evidence." },
@@ -139,6 +143,7 @@ export function cliCommandMeta(id) {
139
143
  "paper-status": { group: "reusable-build", purpose: "Report explicit evidence for every paper lifecycle state without unsupported inference." },
140
144
  "paper-work-start": { group: "getting-started", purpose: "Create a safe Paper work branch from the exact canonical remote development SHA." },
141
145
  "paper-work-submit": { group: "governance-versioning", purpose: "Push a Paper work branch without force and open or reuse the correctly targeted development PR." },
146
+ "next-development": { group: "governance-versioning", purpose: "Plan or apply one rooted declared-path next-development version transition without release or ref authority." },
142
147
  "publish-source": { group: "release-passport-trust", purpose: "Create, inspect, or verify publish-gate source-lock refs." },
143
148
  "publication-artifact": { group: "reusable-build", purpose: "Generate publication artifact manifests, passports, and source bundles for paper/report repositories." },
144
149
  "publication-artifact-manifest": { group: "reusable-build", purpose: "Write a site-consumable publication artifact manifest, publication passport, and source bundle." },
@@ -151,6 +156,7 @@ export function cliCommandMeta(id) {
151
156
  "release-governance": { group: "governance-versioning", purpose: "Reconcile a managed branch's Buildchain aggregate check to an already-tested pull request SHA." },
152
157
  "release-propagation": { group: "site-and-propagation", purpose: "Route exact Paper, KFD, Buildchain, or Core Site updates through one resumable propagation Work." },
153
158
  "release-tail": { group: "release-passport-trust", purpose: "Plan, initialize, resume, and verify one declarative provider-owned release-tail transaction." },
159
+ "tail-reseal": { group: "release-passport-trust", purpose: "Plan, admit, byte-verify, and seal one exact retained v4 Alpha candidate signing-finalization tail." },
154
160
  "release-transaction": { group: "release-passport-trust", purpose: "Inspect, recover, finalize, or abort durable release transactions." },
155
161
  sample: { group: "observability-diagnostics", purpose: "Inspect sampler command families." },
156
162
  "sample-process-tree": { group: "observability-diagnostics", purpose: "Sample process-tree diagnostics for a wrapped command." },
@@ -215,8 +221,13 @@ export function nodeApiMeta(exportName) {
215
221
  "./release-candidate": { group: "reusable-build", summary: "PR-stage release-candidate artifact, passport, and promote-only resolver APIs." },
216
222
  "./v4-floating-consumer-policy": { group: "governance-versioning", summary: "Semantic floating-selector admission, dual-lock receipt, and independent v4 consumer certification APIs." },
217
223
  "./v4-runtime-ref-resume-authority": { group: "release-passport-trust", summary: "Transient exact-runtime authorization, persisted-selector rejection, fresh-attempt Stage Capsule reuse, and A+B Passport lineage APIs." },
224
+ "./v4-tail-reseal": { group: "release-passport-trust", summary: "Effect-pure retained Stage Capsule validation and explicit Warrant-, credential-, and release-tail-fenced macOS reseal planning APIs." },
225
+ "./v4-tail-reseal-receipt": { group: "release-passport-trust", summary: "Four-platform byte readback, standard candidate Passport binding, and terminal v4 tail-reseal receipt APIs." },
218
226
  "./release-candidate-recovery": { group: "release-passport-trust", summary: "Fail-closed verification and immutable receipts for reusing a successful sealed candidate run without rebuilding product payloads." },
219
227
  "./release-train": { group: "governance-versioning", summary: "Frozen Release Cut identity, rooted Release Train transitions, Dev observations, supersession, replay, and legacy read compatibility APIs." },
228
+ "./next-development-transition": { group: "governance-versioning", summary: "Provider-neutral completed-Alpha preservation and rooted next-development state, version-model, idempotency, and local materialization APIs." },
229
+ "./next-development-controller": { group: "governance-versioning", summary: "Durable completed-Alpha child scheduling, fresh-runner checkpoint resume, latest protected-Dev reconciliation, and exact version-root readback APIs." },
230
+ "./next-development-projection": { group: "governance-versioning", summary: "Canonical generated config, Agent, workflow-header, and manual projections for the next-development transition contract." },
220
231
  "./stable-candidate-ledger": { group: "governance-versioning", summary: "Immutable alpha candidate ledger, qualification, revocation, selection, and exact stable source-lock APIs." },
221
232
  "./release-propagation": { group: "site-and-propagation", summary: "Release propagation graph, plan, and exact upstream lock APIs." },
222
233
  "./release-activation-transaction": { group: "release-passport-trust", summary: "Ordered cross-repository activation, exact receipt-set binding, retry, abort, rollback, and shadow-rehearsal APIs." },
@@ -225,6 +236,7 @@ export function nodeApiMeta(exportName) {
225
236
  "./release-tail-compatibility": { group: "release-passport-trust", summary: "Bounded v3 release-hook compatibility diagnostics that reject new executable release-tail inputs." },
226
237
  "./release-line-bootstrap": { group: "governance-versioning", summary: "Semver release-line bootstrap planning and version-state APIs." },
227
238
  "./buildchain-contract": { group: "governance-versioning", summary: "Runtime contract world and compatibility digest APIs for floating-ref drift checks." },
239
+ "./compatibility-fact-authority": { group: "governance-versioning", summary: "Directional Cut-bound compatibility Fact, lifecycle, explicit path receipt, legacy projection, and Release Passport evidence APIs." },
228
240
  "./controller-evidence": { group: "reusable-build", summary: "Project-independent controller descriptors, source/runtime-bound plans, receipts, aggregates, and validation APIs." },
229
241
  "./surface-manifest": { group: "site-and-propagation", summary: "Surface manifest timestamp and reproducibility policy APIs." },
230
242
  "./issue-reporting": { group: "observability-diagnostics", summary: "Buildchain-owned issue reporting API for workflow friction feedback." },