@kungfu-tech/buildchain 3.0.8 → 3.0.9-alpha.1

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 (79) hide show
  1. package/actions/promote-buildchain-ref/README.md +8 -7
  2. package/bin/buildchain.mjs +34 -33
  3. package/bin/internal/trust-release-release-handlers.mjs +5 -0
  4. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json +16 -0
  5. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json +57 -0
  6. package/contracts/release-cut-v1.schema.json +1 -0
  7. package/contracts/release-train-transition-v1.schema.json +1 -0
  8. package/dist/site/agent-index.json +0 -1
  9. package/dist/site/artifact-schemas.json +0 -2
  10. package/dist/site/badge-endpoint-registry.json +9 -9
  11. package/dist/site/badges/v1/kfd-8/aligned.json +1 -1
  12. package/dist/site/badges/v1/kfd-8/declared.json +1 -1
  13. package/dist/site/badges/v1/kfd-8/downgraded.json +1 -1
  14. package/dist/site/badges/v1/kfd-8/draft.json +1 -1
  15. package/dist/site/badges/v1/kfd-8/failed.json +1 -1
  16. package/dist/site/badges/v1/kfd-8/missing.json +1 -1
  17. package/dist/site/badges/v1/kfd-8/passed.json +1 -1
  18. package/dist/site/badges/v1/kfd-8/planned.json +1 -1
  19. package/dist/site/buildchain-contract.json +38 -34
  20. package/dist/site/buildchain-site.json +59 -39
  21. package/dist/site/capability-registry.json +1 -1
  22. package/dist/site/cli-registry.json +8 -7
  23. package/dist/site/controller-registry.json +13 -5
  24. package/dist/site/kfd-claims.json +35 -8
  25. package/dist/site/kfd-upstream-aggregate.json +10 -10
  26. package/dist/site/manual-registry.json +9 -9
  27. package/dist/site/node-api-registry.json +1143 -320
  28. package/dist/site/page-registry.json +46 -26
  29. package/dist/site/public-surface-audit.json +19 -9
  30. package/dist/site/publication-registry.json +4 -4
  31. package/dist/site/release-passport-check-manifest.json +33 -5
  32. package/dist/site/release-provenance.json +2 -1
  33. package/dist/site/schemas/release-passport-v1.schema.json +3 -0
  34. package/dist/site/site-manifest.json +13 -13
  35. package/dist/site/workflow-registry.json +19 -9
  36. package/docs/aws-us-elastic-runner-burst-plane.md +15 -3
  37. package/docs/cli-reference.md +6 -6
  38. package/docs/cli.md +2 -3
  39. package/docs/dev-alpha-candidate-patrol.md +45 -20
  40. package/docs/dev-delivery-warrant.md +12 -2
  41. package/docs/kfd-support.md +7 -7
  42. package/docs/node-api-reference.md +295 -246
  43. package/docs/release-passport.md +25 -12
  44. package/docs/release-train.md +54 -4
  45. package/docs/reusable-build-surface.md +26 -9
  46. package/docs/runtime-train-validation.md +6 -0
  47. package/docs/versioning.md +3 -2
  48. package/package.json +4 -3
  49. package/packages/core/artifact-verification-envelope.js +114 -0
  50. package/packages/core/buildchain-channel-identity.js +119 -0
  51. package/packages/core/buildchain-compatibility-proof.js +32 -0
  52. package/packages/core/buildchain-contract.js +7 -0
  53. package/packages/core/controller-evidence.js +2 -1
  54. package/packages/core/dev-alpha-active-release-train.js +460 -0
  55. package/packages/core/dev-alpha-candidate-selection.js +181 -0
  56. package/packages/core/dev-delivery-warrant.js +15 -4
  57. package/packages/core/index.js +4 -5
  58. package/packages/core/kfd-adopter-manifest.js +390 -0
  59. package/packages/core/kfd-product-gates.js +0 -300
  60. package/packages/core/release-blocker-priority.js +192 -0
  61. package/packages/core/release-passport-contract.js +219 -6
  62. package/packages/core/release-passport.js +139 -242
  63. package/packages/core/release-train.js +220 -0
  64. package/scripts/aws-macos-jit-controller-core.mjs +76 -0
  65. package/scripts/aws-macos-jit-controller.mjs +29 -0
  66. package/scripts/aws-macos-jit-source-rebind.mjs +503 -0
  67. package/scripts/buildchain-channel-router.mjs +18 -2
  68. package/scripts/buildchain-cli-help.mjs +4 -2
  69. package/scripts/buildchain-contract-lock.mjs +11 -1
  70. package/scripts/check-inventory.mjs +4 -4
  71. package/scripts/dev-alpha-candidate-patrol.mjs +196 -201
  72. package/scripts/generate-buildchain-kfd-witnesses.mjs +88 -94
  73. package/scripts/generate-channel-build-workflow.mjs +78 -31
  74. package/scripts/generate-site-bundle.mjs +1 -8
  75. package/scripts/promotion-channel-router.mjs +5 -3
  76. package/scripts/release-train-self-dogfood.mjs +579 -0
  77. package/scripts/runtime-ref-core.mjs +4 -17
  78. package/scripts/site-capability-metadata.mjs +3 -1
  79. package/dist/site/schemas/kfd-support-projection-v1.schema.json +0 -106
