@kungfu-tech/buildchain 4.0.2-alpha.4 → 4.0.2-alpha.41

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 (153) hide show
  1. package/AGENTS.md +10 -1
  2. package/CONTRIBUTING.md +24 -0
  3. package/README.md +2 -2
  4. package/actions/promote-buildchain-ref/README.md +1 -1
  5. package/actions/v4-release-candidate-promote/README.md +28 -0
  6. package/architecture/agent-change-map.md +66 -7
  7. package/architecture/ci-lane-change-budget.json +366 -0
  8. package/architecture/internal-capabilities.json +52 -8
  9. package/architecture/maintainability-debt.json +148 -92
  10. package/architecture/maintainability-policy.json +34 -30
  11. package/architecture/release-tail-contract-inventory.json +6 -6
  12. package/architecture/v4-architecture-constitution.md +23 -20
  13. package/architecture/v4-cross-platform-adopter-qualification.json +1 -1
  14. package/architecture/v4-delivery-authority-parity.json +2 -2
  15. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +1 -1
  16. package/architecture/v4-floating-consumer-policy.json +2 -2
  17. package/architecture/v4-next-development-parity.json +5 -5
  18. package/architecture/v4-partial-mutation-recovery-qualification.json +4 -1
  19. package/architecture/v4-platform-stage-checkpoints.json +1 -1
  20. package/architecture/v4-provider-operation-journal-contract.json +5 -2
  21. package/architecture/v4-publication-facade-patches.json +64 -0
  22. package/architecture/v4-release-activation-shadow-domain.json +5 -2
  23. package/architecture/v4-release-topology.json +143 -35
  24. package/architecture/v4-rust-wasm-production-authority.json +58 -0
  25. package/architecture/v4-stable-publication-fence.json +5 -2
  26. package/architecture/v4-stage-capsule-qualification.json +2 -2
  27. package/architecture/v4-tail-reseal-parity.json +8 -6
  28. package/architecture/v4-universal-workflow-bootstrap.json +171 -0
  29. package/architecture/v4-universal-workflow-fault-campaign.json +72 -0
  30. package/architecture/v4-universal-workflow-train-admission.json +40 -0
  31. package/architecture/workflow-taxonomy.json +1451 -0
  32. package/bin/buildchain.mjs +7 -7
  33. package/contracts/buildchain-v2-residuals-v1.json +57 -48
  34. package/contracts/dev-delivery-authority-v2.schema.json +16 -2
  35. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
  36. package/contracts/v4-canonical-contracts-v1.schema.json +1 -0
  37. package/dist/site/buildchain-contract.json +93 -48
  38. package/dist/site/buildchain-site.json +222 -69
  39. package/dist/site/capability-registry.json +4 -4
  40. package/dist/site/controller-registry.json +50 -13
  41. package/dist/site/kfd-claims.json +2569 -982
  42. package/dist/site/kfd-upstream-aggregate.json +1 -1
  43. package/dist/site/manual-registry.json +13 -13
  44. package/dist/site/node-api-registry.json +88 -83
  45. package/dist/site/page-registry.json +204 -51
  46. package/dist/site/public-surface-audit.json +3207 -1219
  47. package/dist/site/publication-authority-registry.json +1124 -362
  48. package/dist/site/publication-registry.json +4 -4
  49. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +16 -2
  50. package/dist/site/site-manifest.json +17 -17
  51. package/dist/site/workflow-registry.json +5063 -1659
  52. package/docs/MAP.md +1 -0
  53. package/docs/auditable-demo.md +1 -1
  54. package/docs/cli.md +3 -3
  55. package/docs/dev-delivery-warrant.md +1 -1
  56. package/docs/engineering-housekeeper.md +3 -3
  57. package/docs/kfd-support.md +26 -2
  58. package/docs/next-development-transition.md +2 -2
  59. package/docs/node-api-reference.md +129 -129
  60. package/docs/publication-authority.md +2 -2
  61. package/docs/release-candidate.md +3 -3
  62. package/docs/release-flow.md +67 -19
  63. package/docs/release-governance.md +8 -8
  64. package/docs/release-passport.md +27 -2
  65. package/docs/reusable-build-surface.md +16 -0
  66. package/docs/v4-adopter-delivery.md +2 -2
  67. package/docs/v4-production-release.md +71 -8
  68. package/docs/v4-rust-wasm-production-authority.md +58 -0
  69. package/docs/v4-stage-capsule.md +2 -2
  70. package/docs/v4-tail-reseal.md +1 -1
  71. package/docs/workflow-catalog.md +154 -0
  72. package/docs/workflow-path-migration.md +109 -0
  73. package/package.json +10 -6
  74. package/packages/core/artifact-verification-envelope.js +5 -5
  75. package/packages/core/buildchain-contract.js +1 -1
  76. package/packages/core/buildchain-kfd-claims.js +2 -2
  77. package/packages/core/buildchain-publication-authority.js +42 -26
  78. package/packages/core/buildchain-v4-domain.wasm +0 -0
  79. package/packages/core/ci-lane-change-budget.js +14 -1
  80. package/packages/core/controller-evidence.js +4 -1
  81. package/packages/core/dev-delivery-candidate-identity.js +40 -6
  82. package/packages/core/dev-delivery-warrant-state.js +3 -4
  83. package/packages/core/dev-delivery-warrant.js +12 -2
  84. package/packages/core/github-governance-authority.js +4 -4
  85. package/packages/core/kfd-adopter-manifest.js +46 -47
  86. package/packages/core/next-development-projection.js +2 -2
  87. package/packages/core/release-line-dry-run.js +1 -1
  88. package/packages/core/release-passport-contract.js +5 -5
  89. package/packages/core/release-passport.js +5 -4
  90. package/packages/core/release-tail-product-capabilities.js +29 -0
  91. package/packages/core/release-tail-provider-plane.js +68 -1048
  92. package/packages/core/v4-canonical-contracts.js +14 -75
  93. package/packages/core/v4-domain-wasm-artifact.js +7 -0
  94. package/packages/core/v4-domain-wasm.js +216 -0
  95. package/packages/core/v4-floating-consumer-evidence.js +1 -1
  96. package/packages/core/v4-floating-consumer-policy.js +1 -1
  97. package/packages/core/v4-partial-mutation-recovery-qualification.js +9 -386
  98. package/packages/core/v4-product-publication.js +57 -0
  99. package/packages/core/v4-protected-publication-source.js +19 -21
  100. package/packages/core/v4-provider-operation-journal.js +18 -487
  101. package/packages/core/v4-provider-readback-idempotency.js +12 -97
  102. package/packages/core/v4-release-activation-shadow.js +13 -500
  103. package/packages/core/v4-release-invocation.js +28 -389
  104. package/packages/core/v4-stable-publication-fence.js +13 -342
  105. package/packages/core/v4-universal-workflow-bootstrap.js +586 -0
  106. package/scripts/binary-publication-evidence.mjs +135 -0
  107. package/scripts/build-contract-core.mjs +1 -14
  108. package/scripts/build-v4-domain-wasm.mjs +189 -0
  109. package/scripts/check-action-bundles.mjs +12 -2
  110. package/scripts/check-ci-lane-change-budget.mjs +4 -1
  111. package/scripts/check-core-mechanism-inventory.mjs +4 -3
  112. package/scripts/check-inventory.mjs +35 -44
  113. package/scripts/check-maintainability.mjs +16 -113
  114. package/scripts/check-v4-floating-consumer-policy-contract.mjs +2 -2
  115. package/scripts/check-v4-public-dogfood-contract.mjs +22 -9
  116. package/scripts/check-v4-release-topology.mjs +214 -50
  117. package/scripts/check-v4-runtime-semantic-closure.mjs +4 -1
  118. package/scripts/check-v4-universal-workflow-bootstrap.mjs +266 -0
  119. package/scripts/check-workflow-taxonomy.mjs +6 -0
  120. package/scripts/copy-v4-domain-wasm.mjs +14 -0
  121. package/scripts/dev-delivery-authority-command-adapters.mjs +1 -1
  122. package/scripts/dev-delivery-authority.mjs +8 -8
  123. package/scripts/dev-delivery-source-proof-reuse.mjs +2 -1
  124. package/scripts/dev-delivery-warrant-options.mjs +14 -9
  125. package/scripts/dev-delivery-warrant-store.mjs +73 -7
  126. package/scripts/dev-delivery-warrant-transition.mjs +109 -0
  127. package/scripts/dev-delivery-warrant.mjs +76 -99
  128. package/scripts/dev-pr-auto-merge.mjs +15 -15
  129. package/scripts/generate-channel-build-workflow.mjs +7 -2
  130. package/scripts/generate-channel-promotion-workflow.mjs +7 -5
  131. package/scripts/generate-site-bundle.mjs +11 -11
  132. package/scripts/generate-v4-universal-workflow-facades.mjs +458 -0
  133. package/scripts/generate-workflow-taxonomy.mjs +25 -0
  134. package/scripts/github-output.mjs +31 -0
  135. package/scripts/maintainability-metrics.mjs +16 -5
  136. package/scripts/maintainability-public-surface.mjs +115 -0
  137. package/scripts/next-development-review.mjs +307 -0
  138. package/scripts/release-asset-client.mjs +91 -0
  139. package/scripts/release-candidate-resolver.mjs +17 -18
  140. package/scripts/resume-from-candidate-run.mjs +1 -1
  141. package/scripts/source-verification-evidence.mjs +344 -0
  142. package/scripts/stable-candidate-qualification.mjs +1 -1
  143. package/scripts/universal-facade-maintainability.mjs +82 -0
  144. package/scripts/v4-product-publication-intent.mjs +121 -0
  145. package/scripts/v4-publication-settlement.mjs +211 -0
  146. package/scripts/v4-universal-workflow-backflow.mjs +212 -0
  147. package/scripts/v4-universal-workflow-engine.mjs +618 -0
  148. package/scripts/v4-universal-workflow-self-dogfood.mjs +205 -0
  149. package/scripts/verify-version-state-delta.mjs +173 -0
  150. package/scripts/workflow-taxonomy.mjs +507 -0
  151. package/templates/native-dev-delivery.yml +4 -7
  152. package/templates/universal-buildchain-bootstrap-recovery.yml +282 -0
  153. package/templates/universal-buildchain-bootstrap.yml +28 -0
