@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
@@ -2,7 +2,9 @@ import { devDeliveryClone as clone, devDeliveryContentRoot, devDeliveryExactRoot
2
2
  import { chainedDevDeliveryAttemptInput, createDevDeliveryCandidateIdentity, validateDevDeliveryCandidateChain } from "./dev-delivery-candidate-identity.js";
3
3
  import { DEV_DELIVERY_CANCELLATION_RECEIPT_SCHEMA, createCancelQueuedDevDeliveryCandidate } from "./dev-delivery-warrant-cancellation.js";
4
4
  import { DEV_DELIVERY_SETTLEMENT_RECEIPT_SCHEMA, createDevDeliveryTerminalSettler } from "./dev-delivery-warrant-settlement.js";
5
+ import { compareReleaseBlockerPriority, normalizeReleaseBlockerPriorityClaim } from "./release-blocker-priority.js";
5
6
  export { devDeliveryContentRoot } from "./dev-delivery-common.js";
7
+ export { RELEASE_BLOCKER_PRIORITY_CLAIM_SCHEMA, createReleaseBlockerPriorityClaim } from "./release-blocker-priority.js";
6
8
  export { SOURCE_QUALIFICATION_PROOF_SCHEMA, PROJECT_CUT_REPLAY_PROOF_SCHEMA, INTEGRATION_DELIVERY_PROOF_SCHEMA, classifyDevDeliveryDelta, createIntegrationDeliveryProof, createProjectCutReplayPlan, createProjectCutReplayProof, createSourceQualificationProof, verifyIntegrationDeliveryProof, verifyProjectCutReplayProof, verifySourceQualificationProof } from "./dev-delivery-proof.js";
7
9
  export { DEV_DELIVERY_CANCELLATION_RECEIPT_SCHEMA };
8
10
  export const DEV_DELIVERY_QUEUE_CONTRACT = "kungfu-buildchain-dev-delivery-warrant-queue";
@@ -60,7 +62,7 @@ function normalizeCandidate(input, expected) {
60
62
  if (!["queued", "selected", "proving", "waiting", "blocked", ...TERMINAL_STATES].includes(status)) {
61
63
  throw new Error(`unsupported candidate status ${status || "<empty>"}`);
62
64
  }
63
- return {
65
+ const candidate = {
64
66
  ...identity,
65
67
  sourceHead: exactSha(input.sourceHead, "sourceHead"),
66
68
  sourcePatchRoot: exactRoot(input.sourcePatchRoot, "sourcePatchRoot"),
@@ -78,6 +80,8 @@ function normalizeCandidate(input, expected) {
78
80
  status,
79
81
  terminal: input.terminal || null,
80
82
  };
83
+ if (Object.hasOwn(input, "releaseBlockerPriority")) candidate.releaseBlockerPriority = normalizeReleaseBlockerPriorityClaim(input.releaseBlockerPriority, candidate, expected);
84
+ return candidate;
81
85
  }
82
86
 
83
87
  function queueBody(queue) {
@@ -140,6 +144,7 @@ export function normalizeDevDeliveryQueue(input, expected = {}) {
140
144
  if (activeCandidates.length !== 1 || activeCandidates[0].candidateId !== warrant.candidateId) {
141
145
  throw new Error("exactly one active candidate must match the active Warrant");
142
146
  }
147
+ if (warrant.releaseBlockerPriority?.claimRoot !== activeCandidates[0].releaseBlockerPriority?.claimRoot) throw new Error("active Warrant release-blocker priority drift");
143
148
  } else if (queue.candidates.some((candidate) => ["selected", "proving", "waiting", "blocked"].includes(candidate.status))) {
144
149
  throw new Error("active candidate exists without an active Warrant");
145
150
  }
@@ -180,6 +185,7 @@ function submissionReceipt({ before, after, candidate, action, now }) {
180
185
  dependencyRoot: candidate.dependencyRoot,
181
186
  toolchainRoot: candidate.toolchainRoot,
182
187
  sourceWorkflowRunId: candidate.sourceWorkflowRunId,
188
+ ...(Object.hasOwn(candidate, "releaseBlockerPriority") ? { releaseBlockerPriority: candidate.releaseBlockerPriority } : {}),
183
189
  deliveryClass: candidate.deliveryClass,
184
190
  priority: candidate.priority,
185
191
  retainedEnqueuedAt: candidate.enqueuedAt,
@@ -219,7 +225,7 @@ export function submitDevDeliveryCandidate(queueInput, input, { now = new Date()
219
225
  throw new Error(`candidate ${attemptedCandidate.candidateId} is terminal and cannot be resubmitted`);
220
226
  }
221
227
  const exactProofFields = ["sourcePatchRoot", "sourceProofRoot", "planRoot", "closureRoot", "dependencyRoot", "toolchainRoot"];
222
- const exactProofMatches = exactProofFields.every((field) => existing[field] === attemptedCandidate[field]);
228
+ const exactProofMatches = exactProofFields.every((field) => existing[field] === attemptedCandidate[field]) && existing.releaseBlockerPriority?.claimRoot === attemptedCandidate.releaseBlockerPriority?.claimRoot;
223
229
  if (existing.sourceHead === attemptedCandidate.sourceHead && exactProofMatches) {
224
230
  action = "duplicate-noop";
225
231
  selected = existing;
@@ -235,6 +241,8 @@ export function submitDevDeliveryCandidate(queueInput, input, { now = new Date()
235
241
  const headChanged = existing.sourceHead !== attemptedCandidate.sourceHead;
236
242
  existing.sourceHead = attemptedCandidate.sourceHead;
237
243
  for (const field of exactProofFields) existing[field] = attemptedCandidate[field];
244
+ if (Object.hasOwn(attemptedCandidate, "releaseBlockerPriority")) existing.releaseBlockerPriority = attemptedCandidate.releaseBlockerPriority;
245
+ else delete existing.releaseBlockerPriority;
238
246
  existing.updatedAt = currentTime;
239
247
  existing.attempts += 1;
240
248
  existing.status = "queued";
@@ -270,6 +278,7 @@ function effectivePriority(candidate, policy, now) {
270
278
  basePriority: DEV_DELIVERY_PRIORITIES[candidate.priority],
271
279
  agingBoost,
272
280
  score: Math.min(policy.maxPriority, DEV_DELIVERY_PRIORITIES[candidate.priority] + agingBoost),
281
+ releaseBlocker: Boolean(candidate.releaseBlockerPriority),
273
282
  };
274
283
  }
275
284
 
@@ -282,7 +291,7 @@ export function rankDevDeliveryCandidates(queueInput, { now = new Date().toISOSt
282
291
  candidate,
283
292
  priority: effectivePriority(candidate, queue.policy, currentTime),
284
293
  }))
285
- .sort((left, right) => right.priority.score - left.priority.score || left.candidate.enqueuedAt.localeCompare(right.candidate.enqueuedAt) || left.candidate.candidateId.localeCompare(right.candidate.candidateId));
294
+ .sort((left, right) => compareReleaseBlockerPriority(left, right) || right.priority.score - left.priority.score || left.candidate.enqueuedAt.localeCompare(right.candidate.enqueuedAt) || left.candidate.candidateId.localeCompare(right.candidate.candidateId));
286
295
  }
287
296
 
288
297
  function warrantToken(input) {
@@ -371,6 +380,7 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
371
380
  dependencyRoot: candidate.dependencyRoot,
372
381
  toolchainRoot: candidate.toolchainRoot,
373
382
  sourceWorkflowRunId: candidate.sourceWorkflowRunId,
383
+ ...(Object.hasOwn(candidate, "releaseBlockerPriority") ? { releaseBlockerPriority: candidate.releaseBlockerPriority } : {}),
374
384
  deliveryClass: candidate.deliveryClass,
375
385
  generation: next.fencingCounter,
376
386
  expectedOldStateRoot: before.stateRoot,
@@ -390,7 +400,7 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
390
400
  const receipt = {
391
401
  schema: DEV_DELIVERY_SELECTION_RECEIPT_SCHEMA,
392
402
  selected: true,
393
- reason: selected.priority.agingBoost > 0 ? "fifo-aging-bounded-priority" : "fifo-bounded-priority",
403
+ reason: selected.priority.releaseBlocker ? "release-blocker-bounded-priority" : selected.priority.agingBoost > 0 ? "fifo-aging-bounded-priority" : "fifo-bounded-priority",
394
404
  repository: transaction.after.repository,
395
405
  protectedBase: transaction.after.protectedBase,
396
406
  candidateId: transaction.result.candidate.candidateId,
@@ -406,6 +416,7 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
406
416
  dependencyRoot: transaction.result.candidate.dependencyRoot,
407
417
  toolchainRoot: transaction.result.candidate.toolchainRoot,
408
418
  sourceWorkflowRunId: transaction.result.candidate.sourceWorkflowRunId,
419
+ ...(Object.hasOwn(transaction.result.candidate, "releaseBlockerPriority") ? { releaseBlockerPriority: transaction.result.candidate.releaseBlockerPriority } : {}),
409
420
  deliveryClass: transaction.result.candidate.deliveryClass,
410
421
  queueAgeSeconds: selected.priority.ageSeconds,
411
422
  basePriority: selected.priority.basePriority,
@@ -305,10 +305,14 @@ export {
305
305
  export {
306
306
  ARTIFACT_VERIFICATION_ENVELOPE_CHECK_CONTRACT,
307
307
  ARTIFACT_VERIFICATION_ENVELOPE_CONTRACT,
308
+ KFD_ADOPTER_RELEASE_BINDING_CONTRACT,
308
309
  KFX_ADMISSION_INPUTS_CONTRACT,
309
310
  artifactVerificationEnvelopeDigest,
311
+ createKfdAdopterReleaseBinding,
312
+ installedKfdPackageArtifactRoot,
310
313
  projectArtifactVerificationEnvelopeToKfx,
311
314
  sealArtifactVerificationReport,
315
+ validateKfdAdopterReleaseBinding,
312
316
  verifyArtifactVerificationEnvelope,
313
317
  } from "./artifact-verification-envelope.js";
314
318
 
@@ -488,15 +492,10 @@ export {
488
492
  KFD_PRODUCT_GATE_INPUT_CONTRACT,
489
493
  KFD_PRODUCT_GATE_INPUT_SCHEMA,
490
494
  KFD_PRODUCT_GATE_INPUT_SCHEMA_ID,
491
- KFD_SUPPORT_PROJECTION_CONTRACT,
492
- KFD_SUPPORT_PROJECTION_SCHEMA,
493
- KFD_SUPPORT_PROJECTION_SCHEMA_ID,
494
- createKfdSupportProjection,
495
495
  evaluateKfdProductGate,
496
496
  kfdProductGateDigest,
497
497
  kfdProductGates,
498
498
  validateKfdProductGateResult,
499
- validateKfdSupportProjection,
500
499
  verifyKfdRecord,
501
500
  } from "./kfd-product-gates.js";
502
501
 
@@ -0,0 +1,390 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import { createRequire } from "node:module";
4
+
5
+ import kfdPackageJson from "@kungfu-tech/kfd/package.json" with { type: "json" };
6
+ import kfdStandards from "@kungfu-tech/kfd/standards.json" with { type: "json" };
7
+ import {
8
+ bundleAdopterManifest,
9
+ verifyAdopterManifestFromPackage,
10
+ } from "@kungfu-tech/kfd/adopter-conformance/toolchain";
11
+
12
+ import {
13
+ KFD_PRODUCT_GATE_CONTRACT,
14
+ kfdProductGateDigest,
15
+ validateKfdProductGateResult,
16
+ } from "./kfd-product-gates.js";
17
+
18
+ export const KFD_ADOPTER_MANIFEST_GATE_CONTRACT =
19
+ "kungfu-buildchain-kfd-adopter-manifest-gate";
20
+ export const KFD_LEGACY_SUPPORT_MATRIX_CONTRACT = "kungfu-kfd-support-matrix";
21
+
22
+ const BUILDCHAIN_ADOPTER_ID = "kungfu-systems/buildchain";
23
+ const ROOT_PATTERN = /^sha256:[0-9a-f]{64}$/;
24
+ const SHA_PATTERN = /^[0-9a-f]{40}$/;
25
+ const REQUIRED_DECISIONS = Object.freeze(["KFD-1", "KFD-2", "KFD-3", "KFD-4", "KFD-5", "KFD-7"]);
26
+ const PRODUCT_GATE_STANDARDS = Object.freeze(["kfd-4", "kfd-5", "kfd-7"]);
27
+ const PRODUCT_GATE_SET = new Set(PRODUCT_GATE_STANDARDS);
28
+ const require = createRequire(import.meta.url);
29
+
30
+ function issue(code, path, message, detail = {}) {
31
+ return { level: "error", code, path, message, ...detail };
32
+ }
33
+
34
+ function text(value) {
35
+ return value === undefined || value === null ? "" : String(value).trim();
36
+ }
37
+
38
+ function standardsFileDigest() {
39
+ const bytes = fs.readFileSync(require.resolve("@kungfu-tech/kfd/standards.json"));
40
+ return `sha256:${crypto.createHash("sha256").update(bytes).digest("hex")}`;
41
+ }
42
+
43
+ function standardMetadata(standard) {
44
+ return kfdStandards?.standards?.[standard] || {};
45
+ }
46
+
47
+ function decisionWitnessRow(row) {
48
+ const roots = (entries) => (entries || []).map((entry) => entry?.root || "");
49
+ return {
50
+ id: row.id,
51
+ state: row.state,
52
+ usage: row.usage,
53
+ implementationRoots: roots(row.implementationEvidence),
54
+ verificationRoots: roots(row.verificationEvidence),
55
+ negativeRoots: roots(row.negativeEvidence),
56
+ reviewRoots: roots(row.reviews),
57
+ witnessRoots: (row.witnessBindings || []).map((entry) => entry?.witnessRoot || ""),
58
+ releaseBindingIds: [...(row.releaseBindingIds || [])],
59
+ claims: [...(row.claims || [])],
60
+ gaps: [...(row.gaps || [])],
61
+ };
62
+ }
63
+
64
+ function verifyPublishedManifest(manifest, packageOptions, issues) {
65
+ try {
66
+ const report = verifyAdopterManifestFromPackage(manifest, packageOptions);
67
+ if (!report.valid) {
68
+ issues.push(issue("adopter-manifest-invalid", "manifest", "published KFD adopter verifier rejected the manifest", {
69
+ manifestIssues: report.issues,
70
+ }));
71
+ return null;
72
+ }
73
+ return bundleAdopterManifest(manifest, packageOptions);
74
+ } catch (error) {
75
+ issues.push(issue("adopter-manifest-invalid", "manifest", error.message));
76
+ return null;
77
+ }
78
+ }
79
+
80
+ function manifestSourceSha(manifest) {
81
+ const match = /^kungfu-systems\/buildchain@([0-9a-f]{40})$/.exec(text(manifest?.adopter?.artifact?.coordinate));
82
+ return match?.[1] || "";
83
+ }
84
+
85
+ function validateManifestIdentity(manifest, packageArtifactRoot, expectedSourceSha, issues) {
86
+ if (manifest?.adopter?.id !== BUILDCHAIN_ADOPTER_ID) {
87
+ issues.push(issue("adopter-identity", "manifest.adopter.id", `manifest adopter must be ${BUILDCHAIN_ADOPTER_ID}`));
88
+ }
89
+ const pinned = manifest?.kfdCut?.package;
90
+ if (pinned?.name !== kfdPackageJson.name
91
+ || pinned?.version !== kfdPackageJson.version
92
+ || pinned?.artifactRoot !== packageArtifactRoot) {
93
+ issues.push(issue("adopter-package-cut", "manifest.kfdCut.package", "manifest must bind the exact installed KFD package cut"));
94
+ }
95
+ const sourceSha = manifestSourceSha(manifest);
96
+ if (manifest?.adopter?.artifact?.kind !== "git-commit" || !sourceSha
97
+ || !ROOT_PATTERN.test(text(manifest?.adopter?.artifact?.root))) {
98
+ issues.push(issue("adopter-source", "manifest.adopter.artifact", "Buildchain adopter authority must bind one exact git commit and artifact root"));
99
+ } else if (expectedSourceSha && sourceSha !== expectedSourceSha) {
100
+ issues.push(issue("adopter-source", "manifest.adopter.artifact.coordinate", "manifest source does not match the requested release source"));
101
+ }
102
+ return sourceSha;
103
+ }
104
+
105
+ function validateRequiredDecisions(decisions, issues) {
106
+ for (const id of REQUIRED_DECISIONS) {
107
+ const row = decisions.get(id);
108
+ if (!row || !["candidate", "adopted"].includes(row.state) || row.usage === "unused") {
109
+ issues.push(issue("adopter-required-decision", `manifest.decisions.${id}`, `${id} must remain an explicit used candidate or adopted declaration`));
110
+ } else if ((row.implementationEvidence || []).length === 0 || (row.verificationEvidence || []).length === 0) {
111
+ issues.push(issue("adopter-required-evidence", `manifest.decisions.${id}`, `${id} must bind implementation and verification evidence`));
112
+ }
113
+ }
114
+ const kfd6 = decisions.get("KFD-6");
115
+ if (kfd6?.state !== "unsupported" || kfd6?.usage !== "unused") {
116
+ issues.push(issue("adopter-kfd6-barrier", "manifest.decisions.KFD-6", "KFD-6 must remain explicitly unsupported and unused"));
117
+ }
118
+ }
119
+
120
+ function validateWarrantWitness(decisions, issues) {
121
+ const row = decisions.get("KFD-10");
122
+ const witnesses = (row?.witnessBindings || []).filter((entry) =>
123
+ entry?.decisionId === "KFD-10" && entry?.profileId === "kfd-warrant-evidence");
124
+ if (row?.state !== "draft-evidence" || row?.usage !== "evaluating" || witnesses.length !== 1) {
125
+ issues.push(issue("adopter-kfd10-witness", "manifest.decisions.KFD-10", "KFD-10 must retain exactly one draft Warrant-evidence witness binding"));
126
+ }
127
+ }
128
+
129
+ function collectProductGates(gateResults, decisions, verificationCut, issues) {
130
+ const gates = new Map();
131
+ for (const [index, gate] of gateResults.entries()) {
132
+ const validation = validateKfdProductGateResult(gate, verificationCut);
133
+ if (!validation.valid) {
134
+ issues.push(issue("adopter-gate-invalid", `gateResults[${index}]`, "Buildchain product gate is invalid", {
135
+ gateIssues: validation.issues,
136
+ }));
137
+ }
138
+ if (!PRODUCT_GATE_SET.has(gate?.standard)) {
139
+ issues.push(issue("adopter-gate-standard", `gateResults[${index}].standard`, "only the exact KFD-4/5/7 product-gate set is allowed"));
140
+ }
141
+ if (gates.has(gate?.standard)) {
142
+ issues.push(issue("adopter-gate-duplicate", `gateResults[${index}].standard`, `${gate.standard} gate is duplicated`));
143
+ }
144
+ gates.set(gate?.standard, gate);
145
+ }
146
+ for (const standard of PRODUCT_GATE_STANDARDS) {
147
+ const gate = gates.get(standard);
148
+ const id = standard.toUpperCase();
149
+ if (!gate) {
150
+ issues.push(issue("adopter-gate-missing", `gateResults.${standard}`, `${id} requires its existing Buildchain product gate`));
151
+ } else if (!(decisions.get(id)?.verificationEvidence || []).some((entry) => entry?.root === gate.gateRoot)) {
152
+ issues.push(issue("adopter-gate-unbound", `manifest.decisions.${id}.verificationEvidence`, `${id} must bind the exact Buildchain gate root`));
153
+ }
154
+ }
155
+ return gates;
156
+ }
157
+
158
+ function projectedProductGates(gates) {
159
+ return PRODUCT_GATE_STANDARDS.map((standard) => {
160
+ const gate = gates.get(standard);
161
+ return gate
162
+ ? { standard, sourceSha: gate.source.sha, gateRoot: gate.gateRoot, status: gate.status }
163
+ : { standard, sourceSha: "", gateRoot: "", status: "missing" };
164
+ });
165
+ }
166
+
167
+ function createGateDocument({ manifest, bundle, gates, authorityPath, packageArtifactRoot, sourceSha, checkedAt, maxAgeSeconds, issues }) {
168
+ const gate = {
169
+ schemaVersion: 1,
170
+ contract: KFD_ADOPTER_MANIFEST_GATE_CONTRACT,
171
+ checkedAt,
172
+ authority: {
173
+ path: authorityPath,
174
+ contract: text(manifest?.contract),
175
+ manifestRoot: bundle?.roots?.manifestRoot || "",
176
+ },
177
+ source: {
178
+ sha: sourceSha,
179
+ artifactRoot: text(manifest?.adopter?.artifact?.root),
180
+ },
181
+ verificationCut: { checkedAt, maxAgeSeconds },
182
+ standardPackage: {
183
+ name: kfdPackageJson.name,
184
+ version: kfdPackageJson.version,
185
+ artifactRoot: text(manifest?.kfdCut?.package?.artifactRoot || packageArtifactRoot),
186
+ registryRoot: text(manifest?.kfdCut?.registry?.root),
187
+ verifierSetRoot: text(manifest?.kfdCut?.verifierSetRoot),
188
+ },
189
+ decisionWitness: {
190
+ rootAlgorithm: "sha256-buildchain-stable-json-v1",
191
+ root: kfdProductGateDigest((manifest?.decisions || []).map(decisionWitnessRow)),
192
+ },
193
+ gateResults: projectedProductGates(gates),
194
+ manifestVerificationReportRoot: bundle?.roots?.verificationReportRoot || "",
195
+ manifestBundleRoot: bundle?.bundleRoot || "",
196
+ status: bundle && issues.length === 0 ? "passed" : "failed",
197
+ qualifying: false,
198
+ selfCertified: false,
199
+ nonClaims: [
200
+ "The standard adopter manifest is the sole declaration authority; legacy support matrices are projections only.",
201
+ "A passing manifest gate does not authorize release, runtime action, activation, or independent certification.",
202
+ ],
203
+ issues,
204
+ };
205
+ gate.gateRoot = kfdProductGateDigest(gate);
206
+ return gate;
207
+ }
208
+
209
+ export function createKfdAdopterManifestGate({
210
+ manifest,
211
+ packageArtifactRoot = "",
212
+ gateResults = [],
213
+ authorityPath = ".buildchain/kfd/adopter-manifest.json",
214
+ expectedSourceSha = "",
215
+ checkedAt = new Date().toISOString(),
216
+ maxAgeSeconds = 86400,
217
+ } = {}) {
218
+ const issues = [];
219
+ const bundle = verifyPublishedManifest(manifest, {
220
+ packageArtifactRoot,
221
+ verifiedAt: checkedAt,
222
+ maxAgeSeconds,
223
+ }, issues);
224
+ const decisions = new Map((manifest?.decisions || []).map((row) => [row.id, row]));
225
+ let sourceSha = manifestSourceSha(manifest);
226
+ if (bundle) {
227
+ sourceSha = validateManifestIdentity(manifest, packageArtifactRoot, expectedSourceSha, issues);
228
+ validateRequiredDecisions(decisions, issues);
229
+ validateWarrantWitness(decisions, issues);
230
+ }
231
+ const gates = collectProductGates(gateResults, decisions, { expectedSourceSha: sourceSha || expectedSourceSha, checkedAt }, issues);
232
+ return createGateDocument({ manifest, bundle, gates, authorityPath, packageArtifactRoot, sourceSha, checkedAt, maxAgeSeconds, issues });
233
+ }
234
+
235
+ function validateGateDocument(gate, issues) {
236
+ const copy = structuredClone(gate);
237
+ const root = copy.gateRoot;
238
+ delete copy.gateRoot;
239
+ if (root !== kfdProductGateDigest(copy)) issues.push(issue("adopter-gate-root", "gateRoot", "adopter manifest gate root does not match its content"));
240
+ if (gate.status !== "passed" || gate.qualifying !== false || gate.selfCertified !== false || (gate.issues || []).length !== 0) {
241
+ issues.push(issue("adopter-gate-status", "status", "release consumption requires a passing non-qualifying, non-self-certifying manifest gate"));
242
+ }
243
+ if (gate?.authority?.contract !== "kfd.adopter-conformance-manifest/v1"
244
+ || !ROOT_PATTERN.test(text(gate?.authority?.manifestRoot))) {
245
+ issues.push(issue("adopter-gate-authority", "authority", "adopter gate must bind the standard manifest contract and root"));
246
+ }
247
+ if (gate?.standardPackage?.name !== kfdPackageJson.name || gate?.standardPackage?.version !== kfdPackageJson.version
248
+ || ![gate?.standardPackage?.artifactRoot, gate?.standardPackage?.registryRoot, gate?.standardPackage?.verifierSetRoot].every((value) => ROOT_PATTERN.test(text(value)))) {
249
+ issues.push(issue("adopter-gate-package", "standardPackage", "adopter gate uses stale KFD package metadata"));
250
+ }
251
+ if (!SHA_PATTERN.test(text(gate?.source?.sha)) || !ROOT_PATTERN.test(text(gate?.source?.artifactRoot))) {
252
+ issues.push(issue("adopter-gate-source", "source", "adopter gate must bind one exact Buildchain source commit and artifact root"));
253
+ }
254
+ if (gate?.decisionWitness?.rootAlgorithm !== "sha256-buildchain-stable-json-v1"
255
+ || !ROOT_PATTERN.test(text(gate?.decisionWitness?.root))
256
+ || !ROOT_PATTERN.test(text(gate?.manifestVerificationReportRoot))
257
+ || !ROOT_PATTERN.test(text(gate?.manifestBundleRoot))) {
258
+ issues.push(issue("adopter-gate-evidence-root", "", "decision, report, and bundle roots are required"));
259
+ }
260
+ }
261
+
262
+ function validateProjectedGates(gate, expectedSourceSha, issues) {
263
+ const seenStandards = new Set();
264
+ for (const [index, productGate] of (gate.gateResults || []).entries()) {
265
+ if (!PRODUCT_GATE_SET.has(productGate?.standard) || productGate?.status !== "passed" || !ROOT_PATTERN.test(text(productGate?.gateRoot))) {
266
+ issues.push(issue("adopter-gate-result", `gateResults[${index}]`, "KFD-4/5/7 gate projections must be passing and rooted"));
267
+ }
268
+ if (seenStandards.has(productGate?.standard)) issues.push(issue("adopter-gate-result-set", `gateResults[${index}]`, "product gate standards must be unique"));
269
+ seenStandards.add(productGate?.standard);
270
+ if (productGate?.sourceSha !== gate?.source?.sha || (expectedSourceSha && productGate?.sourceSha !== expectedSourceSha)) {
271
+ issues.push(issue("adopter-gate-source", `gateResults[${index}].sourceSha`, "product gate source must match the release source"));
272
+ }
273
+ }
274
+ if (seenStandards.size !== PRODUCT_GATE_STANDARDS.length || PRODUCT_GATE_STANDARDS.some((standard) => !seenStandards.has(standard))) {
275
+ issues.push(issue("adopter-gate-result-set", "gateResults", "adopter gate must contain exactly one KFD-4, KFD-5, and KFD-7 product gate"));
276
+ }
277
+ }
278
+
279
+ export function validateKfdAdopterManifestGate(gate, {
280
+ expectedSourceSha = "",
281
+ checkedAt = gate?.checkedAt || new Date().toISOString(),
282
+ } = {}) {
283
+ const issues = [];
284
+ if (!gate || gate.schemaVersion !== 1 || gate.contract !== KFD_ADOPTER_MANIFEST_GATE_CONTRACT) {
285
+ return { valid: false, issues: [issue("adopter-gate-contract", "", `gate must use ${KFD_ADOPTER_MANIFEST_GATE_CONTRACT} v1`)] };
286
+ }
287
+ validateGateDocument(gate, issues);
288
+ validateProjectedGates(gate, expectedSourceSha, issues);
289
+ if (gate.checkedAt !== checkedAt || gate?.verificationCut?.checkedAt !== checkedAt || !Number.isFinite(Date.parse(checkedAt))
290
+ || !Number.isSafeInteger(gate?.verificationCut?.maxAgeSeconds) || gate.verificationCut.maxAgeSeconds < 0) {
291
+ issues.push(issue("adopter-gate-time", "verificationCut", "adopter gate verification cut does not match the requested cut"));
292
+ }
293
+ return { valid: issues.length === 0, issues };
294
+ }
295
+
296
+ function legacyStatus(row) {
297
+ if (row.state === "adopted") return "source-supported-release-bound";
298
+ if (row.state === "candidate") return "candidate";
299
+ if (row.state === "draft-evidence") return "draft-adopter-evidence";
300
+ return row.state;
301
+ }
302
+
303
+ function legacyRow(row, gates) {
304
+ const key = row.id.toLowerCase();
305
+ const productGate = gates.get(key);
306
+ return {
307
+ id: row.id,
308
+ key,
309
+ title: standardMetadata(key).title,
310
+ supportStatus: legacyStatus(row),
311
+ normative: { status: row.registryStatus, revision: standardMetadata(key).revision },
312
+ implementation: { status: row.implementationEvidence.length > 0 ? "implemented" : "not-declared" },
313
+ verification: { status: row.verificationEvidence.length > 0 || row.witnessBindings.length > 0 ? "passed" : "not-declared" },
314
+ buildchain: {
315
+ protocol: productGate ? `${KFD_PRODUCT_GATE_CONTRACT}/v1` : `${KFD_ADOPTER_MANIFEST_GATE_CONTRACT}/v1`,
316
+ gateStatus: productGate?.status || "manifest-verified",
317
+ },
318
+ releaseQualification: { shippedSupport: false },
319
+ claimClass: "standard-adopter-manifest-projection",
320
+ knownLimitations: [...row.gaps],
321
+ owner: BUILDCHAIN_ADOPTER_ID,
322
+ nextGate: "Release Passport artifact binding and independent release decision",
323
+ declaration: { state: row.state, usage: row.usage, root: kfdProductGateDigest(decisionWitnessRow(row)) },
324
+ };
325
+ }
326
+
327
+ export function createKfdLegacySupportMatrixProjection({ manifest, manifestGate } = {}) {
328
+ const validation = validateKfdAdopterManifestGate(manifestGate, {
329
+ expectedSourceSha: manifestGate?.source?.sha,
330
+ checkedAt: manifestGate?.checkedAt,
331
+ });
332
+ if (!validation.valid || manifest?.contract !== "kfd.adopter-conformance-manifest/v1") {
333
+ throw new Error("legacy support projection requires the exact passing standard adopter manifest authority");
334
+ }
335
+ const authorityIssues = [];
336
+ const bundle = verifyPublishedManifest(manifest, {
337
+ packageArtifactRoot: manifestGate.standardPackage.artifactRoot,
338
+ verifiedAt: manifestGate.verificationCut.checkedAt,
339
+ maxAgeSeconds: manifestGate.verificationCut.maxAgeSeconds,
340
+ }, authorityIssues);
341
+ const sourceSha = validateManifestIdentity(manifest, manifestGate.standardPackage.artifactRoot, manifestGate.source.sha, authorityIssues);
342
+ const decisionRoot = kfdProductGateDigest(manifest.decisions.map(decisionWitnessRow));
343
+ if (!bundle || sourceSha !== manifestGate.source.sha || manifest.adopter.artifact.root !== manifestGate.source.artifactRoot
344
+ || bundle.roots.manifestRoot !== manifestGate.authority.manifestRoot
345
+ || bundle.roots.verificationReportRoot !== manifestGate.manifestVerificationReportRoot
346
+ || bundle.bundleRoot !== manifestGate.manifestBundleRoot
347
+ || decisionRoot !== manifestGate.decisionWitness.root
348
+ || manifest.kfdCut.registry.root !== manifestGate.standardPackage.registryRoot
349
+ || manifest.kfdCut.verifierSetRoot !== manifestGate.standardPackage.verifierSetRoot) {
350
+ authorityIssues.push(issue("legacy-projection-authority", "manifest", "manifest does not match the exact gate authority closure"));
351
+ }
352
+ const gates = new Map(manifestGate.gateResults.map((entry) => [entry.standard, entry]));
353
+ for (const [standard, gate] of gates) {
354
+ const row = manifest.decisions.find((entry) => entry.id === standard.toUpperCase());
355
+ if (!(row?.verificationEvidence || []).some((entry) => entry?.root === gate.gateRoot)) {
356
+ authorityIssues.push(issue("legacy-projection-gate-binding", `manifest.decisions.${standard.toUpperCase()}`, "manifest does not bind the projected product gate root"));
357
+ }
358
+ }
359
+ if (authorityIssues.length > 0) throw new Error(`legacy support projection authority failed: ${JSON.stringify(authorityIssues)}`);
360
+ return {
361
+ schemaVersion: 1,
362
+ contract: KFD_LEGACY_SUPPORT_MATRIX_CONTRACT,
363
+ authority: {
364
+ path: manifestGate.authority.path,
365
+ contract: manifest.contract,
366
+ root: manifestGate.authority.manifestRoot,
367
+ gateRoot: manifestGate.gateRoot,
368
+ },
369
+ upstream: {
370
+ package: manifestGate.standardPackage.name,
371
+ version: manifestGate.standardPackage.version,
372
+ artifactRoot: manifestGate.standardPackage.artifactRoot,
373
+ registryRoot: manifestGate.standardPackage.registryRoot,
374
+ verifierSetRoot: manifestGate.standardPackage.verifierSetRoot,
375
+ standardsSha256: standardsFileDigest(),
376
+ },
377
+ rows: manifest.decisions.map((row) => legacyRow(row, gates)),
378
+ };
379
+ }
380
+
381
+ export function validateKfdLegacySupportMatrixProjection(matrix, { manifest, manifestGate } = {}) {
382
+ try {
383
+ const expected = createKfdLegacySupportMatrixProjection({ manifest, manifestGate });
384
+ return kfdProductGateDigest(matrix) === kfdProductGateDigest(expected)
385
+ ? { valid: true, issues: [] }
386
+ : { valid: false, issues: [issue("legacy-projection-drift", "", "legacy support matrix differs from the sole standard adopter manifest projection")] };
387
+ } catch (error) {
388
+ return { valid: false, issues: [issue("legacy-projection-authority", "", error.message)] };
389
+ }
390
+ }