@kungfu-tech/buildchain 3.0.9-alpha.8 → 4.0.0-alpha.0

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 (255) hide show
  1. package/AGENTS.md +39 -0
  2. package/README.md +17 -13
  3. package/actions/promote-buildchain-ref/README.md +0 -10
  4. package/actions/release-tail/README.md +6 -10
  5. package/architecture/internal-capabilities.json +502 -0
  6. package/architecture/maintainability-baseline.json +59 -0
  7. package/architecture/maintainability-policy.json +1384 -0
  8. package/architecture/release-tail-contract-inventory.json +587 -0
  9. package/architecture/v3-core-mechanism-inventory.json +1043 -0
  10. package/architecture/v3-core-mechanism-inventory.md +67 -0
  11. package/architecture/v4-adopter-delivery-parity.json +47 -0
  12. package/architecture/v4-architecture-constitution.md +210 -0
  13. package/architecture/v4-bootstrap-authority.json +56 -0
  14. package/architecture/v4-canonical-contract-fixtures.json +105 -0
  15. package/architecture/v4-capability-state-machine-manifest.json +480 -0
  16. package/architecture/v4-capability-state-machine-manifest.schema.json +202 -0
  17. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +830 -0
  18. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.md +223 -0
  19. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.schema.json +318 -0
  20. package/architecture/v4-delivery-warrant-shadow-fixtures.json +227 -0
  21. package/architecture/v4-delivery-warrant-shadow-fixtures.schema.json +67 -0
  22. package/architecture/v4-exception-ledger.json +5 -0
  23. package/architecture/v4-exception-ledger.schema.json +56 -0
  24. package/architecture/v4-partial-mutation-recovery-qualification.json +65 -0
  25. package/architecture/v4-platform-stage-checkpoints.json +97 -0
  26. package/architecture/v4-provider-operation-journal-contract.json +113 -0
  27. package/architecture/v4-release-activation-shadow-domain.json +61 -0
  28. package/architecture/v4-release-train-parity.json +68 -0
  29. package/architecture/v4-rust-libnode-bridge-evaluation.json +107 -0
  30. package/architecture/v4-rust-libnode-bridge-spike.md +85 -0
  31. package/architecture/v4-stable-publication-fence.json +66 -0
  32. package/architecture/v4-stage-capsule-contract.json +90 -0
  33. package/architecture/v4-stage-capsule-qualification.json +99 -0
  34. package/architecture/v4-stage-capsule-resume-planner.json +52 -0
  35. package/architecture/v4-stage-capsule-store-contract.json +72 -0
  36. package/bin/buildchain.mjs +15 -6
  37. package/contracts/auditable-demo-scenario-v1.schema.json +1 -1
  38. package/contracts/buildchain-v2-residuals-v1.json +2 -2
  39. package/contracts/fixtures/v4-delivery-warrant-trace-v1/golden.json +158 -0
  40. package/contracts/fixtures/v4-delivery-warrant-trace-v1/property.json +380 -0
  41. package/contracts/fixtures/v4-delivery-warrant-trace-v1/replay.json +163 -0
  42. package/contracts/fixtures/v4-partial-mutation-recovery-v1/shared.json +155 -0
  43. package/contracts/fixtures/v4-provider-operation-journal-v1/shared.json +457 -0
  44. package/contracts/fixtures/v4-provider-readback-idempotency-v1/shared.json +682 -0
  45. package/contracts/fixtures/v4-release-activation-shadow-v1/shared.json +53 -0
  46. package/contracts/fixtures/v4-stable-publication-fence-v1/shared.json +56 -0
  47. package/contracts/fixtures/v4-stage-capsule-resume-v1/late-platform-failure.json +176 -0
  48. package/contracts/fixtures/v4-stage-capsule-store-v1/shared.json +132 -0
  49. package/contracts/fixtures/v4-stage-capsule-v1/shared.json +111 -0
  50. package/contracts/v4-canonical-contracts-v1.schema.json +182 -0
  51. package/contracts/v4-delivery-warrant-semantic-diff-report-v1.schema.json +284 -0
  52. package/contracts/v4-delivery-warrant-trace-v1.schema.json +215 -0
  53. package/contracts/v4-host-contract-v1.schema.json +135 -0
  54. package/contracts/v4-partial-mutation-recovery-v1.schema.json +168 -0
  55. package/contracts/v4-provider-operation-journal-v1.schema.json +381 -0
  56. package/contracts/v4-release-activation-shadow-v1.schema.json +186 -0
  57. package/contracts/v4-stable-publication-fence-v1.schema.json +125 -0
  58. package/contracts/v4-stage-capsule-resume-v1.schema.json +225 -0
  59. package/contracts/v4-stage-capsule-store-v1.schema.json +154 -0
  60. package/contracts/v4-stage-capsule-v1.schema.json +178 -0
  61. package/crates/buildchain-v4-bridge/Cargo.lock +213 -0
  62. package/crates/buildchain-v4-bridge/Cargo.toml +12 -0
  63. package/crates/buildchain-v4-bridge/src/main.rs +495 -0
  64. package/dist/site/agent-index.json +0 -3
  65. package/dist/site/artifact-schemas.json +0 -6
  66. package/dist/site/buildchain-contract.json +103 -397
  67. package/dist/site/buildchain-site.json +302 -270
  68. package/dist/site/capability-registry.json +9 -11
  69. package/dist/site/cli-registry.json +8 -30
  70. package/dist/site/controller-registry.json +48 -8
  71. package/dist/site/kfd-claims.json +129 -142
  72. package/dist/site/kfd-upstream-aggregate.json +9 -9
  73. package/dist/site/manual-registry.json +18 -49
  74. package/dist/site/node-api-registry.json +1882 -4118
  75. package/dist/site/page-registry.json +278 -230
  76. package/dist/site/public-surface-audit.json +87 -185
  77. package/dist/site/publication-authority-registry.json +11 -1
  78. package/dist/site/publication-registry.json +4 -4
  79. package/dist/site/release-provenance.json +3 -7
  80. package/dist/site/schemas/kfd-support-projection-v1.schema.json +106 -0
  81. package/dist/site/site-manifest.json +22 -38
  82. package/dist/site/workflow-registry.json +80 -35
  83. package/docs/MAP.md +8 -4
  84. package/docs/auditable-demo.md +2 -2
  85. package/docs/aws-us-elastic-runner-burst-plane.md +7 -59
  86. package/docs/cli-reference.md +15 -92
  87. package/docs/cli.md +14 -14
  88. package/docs/dev-alpha-candidate-patrol.md +3 -11
  89. package/docs/dev-delivery-warrant.md +28 -100
  90. package/docs/engineering-housekeeper.md +12 -4
  91. package/docs/getting-started.md +1 -1
  92. package/docs/install.md +5 -5
  93. package/docs/kfd-support.md +2 -7
  94. package/docs/lifecycle-protocol.md +2 -4
  95. package/docs/node-api-reference.md +414 -523
  96. package/docs/release-flow.md +31 -31
  97. package/docs/release-governance.md +16 -28
  98. package/docs/release-passport.md +2 -15
  99. package/docs/release-tail-contract.md +13 -6
  100. package/docs/release-tail-provider-plane.md +13 -19
  101. package/docs/release-train.md +4 -4
  102. package/docs/reusable-build-surface.md +14 -27
  103. package/docs/site-bundle-contract.md +1 -5
  104. package/docs/stable-candidate-patrol.md +7 -7
  105. package/docs/v4-canonical-contracts.md +92 -0
  106. package/docs/v4-delivery-warrant-read-candidate.md +73 -0
  107. package/docs/v4-delivery-warrant-semantic-diff.md +75 -0
  108. package/docs/v4-production-release.md +63 -0
  109. package/docs/v4-stage-capsule.md +193 -0
  110. package/docs/versioning.md +3 -3
  111. package/package.json +19 -17
  112. package/packages/core/adopter-delivery-gate.js +576 -0
  113. package/packages/core/adopter-delivery-json.js +66 -0
  114. package/packages/core/artifact-signing.js +0 -61
  115. package/packages/core/artifact-verification-envelope.js +5 -5
  116. package/packages/core/build-facts.js +12 -4
  117. package/packages/core/buildchain-agent-manuals.js +0 -2
  118. package/packages/core/buildchain-config.js +4 -69
  119. package/packages/core/buildchain-contract.js +232 -46
  120. package/packages/core/buildchain-kfd-claims.js +1 -1
  121. package/packages/core/channel-candidate.js +0 -8
  122. package/packages/core/channel-promotion-baseline.js +0 -52
  123. package/packages/core/controller-evidence.js +3 -4
  124. package/packages/core/dev-alpha-candidate-selection.js +2 -10
  125. package/packages/core/dev-delivery-warrant-cancellation.js +0 -1
  126. package/packages/core/dev-delivery-warrant-settlement.js +1 -5
  127. package/packages/core/dev-delivery-warrant.js +12 -52
  128. package/packages/core/diagnostics.js +3 -8
  129. package/packages/core/github-governance-authority.js +3 -1
  130. package/packages/core/kfd-adopter-category-driver.js +167 -0
  131. package/packages/core/kfd-adopter-manifest.js +47 -46
  132. package/packages/core/kfd-gate.js +15 -45
  133. package/packages/core/paper-agent-entry.js +7 -16
  134. package/packages/core/paper-fleet.js +2 -2
  135. package/packages/core/paper-repository.js +2 -3
  136. package/packages/core/paper-scaffold-content.js +2 -23
  137. package/packages/core/paper.js +11 -43
  138. package/packages/core/publication-reproducibility.js +4 -4
  139. package/packages/core/release-line-bootstrap.js +21 -8
  140. package/packages/core/release-passport-contract.js +5 -5
  141. package/packages/core/release-passport.js +20 -131
  142. package/packages/core/self-dogfood-version.js +48 -35
  143. package/packages/core/spawn-command.js +232 -8
  144. package/packages/core/v4-adopter-delivery-parity.js +219 -0
  145. package/packages/core/v4-canonical-contracts.js +284 -0
  146. package/packages/core/v4-delivery-warrant-fixture-runner.js +371 -0
  147. package/packages/core/v4-delivery-warrant-read-candidate.js +279 -0
  148. package/packages/core/v4-delivery-warrant-semantic-diff-gate.js +352 -0
  149. package/packages/core/v4-delivery-warrant-shadow-adapter.js +447 -0
  150. package/packages/core/v4-partial-mutation-recovery-qualification.js +395 -0
  151. package/packages/core/v4-platform-stage-checkpoints.js +471 -0
  152. package/packages/core/v4-provider-operation-journal.js +531 -0
  153. package/packages/core/v4-provider-readback-idempotency.js +394 -0
  154. package/packages/core/v4-release-activation-shadow.js +519 -0
  155. package/packages/core/v4-stable-publication-fence.js +357 -0
  156. package/packages/core/v4-stage-capsule-local-store.js +426 -0
  157. package/packages/core/v4-stage-capsule-qualification-campaign.js +512 -0
  158. package/packages/core/v4-stage-capsule-qualification.js +456 -0
  159. package/packages/core/v4-stage-capsule-resume-planner.js +397 -0
  160. package/packages/core/v4-stage-capsule-store.js +401 -0
  161. package/packages/core/v4-stage-capsule.js +319 -0
  162. package/scripts/assemble-self-publication-admission.mjs +1 -1
  163. package/scripts/audit-publication-control-plane.mjs +5 -5
  164. package/scripts/auditable-demo-bundle-verification.mjs +3 -2
  165. package/scripts/auditable-demo-platform.mjs +2 -2
  166. package/scripts/auditable-demo-renditions.mjs +1 -1
  167. package/scripts/auditable-demo.mjs +2 -2
  168. package/scripts/aws-macos-jit-controller-core.mjs +13 -346
  169. package/scripts/aws-macos-jit-controller-runtime.mjs +2 -210
  170. package/scripts/aws-macos-jit-controller.mjs +37 -275
  171. package/scripts/aws-macos-jit-core.mjs +3 -41
  172. package/scripts/aws-macos-jit.mjs +0 -12
  173. package/scripts/aws-windows-jit-campaign.mjs +2 -2
  174. package/scripts/aws-windows-jit-controller-core.mjs +1 -1
  175. package/scripts/aws-windows-jit-controller.mjs +3 -3
  176. package/scripts/build-contract-core.mjs +3 -8
  177. package/scripts/build-standalone-binary.mjs +3 -14
  178. package/scripts/buildchain-channel-router.mjs +4 -0
  179. package/scripts/buildchain-cli-help.mjs +7 -13
  180. package/scripts/buildchain-contract-lock.mjs +0 -6
  181. package/scripts/check-action-bundles.mjs +3 -4
  182. package/scripts/check-internal-architecture.mjs +7 -6
  183. package/scripts/check-inventory.mjs +30 -25
  184. package/scripts/check-v4-public-dogfood-contract.mjs +270 -0
  185. package/scripts/create-release-bundle.mjs +8 -4
  186. package/scripts/dev-alpha-candidate-patrol.mjs +1 -22
  187. package/scripts/dev-delivery-proof.mjs +2 -54
  188. package/scripts/dev-delivery-warrant.mjs +59 -77
  189. package/scripts/dev-pr-auto-merge.mjs +4 -30
  190. package/scripts/dev-pr-delivery-warrant.mjs +0 -55
  191. package/scripts/dispatch-artifact-signing-authority.mjs +7 -4
  192. package/scripts/generate-buildchain-kfd-witnesses.mjs +94 -88
  193. package/scripts/generate-channel-build-workflow.mjs +54 -24
  194. package/scripts/generate-channel-promotion-workflow.mjs +15 -6
  195. package/scripts/generate-site-bundle.mjs +5 -21
  196. package/scripts/git-fetch-process-tree.mjs +34 -1
  197. package/scripts/init-repo.mjs +64 -159
  198. package/scripts/inspect-artifact-signing-requests.mjs +0 -6
  199. package/scripts/locked-source-checkout.mjs +3 -4
  200. package/scripts/maintainability-metrics.mjs +8 -2
  201. package/scripts/npm-publish-dry-run.mjs +2 -2
  202. package/scripts/npm-publish-transaction.mjs +2 -2
  203. package/scripts/publication-commit-evidence.mjs +23 -69
  204. package/scripts/release-candidate-resolver.mjs +11 -17
  205. package/scripts/release-tail.mjs +3 -49
  206. package/scripts/resume-from-candidate-run.mjs +9 -123
  207. package/scripts/run-lifecycle-core.mjs +12 -13
  208. package/scripts/seal-artifact-signing-requests.mjs +17 -21
  209. package/scripts/site-capability-metadata.mjs +2 -7
  210. package/scripts/stable-candidate-qualification.mjs +10 -10
  211. package/scripts/v4-architecture.mjs +12 -2
  212. package/scripts/v4-bridge-bootstrap.mjs +141 -0
  213. package/scripts/v4-bridge-evidence.mjs +141 -0
  214. package/scripts/v4-host-adapter.mjs +182 -0
  215. package/scripts/v4-platform-stage-checkpoint-rehearsal.mjs +207 -0
  216. package/scripts/v4-stage-capsule-qualification.mjs +528 -0
  217. package/scripts/v4-stage-capsule-resume-rehearsal.mjs +57 -0
  218. package/scripts/v4-warrant-shadow-plan.mjs +601 -0
  219. package/scripts/verify-golden-path.mjs +5 -5
  220. package/scripts/web-surface-cloudfront-rewrite.mjs +15 -15
  221. package/scripts/web-surface-core.mjs +2 -8
  222. package/scripts/workflow-call-contract.mjs +5 -184
  223. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json +0 -16
  224. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json +0 -57
  225. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +0 -47
  226. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +0 -47
  227. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +0 -40
  228. package/contracts/next-development-request-v1.schema.json +0 -66
  229. package/contracts/next-development-transition-v1.schema.json +0 -292
  230. package/contracts/publication-rehearsal-capsule-v1.schema.json +0 -173
  231. package/dist/site/schemas/publication-rehearsal-capsule-v1.schema.json +0 -269
  232. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +0 -353
  233. package/dist/site/schemas/release-tail-provider-bindings-v1.schema.json +0 -94
  234. package/docs/next-development-transition.md +0 -119
  235. package/docs/publication-rehearsal.md +0 -94
  236. package/packages/core/buildchain-compatibility-proof.js +0 -631
  237. package/packages/core/dev-delivery-native-proof.js +0 -333
  238. package/packages/core/dev-delivery-warrant-shadow.js +0 -502
  239. package/packages/core/next-development-candidate-reservation.js +0 -186
  240. package/packages/core/next-development-controller.js +0 -726
  241. package/packages/core/next-development-projection.js +0 -288
  242. package/packages/core/next-development-transition.js +0 -738
  243. package/packages/core/publication-rehearsal-projection.js +0 -173
  244. package/packages/core/publication-rehearsal-runtime.js +0 -921
  245. package/scripts/aws-macos-jit-instance-rehydrate.mjs +0 -260
  246. package/scripts/aws-macos-jit-source-rebind.mjs +0 -724
  247. package/scripts/dev-delivery-native-run.mjs +0 -187
  248. package/scripts/dev-delivery-two-phase.mjs +0 -598
  249. package/scripts/generate-next-development-guidance.mjs +0 -49
  250. package/scripts/materialize-self-release-candidate-version.mjs +0 -137
  251. package/scripts/next-development-self-dogfood-harness.mjs +0 -409
  252. package/scripts/next-development-self-dogfood.mjs +0 -532
  253. package/scripts/next-development-transition.mjs +0 -47
  254. package/scripts/release-candidate-tail-reseal.mjs +0 -426
  255. package/templates/native-dev-delivery.yml +0 -82