@@ -20,7 +20,21 @@ export const EXACT_DEV_DELIVERY_PROOF_FIELDS = Object.freeze([
20
20
  "environmentRoot",
21
21
  "sourceWorkflowRunId",
22
22
  ]);
23
-
23
+ export function devDeliverySourceBinding(input = {}) {
24
+ const [sourceRoot, assignmentRoot, initiativeRoot] = [
25
+ "sourceRoot",
26
+ "assignmentRoot",
27
+ "initiativeRoot",
28
+ ].map((field) => String(input[field] || "").trim());
29
+ if (sourceRoot && !assignmentRoot && !initiativeRoot)
30
+ return { sourceRoot: exactRoot(sourceRoot, "sourceRoot") };
31
+ if (!sourceRoot && assignmentRoot && initiativeRoot)
32
+ return {
33
+ assignmentRoot: exactRoot(assignmentRoot, "assignmentRoot"),
34
+ initiativeRoot: exactRoot(initiativeRoot, "initiativeRoot"),
35
+ };
36
+ throw new Error("provide sourceRoot alone or both historical roots");
37
+ }
24
38
  export function matchesExactDevDeliveryCandidate(existing, attempted) {
25
39
  return (
26
40
  existing.sourceHead === attempted.sourceHead &&
@@ -37,6 +51,29 @@ export function matchesExactDevDeliveryCandidate(existing, attempted) {
37
51
  attempted.releaseBlockerPriority?.claimRoot
38
52
  );
39
53
  }
54
+ export function reuseExactActiveDevDeliverySourceProof(active, input) {
55
+ const phaseCompatible =
56
+ ["provisional", "qualified"].includes(active?.phase) ||
57
+ (!Object.hasOwn(active || {}, "phase") &&
58
+ active?.deliveryClass === "non-native-fast" &&
59
+ !Object.hasOwn(active || {}, "environmentRoot"));
60
+ const exact =
61
+ phaseCompatible &&
62
+ ["sourceRoot", "assignmentRoot", "initiativeRoot"].every(
63
+ (field) => active[field] === input[field],
64
+ ) &&
65
+ [
66
+ "pullRequestNumber",
67
+ "sourceIdentityRoot",
68
+ "deliveryClass",
69
+ "priority",
70
+ ].every((field) => active[field] === input[field]) &&
71
+ matchesExactDevDeliveryCandidate(active, {
72
+ ...input,
73
+ sourceProofRoot: active.sourceProofRoot,
74
+ });
75
+ return exact ? { ...input, sourceProofRoot: active.sourceProofRoot } : input;
76
+ }
40
77
 
41
78
  export function createDevDeliveryCandidateIdentity(
42
79
  input,
@@ -50,8 +87,7 @@ export function createDevDeliveryCandidateIdentity(
50
87
  input.pullRequestNumber,
51
88
  "pullRequestNumber",
52
89
  ),
53
- assignmentRoot: exactRoot(input.assignmentRoot, "assignmentRoot"),
54
- initiativeRoot: exactRoot(input.initiativeRoot, "initiativeRoot"),
90
+ ...devDeliverySourceBinding(input),
55
91
  sourceIdentityRoot: exactRoot(
56
92
  input.sourceIdentityRoot,
57
93
  "sourceIdentityRoot",
@@ -59,11 +95,10 @@ export function createDevDeliveryCandidateIdentity(
59
95
  deliveryClass: deliveryClass(input.deliveryClass),
60
96
  };
61
97
  if (input.identitySemantics) {
62
- if (text(input.identitySemantics) !== CHAINED_ATTEMPT_IDENTITY) {
98
+ if (text(input.identitySemantics) !== CHAINED_ATTEMPT_IDENTITY)
63
99
  throw new Error(
64
100
  `unsupported candidate identity semantics ${input.identitySemantics}`,
65
101
  );
66
- }
67
102
  identity.identitySemantics = CHAINED_ATTEMPT_IDENTITY;
68
103
  identity.predecessorCandidateId = exactRoot(
69
104
  input.predecessorCandidateId,
@@ -72,7 +107,6 @@ export function createDevDeliveryCandidateIdentity(
72
107
  }
73
108
  return { ...identity, candidateId: devDeliveryContentRoot(identity) };
74
109
  }
75
-
76
110
  export function validateDevDeliveryCandidateChain(candidates, terminalStates) {
77
111
  const precedingCandidates = new Map();
78
112
  const latestByPullRequest = new Map();
@@ -12,6 +12,7 @@ import {
12
12
  import {
13
13
  chainedDevDeliveryAttemptInput,
14
14
  createDevDeliveryCandidateIdentity,
15
+ devDeliverySourceBinding,
15
16
  EXACT_DEV_DELIVERY_PROOF_FIELDS,
16
17
  matchesExactDevDeliveryCandidate,
17
18
  validateDevDeliveryCandidateChain,
@@ -86,8 +87,7 @@ export function issueDevDeliveryWarrant(
86
87
  candidateId: candidate.candidateId,
87
88
  pullRequestNumber: candidate.pullRequestNumber,
88
89
  sourceHead: candidate.sourceHead,
89
- assignmentRoot: candidate.assignmentRoot,
90
- initiativeRoot: candidate.initiativeRoot,
90
+ ...devDeliverySourceBinding(candidate),
91
91
  sourceIdentityRoot: candidate.sourceIdentityRoot,
92
92
  sourcePatchRoot: candidate.sourcePatchRoot,
93
93
  sourceProofRoot: candidate.sourceProofRoot,
@@ -413,8 +413,7 @@ function submissionReceipt({ before, after, candidate, action, now }) {
413
413
  candidateId: candidate.candidateId,
414
414
  pullRequestNumber: candidate.pullRequestNumber,
415
415
  sourceHead: candidate.sourceHead,
416
- assignmentRoot: candidate.assignmentRoot,
417
- initiativeRoot: candidate.initiativeRoot,
416
+ ...devDeliverySourceBinding(candidate),
418
417
  sourceIdentityRoot: candidate.sourceIdentityRoot,
419
418
  sourcePatchRoot: candidate.sourcePatchRoot,
420
419
  sourceProofRoot: candidate.sourceProofRoot,
@@ -198,8 +198,8 @@ export function selectDevDeliveryWarrant(
198
198
  candidateId: transaction.result.candidate.candidateId,
199
199
  pullRequestNumber: transaction.result.candidate.pullRequestNumber,
200
200
  sourceHead: transaction.result.candidate.sourceHead,
201
- assignmentRoot: transaction.result.candidate.assignmentRoot,
202
- initiativeRoot: transaction.result.candidate.initiativeRoot,
201
+ ...candidateSourceBinding(transaction.result.candidate),
202
+
203
203
  sourceIdentityRoot: transaction.result.candidate.sourceIdentityRoot,
204
204
  sourcePatchRoot: transaction.result.candidate.sourcePatchRoot,
205
205
  sourceProofRoot: transaction.result.candidate.sourceProofRoot,
@@ -488,6 +488,7 @@ function createDevDeliverySuccessorWake(queue, now) {
488
488
  "candidateId",
489
489
  "pullRequestNumber",
490
490
  "sourceHead",
491
+ "sourceRoot",
491
492
  "assignmentRoot",
492
493
  "initiativeRoot",
493
494
  "sourceIdentityRoot",
@@ -586,3 +587,12 @@ export function observeDevDeliveryQueue(
586
587
  observedAt: currentTime,
587
588
  };
588
589
  }
590
+
591
+ function candidateSourceBinding(candidate) {
592
+ return candidate.sourceRoot
593
+ ? { sourceRoot: candidate.sourceRoot }
594
+ : {
595
+ assignmentRoot: candidate.assignmentRoot,
596
+ initiativeRoot: candidate.initiativeRoot,
597
+ };
598
+ }
@@ -118,12 +118,12 @@ const PROTECTED_AUTHORITY_PATHS = Object.freeze([
118
118
  ".github/CODEOWNERS",
119
119
  ".github/workflows/.publication-authority.yml",
120
120
  ".github/workflows/.release-candidate-promote.yml",
121
- ".github/workflows/buildchain-ref-promotion-recovery.yml",
122
- ".github/workflows/buildchain-ref-promotion.yml",
123
- ".github/workflows/github-governance-audit.yml",
121
+ ".github/workflows/self-ops-promotion-recovery.yml",
122
+ ".github/workflows/self-release-promote.yml",
123
+ ".github/workflows/self-ops-governance-audit.yml",
124
124
  ".github/workflows/paper-release-sealed.yml",
125
125
  ".github/workflows/paper-release.yml",
126
- ".github/workflows/release-line-bootstrap.yml",
126
+ ".github/workflows/self-release-line-open.yml",
127
127
  ".github/workflows/release-candidate-promote.yml",
128
128
  "actions/promote-buildchain-ref/action.yml",
129
129
  "actions/promote-buildchain-ref/dist/index.js",
@@ -21,7 +21,7 @@ export const KFD_LEGACY_SUPPORT_MATRIX_CONTRACT = "kungfu-kfd-support-matrix";
21
21
 
22
22
  const BUILDCHAIN_ADOPTER_ID = "kungfu-systems/buildchain";
23
23
  const ROOT_PATTERN = /^sha256:[0-9a-f]{64}$/;
24
- const SHA_PATTERN = /^[0-9a-f]{40}$/;
24
+ const SHA_PATTERN = /^[0-9a-f]{40}$/, SOURCE_REPOSITORY_PATTERN = /^[^@\s]+$/;
25
25
  const REQUIRED_DECISIONS = Object.freeze(["KFD-1", "KFD-2", "KFD-3", "KFD-4", "KFD-5", "KFD-7"]);
26
26
  const PRODUCT_GATE_STANDARDS = Object.freeze(["kfd-4", "kfd-5", "kfd-7"]);
27
27
  const PRODUCT_GATE_SET = new Set(PRODUCT_GATE_STANDARDS);
@@ -77,29 +77,27 @@ function verifyPublishedManifest(manifest, packageOptions, issues) {
77
77
  }
78
78
  }
79
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
- }
80
+ function adopterExpectation({ expectedAdopterId = BUILDCHAIN_ADOPTER_ID, expectedSourceRepository = "" } = {}) { const adopterId = text(expectedAdopterId) || BUILDCHAIN_ADOPTER_ID; return { adopterId, sourceRepository: text(expectedSourceRepository) || adopterId }; }
84
81
 
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
- }
82
+ function manifestSource(manifest) { const coordinate = text(manifest?.adopter?.artifact?.coordinate), match = /^([^@\s]+)@([0-9a-f]{40})$/.exec(coordinate); return { coordinate, repository: match?.[1] || "", sha: match?.[2] || "" }; }
83
+
84
+ function validateManifestIdentity(manifest, packageArtifactRoot, expectation, expectedSourceSha, issues) {
85
+ if (manifest?.adopter?.id !== expectation.adopterId) issues.push(issue("adopter-identity", "manifest.adopter.id", `manifest adopter must be ${expectation.adopterId}`));
89
86
  const pinned = manifest?.kfdCut?.package;
90
87
  if (pinned?.name !== kfdPackageJson.name
91
88
  || pinned?.version !== kfdPackageJson.version
92
89
  || pinned?.artifactRoot !== packageArtifactRoot) {
93
90
  issues.push(issue("adopter-package-cut", "manifest.kfdCut.package", "manifest must bind the exact installed KFD package cut"));
94
91
  }
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) {
92
+ const source = manifestSource(manifest);
93
+ if (!SOURCE_REPOSITORY_PATTERN.test(expectation.sourceRepository) || manifest?.adopter?.artifact?.kind !== "git-commit" || !source.sha || !ROOT_PATTERN.test(text(manifest?.adopter?.artifact?.root))) {
94
+ issues.push(issue("adopter-source", "manifest.adopter.artifact", "adopter authority must bind one exact repository, git commit, and artifact root"));
95
+ } else if (source.repository !== expectation.sourceRepository) {
96
+ issues.push(issue("adopter-source", "manifest.adopter.artifact.coordinate", `manifest source repository must be ${expectation.sourceRepository}`));
97
+ } else if (expectedSourceSha && source.sha !== expectedSourceSha) {
100
98
  issues.push(issue("adopter-source", "manifest.adopter.artifact.coordinate", "manifest source does not match the requested release source"));
101
99
  }
102
- return sourceSha;
100
+ return source;
103
101
  }
104
102
 
105
103
  function validateRequiredDecisions(decisions, issues) {
@@ -131,7 +129,7 @@ function collectProductGates(gateResults, decisions, verificationCut, issues) {
131
129
  for (const [index, gate] of gateResults.entries()) {
132
130
  const validation = validateKfdProductGateResult(gate, verificationCut);
133
131
  if (!validation.valid) {
134
- issues.push(issue("adopter-gate-invalid", `gateResults[${index}]`, "Buildchain product gate is invalid", {
132
+ issues.push(issue("adopter-gate-invalid", `gateResults[${index}]`, "adopter product gate is invalid", {
135
133
  gateIssues: validation.issues,
136
134
  }));
137
135
  }
@@ -141,15 +139,16 @@ function collectProductGates(gateResults, decisions, verificationCut, issues) {
141
139
  if (gates.has(gate?.standard)) {
142
140
  issues.push(issue("adopter-gate-duplicate", `gateResults[${index}].standard`, `${gate.standard} gate is duplicated`));
143
141
  }
142
+ if (gate?.source?.repository !== verificationCut.expectedSourceRepository) issues.push(issue("adopter-gate-source", `gateResults[${index}].source.repository`, "product gate repository must match the adopter source repository"));
144
143
  gates.set(gate?.standard, gate);
145
144
  }
146
145
  for (const standard of PRODUCT_GATE_STANDARDS) {
147
146
  const gate = gates.get(standard);
148
147
  const id = standard.toUpperCase();
149
148
  if (!gate) {
150
- issues.push(issue("adopter-gate-missing", `gateResults.${standard}`, `${id} requires its existing Buildchain product gate`));
149
+ issues.push(issue("adopter-gate-missing", `gateResults.${standard}`, `${id} requires its exact adopter product gate`));
151
150
  } 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`));
151
+ issues.push(issue("adopter-gate-unbound", `manifest.decisions.${id}.verificationEvidence`, `${id} must bind the exact adopter gate root`));
153
152
  }
154
153
  }
155
154
  return gates;
@@ -159,12 +158,12 @@ function projectedProductGates(gates) {
159
158
  return PRODUCT_GATE_STANDARDS.map((standard) => {
160
159
  const gate = gates.get(standard);
161
160
  return gate
162
- ? { standard, sourceSha: gate.source.sha, gateRoot: gate.gateRoot, status: gate.status }
163
- : { standard, sourceSha: "", gateRoot: "", status: "missing" };
161
+ ? { standard, sourceRepository: gate.source.repository, sourceSha: gate.source.sha, gateRoot: gate.gateRoot, status: gate.status }
162
+ : { standard, sourceRepository: "", sourceSha: "", gateRoot: "", status: "missing" };
164
163
  });
165
164
  }
166
165
 
167
- function createGateDocument({ manifest, bundle, gates, authorityPath, packageArtifactRoot, sourceSha, checkedAt, maxAgeSeconds, issues }) {
166
+ function createGateDocument({ manifest, bundle, gates, authorityPath, packageArtifactRoot, source, checkedAt, maxAgeSeconds, issues }) {
168
167
  const gate = {
169
168
  schemaVersion: 1,
170
169
  contract: KFD_ADOPTER_MANIFEST_GATE_CONTRACT,
@@ -174,10 +173,8 @@ function createGateDocument({ manifest, bundle, gates, authorityPath, packageArt
174
173
  contract: text(manifest?.contract),
175
174
  manifestRoot: bundle?.roots?.manifestRoot || "",
176
175
  },
177
- source: {
178
- sha: sourceSha,
179
- artifactRoot: text(manifest?.adopter?.artifact?.root),
180
- },
176
+ adopter: { id: text(manifest?.adopter?.id) },
177
+ source: { repository: source.repository, coordinate: source.coordinate, sha: source.sha, artifactRoot: text(manifest?.adopter?.artifact?.root) },
181
178
  verificationCut: { checkedAt, maxAgeSeconds },
182
179
  standardPackage: {
183
180
  name: kfdPackageJson.name,
@@ -211,28 +208,28 @@ export function createKfdAdopterManifestGate({
211
208
  packageArtifactRoot = "",
212
209
  gateResults = [],
213
210
  authorityPath = ".buildchain/kfd/adopter-manifest.json",
214
- expectedSourceSha = "",
211
+ expectedAdopterId = BUILDCHAIN_ADOPTER_ID, expectedSourceRepository = "", expectedSourceSha = "",
215
212
  checkedAt = new Date().toISOString(),
216
213
  maxAgeSeconds = 86400,
217
214
  } = {}) {
218
- const issues = [];
215
+ const issues = [], expectation = adopterExpectation({ expectedAdopterId, expectedSourceRepository });
219
216
  const bundle = verifyPublishedManifest(manifest, {
220
217
  packageArtifactRoot,
221
218
  verifiedAt: checkedAt,
222
219
  maxAgeSeconds,
223
220
  }, issues);
224
221
  const decisions = new Map((manifest?.decisions || []).map((row) => [row.id, row]));
225
- let sourceSha = manifestSourceSha(manifest);
222
+ let source = manifestSource(manifest);
226
223
  if (bundle) {
227
- sourceSha = validateManifestIdentity(manifest, packageArtifactRoot, expectedSourceSha, issues);
224
+ source = validateManifestIdentity(manifest, packageArtifactRoot, expectation, expectedSourceSha, issues);
228
225
  validateRequiredDecisions(decisions, issues);
229
226
  validateWarrantWitness(decisions, issues);
230
227
  }
231
- const gates = collectProductGates(gateResults, decisions, { expectedSourceSha: sourceSha || expectedSourceSha, checkedAt }, issues);
232
- return createGateDocument({ manifest, bundle, gates, authorityPath, packageArtifactRoot, sourceSha, checkedAt, maxAgeSeconds, issues });
228
+ const gates = collectProductGates(gateResults, decisions, { expectedSourceRepository: expectation.sourceRepository, expectedSourceSha: source.sha || expectedSourceSha, checkedAt }, issues);
229
+ return createGateDocument({ manifest, bundle, gates, authorityPath, packageArtifactRoot, source, checkedAt, maxAgeSeconds, issues });
233
230
  }
234
231
 
235
- function validateGateDocument(gate, issues) {
232
+ function validateGateDocument(gate, expectation, issues) {
236
233
  const copy = structuredClone(gate);
237
234
  const root = copy.gateRoot;
238
235
  delete copy.gateRoot;
@@ -244,12 +241,13 @@ function validateGateDocument(gate, issues) {
244
241
  || !ROOT_PATTERN.test(text(gate?.authority?.manifestRoot))) {
245
242
  issues.push(issue("adopter-gate-authority", "authority", "adopter gate must bind the standard manifest contract and root"));
246
243
  }
244
+ if (gate?.adopter?.id !== expectation.adopterId) issues.push(issue("adopter-gate-identity", "adopter.id", `adopter gate must bind ${expectation.adopterId}`));
247
245
  if (gate?.standardPackage?.name !== kfdPackageJson.name || gate?.standardPackage?.version !== kfdPackageJson.version
248
246
  || ![gate?.standardPackage?.artifactRoot, gate?.standardPackage?.registryRoot, gate?.standardPackage?.verifierSetRoot].every((value) => ROOT_PATTERN.test(text(value)))) {
249
247
  issues.push(issue("adopter-gate-package", "standardPackage", "adopter gate uses stale KFD package metadata"));
250
248
  }
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"));
249
+ if (gate?.source?.repository !== expectation.sourceRepository || gate?.source?.coordinate !== `${expectation.sourceRepository}@${gate?.source?.sha || ""}` || !SHA_PATTERN.test(text(gate?.source?.sha)) || !ROOT_PATTERN.test(text(gate?.source?.artifactRoot))) {
250
+ issues.push(issue("adopter-gate-source", "source", "adopter gate must bind the expected repository, exact source commit, coordinate, and artifact root"));
253
251
  }
254
252
  if (gate?.decisionWitness?.rootAlgorithm !== "sha256-buildchain-stable-json-v1"
255
253
  || !ROOT_PATTERN.test(text(gate?.decisionWitness?.root))
@@ -259,7 +257,7 @@ function validateGateDocument(gate, issues) {
259
257
  }
260
258
  }
261
259
 
262
- function validateProjectedGates(gate, expectedSourceSha, issues) {
260
+ function validateProjectedGates(gate, expectation, expectedSourceSha, issues) {
263
261
  const seenStandards = new Set();
264
262
  for (const [index, productGate] of (gate.gateResults || []).entries()) {
265
263
  if (!PRODUCT_GATE_SET.has(productGate?.standard) || productGate?.status !== "passed" || !ROOT_PATTERN.test(text(productGate?.gateRoot))) {
@@ -267,7 +265,7 @@ function validateProjectedGates(gate, expectedSourceSha, issues) {
267
265
  }
268
266
  if (seenStandards.has(productGate?.standard)) issues.push(issue("adopter-gate-result-set", `gateResults[${index}]`, "product gate standards must be unique"));
269
267
  seenStandards.add(productGate?.standard);
270
- if (productGate?.sourceSha !== gate?.source?.sha || (expectedSourceSha && productGate?.sourceSha !== expectedSourceSha)) {
268
+ if (productGate?.sourceRepository !== gate?.source?.repository || productGate?.sourceRepository !== expectation.sourceRepository || productGate?.sourceSha !== gate?.source?.sha || (expectedSourceSha && productGate?.sourceSha !== expectedSourceSha)) {
271
269
  issues.push(issue("adopter-gate-source", `gateResults[${index}].sourceSha`, "product gate source must match the release source"));
272
270
  }
273
271
  }
@@ -277,15 +275,15 @@ function validateProjectedGates(gate, expectedSourceSha, issues) {
277
275
  }
278
276
 
279
277
  export function validateKfdAdopterManifestGate(gate, {
280
- expectedSourceSha = "",
278
+ expectedAdopterId = BUILDCHAIN_ADOPTER_ID, expectedSourceRepository = "", expectedSourceSha = "",
281
279
  checkedAt = gate?.checkedAt || new Date().toISOString(),
282
280
  } = {}) {
283
- const issues = [];
281
+ const issues = [], expectation = adopterExpectation({ expectedAdopterId, expectedSourceRepository });
284
282
  if (!gate || gate.schemaVersion !== 1 || gate.contract !== KFD_ADOPTER_MANIFEST_GATE_CONTRACT) {
285
283
  return { valid: false, issues: [issue("adopter-gate-contract", "", `gate must use ${KFD_ADOPTER_MANIFEST_GATE_CONTRACT} v1`)] };
286
284
  }
287
- validateGateDocument(gate, issues);
288
- validateProjectedGates(gate, expectedSourceSha, issues);
285
+ validateGateDocument(gate, expectation, issues);
286
+ validateProjectedGates(gate, expectation, expectedSourceSha, issues);
289
287
  if (gate.checkedAt !== checkedAt || gate?.verificationCut?.checkedAt !== checkedAt || !Number.isFinite(Date.parse(checkedAt))
290
288
  || !Number.isSafeInteger(gate?.verificationCut?.maxAgeSeconds) || gate.verificationCut.maxAgeSeconds < 0) {
291
289
  issues.push(issue("adopter-gate-time", "verificationCut", "adopter gate verification cut does not match the requested cut"));
@@ -300,7 +298,7 @@ function legacyStatus(row) {
300
298
  return row.state;
301
299
  }
302
300
 
303
- function legacyRow(row, gates) {
301
+ function legacyRow(row, gates, adopterId) {
304
302
  const key = row.id.toLowerCase();
305
303
  const productGate = gates.get(key);
306
304
  return {
@@ -318,7 +316,7 @@ function legacyRow(row, gates) {
318
316
  releaseQualification: { shippedSupport: false },
319
317
  claimClass: "standard-adopter-manifest-projection",
320
318
  knownLimitations: [...row.gaps],
321
- owner: BUILDCHAIN_ADOPTER_ID,
319
+ owner: adopterId,
322
320
  nextGate: "Release Passport artifact binding and independent release decision",
323
321
  declaration: { state: row.state, usage: row.usage, root: kfdProductGateDigest(decisionWitnessRow(row)) },
324
322
  };
@@ -326,7 +324,7 @@ function legacyRow(row, gates) {
326
324
 
327
325
  export function createKfdLegacySupportMatrixProjection({ manifest, manifestGate } = {}) {
328
326
  const validation = validateKfdAdopterManifestGate(manifestGate, {
329
- expectedSourceSha: manifestGate?.source?.sha,
327
+ expectedAdopterId: manifestGate?.adopter?.id, expectedSourceRepository: manifestGate?.source?.repository, expectedSourceSha: manifestGate?.source?.sha,
330
328
  checkedAt: manifestGate?.checkedAt,
331
329
  });
332
330
  if (!validation.valid || manifest?.contract !== "kfd.adopter-conformance-manifest/v1") {
@@ -338,9 +336,9 @@ export function createKfdLegacySupportMatrixProjection({ manifest, manifestGate
338
336
  verifiedAt: manifestGate.verificationCut.checkedAt,
339
337
  maxAgeSeconds: manifestGate.verificationCut.maxAgeSeconds,
340
338
  }, authorityIssues);
341
- const sourceSha = validateManifestIdentity(manifest, manifestGate.standardPackage.artifactRoot, manifestGate.source.sha, authorityIssues);
339
+ const source = validateManifestIdentity(manifest, manifestGate.standardPackage.artifactRoot, { adopterId: manifestGate.adopter.id, sourceRepository: manifestGate.source.repository }, manifestGate.source.sha, authorityIssues);
342
340
  const decisionRoot = kfdProductGateDigest(manifest.decisions.map(decisionWitnessRow));
343
- if (!bundle || sourceSha !== manifestGate.source.sha || manifest.adopter.artifact.root !== manifestGate.source.artifactRoot
341
+ if (!bundle || source.sha !== manifestGate.source.sha || source.repository !== manifestGate.source.repository || source.coordinate !== manifestGate.source.coordinate || manifest.adopter.artifact.root !== manifestGate.source.artifactRoot
344
342
  || bundle.roots.manifestRoot !== manifestGate.authority.manifestRoot
345
343
  || bundle.roots.verificationReportRoot !== manifestGate.manifestVerificationReportRoot
346
344
  || bundle.bundleRoot !== manifestGate.manifestBundleRoot
@@ -364,7 +362,8 @@ export function createKfdLegacySupportMatrixProjection({ manifest, manifestGate
364
362
  path: manifestGate.authority.path,
365
363
  contract: manifest.contract,
366
364
  root: manifestGate.authority.manifestRoot,
367
- gateRoot: manifestGate.gateRoot,
365
+ gateRoot: manifestGate.gateRoot, adopterId: manifestGate.adopter.id,
366
+ sourceRepository: manifestGate.source.repository, sourceSha: manifestGate.source.sha,
368
367
  },
369
368
  upstream: {
370
369
  package: manifestGate.standardPackage.name,
@@ -374,7 +373,7 @@ export function createKfdLegacySupportMatrixProjection({ manifest, manifestGate
374
373
  verifierSetRoot: manifestGate.standardPackage.verifierSetRoot,
375
374
  standardsSha256: standardsFileDigest(),
376
375
  },
377
- rows: manifest.decisions.map((row) => legacyRow(row, gates)),
376
+ rows: manifest.decisions.map((row) => legacyRow(row, gates, manifestGate.adopter.id)),
378
377
  };
379
378
  }
380
379
 
@@ -243,8 +243,8 @@ invalid.
243
243
 
244
244
  ## Public self-dogfood and adoption
245
245
 
246
- \`.github/workflows/v4-public-consumer-dogfood.yml\` remains the exact thin
247
- consumer of the public \`v4-stage-capsule-canary.yml@v4-alpha\` contract. Its
246
+ \`.github/workflows/self-build-public-consumer-dogfood.yml\` remains the exact thin
247
+ consumer of the public \`public-build-stage-capsule-canary.yml@v4-alpha\` contract. Its
248
248
  declared \`lifecycle.verify\` runs \`pnpm run check\`, so the same public path
249
249
  executes pure recovery tests that inject a transient durable-state write
250
250
  failure, restore the adapter operation on a fresh runner, supersede stale work
@@ -201,7 +201,7 @@ function explainReleaseLineDryRun({
201
201
  );
202
202
  plan.branchUpdates.push(
203
203
  { ref: targetRef, action: "would move to alpha version-state commit" },
204
- { ref: `dev/v${rule.major}/v${rule.major}.${rule.minor}`, action: "would align dev with the published alpha state" },
204
+ { ref: `dev/v${rule.major}/v${rule.major}.${rule.minor}`, action: rule.major === 4 ? "would prepare the next alpha version on dev through a separate protected PR after publication" : "would align dev with the published alpha state" },
205
205
  );
206
206
  plan.versionState.targetVersions = [exactAlpha.replace(/^next v?/, "").replace(/^v/, "")];
207
207
  plan.notes.push("Alpha promotion opens or advances the test channel; it does not move production refs.");
@@ -405,7 +405,7 @@ export function prepareReleasePassportKfdSections({ kfd1, kfd2Claims, kfd3, kfdA
405
405
  };
406
406
  }
407
407
 
408
- export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], comparisonMatrix, sourceSha = "", checkedAt } = {}) {
408
+ export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], comparisonMatrix, expectedAdopterId = "kungfu-systems/buildchain", expectedSourceRepository = "", sourceSha = "", checkedAt } = {}) {
409
409
  if (!manifest) {
410
410
  if (comparisonMatrix || gateResults.length > 0) {
411
411
  throw new Error("KFD support and product-gate inputs require --kfd-adopter-manifest-json; --kfd-support-matrix-json is comparison-only");
@@ -414,7 +414,7 @@ export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], c
414
414
  }
415
415
  const manifestGate = createKfdAdopterManifestGate({
416
416
  manifest, packageArtifactRoot: installedKfdPackageArtifactRoot(), gateResults,
417
- expectedSourceSha: sourceSha, checkedAt,
417
+ expectedAdopterId, expectedSourceRepository, expectedSourceSha: sourceSha, checkedAt,
418
418
  });
419
419
  const legacyProjection = createKfdLegacySupportMatrixProjection({ manifest, manifestGate });
420
420
  if (comparisonMatrix) {
@@ -425,18 +425,18 @@ export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], c
425
425
  }
426
426
  return {
427
427
  manifest, manifestGate, legacyProjection,
428
- binding: createKfdAdopterReleaseBinding({ manifest, manifestGate, legacyProjection, expectedSourceSha: sourceSha }),
428
+ binding: createKfdAdopterReleaseBinding({ manifest, manifestGate, legacyProjection, expectedAdopterId, expectedSourceRepository, expectedSourceSha: sourceSha }),
429
429
  };
430
430
  }
431
431
 
432
- export function validateKfdAdopterReleaseEvidence({ binding, artifactBinding, manifest, manifestGate, legacyProjection, passportLegacyProjection, expectedSourceSha = "" } = {}) {
432
+ export function validateKfdAdopterReleaseEvidence({ binding, artifactBinding, manifest, manifestGate, legacyProjection, passportLegacyProjection, expectedAdopterId = "kungfu-systems/buildchain", expectedSourceRepository = "", expectedSourceSha = "" } = {}) {
433
433
  if (!binding) {
434
434
  return passportLegacyProjection
435
435
  ? [{ code: "kfdSupport.authority", message: "legacy KFD support projection requires the standard adopter manifest binding" }]
436
436
  : [];
437
437
  }
438
438
  const issues = validateKfdAdopterReleaseBinding(binding, {
439
- manifest, manifestGate, legacyProjection, expectedSourceSha,
439
+ manifest, manifestGate, legacyProjection, expectedAdopterId, expectedSourceRepository, expectedSourceSha,
440
440
  }).issues.map((entry) => ({ code: `kfdAdopter.${entry.path || entry.code}`, message: entry.message, details: entry }));
441
441
  if (!artifactBinding || passportStableJson(artifactBinding) !== passportStableJson(binding)) {
442
442
  issues.push({ code: "kfdAdopter.artifactEvidence", message: "release passport and artifact evidence must bind the same exact KFD adopter closure" });
@@ -1431,7 +1431,7 @@ export function createReleasePassport(options = {}) {
1431
1431
  };
1432
1432
  }
1433
1433
 
1434
- function collectKfdAdopterReleaseInputs({ cwd, manifestJson, supportMatrixJson, productGateJsons, sourceSha, checkedAt }) {
1434
+ function collectKfdAdopterReleaseInputs({ cwd, manifestJson, supportMatrixJson, productGateJsons, repository, sourceSha, checkedAt }) {
1435
1435
  const manifestMeta = parseJsonInputWithMeta(manifestJson, undefined, { cwd, label: "kfdAdopterManifestJson" });
1436
1436
  const supportMatrixMeta = parseJsonInputWithMeta(supportMatrixJson, undefined, { cwd, label: "kfdSupportMatrixJson" });
1437
1437
  const productGateMetas = (productGateJsons || [])
@@ -1442,7 +1442,7 @@ function collectKfdAdopterReleaseInputs({ cwd, manifestJson, supportMatrixJson,
1442
1442
  manifest: manifestMeta.value,
1443
1443
  gateResults: productGateMetas.map((meta) => meta.value),
1444
1444
  comparisonMatrix: supportMatrixMeta.value,
1445
- sourceSha,
1445
+ expectedAdopterId: repository || "kungfu-systems/buildchain", expectedSourceRepository: repository, sourceSha,
1446
1446
  checkedAt,
1447
1447
  });
1448
1448
  }
@@ -1620,7 +1620,7 @@ export function collectGitHubReleasePassport({
1620
1620
  const productMechanism = defaultProductMechanism({ repository, productName });
1621
1621
  const kfdAdopterEvidence = collectKfdAdopterReleaseInputs({
1622
1622
  cwd, manifestJson: kfdAdopterManifestJson, supportMatrixJson: kfdSupportMatrixJson,
1623
- productGateJsons: kfdProductGateJsons, sourceSha, checkedAt: resolvedCheckedAt,
1623
+ productGateJsons: kfdProductGateJsons, repository, sourceSha, checkedAt: resolvedCheckedAt,
1624
1624
  });
1625
1625
  const {
1626
1626
  manifest: kfdAdopterManifest,
@@ -2060,7 +2060,8 @@ function validateReleaseEvidenceContracts({
2060
2060
  manifestGate: kfdAdopterManifestGate,
2061
2061
  legacyProjection: kfdSupportEvidence,
2062
2062
  passportLegacyProjection: passport?.kfdSupport,
2063
- expectedSourceSha: optionalString(passport?.release?.sourceSha),
2063
+ expectedAdopterId: optionalString(passport?.product?.repository) || "kungfu-systems/buildchain",
2064
+ expectedSourceRepository: optionalString(passport?.product?.repository), expectedSourceSha: optionalString(passport?.release?.sourceSha),
2064
2065
  })) {
2065
2066
  issues.push(issue("error", entry.code, entry.message, entry.details));
2066
2067
  }
@@ -0,0 +1,29 @@
1
+ export const RELEASE_TAIL_PRODUCT_CAPABILITIES = Object.freeze([
2
+ Object.freeze({
3
+ id: "product.version-state.materialize",
4
+ executor: "provider-adapter",
5
+ adapter: "github-version-state",
6
+ effectKind: "product-version-state-materialization",
7
+ observationKind: "product-version-state-readback",
8
+ receiptKind: "product-version-state",
9
+ transactionState: "preparing",
10
+ }),
11
+ Object.freeze({
12
+ id: "product.package.publish",
13
+ executor: "provider-adapter",
14
+ adapter: "npm-trusted-publishing",
15
+ effectKind: "product-package-publication",
16
+ observationKind: "product-package-readback",
17
+ receiptKind: "product-package-publication",
18
+ transactionState: "publishing",
19
+ }),
20
+ Object.freeze({
21
+ id: "product.release-refs.converge",
22
+ executor: "provider-adapter",
23
+ adapter: "github-release-refs",
24
+ effectKind: "product-release-ref-convergence",
25
+ observationKind: "product-release-ref-readback",
26
+ receiptKind: "product-release-ref-convergence",
27
+ transactionState: "committing",
28
+ }),
29
+ ]);