@kungfu-tech/buildchain 4.0.1-alpha.2 → 4.0.1-alpha.21

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 (203) hide show
  1. package/actions/release-tail/README.md +8 -0
  2. package/architecture/ci-lane-change-budget.json +187 -0
  3. package/architecture/decisions/0002-next-development-transition.md +101 -0
  4. package/architecture/decisions/0003-two-phase-delivery-warrant.md +152 -0
  5. package/architecture/internal-capabilities.json +211 -8
  6. package/architecture/maintainability-policy.json +113 -28
  7. package/architecture/release-tail-contract-inventory.json +5 -2
  8. package/architecture/v3-core-mechanism-inventory.json +91 -0
  9. package/architecture/v4-adopter-delivery-parity.json +32 -5
  10. package/architecture/v4-capability-state-machine-manifest.json +73 -0
  11. package/architecture/v4-compatibility-facts-parity.json +77 -0
  12. package/architecture/v4-delivery-authority-parity.json +250 -0
  13. package/architecture/v4-delivery-warrant-shadow-fixtures.json +41 -9
  14. package/architecture/v4-floating-consumer-policy.json +6 -0
  15. package/architecture/v4-next-development-parity.json +192 -0
  16. package/architecture/v4-publication-rehearsal-parity.json +84 -0
  17. package/architecture/v4-release-train-parity.json +1 -0
  18. package/architecture/v4-tail-reseal-parity.json +150 -0
  19. package/bin/buildchain.mjs +32 -3
  20. package/bin/internal/adopter-delivery-cli.mjs +70 -0
  21. package/bin/internal/command-registry.mjs +3 -0
  22. package/bin/internal/compatibility-facts-cli.mjs +101 -0
  23. package/contracts/dev-delivery-authority-v2.schema.json +662 -0
  24. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
  25. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
  26. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
  27. package/contracts/fixtures/v4-adopter-delivery-v1/archive-template.json +19 -0
  28. package/contracts/fixtures/v4-adopter-delivery-v1/bootstrap-positive.json +93 -0
  29. package/contracts/fixtures/v4-adopter-delivery-v1/gate-positive.json +29 -0
  30. package/contracts/fixtures/v4-adopter-delivery-v1/gate-unknown-selector.json +26 -0
  31. package/contracts/fixtures/v4-adopter-delivery-v1/offline-vectors.json +50 -0
  32. package/contracts/fixtures/v4-compatibility-facts-v1/shared.json +1129 -0
  33. package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +7 -1
  34. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/artifacts/product.bin +1 -0
  35. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/config/buildchain.toml +5 -0
  36. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/release-activation.json +1 -0
  37. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/signed-channel.json +1 -0
  38. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/evidence/qualification.json +1 -0
  39. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/candidate.json +5 -0
  40. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/release-passport.json +1 -0
  41. package/contracts/fixtures/v4-publication-rehearsal-v1/capsule.json +707 -0
  42. package/contracts/fixtures/v4-publication-rehearsal-v1/offline-vectors.json +27 -0
  43. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +229 -0
  44. package/contracts/next-development-request-v1.schema.json +66 -0
  45. package/contracts/next-development-transition-v1.schema.json +292 -0
  46. package/contracts/v4-adopter-delivery-v1.schema.json +81 -0
  47. package/contracts/v4-compatibility-facts-v1.schema.json +230 -0
  48. package/contracts/v4-floating-consumer-policy-receipt-v1.schema.json +4 -2
  49. package/contracts/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  50. package/contracts/v4-tail-reseal-v1.schema.json +276 -0
  51. package/dist/site/agent-index.json +5 -0
  52. package/dist/site/artifact-schemas.json +10 -0
  53. package/dist/site/buildchain-contract.json +1475 -27
  54. package/dist/site/buildchain-site.json +627 -31
  55. package/dist/site/capability-registry.json +17 -14
  56. package/dist/site/cli-registry.json +205 -3
  57. package/dist/site/kfd-claims.json +490 -16
  58. package/dist/site/kfd-upstream-aggregate.json +1 -1
  59. package/dist/site/manual-registry.json +52 -6
  60. package/dist/site/node-api-registry.json +14736 -8851
  61. package/dist/site/page-registry.json +593 -21
  62. package/dist/site/public-surface-audit.json +837 -48
  63. package/dist/site/publication-authority-registry.json +44 -8
  64. package/dist/site/publication-registry.json +4 -4
  65. package/dist/site/release-provenance.json +24 -0
  66. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +662 -0
  67. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +199 -0
  68. package/dist/site/schemas/v4-adopter-delivery-v1.schema.json +81 -0
  69. package/dist/site/schemas/v4-compatibility-facts-v1.schema.json +230 -0
  70. package/dist/site/schemas/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  71. package/dist/site/site-manifest.json +34 -10
  72. package/dist/site/workflow-registry.json +160 -10
  73. package/docs/MAP.md +8 -2
  74. package/docs/cli-reference.md +404 -13
  75. package/docs/cli.md +8 -0
  76. package/docs/dev-alpha-candidate-patrol.md +8 -0
  77. package/docs/dev-delivery-qualification-landing-adr.md +251 -0
  78. package/docs/dev-delivery-warrant.md +351 -38
  79. package/docs/next-development-transition.md +118 -0
  80. package/docs/node-api-reference.md +646 -293
  81. package/docs/release-tail-provider-plane.md +30 -0
  82. package/docs/v4-adopter-delivery.md +133 -0
  83. package/docs/v4-compatibility-facts.md +91 -0
  84. package/docs/v4-publication-rehearsal.md +130 -0
  85. package/docs/v4-tail-reseal.md +73 -0
  86. package/docs/versioning.md +4 -3
  87. package/package.json +34 -6
  88. package/packages/core/adopter-delivery-passport.js +259 -0
  89. package/packages/core/adopter-delivery-vectors.js +158 -0
  90. package/packages/core/adopter-delivery-vectors.json +77 -0
  91. package/packages/core/buildchain-agent-manuals.js +3 -0
  92. package/packages/core/buildchain-compatibility-authority.js +336 -0
  93. package/packages/core/buildchain-compatibility-fact.js +394 -0
  94. package/packages/core/buildchain-compatibility-facts.json +217 -0
  95. package/packages/core/buildchain-compatibility-proof.js +566 -0
  96. package/packages/core/buildchain-config.js +84 -0
  97. package/packages/core/buildchain-contract.js +96 -143
  98. package/packages/core/buildchain-delivery-bootstrap.js +240 -0
  99. package/packages/core/buildchain-delivery-infrastructure.js +164 -0
  100. package/packages/core/buildchain-delivery-self-dogfood.js +395 -0
  101. package/packages/core/buildchain-publication-authority.js +1 -0
  102. package/packages/core/channel-candidate.js +8 -0
  103. package/packages/core/channel-promotion-baseline.js +55 -0
  104. package/packages/core/ci-lane-change-budget.js +247 -0
  105. package/packages/core/dev-alpha-candidate-selection.js +10 -2
  106. package/packages/core/dev-delivery-authority-candidate.js +270 -0
  107. package/packages/core/dev-delivery-authority-evidence.js +146 -0
  108. package/packages/core/dev-delivery-authority-landing.js +461 -0
  109. package/packages/core/dev-delivery-authority-observation.js +48 -0
  110. package/packages/core/dev-delivery-authority-qualification.js +591 -0
  111. package/packages/core/dev-delivery-authority-settlement.js +213 -0
  112. package/packages/core/dev-delivery-authority-state.js +583 -0
  113. package/packages/core/dev-delivery-candidate-identity.js +13 -0
  114. package/packages/core/dev-delivery-contract-surface.js +76 -0
  115. package/packages/core/dev-delivery-execution-failure.js +133 -0
  116. package/packages/core/dev-delivery-execution-transfer.js +592 -0
  117. package/packages/core/dev-delivery-landing-admission-core.js +119 -0
  118. package/packages/core/dev-delivery-landing-readback.js +598 -0
  119. package/packages/core/dev-delivery-landing-terminal-evidence.js +271 -0
  120. package/packages/core/dev-delivery-landing-testing-port.js +6 -0
  121. package/packages/core/dev-delivery-native-execution.js +110 -0
  122. package/packages/core/dev-delivery-native-proof.js +562 -0
  123. package/packages/core/dev-delivery-process-boundary.js +563 -0
  124. package/packages/core/dev-delivery-provider-attempt.js +127 -0
  125. package/packages/core/dev-delivery-provider-heartbeat.js +382 -0
  126. package/packages/core/dev-delivery-warrant-cancellation.js +1 -0
  127. package/packages/core/dev-delivery-warrant-qualification.js +145 -0
  128. package/packages/core/dev-delivery-warrant-settlement.js +237 -36
  129. package/packages/core/dev-delivery-warrant-state.js +587 -0
  130. package/packages/core/dev-delivery-warrant.js +328 -370
  131. package/packages/core/github-governance-authority.js +1 -0
  132. package/packages/core/index.js +5 -0
  133. package/packages/core/kungfu-temporal-fact.js +557 -0
  134. package/packages/core/legacy-kfd-adopter-driver.js +167 -0
  135. package/packages/core/next-development-candidate-reservation.js +186 -0
  136. package/packages/core/next-development-controller.js +728 -0
  137. package/packages/core/next-development-projection.js +287 -0
  138. package/packages/core/next-development-transition.js +738 -0
  139. package/packages/core/paper-agent-entry.js +11 -5
  140. package/packages/core/paper.js +16 -5
  141. package/packages/core/published-delivery-authority.js +266 -0
  142. package/packages/core/release-candidate-recovery.js +70 -15
  143. package/packages/core/release-candidate.js +2 -2
  144. package/packages/core/release-passport.js +36 -9
  145. package/packages/core/v4-adopter-delivery-parity.js +3 -3
  146. package/packages/core/v4-adopter-delivery.js +359 -0
  147. package/packages/core/v4-canonical-contracts.js +5 -0
  148. package/packages/core/v4-delivery-warrant-read-candidate.js +10 -3
  149. package/packages/core/v4-floating-consumer-evidence.js +18 -4
  150. package/packages/core/v4-floating-consumer-policy.js +143 -20
  151. package/packages/core/v4-floating-consumer-release-passport.js +32 -5
  152. package/packages/core/v4-publication-rehearsal-capsule.js +468 -0
  153. package/packages/core/v4-publication-rehearsal-provider-bindings.js +212 -0
  154. package/packages/core/v4-publication-rehearsal.js +481 -0
  155. package/packages/core/v4-tail-reseal-contract.js +26 -0
  156. package/packages/core/v4-tail-reseal-github.js +178 -0
  157. package/packages/core/v4-tail-reseal-receipt.js +225 -0
  158. package/packages/core/v4-tail-reseal.js +594 -0
  159. package/packages/core/workflow-yaml-contract.js +24 -2
  160. package/scripts/buildchain-cli-help.mjs +41 -2
  161. package/scripts/check-ci-lane-change-budget.mjs +100 -0
  162. package/scripts/check-inventory.mjs +14 -3
  163. package/scripts/check-v4-floating-consumer-policy-contract.mjs +23 -4
  164. package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
  165. package/scripts/dev-delivery-authority-command-adapters.mjs +206 -0
  166. package/scripts/dev-delivery-authority-provider.mjs +28 -0
  167. package/scripts/dev-delivery-authority.mjs +490 -0
  168. package/scripts/dev-delivery-native-run.mjs +177 -0
  169. package/scripts/dev-delivery-process-boundary.mjs +260 -0
  170. package/scripts/dev-delivery-proof.mjs +67 -2
  171. package/scripts/dev-delivery-provider-heartbeat.mjs +215 -0
  172. package/scripts/dev-delivery-source-proof-replay.mjs +153 -0
  173. package/scripts/dev-delivery-source-proof-reuse.mjs +13 -97
  174. package/scripts/dev-delivery-two-phase-resume.mjs +345 -0
  175. package/scripts/dev-delivery-two-phase.mjs +573 -0
  176. package/scripts/dev-delivery-warrant-options.mjs +266 -0
  177. package/scripts/dev-delivery-warrant-store.mjs +231 -0
  178. package/scripts/dev-delivery-warrant.mjs +232 -194
  179. package/scripts/dev-pr-auto-merge.mjs +1 -1
  180. package/scripts/dev-pr-delivery-warrant.mjs +11 -0
  181. package/scripts/dev-qualification-patrol.mjs +9 -9
  182. package/scripts/dispatch-artifact-signing-authority.mjs +1 -1
  183. package/scripts/generate-channel-promotion-workflow.mjs +2 -2
  184. package/scripts/generate-next-development-guidance.mjs +49 -0
  185. package/scripts/generate-release-candidate-passport.mjs +152 -0
  186. package/scripts/generate-site-bundle.mjs +69 -4
  187. package/scripts/init-repo.mjs +22 -4
  188. package/scripts/next-development-self-dogfood-harness.mjs +460 -0
  189. package/scripts/next-development-self-dogfood.mjs +597 -0
  190. package/scripts/next-development-transition.mjs +47 -0
  191. package/scripts/npm-publish-transaction.mjs +2 -2
  192. package/scripts/promotion-channel-router.mjs +4 -4
  193. package/scripts/release-candidate-anchor-provenance.mjs +99 -0
  194. package/scripts/release-tail.mjs +51 -3
  195. package/scripts/release-train-self-dogfood.mjs +94 -92
  196. package/scripts/resume-from-candidate-run.mjs +557 -30
  197. package/scripts/site-capability-metadata.mjs +41 -0
  198. package/scripts/stable-candidate-qualification.mjs +9 -10
  199. package/scripts/v4-consumer-policy.mjs +5 -5
  200. package/scripts/v4-publication-rehearsal-fixture.mjs +144 -0
  201. package/scripts/v4-tail-reseal-macos-rehearsal.mjs +134 -0
  202. package/scripts/v4-tail-reseal.mjs +416 -0
  203. package/templates/native-dev-delivery.yml +143 -0