@@ -0,0 +1,579 @@
1
+ #!/usr/bin/env node
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import fs from "node:fs";
5
+
6
+ import {
7
+ closeDevDeliveryWarrant,
8
+ createDevDeliveryQueue,
9
+ createReleaseBlockerPriorityClaim,
10
+ selectDevDeliveryWarrant,
11
+ submitDevDeliveryCandidate,
12
+ } from "../packages/core/dev-delivery-warrant.js";
13
+ import { reconcileActiveReleaseTrain } from "../packages/core/dev-alpha-active-release-train.js";
14
+ import {
15
+ createReleaseBlockerRepair,
16
+ createReleaseTrain,
17
+ releaseTrainRoot,
18
+ settleReleaseBlockerDevLanding,
19
+ transitionReleaseTrain,
20
+ } from "../packages/core/release-train.js";
21
+
22
+ export const RELEASE_TRAIN_SELF_DOGFOOD_SCHEMA =
23
+ "kungfu-buildchain-release-train-self-dogfood/v1";
24
+
25
+ const SHA = /^[0-9a-f]{40}$/u;
26
+ const ROOT = /^sha256:[0-9a-f]{64}$/u;
27
+
28
+ function text(value, label) {
29
+ const normalized = String(value ?? "").trim();
30
+ if (!normalized) throw new Error(`${label} is required`);
31
+ return normalized;
32
+ }
33
+
34
+ function sha(value, label) {
35
+ const normalized = text(value, label).toLowerCase();
36
+ if (!SHA.test(normalized)) {
37
+ throw new Error(`${label} must be an exact 40-character Git SHA`);
38
+ }
39
+ return normalized;
40
+ }
41
+
42
+ function root(value, label) {
43
+ const normalized = text(value, label).toLowerCase();
44
+ if (!ROOT.test(normalized)) throw new Error(`${label} must be a sha256 root`);
45
+ return normalized;
46
+ }
47
+
48
+ function positiveInteger(value, label) {
49
+ const normalized = Number(value);
50
+ if (!Number.isSafeInteger(normalized) || normalized < 1) {
51
+ throw new Error(`${label} must be a positive integer`);
52
+ }
53
+ return normalized;
54
+ }
55
+
56
+ function timestamp(value, label) {
57
+ const normalized = text(value, label);
58
+ const milliseconds = Date.parse(normalized);
59
+ if (!Number.isFinite(milliseconds)) {
60
+ throw new Error(`${label} must be an ISO-8601 timestamp`);
61
+ }
62
+ const canonical = new Date(milliseconds).toISOString();
63
+ if (canonical !== normalized) {
64
+ throw new Error(`${label} must be a canonical ISO-8601 timestamp`);
65
+ }
66
+ return normalized;
67
+ }
68
+
69
+ function repository(value) {
70
+ const normalized = text(value, "repository");
71
+ if (!/^[^/\s]+\/[^/\s]+$/u.test(normalized)) {
72
+ throw new Error("repository must be owner/repo");
73
+ }
74
+ return normalized;
75
+ }
76
+
77
+ function branch(value, label) {
78
+ const normalized = text(value, label).replace(/^refs\/heads\//u, "");
79
+ if (/\s/u.test(normalized))
80
+ throw new Error(`${label} must not contain spaces`);
81
+ return normalized;
82
+ }
83
+
84
+ function at(recordedAt, seconds) {
85
+ return new Date(Date.parse(recordedAt) + seconds * 1000).toISOString();
86
+ }
87
+
88
+ function normalizeDelivery(input, expected) {
89
+ const delivery = {
90
+ pullRequestNumber: positiveInteger(
91
+ input?.pullRequestNumber,
92
+ "delivery.pullRequestNumber",
93
+ ),
94
+ baseBranch: branch(input?.baseBranch, "delivery.baseBranch"),
95
+ headSha: sha(input?.headSha, "delivery.headSha"),
96
+ headTreeSha: sha(input?.headTreeSha, "delivery.headTreeSha"),
97
+ state: text(input?.state, "delivery.state"),
98
+ reviewState: text(input?.reviewState, "delivery.reviewState"),
99
+ reviewHeadSha: sha(input?.reviewHeadSha, "delivery.reviewHeadSha"),
100
+ mergeSha: sha(input?.mergeSha, "delivery.mergeSha"),
101
+ mergeTreeSha: sha(input?.mergeTreeSha, "delivery.mergeTreeSha"),
102
+ ciHeadSha: sha(input?.ciHeadSha, "delivery.ciHeadSha"),
103
+ ciConclusion: text(input?.ciConclusion, "delivery.ciConclusion"),
104
+ reviewRoot: root(input?.reviewRoot, "delivery.reviewRoot"),
105
+ ciRoot: root(input?.ciRoot, "delivery.ciRoot"),
106
+ mergeRoot: root(input?.mergeRoot, "delivery.mergeRoot"),
107
+ artifactRoot: root(input?.artifactRoot, "delivery.artifactRoot"),
108
+ installedProductRoot: root(
109
+ input?.installedProductRoot,
110
+ "delivery.installedProductRoot",
111
+ ),
112
+ };
113
+ if (delivery.baseBranch !== expected.sourceBranch) {
114
+ throw new Error(
115
+ "protected delivery base does not match the Release Cut source branch",
116
+ );
117
+ }
118
+ if (
119
+ delivery.state !== "MERGED" ||
120
+ delivery.reviewState !== "APPROVED" ||
121
+ delivery.ciConclusion !== "success"
122
+ ) {
123
+ throw new Error(
124
+ "protected delivery is not merged, approved, and CI-successful",
125
+ );
126
+ }
127
+ if (
128
+ delivery.headSha !== expected.devLandingSha ||
129
+ delivery.reviewHeadSha !== delivery.headSha
130
+ ) {
131
+ throw new Error(
132
+ "protected delivery review does not bind the exact repaired head",
133
+ );
134
+ }
135
+ if (
136
+ delivery.headTreeSha !== expected.cutCandidateTreeSha ||
137
+ delivery.mergeTreeSha !== delivery.headTreeSha
138
+ ) {
139
+ throw new Error(
140
+ "protected delivery merge tree does not equal the repaired candidate tree",
141
+ );
142
+ }
143
+ if (delivery.ciHeadSha !== delivery.mergeSha) {
144
+ throw new Error(
145
+ "protected delivery CI does not bind the merge-group result",
146
+ );
147
+ }
148
+ return delivery;
149
+ }
150
+
151
+ function normalizeInput(input = {}) {
152
+ const normalized = {
153
+ repository: repository(input.repository),
154
+ sourceBranch: branch(input.sourceBranch, "sourceBranch"),
155
+ targetBranch: branch(input.targetBranch, "targetBranch"),
156
+ assignmentRoot: root(input.assignmentRoot, "assignmentRoot"),
157
+ initiativeRoot: root(input.initiativeRoot, "initiativeRoot"),
158
+ dependencyProofRoot: root(input.dependencyProofRoot, "dependencyProofRoot"),
159
+ originDevSha: sha(input.originDevSha, "originDevSha"),
160
+ candidateSha: sha(input.candidateSha, "candidateSha"),
161
+ candidateTreeSha: sha(input.candidateTreeSha, "candidateTreeSha"),
162
+ alphaBaseSha: sha(input.alphaBaseSha, "alphaBaseSha"),
163
+ buildchainRuntimeSha: sha(
164
+ input.buildchainRuntimeSha,
165
+ "buildchainRuntimeSha",
166
+ ),
167
+ observedDevSha: sha(input.observedDevSha, "observedDevSha"),
168
+ blockerRoot: root(input.blockerRoot, "blockerRoot"),
169
+ patchRoot: root(input.patchRoot, "patchRoot"),
170
+ cutCandidateSha: sha(input.cutCandidateSha, "cutCandidateSha"),
171
+ cutCandidateTreeSha: sha(input.cutCandidateTreeSha, "cutCandidateTreeSha"),
172
+ cutLandingEvidenceRoot: root(
173
+ input.cutLandingEvidenceRoot,
174
+ "cutLandingEvidenceRoot",
175
+ ),
176
+ devBaseSha: sha(input.devBaseSha, "devBaseSha"),
177
+ devLandingSha: sha(input.devLandingSha, "devLandingSha"),
178
+ devConflictEvidenceRoot: root(
179
+ input.devConflictEvidenceRoot,
180
+ "devConflictEvidenceRoot",
181
+ ),
182
+ devLandingEvidenceRoot: root(
183
+ input.devLandingEvidenceRoot,
184
+ "devLandingEvidenceRoot",
185
+ ),
186
+ ordinaryPullRequestNumber: positiveInteger(
187
+ input.ordinaryPullRequestNumber,
188
+ "ordinaryPullRequestNumber",
189
+ ),
190
+ recordedAt: timestamp(input.recordedAt, "recordedAt"),
191
+ };
192
+ if (normalized.observedDevSha === normalized.originDevSha) {
193
+ throw new Error(
194
+ "self-dogfood requires dev to advance beyond the frozen origin",
195
+ );
196
+ }
197
+ if (normalized.cutCandidateSha === normalized.candidateSha) {
198
+ throw new Error("self-dogfood requires a successor repair candidate");
199
+ }
200
+ normalized.delivery = normalizeDelivery(input.delivery, normalized);
201
+ return normalized;
202
+ }
203
+
204
+ function deliveryCandidate(input, deliveryClass = "release") {
205
+ return {
206
+ pullRequestNumber: input.pullRequestNumber,
207
+ sourceHead: input.sourceHead,
208
+ assignmentRoot: input.assignmentRoot,
209
+ initiativeRoot: input.initiativeRoot,
210
+ sourceIdentityRoot: input.sourceIdentityRoot,
211
+ sourcePatchRoot: input.sourcePatchRoot,
212
+ sourceProofRoot: input.sourceProofRoot,
213
+ planRoot: input.planRoot,
214
+ closureRoot: input.closureRoot,
215
+ dependencyRoot: input.dependencyRoot,
216
+ toolchainRoot: input.toolchainRoot,
217
+ deliveryClass,
218
+ priority: "ordinary",
219
+ ...(input.releaseBlockerPriority
220
+ ? { releaseBlockerPriority: input.releaseBlockerPriority }
221
+ : {}),
222
+ };
223
+ }
224
+
225
+ function captureExpectedError(run, pattern, label) {
226
+ try {
227
+ run();
228
+ } catch (error) {
229
+ const message = String(error?.message || error);
230
+ if (!pattern.test(message)) throw error;
231
+ return message;
232
+ }
233
+ throw new Error(`${label} did not fail closed`);
234
+ }
235
+
236
+ function runTrainCampaign(value, authorityRoots) {
237
+ let train = createReleaseTrain({
238
+ repository: value.repository,
239
+ sourceBranch: value.sourceBranch,
240
+ targetBranch: value.targetBranch,
241
+ originDevSha: value.originDevSha,
242
+ candidateSha: value.candidateSha,
243
+ candidateTreeSha: value.candidateTreeSha,
244
+ alphaBaseSha: value.alphaBaseSha,
245
+ buildchainRuntimeSha: value.buildchainRuntimeSha,
246
+ authorityRoots,
247
+ createdAt: value.recordedAt,
248
+ });
249
+ train = transitionReleaseTrain(train, {
250
+ to: "building",
251
+ expectedStateRoot: train.state.stateRoot,
252
+ event: "self-dogfood-build-started",
253
+ reason: "the frozen Buildchain candidate entered its protected campaign",
254
+ authorityRoots: [value.dependencyProofRoot],
255
+ recordedAt: at(value.recordedAt, 1),
256
+ });
257
+ train = transitionReleaseTrain(train, {
258
+ to: "repair-required",
259
+ expectedStateRoot: train.state.stateRoot,
260
+ event: "self-dogfood-build-failed",
261
+ reason: "the injected deterministic build failure requires a rooted repair",
262
+ authorityRoots: [value.blockerRoot],
263
+ recordedAt: at(value.recordedAt, 2),
264
+ });
265
+
266
+ const reconciliation = reconcileActiveReleaseTrain({
267
+ releaseTrain: train,
268
+ repository: value.repository,
269
+ sourceBranch: value.sourceBranch,
270
+ targetBranch: value.targetBranch,
271
+ activeCandidateSha: value.candidateSha,
272
+ sourceLockSha: value.candidateSha,
273
+ candidateTreeSha: value.candidateTreeSha,
274
+ alphaBaseSha: value.alphaBaseSha,
275
+ buildchainRuntimeSha: value.buildchainRuntimeSha,
276
+ observedDevSha: value.observedDevSha,
277
+ observedAt: at(value.recordedAt, 3),
278
+ });
279
+ if (reconciliation.status !== "active" || !reconciliation.drift.moved) {
280
+ throw new Error("the frozen candidate did not survive moving dev");
281
+ }
282
+
283
+ const invalidAuthority = reconcileActiveReleaseTrain({
284
+ releaseTrain: train,
285
+ repository: "invalid-authority/buildchain",
286
+ sourceBranch: value.sourceBranch,
287
+ targetBranch: value.targetBranch,
288
+ activeCandidateSha: value.candidateSha,
289
+ sourceLockSha: value.candidateSha,
290
+ candidateTreeSha: value.candidateTreeSha,
291
+ alphaBaseSha: value.alphaBaseSha,
292
+ buildchainRuntimeSha: value.buildchainRuntimeSha,
293
+ observedDevSha: value.observedDevSha,
294
+ observedAt: at(value.recordedAt, 3),
295
+ });
296
+ if (
297
+ invalidAuthority.status !== "held" ||
298
+ invalidAuthority.hold?.code !== "invalid-authority"
299
+ ) {
300
+ throw new Error("invalid authority did not fail closed");
301
+ }
302
+
303
+ const conflicted = createReleaseBlockerRepair(reconciliation.train, {
304
+ expectedStateRoot: reconciliation.train.state.stateRoot,
305
+ blockerRoot: value.blockerRoot,
306
+ patchRoot: value.patchRoot,
307
+ cutCandidateSha: value.cutCandidateSha,
308
+ cutCandidateTreeSha: value.cutCandidateTreeSha,
309
+ cutPatchRoot: value.patchRoot,
310
+ cutLandingEvidenceRoot: value.cutLandingEvidenceRoot,
311
+ devLandingStatus: "conflict",
312
+ devBaseSha: value.devBaseSha,
313
+ devLandingSha: "",
314
+ devPatchRoot: value.patchRoot,
315
+ devLandingEvidenceRoot: value.devConflictEvidenceRoot,
316
+ authorityRoots,
317
+ createdAt: at(value.recordedAt, 4),
318
+ });
319
+ if (conflicted.publication.eligible || !conflicted.candidateBuild.eligible) {
320
+ throw new Error(
321
+ "dev conflict did not block publication independently of build",
322
+ );
323
+ }
324
+ const repaired = settleReleaseBlockerDevLanding(conflicted, {
325
+ expectedRepairRoot: conflicted.repairRoot,
326
+ devBaseSha: value.devBaseSha,
327
+ devLandingSha: value.devLandingSha,
328
+ patchRoot: value.patchRoot,
329
+ devLandingEvidenceRoot: value.devLandingEvidenceRoot,
330
+ });
331
+ if (!repaired.publication.eligible) {
332
+ throw new Error("settled dual landing did not open publication");
333
+ }
334
+ const priorityClaim = createReleaseBlockerPriorityClaim(repaired, {
335
+ assignmentRoot: value.assignmentRoot,
336
+ initiativeRoot: value.initiativeRoot,
337
+ issuedAt: at(value.recordedAt, 5),
338
+ });
339
+ return {
340
+ reconciliation,
341
+ invalidAuthority,
342
+ conflicted,
343
+ repaired,
344
+ priorityClaim,
345
+ };
346
+ }
347
+
348
+ function runQueueCampaign(value, repaired, priorityClaim) {
349
+ let queue = createDevDeliveryQueue({
350
+ repository: value.repository,
351
+ protectedBase: value.sourceBranch,
352
+ policy: { agingSeconds: 300, leaseSeconds: 600 },
353
+ now: at(value.recordedAt, 6),
354
+ });
355
+ const ordinary = deliveryCandidate(
356
+ {
357
+ pullRequestNumber: value.ordinaryPullRequestNumber,
358
+ sourceHead: value.originDevSha,
359
+ assignmentRoot: value.dependencyProofRoot,
360
+ initiativeRoot: value.initiativeRoot,
361
+ sourceIdentityRoot: value.dependencyProofRoot,
362
+ sourcePatchRoot: value.dependencyProofRoot,
363
+ sourceProofRoot: value.dependencyProofRoot,
364
+ planRoot: value.dependencyProofRoot,
365
+ closureRoot: value.dependencyProofRoot,
366
+ dependencyRoot: value.dependencyProofRoot,
367
+ toolchainRoot: value.dependencyProofRoot,
368
+ },
369
+ "native-proof-required",
370
+ );
371
+ queue = submitDevDeliveryCandidate(queue, ordinary, {
372
+ now: at(value.recordedAt, 6),
373
+ }).queue;
374
+ const activeOrdinary = selectDevDeliveryWarrant(queue, {
375
+ now: at(value.recordedAt, 7),
376
+ });
377
+ queue = activeOrdinary.queue;
378
+
379
+ const blocker = deliveryCandidate({
380
+ pullRequestNumber: value.delivery.pullRequestNumber,
381
+ sourceHead: value.devLandingSha,
382
+ assignmentRoot: value.assignmentRoot,
383
+ initiativeRoot: value.initiativeRoot,
384
+ sourceIdentityRoot: repaired.successorTrain.releaseCut.cutRoot,
385
+ sourcePatchRoot: value.patchRoot,
386
+ sourceProofRoot: value.delivery.ciRoot,
387
+ planRoot: repaired.repairRoot,
388
+ closureRoot: value.delivery.mergeRoot,
389
+ dependencyRoot: value.dependencyProofRoot,
390
+ toolchainRoot: value.delivery.installedProductRoot,
391
+ releaseBlockerPriority: priorityClaim,
392
+ });
393
+ const submitted = submitDevDeliveryCandidate(queue, blocker, {
394
+ now: at(value.recordedAt, 8),
395
+ });
396
+ queue = submitted.queue;
397
+ const duplicate = submitDevDeliveryCandidate(queue, blocker, {
398
+ now: at(value.recordedAt, 9),
399
+ });
400
+ if (duplicate.receipt.action !== "duplicate-noop") {
401
+ throw new Error("duplicate delivery event was not idempotent");
402
+ }
403
+ queue = duplicate.queue;
404
+ const retained = selectDevDeliveryWarrant(queue, {
405
+ now: at(value.recordedAt, 10),
406
+ });
407
+ if (
408
+ retained.receipt.reason !== "non-preemptive-active-warrant" ||
409
+ retained.warrant.pullRequestNumber !== value.ordinaryPullRequestNumber
410
+ ) {
411
+ throw new Error("release-blocker priority preempted an active Warrant");
412
+ }
413
+ queue = closeDevDeliveryWarrant(retained.queue, retained.warrant, {
414
+ outcome: "merged",
415
+ evidenceRoot: value.dependencyProofRoot,
416
+ now: at(value.recordedAt, 11),
417
+ }).queue;
418
+ const selected = selectDevDeliveryWarrant(queue, {
419
+ now: at(value.recordedAt, 12),
420
+ });
421
+ if (
422
+ selected.receipt.reason !== "release-blocker-bounded-priority" ||
423
+ selected.warrant.pullRequestNumber !== value.delivery.pullRequestNumber
424
+ ) {
425
+ throw new Error(
426
+ "eligible release blocker did not receive bounded priority",
427
+ );
428
+ }
429
+ const closed = closeDevDeliveryWarrant(selected.queue, selected.warrant, {
430
+ outcome: "merged",
431
+ evidenceRoot: value.delivery.mergeRoot,
432
+ now: at(value.recordedAt, 13),
433
+ });
434
+
435
+ const unrelatedPriorityError = captureExpectedError(
436
+ () =>
437
+ submitDevDeliveryCandidate(
438
+ createDevDeliveryQueue({
439
+ repository: value.repository,
440
+ protectedBase: value.sourceBranch,
441
+ now: at(value.recordedAt, 14),
442
+ }),
443
+ { ...blocker, sourceHead: value.originDevSha },
444
+ { now: at(value.recordedAt, 14) },
445
+ ),
446
+ /source identity mismatch/u,
447
+ "unrelated release-blocker priority",
448
+ );
449
+ return {
450
+ submitted,
451
+ duplicate,
452
+ retained,
453
+ selected,
454
+ closed,
455
+ unrelatedPriorityError,
456
+ };
457
+ }
458
+
459
+ export function runReleaseTrainSelfDogfoodCampaign(input = {}) {
460
+ const value = normalizeInput(input);
461
+ const authorityRoots = [
462
+ value.assignmentRoot,
463
+ value.dependencyProofRoot,
464
+ value.initiativeRoot,
465
+ ].sort();
466
+ const {
467
+ reconciliation,
468
+ invalidAuthority,
469
+ conflicted,
470
+ repaired,
471
+ priorityClaim,
472
+ } = runTrainCampaign(value, authorityRoots);
473
+ const {
474
+ submitted,
475
+ duplicate,
476
+ retained,
477
+ selected,
478
+ closed,
479
+ unrelatedPriorityError,
480
+ } = runQueueCampaign(value, repaired, priorityClaim);
481
+
482
+ const body = {
483
+ schema: RELEASE_TRAIN_SELF_DOGFOOD_SCHEMA,
484
+ status: "passed",
485
+ input: value,
486
+ train: {
487
+ trainRoot: reconciliation.train.trainRoot,
488
+ cutRoot: reconciliation.train.releaseCut.cutRoot,
489
+ stateRoot: reconciliation.train.state.stateRoot,
490
+ candidateSha: reconciliation.train.releaseCut.candidateSha,
491
+ observedDevSha: value.observedDevSha,
492
+ movingDevObservationRoot: reconciliation.drift.observationRoot,
493
+ },
494
+ repair: {
495
+ conflictedRepairRoot: conflicted.repairRoot,
496
+ successorRepairRoot: repaired.repairRoot,
497
+ successorCutRoot: repaired.successorTrain.releaseCut.cutRoot,
498
+ successorGeneration: repaired.successorTrain.releaseCut.generation,
499
+ patchRoot: repaired.patchRoot,
500
+ conflictPublicationGateRoot: conflicted.publication.gateRoot,
501
+ publicationGateRoot: repaired.publication.gateRoot,
502
+ priorityClaimRoot: priorityClaim.claimRoot,
503
+ },
504
+ queue: {
505
+ blockerSubmissionReceiptRoot: submitted.receiptRoot,
506
+ duplicateAction: duplicate.receipt.action,
507
+ retainedWarrantReceiptRoot: retained.receiptRoot,
508
+ blockerSelectionReceiptRoot: selected.receiptRoot,
509
+ terminalReceiptRoot: closed.receiptRoot,
510
+ terminalStateRoot: closed.queue.stateRoot,
511
+ },
512
+ negativeCases: {
513
+ invalidAuthorityHoldRoot: invalidAuthority.hold.holdRoot,
514
+ unrelatedPriorityError,
515
+ },
516
+ protectedDelivery: value.delivery,
517
+ assertions: {
518
+ frozenCandidateSurvivedMovingDev: true,
519
+ successorRepairAdvancedGeneration: true,
520
+ devConflictBlockedOnlyPublication: true,
521
+ exactPatchDualLandingOpenedPublication: true,
522
+ activeWarrantWasNotPreempted: true,
523
+ eligibleBlockerReceivedBoundedPriority: true,
524
+ duplicateEventWasNoop: true,
525
+ invalidAuthorityFailedClosed: true,
526
+ unrelatedPriorityFailedClosed: true,
527
+ protectedDeliveryReadbackComplete: true,
528
+ },
529
+ recordedAt: at(value.recordedAt, 15),
530
+ };
531
+ return { ...body, campaignRoot: releaseTrainRoot(body) };
532
+ }
533
+
534
+ export function validateReleaseTrainSelfDogfoodCampaign(report) {
535
+ if (report?.schema !== RELEASE_TRAIN_SELF_DOGFOOD_SCHEMA) {
536
+ throw new Error("self-dogfood campaign schema is unsupported");
537
+ }
538
+ const rebuilt = runReleaseTrainSelfDogfoodCampaign(report.input);
539
+ if (report.campaignRoot !== rebuilt.campaignRoot) {
540
+ throw new Error("self-dogfood campaign root drift");
541
+ }
542
+ if (releaseTrainRoot(report) !== releaseTrainRoot(rebuilt)) {
543
+ throw new Error("self-dogfood campaign content drift");
544
+ }
545
+ return structuredClone(report);
546
+ }
547
+
548
+ function parseArguments(argv) {
549
+ const options = { input: "", output: "" };
550
+ for (let index = 0; index < argv.length; index += 1) {
551
+ const argument = argv[index];
552
+ if (argument === "--input" || argument === "--output") {
553
+ options[argument.slice(2)] = text(argv[index + 1], argument);
554
+ index += 1;
555
+ } else {
556
+ throw new Error(`unsupported argument: ${argument}`);
557
+ }
558
+ }
559
+ if (!options.input) throw new Error("--input is required");
560
+ return options;
561
+ }
562
+
563
+ function main() {
564
+ const options = parseArguments(process.argv.slice(2));
565
+ const input = JSON.parse(fs.readFileSync(options.input, "utf8"));
566
+ const report = runReleaseTrainSelfDogfoodCampaign(input);
567
+ const output = `${JSON.stringify(report, null, 2)}\n`;
568
+ if (options.output) fs.writeFileSync(options.output, output);
569
+ process.stdout.write(output);
570
+ }
571
+
572
+ if (import.meta.url === `file://${process.argv[1]}`) {
573
+ try {
574
+ main();
575
+ } catch (error) {
576
+ console.error(error.stack || error.message);
577
+ process.exitCode = 1;
578
+ }
579
+ }
@@ -1,3 +1,5 @@
1
+ import { parseBuildchainRefIdentity } from "../packages/core/buildchain-channel-identity.js";
2
+
1
3
  const EXACT_SHA_RE = /^[0-9a-f]{40}$/i;
2
4
  const TRAIN_REF_RE = /^train\/v\d+\/v\d+\.\d+\/[A-Za-z0-9._/-]+$/;
3
5
  const AUTHORITY_REF_RE = /^authority\/v\d+\/v\d+\.\d+\/[A-Za-z0-9._/-]+$/;
@@ -14,23 +16,8 @@ export function parseWorkflowShellRef(workflowRef = "", fallback = "v3", buildch
14
16
  }
15
17
 
16
18
  export function classifyBuildchainRuntimeRef(ref = "") {
17
- const value = String(ref || "").trim().replace(/^refs\/heads\//, "").replace(/^refs\/tags\//, "");
18
- if (EXACT_SHA_RE.test(value)) {
19
- return "exact-sha";
20
- }
21
- if (TRAIN_REF_RE.test(value)) {
22
- return "train";
23
- }
24
- if (AUTHORITY_REF_RE.test(value)) {
25
- return "authority";
26
- }
27
- if (/^v\d+(?:\.\d+)?$/.test(value) || /^v\d+\.\d+\.\d+$/.test(value)) {
28
- return "stable";
29
- }
30
- if (/^v\d+(?:\.\d+)?-alpha$/.test(value) || /^v\d+\.\d+\.\d+-alpha\.\d+$/.test(value)) {
31
- return "alpha";
32
- }
33
- return "development";
19
+ const identity = parseBuildchainRefIdentity(ref);
20
+ return identity.channel || (identity.kind === "missing" ? "development" : identity.kind);
34
21
  }
35
22
 
36
23
  export function isOfficialBuildchainChannelRef(ref = "") {
@@ -84,7 +84,7 @@ export function cliCommandMeta(id) {
84
84
  "kfd-7-schema": { group: "kfd-trust", purpose: "Print the default KFD-7 schema exposed by the KFD package standards metadata." },
85
85
  "kfd-7-gate": { group: "kfd-trust", purpose: "Evaluate a source-bound KFD-7 Domain Profile, evidence obligations, and independent review." },
86
86
  "kfd-7-verify": { group: "kfd-trust", purpose: "Verify a retained KFD-7 product-gate result without widening product support." },
87
- "kfd-support": { group: "kfd-trust", purpose: "Project and verify a product-owned KFD-1 through KFD-13 support matrix against KFD-4/5/7 gates." },
87
+ "kfd-support": { group: "kfd-trust", purpose: "Project and verify a legacy KFD support matrix from one exact standard adopter manifest authority closure." },
88
88
  "kfd-aggregate": { group: "kfd-trust", purpose: "Return a product KFD view that combines own KFD status with upstream KFD aggregate facts." },
89
89
  "kfd-upstream": { group: "kfd-trust", purpose: "Inspect KFD upstream aggregate command families." },
90
90
  "kfd-upstream-check": { group: "kfd-trust", purpose: "Validate a KFD upstream aggregate document and fail closed on missing evidence." },
@@ -218,6 +218,8 @@ export function nodeApiMeta(exportName) {
218
218
  "./issue-reporting": { group: "observability-diagnostics", summary: "Buildchain-owned issue reporting API for workflow friction feedback." },
219
219
  "./buildchain-layout": { group: "kfd-trust", summary: "Versioned Buildchain repository-layout discovery contract plus canonical .buildchain path resolution and migration APIs." },
220
220
  "./kfd": { group: "kfd-trust", summary: "Unified KFD standards, schema discovery, KFD-1/KFD-2/KFD-3 grouped APIs, KFD-4 schema discovery, upstream KFD aggregate facts, and Buildchain KFD claim helpers." },
221
+ "./kfd-adopter-manifest": { group: "kfd-trust", summary: "Exact-cut KFD adopter manifest verification, Buildchain evidence binding, and one-way legacy support-matrix projection APIs." },
222
+ "./kfd-adopter-release-binding": { group: "kfd-trust", summary: "Release Passport and artifact-evidence binding for one exact standard adopter manifest closure." },
221
223
  "./kfd-product-gates": { group: "kfd-trust", summary: "Fail-closed KFD-4, KFD-5, and KFD-7 product evidence gates plus non-widening KFD support-matrix release projections." },
222
224
  "./public-surface-audit": { group: "kfd-trust", summary: "Reverse audit APIs for CLI, workflow, action, site page, and documentation command surfaces." },
223
225
  "./kfd-gate": { group: "kfd-trust", summary: "KFD-1/KFD-2/KFD-3 release gate evidence and validation APIs." },