@@ -9,7 +9,6 @@ export const ARTIFACT_SIGNING_AUTHORITY_CONTRACT =
9
9
 
10
10
  const SHA256_PATTERN = /^sha256:[0-9a-f]{64}$/u;
11
11
  const SOURCE_SHA_PATTERN = /^[0-9a-f]{40}$/u;
12
- const ENTITLEMENTS_PROFILES = new Set(["none", "jit-executable-v1"]);
13
12
  const FORBIDDEN_CREDENTIAL_KEYS =
14
13
  /(?:certificate|password|private.?key|secret|token|notary|issuer|team.?id|environment)/iu;
15
14
 
@@ -89,64 +88,6 @@ function exactSourceSha(value, label) {
89
88
  return normalized;
90
89
  }
91
90
 
92
- function entitlementsPaths(value) {
93
- if (value === undefined) return [];
94
- if (!Array.isArray(value)) {
95
- throw new Error("signing entitlements paths must be an array");
96
- }
97
- const paths = value.map((entry, index) => {
98
- const normalized = nonEmptyString(
99
- entry,
100
- `signing entitlements paths[${index}]`,
101
- );
102
- const parts = normalized.split("/");
103
- if (
104
- normalized.startsWith("/") ||
105
- normalized.includes("\\") ||
106
- normalized.includes(",") ||
107
- parts.some((part) => part === "" || part === "." || part === "..")
108
- ) {
109
- throw new Error(
110
- `signing entitlements paths[${index}] must be a safe archive-relative path`,
111
- );
112
- }
113
- return normalized;
114
- });
115
- if (new Set(paths).size !== paths.length) {
116
- throw new Error("signing entitlements paths must not contain duplicates");
117
- }
118
- return paths;
119
- }
120
-
121
- function signingEntitlements(profileId, kind, signature) {
122
- const profile = String(signature.entitlementsProfile || "none").trim();
123
- const paths = entitlementsPaths(signature.entitlementsPaths);
124
- if (!ENTITLEMENTS_PROFILES.has(profile)) {
125
- throw new Error(
126
- `unsupported signing entitlements profile: ${profile || "<empty>"}`,
127
- );
128
- }
129
- if (
130
- profile !== "none" &&
131
- (profileId !== "apple-developer-id" || kind !== "archive")
132
- ) {
133
- throw new Error(
134
- `signing entitlements profile ${profile} requires an Apple archive`,
135
- );
136
- }
137
- if (
138
- (profile === "none" && paths.length !== 0) ||
139
- (profile !== "none" && paths.length === 0)
140
- ) {
141
- throw new Error(
142
- "signing entitlements paths must be non-empty exactly when an entitlements profile is enabled",
143
- );
144
- }
145
- return profile === "none"
146
- ? {}
147
- : { entitlementsProfile: profile, entitlementsPaths: paths };
148
- }
149
-
150
91
  function assertNoCredentialMaterial(value, path = "request") {
151
92
  if (!value || typeof value !== "object") return;
152
93
  for (const [key, child] of Object.entries(value)) {
@@ -250,7 +191,6 @@ export function createArtifactSigningRequest({
250
191
  platform,
251
192
  artifactKind: kind,
252
193
  });
253
- const entitlementIntent = signingEntitlements(profile.id, kind, signature);
254
194
  const request = {
255
195
  schemaVersion: 1,
256
196
  contract: ARTIFACT_SIGNING_REQUEST_CONTRACT,
@@ -313,7 +253,6 @@ export function createArtifactSigningRequest({
313
253
  profile: profile.id,
314
254
  provider: profile.provider,
315
255
  semantics: profile.semantics,
316
- ...entitlementIntent,
317
256
  },
318
257
  delivery: {
319
258
  mode: nonEmptyString(
@@ -417,7 +417,7 @@ function kfdBindingBody({ manifest, manifestGate, legacyProjection, paths }) {
417
417
  gatePath: paths.gate,
418
418
  gateRoot: manifestGate.gateRoot,
419
419
  },
420
- adopter: jsonClone(manifestGate.adopter), source: jsonClone(manifestGate.source),
420
+ source: jsonClone(manifestGate.source),
421
421
  standardPackage: jsonClone(manifestGate.standardPackage),
422
422
  witness: {
423
423
  decisionRoot: manifestGate.decisionWitness.root,
@@ -445,10 +445,10 @@ export function createKfdAdopterReleaseBinding({
445
445
  manifestPath = "kfd-adopter-manifest.json",
446
446
  gatePath = "kfd-adopter-manifest-gate.json",
447
447
  legacyProjectionPath = "kfd-support.json",
448
- expectedAdopterId = "kungfu-systems/buildchain", expectedSourceRepository = "", expectedSourceSha = "",
448
+ expectedSourceSha = "",
449
449
  } = {}) {
450
450
  const gate = validateKfdAdopterManifestGate(manifestGate, {
451
- expectedAdopterId, expectedSourceRepository, expectedSourceSha,
451
+ expectedSourceSha,
452
452
  checkedAt: manifestGate?.checkedAt,
453
453
  });
454
454
  const legacy = validateKfdLegacySupportMatrixProjection(legacyProjection, { manifest, manifestGate });
@@ -468,7 +468,7 @@ export function validateKfdAdopterReleaseBinding(binding, {
468
468
  manifest,
469
469
  manifestGate,
470
470
  legacyProjection,
471
- expectedAdopterId = "kungfu-systems/buildchain", expectedSourceRepository = "", expectedSourceSha = "",
471
+ expectedSourceSha = "",
472
472
  } = {}) {
473
473
  const issues = [];
474
474
  if (!binding || binding.schemaVersion !== 1 || binding.contract !== KFD_ADOPTER_RELEASE_BINDING_CONTRACT) {
@@ -488,7 +488,7 @@ export function validateKfdAdopterReleaseBinding(binding, {
488
488
  manifestPath: binding.authority?.manifestPath,
489
489
  gatePath: binding.authority?.gatePath,
490
490
  legacyProjectionPath: binding.legacyProjection?.path,
491
- expectedAdopterId, expectedSourceRepository, expectedSourceSha,
491
+ expectedSourceSha,
492
492
  });
493
493
  if (stableJson(binding) !== stableJson(expected)) {
494
494
  issues.push({ code: "adopter-release-binding-drift", path: "", message: "release binding differs from the exact manifest, gate, or legacy projection closure" });
@@ -81,10 +81,18 @@ function repositorySlug(cwd) {
81
81
  function readTrackedFiles(cwd, root = ".") {
82
82
  const repoRoot = fs.realpathSync(path.resolve(cwd));
83
83
  const requestedRoot = fs.realpathSync(path.resolve(cwd, root));
84
- const relativeRoot = posixPath(path.relative(repoRoot, requestedRoot) || ".");
85
- const args = relativeRoot === "." ? ["ls-files", "-z"] : ["ls-files", "-z", "--", relativeRoot];
86
- return parseZeroSeparated(git(repoRoot, args))
87
- .filter((entry) => entry && !entry.startsWith(".git/"))
84
+ const relativeRoot = posixPath(
85
+ git(requestedRoot, ["rev-parse", "--show-prefix"]),
86
+ ).replace(/\/+$/u, "") || ".";
87
+ return parseZeroSeparated(git(repoRoot, ["ls-files", "-z"]))
88
+ .filter((entry) =>
89
+ entry
90
+ && !entry.startsWith(".git/")
91
+ && (
92
+ relativeRoot === "."
93
+ || entry === relativeRoot
94
+ || entry.startsWith(`${relativeRoot}/`)
95
+ ))
88
96
  .sort();
89
97
  }
90
98
 
@@ -10,7 +10,6 @@ export const BUILDCHAIN_AGENT_MANUALS = Object.freeze([
10
10
  { id: "github-governance-authority", title: "GitHub governance authority", path: "docs/github-governance-authority.md", plane: "verify" },
11
11
  { id: "release-candidate", title: "Release Candidate Passport", path: "docs/release-candidate.md", plane: "verify" },
12
12
  { id: "release-train", title: "Release Train and Release Cut", path: "docs/release-train.md", plane: "verify" },
13
- { id: "next-development-transition", title: "Next-development transition", path: "docs/next-development-transition.md", plane: "verify" },
14
13
  { id: "release-propagation", title: "Release propagation", path: "docs/release-propagation.md", plane: "use" },
15
14
  { id: "readme-badges", title: "README badge blocks", path: "docs/readme-badges.md", plane: "use" },
16
15
  { id: "homebrew", title: "Homebrew distribution indexes", path: "docs/homebrew.md", plane: "use" },
@@ -33,7 +32,6 @@ export const BUILDCHAIN_AGENT_MANUALS = Object.freeze([
33
32
  { id: "publish-transaction", title: "Publish transaction", path: "docs/publish-transaction.md", plane: "verify" },
34
33
  { id: "release-tail-contract", title: "Declarative release-tail contract", path: "docs/release-tail-contract.md", plane: "verify" },
35
34
  { id: "release-tail-provider-plane", title: "Declarative release-tail provider plane", path: "docs/release-tail-provider-plane.md", plane: "use" },
36
- { id: "publication-rehearsal", title: "Publication rehearsal", path: "docs/publication-rehearsal.md", plane: "use" },
37
35
  { id: "release-governance", title: "Release governance", path: "docs/release-governance.md", plane: "why" },
38
36
  { id: "release-flow", title: "Release flow", path: "docs/release-flow.md", plane: "verify" },
39
37
  { id: "runtime-train-validation", title: "Runtime train validation", path: "docs/runtime-train-validation.md", plane: "verify" },
@@ -1,4 +1,3 @@
1
- import { execSync } from "node:child_process";
2
1
  import fs from "node:fs";
3
2
  import os from "node:os";
4
3
  import path from "node:path";
@@ -8,6 +7,7 @@ import {
8
7
  BUILDCHAIN_CONFIG_PATH,
9
8
  resolveBuildchainConfigPath,
10
9
  } from "./buildchain-layout.js";
10
+ import { runShellCommandSync } from "./spawn-command.js";
11
11
 
12
12
  const CONFIG_FILE = BUILDCHAIN_CONFIG_PATH;
13
13
  const RESERVED_LIFECYCLE_KEYS = new Set(["env", "shell"]);
@@ -61,10 +61,6 @@ const SUPPORTED_SIGNING_PROFILES = new Set([
61
61
  "windows-authenticode",
62
62
  "detached-signature-v1",
63
63
  ]);
64
- const SUPPORTED_SIGNING_ENTITLEMENTS_PROFILES = new Set([
65
- "none",
66
- "jit-executable-v1",
67
- ]);
68
64
  const SUPPORTED_SIGNING_ARTIFACT_KINDS = new Set([
69
65
  "auto", "binary", "archive", "blob", "directory", "mach-o", "app-bundle",
70
66
  "framework-bundle", "plugin-bundle", "xpc-bundle", "dylib", "pkg", "dmg",
@@ -103,27 +99,6 @@ function normalizeStringArray(value, label) {
103
99
  return value.map((entry, index) => assertString(entry, `${label}[${index}]`));
104
100
  }
105
101
 
106
- function normalizeSigningEntitlementsPaths(value, label) {
107
- const paths = normalizeStringArray(value, label);
108
- for (const [index, entry] of paths.entries()) {
109
- const parts = entry.split("/");
110
- if (
111
- entry.startsWith("/") ||
112
- entry.includes("\\") ||
113
- entry.includes(",") ||
114
- parts.some((part) => part === "" || part === "." || part === "..")
115
- ) {
116
- throw new Error(
117
- `${label}[${index}] must be a safe archive-relative path`,
118
- );
119
- }
120
- }
121
- if (new Set(paths).size !== paths.length) {
122
- throw new Error(`${label} must not contain duplicate paths`);
123
- }
124
- return paths;
125
- }
126
-
127
102
  function getByDottedKey(target, key) {
128
103
  return String(key)
129
104
  .split(".")
@@ -387,16 +362,7 @@ function normalizeSigningSection(signing) {
387
362
  const artifacts = signing.artifacts.map((artifact, index) => {
388
363
  const label = `signing.artifacts[${index}]`;
389
364
  assertPlainObject(artifact, label);
390
- const allowedKeys = new Set([
391
- "id",
392
- "path",
393
- "profile",
394
- "entitlements_profile",
395
- "entitlements_paths",
396
- "kind",
397
- "platforms",
398
- "required",
399
- ]);
365
+ const allowedKeys = new Set(["id", "path", "profile", "kind", "platforms", "required"]);
400
366
  for (const key of Object.keys(artifact)) {
401
367
  if (!allowedKeys.has(key)) {
402
368
  throw new Error(`${label}.${key} is not supported; declare desired signature state only`);
@@ -411,41 +377,10 @@ function normalizeSigningSection(signing) {
411
377
  if (!SUPPORTED_SIGNING_ARTIFACT_KINDS.has(kind)) {
412
378
  throw new Error(`${label}.kind is not a supported signing artifact kind`);
413
379
  }
414
- const entitlementsProfile =
415
- artifact.entitlements_profile === undefined
416
- ? "none"
417
- : assertString(
418
- artifact.entitlements_profile,
419
- `${label}.entitlements_profile`,
420
- );
421
- if (!SUPPORTED_SIGNING_ENTITLEMENTS_PROFILES.has(entitlementsProfile)) {
422
- throw new Error(
423
- `${label}.entitlements_profile must be one of none or jit-executable-v1`,
424
- );
425
- }
426
- if (entitlementsProfile !== "none" && kind !== "archive") {
427
- throw new Error(
428
- `${label}.entitlements_profile ${entitlementsProfile} requires kind = "archive"`,
429
- );
430
- }
431
- const entitlementsPaths = normalizeSigningEntitlementsPaths(
432
- artifact.entitlements_paths,
433
- `${label}.entitlements_paths`,
434
- );
435
- if (
436
- (entitlementsProfile === "none" && entitlementsPaths.length !== 0) ||
437
- (entitlementsProfile !== "none" && entitlementsPaths.length === 0)
438
- ) {
439
- throw new Error(
440
- `${label}.entitlements_paths must be non-empty exactly when entitlements_profile is enabled`,
441
- );
442
- }
443
380
  return {
444
381
  id: artifact.id === undefined ? artifactPath : assertString(artifact.id, `${label}.id`),
445
382
  path: artifactPath,
446
383
  profile,
447
- entitlementsProfile,
448
- entitlementsPaths,
449
384
  kind,
450
385
  platforms: normalizeStringArray(artifact.platforms, `${label}.platforms`),
451
386
  required: optionalBoolean(artifact.required, true),
@@ -1463,11 +1398,11 @@ export function runLifecycleStage({ cwd = process.cwd(), loadedConfig, name, sta
1463
1398
  };
1464
1399
  const runOnce = () => {
1465
1400
  if (selected.mode === "script") {
1466
- execSync(selected.script, execOptions);
1401
+ runShellCommandSync(selected.script, execOptions);
1467
1402
  return;
1468
1403
  }
1469
1404
  for (const command of selected.commands) {
1470
- execSync(command, execOptions);
1405
+ runShellCommandSync(command, execOptions);
1471
1406
  }
1472
1407
  };
1473
1408
  let lastError;
@@ -2,10 +2,11 @@ import crypto from "node:crypto";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import {
5
- assertBuildchainCompatibilityProjection,
6
- createBuildchainCompatibilityProofRegistry,
7
- createHistoricalBuildchainCompatibilityProofs,
8
- } from "./buildchain-compatibility-proof.js";
5
+ BUILDCHAIN_CHANNELS,
6
+ evaluateBuildchainChannelBinding,
7
+ normalizeBuildchainRef,
8
+ parseBuildchainRefIdentity,
9
+ } from "./buildchain-channel-identity.js";
9
10
  import { createControllerRegistry } from "./controller-evidence.js";
10
11
  import { enumerateWorkflowInputs } from "./public-surface-audit.js";
11
12
 
@@ -14,28 +15,13 @@ export {
14
15
  evaluateBuildchainChannelBinding,
15
16
  normalizeBuildchainRef,
16
17
  parseBuildchainRefIdentity,
17
- } from "./buildchain-channel-identity.js";
18
-
19
- export {
20
- BUILDCHAIN_COMPATIBILITY_PROOF_REGISTRY_SCHEMA,
21
- BUILDCHAIN_COMPATIBILITY_PROOF_SCHEMA,
22
- BUILDCHAIN_COMPATIBILITY_VERIFICATION_RECEIPT_SCHEMA,
23
- assertBuildchainCompatibilityProjection,
24
- contractSummary,
25
- createBuildchainCompatibilityProof,
26
- createBuildchainCompatibilityProofRegistry,
27
- createBuildchainCompatibilityVerificationReceipt,
28
- createHistoricalBuildchainCompatibilityProofs,
29
- evaluateBuildchainContractLock,
30
- renderBuildchainContractDriftIssueBody,
31
- verifyBuildchainCompatibilityProof,
32
- verifyBuildchainCompatibilityVerificationReceipt,
33
- } from "./buildchain-compatibility-proof.js";
18
+ };
34
19
 
35
20
  export const BUILDCHAIN_RUNTIME_CONTRACT_WORLD = "kungfu-buildchain-runtime-contract-world";
36
21
  export const BUILDCHAIN_CONTRACT_LOCK = "kungfu-buildchain-contract-lock";
37
22
 
38
23
  const DEFAULT_POLICY = "major-compatible";
24
+ const FLOATING_CLASSES = new Set(["stable", "alpha"]);
39
25
 
40
26
  function optionalString(value) {
41
27
  return value === undefined || value === null ? "" : String(value);
@@ -311,6 +297,9 @@ export function createBuildchainContractWorld({
311
297
  "publish-gate source locks are created by the wrapper and enforced by promote-buildchain-ref before publish side effects",
312
298
  "GitHub Release passport and evidence publication is delegated to promote-buildchain-ref after the semver release transaction completes",
313
299
  ],
300
+ compatibleBreakingDigests: [
301
+ "sha256:acd401cfc46450115a3763fd4b679d85f185e8757ebd52510d6262e1533df4cf",
302
+ ],
314
303
  }),
315
304
  surface(root, {
316
305
  id: "advanced-release-candidate-promote",
@@ -325,6 +314,8 @@ export function createBuildchainContractWorld({
325
314
  },
326
315
  optionalInputs: [
327
316
  "buildchain-ref",
317
+ "buildchain-expected-channel",
318
+ "buildchain-expected-major",
328
319
  "buildchain-contract-lock-path",
329
320
  "promotion-router-ref",
330
321
  "promotion-router-sha",
@@ -352,6 +343,9 @@ export function createBuildchainContractWorld({
352
343
  "promotion reuses PR-stage release-candidate artifacts and does not run the heavy native build matrix",
353
344
  "resume-from-candidate-run is fail-closed and uses a fresh caller event instead of rerunning a frozen startup graph",
354
345
  ],
346
+ compatibleBreakingDigests: [
347
+ "sha256:aa30f22e3af0a89841310bdbdc900844dd95a66974db173fa140a71bbd7e82c0",
348
+ ],
355
349
  }),
356
350
  surface(root, {
357
351
  id: "web-surface",
@@ -498,6 +492,9 @@ export function createBuildchainContractWorld({
498
492
  "publish transactions can require a resolved publish-gate source lock to prevent floating-ref drift",
499
493
  "semver GitHub Releases are created or updated only after transaction completion, with prerelease/latest metadata bound to the authoritative publication channel and tag syntax retained as the fallback for ordinary callers",
500
494
  ],
495
+ compatibleBreakingDigests: [
496
+ "sha256:a59f0910e6df842e7699139472e5dd69ac2fdd7f7213bf2cb346d1d622556874",
497
+ ],
501
498
  }),
502
499
  surface(root, {
503
500
  id: "macos-credential-island-action",
@@ -773,6 +770,14 @@ export function createBuildchainContractWorld({
773
770
  registryDigest: resolvedControllerRegistry.digest,
774
771
  inputClassifications: descriptor.inputs,
775
772
  },
773
+ ...(descriptor.id === "build-lifecycle"
774
+ ? {
775
+ compatibleBreakingDigests: [
776
+ "sha256:e264a79f9f399038c2fcfd21e4168c68c2e1485ee5c651c02242a02b622ac2be",
777
+ "sha256:30745921541e9b0f70475bb2178c2559f6aef248f6680670ccd44d8c5a69a6b1",
778
+ ],
779
+ }
780
+ : {}),
776
781
  guarantees: [
777
782
  "plans bind exact consumer source SHA, exact Buildchain runtime SHA, and the runtime contract digest",
778
783
  "receipts bind the plan digest and preserve pass, fail, skip, and partial stage outcomes",
@@ -792,45 +797,24 @@ export function createBuildchainContractWorld({
792
797
  },
793
798
  majorLine,
794
799
  compatibilityPolicy: DEFAULT_POLICY,
795
- compatibilityProofs: createHistoricalBuildchainCompatibilityProofs(),
796
800
  surfaces,
797
801
  };
798
802
  return finalizeBuildchainContractWorld(base);
799
803
  }
800
804
 
801
805
  export function finalizeBuildchainContractWorld(contractWorld) {
802
- const sourceSurfaces = (contractWorld.surfaces || []).map((entry) => ({ ...entry }));
803
- const proofRegistry = createBuildchainCompatibilityProofRegistry({
804
- proofs: contractWorld.compatibilityProofs || createHistoricalBuildchainCompatibilityProofs(),
805
- surfaces: sourceSurfaces,
806
- majorLine: contractWorld.majorLine,
807
- });
808
806
  const world = {
809
807
  ...contractWorld,
810
- compatibilityProofs: proofRegistry.proofs,
811
- compatibilityProofRegistryRoot: proofRegistry.registryRoot,
812
- surfaces: sourceSurfaces.map((entry) => {
813
- const surfaceEntry = { ...entry };
814
- delete surfaceEntry.compatibleBreakingDigests;
815
- delete surfaceEntry.compatibilityProofRoots;
816
- const projection = proofRegistry.projections[entry.id] || [];
817
- if (projection.length > 0) {
818
- surfaceEntry.compatibleBreakingDigests = projection.map((item) => item.breakingDigest);
819
- surfaceEntry.compatibilityProofRoots = projection.map((item) => item.proofRoot);
820
- }
821
- return surfaceEntry;
822
- }),
808
+ surfaces: (contractWorld.surfaces || []).map((entry) => ({ ...entry })),
823
809
  };
824
810
  const compatibilityModel = {
825
811
  schemaVersion: world.schemaVersion,
826
812
  contract: world.contract,
827
813
  majorLine: world.majorLine,
828
- compatibilityProofRegistryRoot: world.compatibilityProofRegistryRoot,
829
814
  surfaces: world.surfaces.map((entry) => ({
830
815
  id: entry.id,
831
816
  kind: entry.kind,
832
817
  breakingDigest: entry.breakingDigest,
833
- compatibilityProofRoots: entry.compatibilityProofRoots || [],
834
818
  })),
835
819
  };
836
820
  const digestModel = {
@@ -862,7 +846,6 @@ export function createBuildchainContractLock({
862
846
  contract: contractWorld.contract,
863
847
  contractDigest: contractWorld.contractDigest,
864
848
  compatibilityDigest: contractWorld.compatibilityDigest,
865
- compatibilityProofRegistryRoot: contractWorld.compatibilityProofRegistryRoot,
866
849
  majorLine: contractWorld.majorLine,
867
850
  compatibilityPolicy,
868
851
  acceptedAt,
@@ -870,7 +853,6 @@ export function createBuildchainContractLock({
870
853
  id: entry.id,
871
854
  kind: entry.kind,
872
855
  breakingDigest: entry.breakingDigest,
873
- compatibilityProofRoots: entry.compatibilityProofRoots || [],
874
856
  })),
875
857
  },
876
858
  };
@@ -881,7 +863,6 @@ export function readBuildchainContractWorld(filePath) {
881
863
  if (!value || value.contract !== BUILDCHAIN_RUNTIME_CONTRACT_WORLD) {
882
864
  throw new Error(`Buildchain contract world is missing or invalid: ${filePath}`);
883
865
  }
884
- assertBuildchainCompatibilityProjection(value);
885
866
  const computed = finalizeBuildchainContractWorld(value);
886
867
  for (const digestName of ["compatibilityDigest", "contractDigest"]) {
887
868
  const published = String(value[digestName] || "").trim();
@@ -907,3 +888,208 @@ export function readBuildchainContractLock(filePath) {
907
888
  }
908
889
  return value;
909
890
  }
891
+
892
+ function surfaceMap(surfaces = []) {
893
+ return new Map(surfaces.map((entry) => [entry.id, entry]));
894
+ }
895
+
896
+ function evaluateChannelBinding({
897
+ lock,
898
+ workflowShellRef,
899
+ runtimeRef,
900
+ expectedChannel,
901
+ expectedMajor,
902
+ allowOpaqueRuntime,
903
+ }) {
904
+ if (!workflowShellRef && !expectedChannel && !expectedMajor) return null;
905
+ return evaluateBuildchainChannelBinding({
906
+ workflowShellRef,
907
+ runtimeRef,
908
+ lockRef: lock?.buildchain?.ref || "",
909
+ lockMajorLine: lock?.buildchain?.majorLine || "",
910
+ expectedChannel,
911
+ expectedMajor,
912
+ allowOpaqueRuntime,
913
+ });
914
+ }
915
+
916
+ export function evaluateBuildchainContractLock({
917
+ lock,
918
+ current,
919
+ runtimeRef = "",
920
+ runtimeSha = "",
921
+ runtimeClass = "",
922
+ compatibilityPolicy = "",
923
+ workflowShellRef = "",
924
+ expectedChannel = "",
925
+ expectedMajor = "",
926
+ allowOpaqueRuntime = false,
927
+ } = {}) {
928
+ if (!current || current.contract !== BUILDCHAIN_RUNTIME_CONTRACT_WORLD) {
929
+ throw new Error("current must be a Buildchain runtime contract world");
930
+ }
931
+ const binding = evaluateChannelBinding({
932
+ lock,
933
+ workflowShellRef,
934
+ runtimeRef,
935
+ expectedChannel,
936
+ expectedMajor,
937
+ allowOpaqueRuntime,
938
+ });
939
+ if (binding?.ok === false) {
940
+ return {
941
+ ok: false,
942
+ status: binding.status,
943
+ drift: false,
944
+ compatible: false,
945
+ issueRecommended: false,
946
+ reasons: binding.reasons,
947
+ channelBinding: binding,
948
+ };
949
+ }
950
+ const floatingRuntime = FLOATING_CLASSES.has(runtimeClass);
951
+ if (!floatingRuntime) {
952
+ return {
953
+ ok: true,
954
+ status: "non-floating-runtime",
955
+ drift: false,
956
+ compatible: true,
957
+ issueRecommended: false,
958
+ reason: `runtime class ${runtimeClass || "unknown"} is not a stable floating ref`,
959
+ };
960
+ }
961
+ if (!lock) {
962
+ return {
963
+ ok: true,
964
+ status: "missing-lock",
965
+ drift: false,
966
+ compatible: true,
967
+ issueRecommended: false,
968
+ reason: "consumer repository has no Buildchain contract lock",
969
+ };
970
+ }
971
+ const accepted = lock.buildchain || {};
972
+ const policy = compatibilityPolicy || accepted.compatibilityPolicy || DEFAULT_POLICY;
973
+ const shaDrift = !!accepted.resolvedSha && !!runtimeSha && accepted.resolvedSha !== runtimeSha;
974
+ const contractDrift = !!accepted.contractDigest && accepted.contractDigest !== current.contractDigest;
975
+ if (!shaDrift && !contractDrift) {
976
+ return {
977
+ ok: true,
978
+ status: "unchanged",
979
+ drift: false,
980
+ compatible: true,
981
+ issueRecommended: false,
982
+ policy,
983
+ accepted,
984
+ current: contractSummary(current, runtimeRef, runtimeSha),
985
+ };
986
+ }
987
+ const reasons = [];
988
+ if (accepted.contract !== current.contract) {
989
+ reasons.push(`contract changed from ${accepted.contract || "(unknown)"} to ${current.contract}`);
990
+ }
991
+ if (accepted.majorLine && accepted.majorLine !== current.majorLine) {
992
+ reasons.push(`major line changed from ${accepted.majorLine} to ${current.majorLine}`);
993
+ }
994
+ if (policy === "exact" && accepted.contractDigest !== current.contractDigest) {
995
+ reasons.push("exact policy requires the contract digest to remain unchanged");
996
+ }
997
+ if (!["major-compatible", "allow-additive", "exact"].includes(policy)) {
998
+ reasons.push(`unsupported compatibility policy: ${policy}`);
999
+ }
1000
+ const currentSurfaces = surfaceMap(current.surfaces);
1001
+ for (const oldSurface of accepted.surfaces || []) {
1002
+ const nextSurface = currentSurfaces.get(oldSurface.id);
1003
+ if (!nextSurface) {
1004
+ reasons.push(`surface removed: ${oldSurface.id}`);
1005
+ continue;
1006
+ }
1007
+ const compatibleBreakingDigests = new Set(nextSurface.compatibleBreakingDigests || []);
1008
+ if (
1009
+ nextSurface.breakingDigest !== oldSurface.breakingDigest
1010
+ && !compatibleBreakingDigests.has(oldSurface.breakingDigest)
1011
+ ) {
1012
+ reasons.push(`surface breaking digest changed: ${oldSurface.id}`);
1013
+ }
1014
+ }
1015
+ const compatible = reasons.length === 0;
1016
+ return {
1017
+ ok: compatible,
1018
+ status: compatible ? "compatible-drift" : "breaking-drift",
1019
+ drift: shaDrift || contractDrift,
1020
+ shaDrift,
1021
+ contractDrift,
1022
+ compatible,
1023
+ issueRecommended: true,
1024
+ policy,
1025
+ reasons,
1026
+ accepted,
1027
+ current: contractSummary(current, runtimeRef, runtimeSha),
1028
+ };
1029
+ }
1030
+
1031
+ export function contractSummary(contractWorld, runtimeRef = "", runtimeSha = "") {
1032
+ return {
1033
+ ref: runtimeRef,
1034
+ resolvedSha: runtimeSha,
1035
+ contract: contractWorld.contract,
1036
+ contractDigest: contractWorld.contractDigest,
1037
+ compatibilityDigest: contractWorld.compatibilityDigest,
1038
+ majorLine: contractWorld.majorLine,
1039
+ surfaceCount: Array.isArray(contractWorld.surfaces) ? contractWorld.surfaces.length : 0,
1040
+ };
1041
+ }
1042
+
1043
+ export function renderBuildchainContractDriftIssueBody({
1044
+ repository = "",
1045
+ workflow = "",
1046
+ runUrl = "",
1047
+ lockPath = "",
1048
+ evaluation,
1049
+ } = {}) {
1050
+ const accepted = evaluation.accepted || {};
1051
+ const current = evaluation.current || {};
1052
+ const severity = evaluation.compatible ? "compatible" : "breaking";
1053
+ return [
1054
+ "# Buildchain contract drift",
1055
+ "",
1056
+ "## Summary",
1057
+ "",
1058
+ `Buildchain detected ${severity} contract drift for a floating runtime ref before expensive Buildchain work continued.`,
1059
+ "",
1060
+ "## Consumer",
1061
+ "",
1062
+ `- Repository: ${repository || "(unknown)"}`,
1063
+ `- Workflow: ${workflow || "(unknown)"}`,
1064
+ `- Run: ${runUrl || "(unknown)"}`,
1065
+ `- Lock path: ${lockPath || "(unknown)"}`,
1066
+ "",
1067
+ "## Accepted Buildchain contract",
1068
+ "",
1069
+ `- Ref: ${accepted.ref || "(unknown)"}`,
1070
+ `- SHA: ${accepted.resolvedSha || "(unknown)"}`,
1071
+ `- Contract digest: ${accepted.contractDigest || "(unknown)"}`,
1072
+ `- Compatibility digest: ${accepted.compatibilityDigest || "(unknown)"}`,
1073
+ `- Policy: ${evaluation.policy || accepted.compatibilityPolicy || "(unknown)"}`,
1074
+ "",
1075
+ "## Current Buildchain contract",
1076
+ "",
1077
+ `- Ref: ${current.ref || "(unknown)"}`,
1078
+ `- SHA: ${current.resolvedSha || "(unknown)"}`,
1079
+ `- Contract digest: ${current.contractDigest || "(unknown)"}`,
1080
+ `- Compatibility digest: ${current.compatibilityDigest || "(unknown)"}`,
1081
+ `- Major line: ${current.majorLine || "(unknown)"}`,
1082
+ "",
1083
+ "## Compatibility",
1084
+ "",
1085
+ `- Status: ${evaluation.status || "(unknown)"}`,
1086
+ `- Compatible: ${evaluation.compatible ? "yes" : "no"}`,
1087
+ evaluation.reasons?.length ? evaluation.reasons.map((reason) => `- ${reason}`).join("\n") : "- No breaking drift detected.",
1088
+ "",
1089
+ "## Suggested next action",
1090
+ "",
1091
+ evaluation.compatible
1092
+ ? "Review the Buildchain release notes, then update the consumer contract lock to the current SHA and contract digest."
1093
+ : "Failing before heavy build is intentional. Review the Buildchain contract change, update the consumer workflow/configuration, or pin the previous Buildchain SHA.",
1094
+ ].join("\n");
1095
+ }
@@ -138,7 +138,7 @@ function immediateReadmes(root, dir) {
138
138
 
139
139
  function publicDocumentationFiles(root) {
140
140
  return uniquePaths([
141
- ...(readJson(root, "dist/site/manual-registry.json").manuals || BUILDCHAIN_AGENT_MANUALS).map((entry) => entry.path),
141
+ ...BUILDCHAIN_AGENT_MANUALS.map((entry) => entry.path),
142
142
  "README.md",
143
143
  "packages/core/README.md",
144
144
  ...immediateReadmes(root, "actions"),