@@ -0,0 +1,566 @@
1
+ import {
2
+ devDeliveryClone as clone,
3
+ devDeliveryContentRoot as contentRoot,
4
+ devDeliveryExactRoot as exactRoot,
5
+ devDeliveryText as text,
6
+ } from "./dev-delivery-common.js";
7
+ import { evaluateBuildchainChannelBinding } from "./buildchain-channel-identity.js";
8
+ import {
9
+ assertBuildchainCompatibilityProjection,
10
+ createBuildchainCompatibilityProofRegistry,
11
+ resolveBuildchainCompatibilityProof,
12
+ } from "./buildchain-compatibility-authority.js";
13
+
14
+ export {
15
+ BUILDCHAIN_COMPATIBILITY_FACT_REGISTRY_SCHEMA,
16
+ BUILDCHAIN_COMPATIBILITY_RELEASE_EVIDENCE_SCHEMA,
17
+ BUILDCHAIN_COMPATIBILITY_FACT_SCHEMA,
18
+ BUILDCHAIN_COMPATIBILITY_PROOF_REGISTRY_SCHEMA,
19
+ BUILDCHAIN_COMPATIBILITY_PROOF_SCHEMA,
20
+ createBuildchainCompatibilityFact,
21
+ createBuildchainCompatibilityFactRegistry,
22
+ createBuildchainCompatibilityProof,
23
+ createHistoricalBuildchainCompatibilityFacts,
24
+ createHistoricalBuildchainCompatibilityProofs,
25
+ verifyBuildchainCompatibilityFact,
26
+ verifyBuildchainCompatibilityFactRegistry,
27
+ verifyBuildchainCompatibilityProof,
28
+ } from "./buildchain-compatibility-fact.js";
29
+ export {
30
+ assertBuildchainCompatibilityProjection,
31
+ createBuildchainCompatibilityPathQuery,
32
+ createBuildchainCompatibilityProofRegistry,
33
+ createBuildchainCompatibilityReleaseEvidence,
34
+ resolveBuildchainCompatibilityProof,
35
+ verifyBuildchainCompatibilityPath,
36
+ } from "./buildchain-compatibility-authority.js";
37
+
38
+ export const BUILDCHAIN_LEGACY_COMPATIBILITY_VERIFICATION_RECEIPT_SCHEMA =
39
+ "kungfu.buildchain.compatibility-verification-receipt/v1";
40
+ export const BUILDCHAIN_COMPATIBILITY_VERIFICATION_RECEIPT_SCHEMA =
41
+ "kungfu.buildchain.compatibility-verification-receipt/v2";
42
+
43
+ const BUILDCHAIN_CONTRACT = "kungfu-buildchain-runtime-contract-world";
44
+ const COMPATIBILITY_OPERATION = "accept-contract-lock";
45
+ const COMPATIBILITY_DIRECTION = "source-to-target";
46
+
47
+ function exactText(value, label) {
48
+ const normalized = text(value);
49
+ if (!normalized) throw new Error(`${label} must not be empty`);
50
+ return normalized;
51
+ }
52
+
53
+ export function createBuildchainCompatibilityVerificationReceipt(input = {}) {
54
+ const decisions = clone(input.decisions || []);
55
+ const usedProofRoots = [
56
+ ...new Set(
57
+ decisions
58
+ .map((decision) => decision.proofRoot)
59
+ .filter(Boolean)
60
+ .map((root) => exactRoot(root, "decision.proofRoot")),
61
+ ),
62
+ ].sort();
63
+ const usedFactRoots = [
64
+ ...new Set(
65
+ decisions
66
+ .map((decision) => decision.factRoot)
67
+ .filter(Boolean)
68
+ .map((root) => exactRoot(root, "decision.factRoot")),
69
+ ),
70
+ ].sort();
71
+ const pathReceiptRoots = [
72
+ ...new Set(
73
+ decisions
74
+ .map((decision) => decision.pathReceiptRoot)
75
+ .filter(Boolean)
76
+ .map((root) => exactRoot(root, "decision.pathReceiptRoot")),
77
+ ),
78
+ ].sort();
79
+ const body = {
80
+ schema: BUILDCHAIN_COMPATIBILITY_VERIFICATION_RECEIPT_SCHEMA,
81
+ operation: COMPATIBILITY_OPERATION,
82
+ direction: COMPATIBILITY_DIRECTION,
83
+ status: exactText(input.status, "status"),
84
+ compatible: input.compatible === true,
85
+ policy: exactText(input.policy, "policy"),
86
+ scope: clone(input.scope || {}),
87
+ acceptedContractDigest: text(input.acceptedContractDigest),
88
+ acceptedCompatibilityDigest: text(input.acceptedCompatibilityDigest),
89
+ acceptedFactRegistryRoot: text(input.acceptedFactRegistryRoot),
90
+ acceptedProofRegistryRoot: text(input.acceptedProofRegistryRoot),
91
+ currentContractDigest: text(input.currentContractDigest),
92
+ currentCompatibilityDigest: text(input.currentCompatibilityDigest),
93
+ currentFactRegistryRoot: exactRoot(
94
+ input.currentFactRegistryRoot,
95
+ "currentFactRegistryRoot",
96
+ ),
97
+ currentFactCutRoot: exactRoot(
98
+ input.currentFactCutRoot,
99
+ "currentFactCutRoot",
100
+ ),
101
+ currentProofRegistryRoot: text(input.currentProofRegistryRoot),
102
+ decisions,
103
+ usedProofRoots,
104
+ usedFactRoots,
105
+ pathReceiptRoots,
106
+ reasonCodes: [
107
+ ...new Set(
108
+ (input.reasonCodes || []).map((reason) =>
109
+ exactText(reason, "reasonCode"),
110
+ ),
111
+ ),
112
+ ].sort(),
113
+ };
114
+ return { ...body, receiptRoot: contentRoot(body) };
115
+ }
116
+
117
+ function createLegacyCompatibilityVerificationReceipt(input = {}) {
118
+ const decisions = clone(input.decisions || []);
119
+ const body = {
120
+ schema: BUILDCHAIN_LEGACY_COMPATIBILITY_VERIFICATION_RECEIPT_SCHEMA,
121
+ operation: COMPATIBILITY_OPERATION,
122
+ direction: COMPATIBILITY_DIRECTION,
123
+ status: exactText(input.status, "status"),
124
+ compatible: input.compatible === true,
125
+ policy: exactText(input.policy, "policy"),
126
+ scope: clone(input.scope || {}),
127
+ acceptedContractDigest: text(input.acceptedContractDigest),
128
+ acceptedCompatibilityDigest: text(input.acceptedCompatibilityDigest),
129
+ acceptedProofRegistryRoot: text(input.acceptedProofRegistryRoot),
130
+ currentContractDigest: text(input.currentContractDigest),
131
+ currentCompatibilityDigest: text(input.currentCompatibilityDigest),
132
+ currentProofRegistryRoot: text(input.currentProofRegistryRoot),
133
+ decisions,
134
+ usedProofRoots: [
135
+ ...new Set(
136
+ decisions
137
+ .map((decision) => decision.proofRoot)
138
+ .filter(Boolean)
139
+ .map((entry) => exactRoot(entry, "decision.proofRoot")),
140
+ ),
141
+ ].sort(),
142
+ reasonCodes: [
143
+ ...new Set(
144
+ (input.reasonCodes || []).map((reason) =>
145
+ exactText(reason, "reasonCode"),
146
+ ),
147
+ ),
148
+ ].sort(),
149
+ };
150
+ return { ...body, receiptRoot: contentRoot(body) };
151
+ }
152
+
153
+ export function verifyBuildchainCompatibilityVerificationReceipt(receiptInput) {
154
+ try {
155
+ const receipt = clone(receiptInput || {});
156
+ const normalized =
157
+ receipt.schema === BUILDCHAIN_COMPATIBILITY_VERIFICATION_RECEIPT_SCHEMA
158
+ ? createBuildchainCompatibilityVerificationReceipt(receipt)
159
+ : receipt.schema ===
160
+ BUILDCHAIN_LEGACY_COMPATIBILITY_VERIFICATION_RECEIPT_SCHEMA
161
+ ? createLegacyCompatibilityVerificationReceipt(receipt)
162
+ : null;
163
+ if (!normalized) return { ok: false, reason: "unsupported-schema" };
164
+ if (normalized.receiptRoot !== receipt.receiptRoot)
165
+ return { ok: false, reason: "receipt-root-drift" };
166
+ if (JSON.stringify(normalized) !== JSON.stringify(receipt))
167
+ return { ok: false, reason: "non-canonical-receipt" };
168
+ return {
169
+ ok: true,
170
+ reason: "exact-compatibility-verification-receipt",
171
+ receiptRoot: receipt.receiptRoot,
172
+ };
173
+ } catch (error) {
174
+ return { ok: false, reason: "invalid-receipt", error: error.message };
175
+ }
176
+ }
177
+
178
+ export function contractSummary(
179
+ contractWorld,
180
+ runtimeRef = "",
181
+ runtimeSha = "",
182
+ ) {
183
+ return {
184
+ ref: runtimeRef,
185
+ resolvedSha: runtimeSha,
186
+ contract: contractWorld.contract,
187
+ contractDigest: contractWorld.contractDigest,
188
+ compatibilityDigest: contractWorld.compatibilityDigest,
189
+ compatibilityFactRegistryRoot: contractWorld.compatibilityFactRegistryRoot,
190
+ compatibilityFactCutRoot: contractWorld.compatibilityFactCutRoot,
191
+ compatibilityProofRegistryRoot:
192
+ contractWorld.compatibilityProofRegistryRoot,
193
+ majorLine: contractWorld.majorLine,
194
+ surfaceCount: Array.isArray(contractWorld.surfaces)
195
+ ? contractWorld.surfaces.length
196
+ : 0,
197
+ };
198
+ }
199
+
200
+ function evaluationReceipt({
201
+ status,
202
+ compatible,
203
+ policy,
204
+ accepted,
205
+ current,
206
+ decisions = [],
207
+ reasons = [],
208
+ }) {
209
+ return createBuildchainCompatibilityVerificationReceipt({
210
+ status,
211
+ compatible,
212
+ policy,
213
+ scope: { contract: current.contract, majorLine: current.majorLine },
214
+ acceptedContractDigest: accepted.contractDigest,
215
+ acceptedCompatibilityDigest: accepted.compatibilityDigest,
216
+ acceptedFactRegistryRoot: accepted.compatibilityFactRegistryRoot,
217
+ acceptedProofRegistryRoot: accepted.compatibilityProofRegistryRoot,
218
+ currentContractDigest: current.contractDigest,
219
+ currentCompatibilityDigest: current.compatibilityDigest,
220
+ currentFactRegistryRoot: current.compatibilityFactRegistryRoot,
221
+ currentFactCutRoot: current.compatibilityFactCutRoot,
222
+ currentProofRegistryRoot: current.compatibilityProofRegistryRoot,
223
+ decisions,
224
+ reasonCodes: reasons,
225
+ });
226
+ }
227
+
228
+ function contractPolicyReasons(accepted, current, policy) {
229
+ const reasons = [];
230
+ if (accepted.contract !== current.contract)
231
+ reasons.push(
232
+ `contract changed from ${accepted.contract || "(unknown)"} to ${current.contract}`,
233
+ );
234
+ if (accepted.majorLine && accepted.majorLine !== current.majorLine)
235
+ reasons.push(
236
+ `major line changed from ${accepted.majorLine} to ${current.majorLine}`,
237
+ );
238
+ if (policy === "exact" && accepted.contractDigest !== current.contractDigest)
239
+ reasons.push(
240
+ "exact policy requires the contract digest to remain unchanged",
241
+ );
242
+ if (!["major-compatible", "allow-additive", "exact"].includes(policy))
243
+ reasons.push(`unsupported compatibility policy: ${policy}`);
244
+ return reasons;
245
+ }
246
+
247
+ function evaluateSurfaceRelation({
248
+ oldSurface,
249
+ nextSurface,
250
+ proofRegistry,
251
+ majorLine,
252
+ }) {
253
+ if (!nextSurface) {
254
+ return {
255
+ reason: `surface removed: ${oldSurface.id}`,
256
+ decision: {
257
+ surfaceId: oldSurface.id,
258
+ status: "surface-removed",
259
+ sourceBreakingDigest: oldSurface.breakingDigest,
260
+ targetBreakingDigest: "",
261
+ reason: "surface-removed",
262
+ },
263
+ };
264
+ }
265
+ if (nextSurface.breakingDigest === oldSurface.breakingDigest) return {};
266
+ const resolution = resolveBuildchainCompatibilityProof({
267
+ registry: proofRegistry,
268
+ surface: nextSurface,
269
+ sourceBreakingDigest: oldSurface.breakingDigest,
270
+ majorLine,
271
+ });
272
+ if (!resolution.ok) {
273
+ return {
274
+ reason: `surface breaking digest changed without a valid compatibility proof: ${oldSurface.id} (${resolution.reason})`,
275
+ decision: {
276
+ surfaceId: oldSurface.id,
277
+ status: "rejected",
278
+ sourceBreakingDigest: oldSurface.breakingDigest,
279
+ targetBreakingDigest: nextSurface.breakingDigest,
280
+ reason: resolution.reason,
281
+ },
282
+ };
283
+ }
284
+ const proof = resolution.proof;
285
+ return {
286
+ decision: {
287
+ surfaceId: oldSurface.id,
288
+ status: "accepted",
289
+ sourceBreakingDigest: oldSurface.breakingDigest,
290
+ targetBreakingDigest: nextSurface.breakingDigest,
291
+ proofRoot: proof.proofRoot,
292
+ factRoot: resolution.factRoot,
293
+ pathReceipt: resolution.pathReceipt,
294
+ pathReceiptRoot: resolution.pathReceiptRoot,
295
+ direction: proof.direction,
296
+ operation: proof.operation,
297
+ scope: proof.scope,
298
+ scopeRoot: proof.scopeRoot,
299
+ evidence: proof.evidence,
300
+ evidenceRoot: proof.evidenceRoot,
301
+ authority: proof.authority,
302
+ authorityRoot: proof.authorityRoot,
303
+ cut: proof.cut,
304
+ cutRoot: proof.cutRoot,
305
+ },
306
+ };
307
+ }
308
+
309
+ function evaluateChannelBinding({
310
+ lock,
311
+ workflowShellRef,
312
+ runtimeRef,
313
+ expectedChannel,
314
+ expectedMajor,
315
+ allowOpaqueRuntime,
316
+ }) {
317
+ if (!workflowShellRef && !expectedChannel && !expectedMajor) return null;
318
+ return evaluateBuildchainChannelBinding({
319
+ workflowShellRef,
320
+ runtimeRef,
321
+ lockRef: lock?.buildchain?.ref || "",
322
+ lockMajorLine: lock?.buildchain?.majorLine || "",
323
+ expectedChannel,
324
+ expectedMajor,
325
+ allowOpaqueRuntime,
326
+ });
327
+ }
328
+
329
+ export function evaluateBuildchainContractLock({
330
+ lock,
331
+ current,
332
+ runtimeRef = "",
333
+ runtimeSha = "",
334
+ runtimeClass = "",
335
+ compatibilityPolicy = "",
336
+ workflowShellRef = "",
337
+ expectedChannel = "",
338
+ expectedMajor = "",
339
+ allowOpaqueRuntime = false,
340
+ } = {}) {
341
+ if (!current || current.contract !== BUILDCHAIN_CONTRACT) {
342
+ throw new Error("current must be a Buildchain runtime contract world");
343
+ }
344
+ assertBuildchainCompatibilityProjection(current);
345
+ const binding = evaluateChannelBinding({
346
+ lock,
347
+ workflowShellRef,
348
+ runtimeRef,
349
+ expectedChannel,
350
+ expectedMajor,
351
+ allowOpaqueRuntime,
352
+ });
353
+ if (binding?.ok === false) {
354
+ return {
355
+ ok: false,
356
+ status: binding.status,
357
+ drift: false,
358
+ compatible: false,
359
+ issueRecommended: false,
360
+ reasons: binding.reasons,
361
+ channelBinding: binding,
362
+ };
363
+ }
364
+ if (!new Set(["stable", "alpha"]).has(runtimeClass)) {
365
+ return {
366
+ ok: true,
367
+ status: "non-floating-runtime",
368
+ drift: false,
369
+ compatible: true,
370
+ issueRecommended: false,
371
+ reason: `runtime class ${runtimeClass || "unknown"} is not a stable floating ref`,
372
+ };
373
+ }
374
+ if (!lock) {
375
+ return {
376
+ ok: true,
377
+ status: "missing-lock",
378
+ drift: false,
379
+ compatible: true,
380
+ issueRecommended: false,
381
+ reason: "consumer repository has no Buildchain contract lock",
382
+ };
383
+ }
384
+ const accepted = lock.buildchain || {};
385
+ const policy =
386
+ compatibilityPolicy || accepted.compatibilityPolicy || "major-compatible";
387
+ const shaDrift =
388
+ !!accepted.resolvedSha &&
389
+ !!runtimeSha &&
390
+ accepted.resolvedSha !== runtimeSha;
391
+ const contractDrift =
392
+ !!accepted.contractDigest &&
393
+ accepted.contractDigest !== current.contractDigest;
394
+ if (!shaDrift && !contractDrift) {
395
+ const verificationReceipt = evaluationReceipt({
396
+ status: "unchanged",
397
+ compatible: true,
398
+ policy,
399
+ accepted,
400
+ current,
401
+ });
402
+ return {
403
+ ok: true,
404
+ status: "unchanged",
405
+ drift: false,
406
+ compatible: true,
407
+ issueRecommended: false,
408
+ policy,
409
+ accepted,
410
+ current: contractSummary(current, runtimeRef, runtimeSha),
411
+ compatibilityDecisions: [],
412
+ usedProofRoots: [],
413
+ usedFactRoots: [],
414
+ pathReceiptRoots: [],
415
+ verificationReceipt,
416
+ receiptRoot: verificationReceipt.receiptRoot,
417
+ };
418
+ }
419
+ const reasons = contractPolicyReasons(accepted, current, policy);
420
+ const compatibilityDecisions = [];
421
+ const currentSurfaces = new Map(
422
+ current.surfaces.map((entry) => [entry.id, entry]),
423
+ );
424
+ const proofRegistry = createBuildchainCompatibilityProofRegistry({
425
+ proofs: current.compatibilityProofs,
426
+ surfaces: current.surfaces,
427
+ majorLine: current.majorLine,
428
+ });
429
+ for (const oldSurface of accepted.surfaces || []) {
430
+ const result = evaluateSurfaceRelation({
431
+ oldSurface,
432
+ nextSurface: currentSurfaces.get(oldSurface.id),
433
+ proofRegistry,
434
+ majorLine: current.majorLine,
435
+ });
436
+ if (result.reason) reasons.push(result.reason);
437
+ if (result.decision) compatibilityDecisions.push(result.decision);
438
+ }
439
+ const compatible = reasons.length === 0;
440
+ const status = compatible ? "compatible-drift" : "breaking-drift";
441
+ const verificationReceipt = evaluationReceipt({
442
+ status,
443
+ compatible,
444
+ policy,
445
+ accepted,
446
+ current,
447
+ decisions: compatibilityDecisions,
448
+ reasons,
449
+ });
450
+ return {
451
+ ok: compatible,
452
+ status,
453
+ drift: shaDrift || contractDrift,
454
+ shaDrift,
455
+ contractDrift,
456
+ compatible,
457
+ issueRecommended: true,
458
+ policy,
459
+ reasons,
460
+ accepted,
461
+ current: contractSummary(current, runtimeRef, runtimeSha),
462
+ compatibilityDecisions,
463
+ usedProofRoots: verificationReceipt.usedProofRoots,
464
+ usedFactRoots: verificationReceipt.usedFactRoots,
465
+ pathReceiptRoots: verificationReceipt.pathReceiptRoots,
466
+ verificationReceipt,
467
+ receiptRoot: verificationReceipt.receiptRoot,
468
+ };
469
+ }
470
+
471
+ function shown(value, fallback = "(unknown)") {
472
+ return value ? value : fallback;
473
+ }
474
+
475
+ function renderCompatibilityDecision(decision) {
476
+ const lines = [
477
+ `- Surface \`${decision.surfaceId}\`: ${decision.status}`,
478
+ ` - Relation: \`${shown(decision.sourceBreakingDigest, "(missing)")}\` -> \`${shown(decision.targetBreakingDigest, "(missing)")}\``,
479
+ ` - Reason: \`${shown(decision.reason, "proof-backed-compatible-relation")}\``,
480
+ ];
481
+ if (!decision.proofRoot) return lines.join("\n");
482
+ lines.push(
483
+ ` - Proof root: \`${decision.proofRoot}\``,
484
+ ` - Fact root: \`${decision.factRoot}\``,
485
+ ` - Temporal path receipt: \`${decision.pathReceiptRoot}\``,
486
+ ` - Direction / operation: \`${decision.direction}\` / \`${decision.operation}\``,
487
+ ` - Scope root: \`${decision.scopeRoot}\``,
488
+ ` - Evidence: ${shown(decision.evidence && decision.evidence.pullRequest)} (\`${decision.evidenceRoot}\`)`,
489
+ ` - Authority: \`${shown(decision.authority && decision.authority.repository)}@${shown(decision.authority && decision.authority.protectedBase)}\` (\`${decision.authorityRoot}\`)`,
490
+ ` - Cut: \`${shown(decision.cut && decision.cut.commit)}\` (\`${decision.cutRoot}\`)`,
491
+ );
492
+ return lines.join("\n");
493
+ }
494
+
495
+ function renderCompatibilityDecisions(decisions) {
496
+ if (decisions.length === 0)
497
+ return "- No breaking-digest relation required proof resolution.";
498
+ return decisions.map(renderCompatibilityDecision).join("\n");
499
+ }
500
+
501
+ export function renderBuildchainContractDriftIssueBody({
502
+ repository = "",
503
+ workflow = "",
504
+ runUrl = "",
505
+ lockPath = "",
506
+ evaluation,
507
+ } = {}) {
508
+ const accepted = evaluation.accepted || {};
509
+ const current = evaluation.current || {};
510
+ const decisions = evaluation.compatibilityDecisions || [];
511
+ const renderedDecisions = renderCompatibilityDecisions(decisions);
512
+ return [
513
+ "# Buildchain contract drift",
514
+ "",
515
+ "## Summary",
516
+ "",
517
+ `Buildchain detected ${evaluation.compatible ? "compatible" : "breaking"} contract drift for a floating runtime ref before expensive Buildchain work continued.`,
518
+ "",
519
+ "## Consumer",
520
+ "",
521
+ `- Repository: ${shown(repository)}`,
522
+ `- Workflow: ${shown(workflow)}`,
523
+ `- Run: ${shown(runUrl)}`,
524
+ `- Lock path: ${shown(lockPath)}`,
525
+ "",
526
+ "## Accepted Buildchain contract",
527
+ "",
528
+ `- Ref: ${shown(accepted.ref)}`,
529
+ `- SHA: ${shown(accepted.resolvedSha)}`,
530
+ `- Contract digest: ${shown(accepted.contractDigest)}`,
531
+ `- Compatibility digest: ${shown(accepted.compatibilityDigest)}`,
532
+ `- Compatibility Fact registry: ${shown(accepted.compatibilityFactRegistryRoot, "(legacy lock without Fact registry)")}`,
533
+ `- Compatibility proof registry: ${shown(accepted.compatibilityProofRegistryRoot, "(legacy lock without proof registry)")}`,
534
+ `- Policy: ${shown(evaluation.policy || accepted.compatibilityPolicy)}`,
535
+ "",
536
+ "## Current Buildchain contract",
537
+ "",
538
+ `- Ref: ${shown(current.ref)}`,
539
+ `- SHA: ${shown(current.resolvedSha)}`,
540
+ `- Contract digest: ${shown(current.contractDigest)}`,
541
+ `- Compatibility digest: ${shown(current.compatibilityDigest)}`,
542
+ `- Compatibility Fact registry: ${shown(current.compatibilityFactRegistryRoot)}`,
543
+ `- Compatibility Fact Cut: ${shown(current.compatibilityFactCutRoot)}`,
544
+ `- Compatibility proof registry: ${shown(current.compatibilityProofRegistryRoot)}`,
545
+ `- Major line: ${shown(current.majorLine)}`,
546
+ "",
547
+ "## Compatibility",
548
+ "",
549
+ `- Status: ${shown(evaluation.status)}`,
550
+ `- Compatible: ${evaluation.compatible ? "yes" : "no"}`,
551
+ evaluation.reasons && evaluation.reasons.length
552
+ ? evaluation.reasons.map((reason) => `- ${reason}`).join("\n")
553
+ : "- No breaking drift detected.",
554
+ "",
555
+ "## Proof-backed decisions",
556
+ "",
557
+ renderedDecisions,
558
+ `- Verification receipt: \`${shown(evaluation.receiptRoot, "(not produced)")}\``,
559
+ "",
560
+ "## Suggested next action",
561
+ "",
562
+ evaluation.compatible
563
+ ? "Review the Buildchain release notes, then update the consumer contract lock to the current SHA and contract digest."
564
+ : "Failing before heavy build is intentional. Review the Buildchain contract change, update the consumer workflow/configuration, or pin the previous Buildchain SHA.",
565
+ ].join("\n");
566
+ }
@@ -236,6 +236,16 @@ export function normalizeBuildchainConfig(config) {
236
236
  if (normalized.publication !== undefined) {
237
237
  normalized.publication = normalizePublicationSection(normalized.publication);
238
238
  }
239
+ if (normalized.publication_rehearsal !== undefined) {
240
+ normalized.publication_rehearsal = normalizePublicationRehearsalSection(
241
+ normalized.publication_rehearsal,
242
+ );
243
+ }
244
+ if (normalized.adopter_delivery !== undefined) {
245
+ normalized.adopter_delivery = normalizeAdopterDeliverySection(
246
+ normalized.adopter_delivery,
247
+ );
248
+ }
239
249
  if (normalized.consumers !== undefined) {
240
250
  normalized.consumers = normalizeConsumersSection(normalized.consumers);
241
251
  }
@@ -700,6 +710,80 @@ function normalizePublicationSection(publication) {
700
710
  };
701
711
  }
702
712
 
713
+ function normalizePublicationRehearsalSection(rehearsal) {
714
+ assertPlainObject(rehearsal, "publication_rehearsal");
715
+ const allowed = ["contract", "capsule_path", "candidate_root", "state_path", "evidence_path", "effect_default"];
716
+ const unknown = Object.keys(rehearsal).filter((key) => !allowed.includes(key));
717
+ if (unknown.length > 0) {
718
+ throw new Error(`publication_rehearsal contains unsupported fields: ${unknown.join(", ")}`);
719
+ }
720
+ const normalized = {
721
+ contract: assertString(rehearsal.contract, "publication_rehearsal.contract"),
722
+ capsulePath: posixPath(assertString(rehearsal.capsule_path, "publication_rehearsal.capsule_path")),
723
+ candidateRoot: posixPath(assertString(rehearsal.candidate_root, "publication_rehearsal.candidate_root")),
724
+ statePath: posixPath(assertString(rehearsal.state_path, "publication_rehearsal.state_path")),
725
+ evidencePath: posixPath(assertString(rehearsal.evidence_path, "publication_rehearsal.evidence_path")),
726
+ effectDefault: assertString(rehearsal.effect_default, "publication_rehearsal.effect_default"),
727
+ };
728
+ if (
729
+ normalized.contract !== "buildchain-v4-publication-rehearsal-capsule/v1" ||
730
+ normalized.effectDefault !== "disabled"
731
+ ) {
732
+ throw new Error("publication_rehearsal must use the v4 capsule contract with effect_default = disabled");
733
+ }
734
+ for (const [key, value] of Object.entries({
735
+ capsule_path: normalized.capsulePath,
736
+ candidate_root: normalized.candidateRoot,
737
+ state_path: normalized.statePath,
738
+ evidence_path: normalized.evidencePath,
739
+ })) {
740
+ if (value.startsWith("/") || value.includes("\\") || value.split("/").includes("..")) {
741
+ throw new Error(`publication_rehearsal.${key} must be repository-relative`);
742
+ }
743
+ }
744
+ return normalized;
745
+ }
746
+
747
+ function normalizeAdopterDeliverySection(delivery) {
748
+ assertPlainObject(delivery, "adopter_delivery");
749
+ const allowed = ["contract", "input_path", "readback_path", "bootstrap_path", "archive_path", "result_path", "driver_selector", "artifact_profile_selector"];
750
+ const unknown = Object.keys(delivery).filter((key) => !allowed.includes(key));
751
+ if (unknown.length > 0) {
752
+ throw new Error(`adopter_delivery contains unsupported fields: ${unknown.join(", ")}`);
753
+ }
754
+ const normalized = {
755
+ contract: assertString(delivery.contract, "adopter_delivery.contract"),
756
+ inputPath: posixPath(assertString(delivery.input_path, "adopter_delivery.input_path")),
757
+ readbackPath: posixPath(assertString(delivery.readback_path, "adopter_delivery.readback_path")),
758
+ bootstrapPath: posixPath(assertString(delivery.bootstrap_path, "adopter_delivery.bootstrap_path")),
759
+ archivePath: posixPath(assertString(delivery.archive_path, "adopter_delivery.archive_path")),
760
+ resultPath: posixPath(assertString(delivery.result_path, "adopter_delivery.result_path")),
761
+ driverSelector: assertString(delivery.driver_selector, "adopter_delivery.driver_selector"),
762
+ artifactProfileSelector: assertString(delivery.artifact_profile_selector, "adopter_delivery.artifact_profile_selector"),
763
+ };
764
+ if (normalized.contract !== "kungfu-buildchain-v4-adopter-delivery/v1") {
765
+ throw new Error("adopter_delivery contract is unsupported");
766
+ }
767
+ if (
768
+ !["json-assertion", "kfd-category", "legacy-kfd"].includes(normalized.driverSelector) ||
769
+ !["git-commit", "package"].includes(normalized.artifactProfileSelector)
770
+ ) {
771
+ throw new Error("adopter_delivery selector is unsupported");
772
+ }
773
+ for (const [key, value] of Object.entries({
774
+ input_path: normalized.inputPath,
775
+ readback_path: normalized.readbackPath,
776
+ bootstrap_path: normalized.bootstrapPath,
777
+ archive_path: normalized.archivePath,
778
+ result_path: normalized.resultPath,
779
+ })) {
780
+ if (value.startsWith("/") || value.includes("\\") || value.split("/").includes("..")) {
781
+ throw new Error(`adopter_delivery.${key} must be repository-relative`);
782
+ }
783
+ }
784
+ return normalized;
785
+ }
786
+
703
787
  function normalizePublicationArchive(archive = undefined) {
704
788
  if (archive === undefined) {
705
789
  return undefined;