@kungfu-tech/buildchain 4.1.3-alpha.9 → 4.1.4-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 (205) hide show
  1. package/AGENTS.md +11 -13
  2. package/CONTRIBUTING.md +32 -9
  3. package/README.md +56 -140
  4. package/actions/release/promotion/ref/README.md +1 -1
  5. package/architecture/action-taxonomy.json +1 -1
  6. package/architecture/agent-change-map.md +32 -45
  7. package/architecture/build-orchestration.json +1 -1
  8. package/architecture/capability-state-machine-manifest.json +5 -5
  9. package/architecture/ci-lane-change-budget.json +92 -92
  10. package/architecture/code-layout.json +2 -12
  11. package/architecture/core-mechanisms.json +38 -39
  12. package/architecture/cross-platform-adopter-qualification.json +1 -1
  13. package/architecture/dev-delivery-orchestration.json +2 -2
  14. package/architecture/floating-consumer-policy.json +3 -3
  15. package/architecture/internal-capabilities.json +27 -28
  16. package/architecture/maintainability-debt.json +60 -94
  17. package/architecture/maintainability-policy.json +7 -13
  18. package/architecture/minimal-consumer-migration.json +43 -5014
  19. package/architecture/platform-stage-checkpoints.json +1 -1
  20. package/architecture/release-tail-contract.json +2 -2
  21. package/architecture/release-topology.json +33 -25
  22. package/architecture/stage-capsule-qualification.json +1 -1
  23. package/architecture/universal-workflow-bootstrap.json +60 -60
  24. package/architecture/universal-workflow-capability-policy.json +3 -3
  25. package/architecture/universal-workflow-fault-campaign.json +7 -7
  26. package/architecture/workflow-taxonomy.json +59 -60
  27. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
  28. package/dist/site/buildchain-contract.json +138 -66
  29. package/dist/site/buildchain-site.json +257 -331
  30. package/dist/site/capability-registry.json +4 -4
  31. package/dist/site/cli-registry.json +6 -142
  32. package/dist/site/controller-registry.json +19 -19
  33. package/dist/site/kfd-claims.json +481 -529
  34. package/dist/site/kfd-upstream-aggregate.json +1 -1
  35. package/dist/site/manual-registry.json +22 -22
  36. package/dist/site/node-api-registry.json +82 -339
  37. package/dist/site/page-registry.json +229 -304
  38. package/dist/site/public-surface-audit.json +544 -754
  39. package/dist/site/publication-authority-registry.json +316 -316
  40. package/dist/site/publication-registry.json +1 -1
  41. package/dist/site/site-manifest.json +23 -23
  42. package/dist/site/workflow-registry.json +1071 -1027
  43. package/docs/MAP.md +28 -20
  44. package/docs/auditable-demo.md +17 -49
  45. package/docs/bootstrap-recovery.md +46 -37
  46. package/docs/cli-reference.md +2 -46
  47. package/docs/cli.md +97 -186
  48. package/docs/code-organization.md +7 -5
  49. package/docs/dev-alpha-candidate-patrol.md +19 -42
  50. package/docs/dev-delivery-orchestration.md +15 -11
  51. package/docs/dev-delivery-qualification-landing-adr.md +10 -9
  52. package/docs/dev-delivery-warrant.md +17 -16
  53. package/docs/dev-qualification-patrol.md +25 -20
  54. package/docs/getting-started.md +80 -139
  55. package/docs/github-artifact-attestation.md +31 -81
  56. package/docs/install.md +66 -30
  57. package/docs/lifecycle-protocol.md +19 -57
  58. package/docs/migration-inventory.md +17 -45
  59. package/docs/next-development-transition.md +13 -13
  60. package/docs/node-api-reference.md +122 -138
  61. package/docs/oci-publication.md +13 -10
  62. package/docs/publication-artifacts.md +128 -486
  63. package/docs/publication-authority.md +15 -45
  64. package/docs/publish-transaction.md +13 -11
  65. package/docs/release-candidate.md +126 -355
  66. package/docs/release-discussions.md +36 -67
  67. package/docs/release-flow.md +80 -339
  68. package/docs/release-governance.md +114 -962
  69. package/docs/release-promotion-request.md +45 -43
  70. package/docs/release-propagation.md +13 -27
  71. package/docs/release-tail-provider-plane.md +38 -65
  72. package/docs/reusable-build-surface.md +78 -196
  73. package/docs/runtime-train-validation.md +8 -6
  74. package/docs/stable-candidate-patrol.md +13 -66
  75. package/docs/v4-adopter-delivery.md +15 -15
  76. package/docs/v4-declarative-release-tail-migration.md +19 -17
  77. package/docs/v4-production-release.md +11 -6
  78. package/docs/v4-publication-rehearsal.md +12 -27
  79. package/docs/v4-stage-capsule.md +14 -20
  80. package/docs/v4-tail-reseal.md +34 -20
  81. package/docs/web-surface-deployments.md +26 -264
  82. package/docs/workflow-catalog.md +31 -31
  83. package/docs/workflow-path-migration.md +10 -4
  84. package/package.json +5 -4
  85. package/packages/core/adoption/buildchain-kfd-claims.js +7 -7
  86. package/packages/core/adoption/cli/output.mjs +1 -9
  87. package/packages/core/adoption/cli/product-gate.mjs +1 -15
  88. package/packages/core/adoption/cli/project.mjs +9 -10
  89. package/packages/core/adoption/cli/standards.mjs +1 -14
  90. package/packages/core/adoption/cli/support.mjs +0 -2
  91. package/packages/core/adoption/cli/surface-register.mjs +0 -2
  92. package/packages/core/adoption/commands/init-repo.mjs +77 -485
  93. package/packages/core/adoption/consumer-init.js +279 -0
  94. package/packages/core/adoption/qualification/admission.js +1 -1
  95. package/packages/core/build/cli/cache.mjs +0 -2
  96. package/packages/core/build/cli/facts.mjs +0 -3
  97. package/packages/core/build/cli/homebrew.mjs +0 -4
  98. package/packages/core/build/cli/lifecycle.mjs +0 -3
  99. package/packages/core/build/github-artifact-attestation.js +2 -2
  100. package/packages/core/build/platform-stage-checkpoints.js +1 -1
  101. package/packages/core/build/signing/dispatch.js +1 -1
  102. package/packages/core/consumer/buildchain-config.js +9 -0
  103. package/packages/core/consumer/contract/inspection.js +351 -9
  104. package/packages/core/consumer/contract/javascript-syntax.js +439 -0
  105. package/packages/core/consumer/contract/javascript-values.js +61 -0
  106. package/packages/core/consumer/contract/javascript.js +555 -0
  107. package/packages/core/consumer/contract/local-validation.js +84 -0
  108. package/packages/core/contracts/buildchain-contract.js +39 -8
  109. package/packages/core/contracts/cli/introspection.mjs +1 -9
  110. package/packages/core/contracts/public-surface-cli.js +0 -1
  111. package/packages/core/dev-delivery/dev-delivery-contract-surface.js +2 -2
  112. package/packages/core/governance/buildchain-publication-authority.js +24 -24
  113. package/packages/core/governance/cli/doctor.mjs +58 -42
  114. package/packages/core/governance/commands/architecture.mjs +6 -1
  115. package/packages/core/governance/commands/audit-publication-control-plane.mjs +1 -1
  116. package/packages/core/governance/commands/workflow-friction-report.mjs +1 -1
  117. package/packages/core/governance/github-governance-authority.js +2 -2
  118. package/packages/core/governance/publication/collection.js +1 -1
  119. package/packages/core/index.js +1 -3
  120. package/packages/core/observability/cli/candidate.mjs +0 -2
  121. package/packages/core/observability/cli/context.mjs +0 -5
  122. package/packages/core/observability/cli/diagnostics.mjs +0 -7
  123. package/packages/core/observability/cli/events.mjs +2 -10
  124. package/packages/core/paper/commands/paper-work-fleet-cli.mjs +1 -1
  125. package/packages/core/paper/commands/paper.mjs +33 -422
  126. package/packages/core/paper/consumer-status.js +72 -0
  127. package/packages/core/paper/operations/identity.js +0 -3
  128. package/packages/core/paper/operations/migration.js +460 -0
  129. package/packages/core/paper/operations/preflight-checks.js +8 -68
  130. package/packages/core/paper/operations/scaffold.js +16 -326
  131. package/packages/core/paper/operations/status.js +27 -53
  132. package/packages/core/paper/paper-agent-entry.js +36 -147
  133. package/packages/core/paper/paper-fleet.js +24 -39
  134. package/packages/core/paper/paper-repository.js +16 -0
  135. package/packages/core/paper/paper-runtime-channels.js +1 -1
  136. package/packages/core/paper/paper-scaffold-content.js +153 -162
  137. package/packages/core/paper/paper-work.js +3 -10
  138. package/packages/core/paper/paper.js +43 -5
  139. package/packages/core/providers/github/artifact-attestation.js +1 -1
  140. package/packages/core/providers/github/pipeline-context-artifacts.js +172 -0
  141. package/packages/core/providers/github/pipeline-release-evidence.js +17 -98
  142. package/packages/core/providers/github/pipeline-stable-baseline.js +86 -0
  143. package/packages/core/providers/github/pipeline-stable-source.js +22 -4
  144. package/packages/core/providers/github/release-evidence-assets.js +97 -0
  145. package/packages/core/publication/authority/control-plane.js +2 -2
  146. package/packages/core/publication/authority/seal.js +1 -1
  147. package/packages/core/publication/cli/dispatch.mjs +1 -12
  148. package/packages/core/publication/pipeline/actions.js +16 -9
  149. package/packages/core/publication/pipeline/apply.js +17 -9
  150. package/packages/core/publication/pipeline/context.js +29 -0
  151. package/packages/core/publication/pipeline/journal.js +13 -1
  152. package/packages/core/publication/pipeline/prepare.js +15 -6
  153. package/packages/core/publication/pipeline/recovery-import.js +1 -1
  154. package/packages/core/publication/pipeline/recovery-materials.js +63 -1
  155. package/packages/core/publication/pipeline/recovery-prepare.js +21 -9
  156. package/packages/core/publication/pipeline/stable-entry.js +12 -3
  157. package/packages/core/publication/pipeline/stable-products.js +21 -19
  158. package/packages/core/publication/pipeline/version-actions.js +15 -6
  159. package/packages/core/publication/publication-rehearsal-projection.js +0 -9
  160. package/packages/core/release/cli/dispatch.mjs +1 -4
  161. package/packages/core/release/cli/inspection-handlers.mjs +1 -33
  162. package/packages/core/release/cli/release-handlers.mjs +2 -19
  163. package/packages/core/release/cli/verification-handlers.mjs +4 -25
  164. package/packages/core/release/next-development-projection.js +13 -13
  165. package/packages/core/release/passport/locations.js +13 -8
  166. package/packages/core/release/release-passport.js +70 -5
  167. package/packages/core/web/cli/badges.mjs +0 -4
  168. package/packages/core/web/publication-admission.js +1 -1
  169. package/packages/core/web/publication-capability.js +1 -1
  170. package/packages/core/web/readme-badges.js +1 -1
  171. package/packages/core/workflow/cli/main.mjs +1 -4
  172. package/packages/core/workflow/cli/process.mjs +1 -1
  173. package/packages/core/workflow/commands/buildchain-cli-help.mjs +2 -8
  174. package/packages/core/workflow/engine/conformance.js +1 -1
  175. package/packages/core/workflow/pipeline/build.js +21 -1
  176. package/packages/core/workflow/pipeline/delivery-observation.js +6 -2
  177. package/packages/core/workflow/workflow-taxonomy.mjs +61 -17
  178. package/scripts/check-code-layout.mjs +2 -0
  179. package/scripts/check-core-mechanism-inventory.mjs +29 -13
  180. package/scripts/check-floating-consumer-policy-contract.mjs +3 -3
  181. package/scripts/check-inventory.mjs +27 -27
  182. package/scripts/check-maintainability.mjs +28 -5
  183. package/scripts/check-public-dogfood-contract.mjs +3 -3
  184. package/scripts/check-release-topology.mjs +1 -1
  185. package/scripts/check-self-consumer-contract.mjs +7 -7
  186. package/scripts/check-universal-workflow-bootstrap.mjs +1 -1
  187. package/scripts/generate-channel-promotion-workflow.mjs +1 -1
  188. package/scripts/generate-minimal-consumer-contract.mjs +21 -1
  189. package/scripts/generate-site-bundle.mjs +2 -1
  190. package/scripts/generate-tail-reseal-fixture.mjs +3 -3
  191. package/scripts/inventory/promotion.mjs +1 -1
  192. package/scripts/next-development-self-dogfood-harness.mjs +1 -1
  193. package/scripts/next-development-self-dogfood.mjs +4 -4
  194. package/scripts/site-capability-metadata.mjs +2 -6
  195. package/scripts/source-metric-lineage.mjs +62 -7
  196. package/scripts/verify-golden-path.mjs +31 -35
  197. package/templates/native-dev-delivery.yml +1 -1
  198. package/templates/universal-buildchain-bootstrap.yml +1 -1
  199. package/packages/core/paper/operations/bootstrap.js +0 -75
  200. package/packages/core/paper/operations/plans.js +0 -213
  201. package/packages/core/paper/operations/provisioning.js +0 -113
  202. package/packages/core/paper/operations/scaffold-config.js +0 -77
  203. package/packages/core/paper/operations/scaffold-workflows.js +0 -116
  204. package/packages/core/paper/operations/workspace.js +0 -60
  205. package/packages/core/paper/paper-npm-bootstrap.js +0 -492
@@ -3,34 +3,14 @@ import path from "node:path";
3
3
  import { spawnSync } from "node:child_process";
4
4
  import { verifyInfraContractEvidenceBundle } from "../../providers/commands/infra-contract-core.mjs";
5
5
  import { verifyBuildchainLogEvents } from "../../observability/logging.js";
6
+ import { verifyReleasePassport } from "../release-passport.js";
7
+ import { verifyPublicationAdmission } from "../../publication/publication-authority.js";
6
8
  import {
7
- explainReleaseLineDryRun,
8
- formatReleaseLineDryRun,
9
- } from "../release-line-dry-run.js";
10
- import {
11
- planReleaseLineBootstrap,
12
- writeReleaseLineBootstrapVersionState,
13
- } from "../release-line-bootstrap.js";
14
- import { collectGitHubReleasePassport } from "../passport/collection.js";
15
- import { explainReleasePassport, verifyReleasePassport } from "../release-passport.js";
16
- import {
17
- createPublicationAdmission,
18
- createRunnerProvenance,
19
- verifyPublicationAdmission,
20
- } from "../../publication/publication-authority.js";
21
- import {
22
- createGitHubArtifactAttestationPolicy,
23
9
  createGitHubArtifactAttestationVerificationPlan,
24
10
  verifyGitHubArtifactAttestationEvidence,
25
11
  } from "../../build/github-artifact-attestation.js";
26
- import {
27
- explainArtifactPassport,
28
- verifyArtifactPassport,
29
- } from "../../build/artifact-passport.js";
30
- import {
31
- projectArtifactVerificationEnvelopeToKfx,
32
- verifyArtifactVerificationEnvelope,
33
- } from "../../build/artifact-verification-envelope.js";
12
+ import { verifyArtifactPassport } from "../../build/artifact-passport.js";
13
+ import { verifyArtifactVerificationEnvelope } from "../../build/artifact-verification-envelope.js";
34
14
  import {
35
15
  artifactEnvelopeOptions,
36
16
  printJson,
@@ -38,7 +18,6 @@ import {
38
18
  readFlag,
39
19
  readJsonInput,
40
20
  readRepeatedFlag,
41
- writeJsonFile,
42
21
  } from "../../contracts/cli/options.mjs";
43
22
 
44
23
  async function verifyGitHubArtifactAttestationCommand({
@@ -266,19 +266,19 @@ invalid.
266
266
 
267
267
  ## Public self-dogfood and adoption
268
268
 
269
- \`.github/workflows/self-build-public-consumer-dogfood.yml\` remains the exact thin
270
- consumer of the public \`public-build-stage-capsule-canary.yml@v4-alpha\` contract. Its
271
- declared \`lifecycle.verify\` runs \`pnpm run check\`, so the same public path
272
- executes pure recovery tests that inject a transient durable-state write
273
- failure, restore the adapter operation on a fresh runner, supersede stale work
274
- when protected Dev moves, preserve \`pr-pending\` during protected-PR delay, and
275
- prove both legal version models. No caller-local qualification job, action,
276
- or private self-dogfood route is added.
277
-
278
- The existing dual-channel self-consumer separately retains exact hosted
279
- \`build.yml@v4-alpha\` and \`build.yml@v4\` runtime evidence. Consumers adopt
280
- the proved contract through the floating v4 coordinates; exact resolved SHAs
281
- remain audit evidence and never become durable selectors.
269
+ \`.github/workflows/buildchain.yml\` calls the published
270
+ \`public-ops-pipeline.yml@v4\` entry. Products declare their verification commands
271
+ in schema-2 TOML, including the full repository check on each required platform.
272
+ Next-development preparation, independent review, protected merge and settlement
273
+ remain runtime responsibilities.
274
+
275
+ \`.github/workflows/buildchain-recover.yml\` calls
276
+ \`public-ops-recover.yml@v4\` with one exact attempt and an optional temporary
277
+ repaired runtime. It preserves completed publication evidence while continuing
278
+ unfinished follow-ups. Both callers use the same generated bytes as external
279
+ consumers. Tool-maintained locks and retained receipts bind exact runtime SHAs.
280
+ Earlier Stage Capsule and channel-build proofs retain their historical source
281
+ identities; they do not define additional current consumer entrypoints.
282
282
 
283
283
  ## Local adapter
284
284
 
@@ -1,29 +1,32 @@
1
1
  import path from "node:path";
2
2
  import fs from "node:fs";
3
- import { readJsonFile } from "./files.js";
4
3
  import https from "node:https";
5
4
  import http from "node:http";
6
5
  import { nonEmptyString } from "./identity.js";
7
- export async function resolveSiblingJson(basePath, relativePath) {
6
+ export async function resolveSiblingJson(basePath, relativePath, options) {
8
7
  if (!basePath || !relativePath) {
9
8
  return undefined;
10
9
  }
11
10
  if (/^https?:\/\//.test(relativePath)) {
12
- return readJsonFromLocation(relativePath);
11
+ return readJsonFromLocation(relativePath, 0, options);
13
12
  }
14
13
  if (/^https?:\/\//.test(basePath)) {
15
- return readJsonFromLocation(new URL(relativePath, basePath).toString());
14
+ return readJsonFromLocation(
15
+ new URL(relativePath, basePath).toString(),
16
+ 0,
17
+ options,
18
+ );
16
19
  }
17
20
  const candidate = path.resolve(path.dirname(basePath), relativePath);
18
21
  if (!fs.existsSync(candidate)) {
19
22
  return undefined;
20
23
  }
21
- return readJsonFile(candidate);
24
+ return readJsonFromLocation(candidate, 0, options);
22
25
  }
23
26
  export async function readJsonFromLocation(
24
27
  location,
25
28
  redirectCount = 0,
26
- { timeoutMs = 15_000 } = {},
29
+ { timeoutMs = 15_000, raw = false } = {},
27
30
  ) {
28
31
  const input = nonEmptyString(location, "location");
29
32
  if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {
@@ -47,6 +50,7 @@ export async function readJsonFromLocation(
47
50
  response.resume();
48
51
  readJsonFromLocation(nextLocation, redirectCount + 1, {
49
52
  timeoutMs,
53
+ raw,
50
54
  }).then(resolve, reject);
51
55
  return;
52
56
  }
@@ -64,7 +68,7 @@ export async function readJsonFromLocation(
64
68
  });
65
69
  response.on("end", () => {
66
70
  try {
67
- resolve(JSON.parse(body));
71
+ resolve(raw ? body : JSON.parse(body));
68
72
  } catch (error) {
69
73
  reject(error);
70
74
  }
@@ -78,5 +82,6 @@ export async function readJsonFromLocation(
78
82
  request.on("error", reject);
79
83
  });
80
84
  }
81
- return readJsonFile(input);
85
+ const bytes = fs.readFileSync(input, "utf8");
86
+ return raw ? bytes : JSON.parse(bytes);
82
87
  }
@@ -1,3 +1,7 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { verifyPublishedDocuments } from "../publication/pipeline/stable-products.js";
1
5
  import { resolveReleasePassportVerificationInputs } from "./release-passport-contract.js";
2
6
  import { nowIso } from "./passport/identity.js";
3
7
  import {
@@ -5,6 +9,56 @@ import {
5
9
  resolveSiblingJson,
6
10
  } from "./passport/locations.js";
7
11
  import { createReleaseCheckReport } from "./passport/report.js";
12
+
13
+ async function verifyPipelinePassport(location, release, checkedAt, execute) {
14
+ const directory = fs.mkdtempSync(
15
+ path.join(fs.realpathSync(os.tmpdir()), "buildchain-passport-"),
16
+ );
17
+ const report = {
18
+ schemaVersion: 1,
19
+ contract: "kungfu-buildchain-release-check-report",
20
+ checkedAt,
21
+ verificationScope: "signed-release-metadata",
22
+ artifactBytesVerified: false,
23
+ providerStateVerified: false,
24
+ completeness: { artifactCount: 0 },
25
+ issues: [],
26
+ };
27
+ try {
28
+ const values = { release };
29
+ for (const name of ["plan", "qualification", "capsules", "invocation"])
30
+ values[name] = await resolveSiblingJson(
31
+ location,
32
+ `buildchain.${name}.json`,
33
+ );
34
+ const bundle = await resolveSiblingJson(
35
+ location,
36
+ "buildchain.attestation.json",
37
+ { raw: true },
38
+ );
39
+ verifyPublishedDocuments(values, bundle, {
40
+ directory,
41
+ token: process.env.GH_TOKEN || process.env.GITHUB_TOKEN,
42
+ execute,
43
+ });
44
+ report.completeness.artifactCount = values.qualification.artifacts.length;
45
+ report.source = release.source;
46
+ report.release = release.release;
47
+ } catch {
48
+ report.issues.push({
49
+ level: "error",
50
+ code: "pipeline.evidence",
51
+ message:
52
+ "Signed release metadata verification failed. Supply all five unchanged companion files and GitHub CLI with attestation verification support.",
53
+ });
54
+ } finally {
55
+ fs.rmSync(directory, { recursive: true, force: true });
56
+ }
57
+ report.ok = report.issues.length === 0;
58
+ report.trust = report.ok ? "pass" : "fail";
59
+ return report;
60
+ }
61
+
8
62
  export async function verifyReleasePassport({
9
63
  passportLocation,
10
64
  artifactEvidenceLocation = "",
@@ -17,7 +71,16 @@ export async function verifyReleasePassport({
17
71
  kfdAdopterManifestGateLocation = "",
18
72
  kfdSupportEvidenceLocation = "",
19
73
  checkedAt = nowIso(),
74
+ execute,
20
75
  } = {}) {
76
+ const passport = await readJsonFromLocation(passportLocation);
77
+ if (passport?.schema === "kungfu.buildchain.release-passport/v4")
78
+ return verifyPipelinePassport(
79
+ passportLocation,
80
+ passport,
81
+ checkedAt,
82
+ execute,
83
+ );
21
84
  const evidence = await resolveReleasePassportVerificationInputs({
22
85
  passportLocation,
23
86
  locations: {
@@ -34,10 +97,7 @@ export async function verifyReleasePassport({
34
97
  readJson: readJsonFromLocation,
35
98
  resolveSibling: resolveSiblingJson,
36
99
  });
37
- return createReleaseCheckReport({
38
- ...evidence,
39
- checkedAt,
40
- });
100
+ return createReleaseCheckReport({ ...evidence, checkedAt });
41
101
  }
42
102
  export async function explainReleasePassport({
43
103
  passportLocation,
@@ -46,7 +106,9 @@ export async function explainReleasePassport({
46
106
  const report = await verifyReleasePassport({ passportLocation });
47
107
  const passport = await readJsonFromLocation(passportLocation);
48
108
  const nextAction = report.ok
49
- ? "install-or-upgrade-after-policy-review"
109
+ ? report.verificationScope === "signed-release-metadata"
110
+ ? "verify-artifact-bytes-and-review-policy"
111
+ : "install-or-upgrade-after-policy-review"
50
112
  : "block-release-and-report-verification-failure";
51
113
  return {
52
114
  schemaVersion: 1,
@@ -54,6 +116,9 @@ export async function explainReleasePassport({
54
116
  audience: forAudience,
55
117
  release: passport.release,
56
118
  trust: report.trust,
119
+ verificationScope: report.verificationScope,
120
+ artifactBytesVerified: report.artifactBytesVerified,
121
+ providerStateVerified: report.providerStateVerified,
57
122
  complete: report.ok,
58
123
  artifactCount: report.completeness.artifactCount,
59
124
  runnerPolicy: passport.runnerPolicy,
@@ -13,10 +13,6 @@ import {
13
13
  printJson,
14
14
  readBooleanFlag,
15
15
  readFlag,
16
- readJsonInput,
17
- readRepeatedFlag,
18
- readRepeatedJsonInputs,
19
- writeJsonFile,
20
16
  } from "../../contracts/cli/options.mjs";
21
17
 
22
18
  export async function runReadmeBadgesCli(args = []) {
@@ -56,7 +56,7 @@ export function assembleWebPublicationAdmission({
56
56
  "managed web-surface publication requires an ephemeral GitHub-hosted Actions runner",
57
57
  );
58
58
  }
59
- const workflowPath = ".github/workflows/public-release-web.yml";
59
+ const workflowPath = ".github/workflows/.release-web.yml";
60
60
  const publisherWorkflowPath = workflowPath;
61
61
  const controlPlaneAudit = createPublicationControlPlaneAudit({
62
62
  repository,
@@ -36,7 +36,7 @@ export function verifyWebPublicationCapability(request, now = Date.now()) {
36
36
  }
37
37
  const roleArn = required(request, "roleArn");
38
38
  const exact = {
39
- workflowPath: ".github/workflows/public-release-web.yml",
39
+ workflowPath: ".github/workflows/.release-web.yml",
40
40
  repository: required(request, "repository"),
41
41
  sourceSha: required(request, "sourceSha").toLowerCase(),
42
42
  runtimeSha: required(request, "runtimeSha").toLowerCase(),
@@ -457,7 +457,7 @@ function normalizePackageRepository(repository) {
457
457
  function discoverWorkflowFacts({ cwd, repository, badgeConfig = {} }) {
458
458
  const workflowDir = path.join(cwd, ".github", "workflows");
459
459
  const configured = normalizeStringArray(badgeConfig.workflows);
460
- const defaults = ["verify.yml", "build.yml", "buildchain-ref-promotion.yml"];
460
+ const defaults = ["verify.yml", ".build-candidate.yml", "buildchain-ref-promotion.yml"];
461
461
  const names = configured.length > 0 ? configured : defaults;
462
462
  if (!fs.existsSync(workflowDir)) {
463
463
  return [];
@@ -1,10 +1,7 @@
1
1
  import { initializeCliRuntime } from "../../contracts/cli/context.mjs";
2
2
  import { BUILDCHAIN_USAGE } from "../commands/buildchain-cli-help.mjs";
3
3
  import { formatCliHelp } from "../../contracts/cli-reference.js";
4
- import {
5
- TRUST_RELEASE_COMMANDS,
6
- dispatchTrustReleaseCommand,
7
- } from "../../release/cli/trust-release.mjs";
4
+ import { TRUST_RELEASE_COMMANDS } from "../../release/cli/trust-release.mjs";
8
5
  import { dispatchRegisteredCommand } from "../../contracts/command-registry.mjs";
9
6
  import { handleAdopterDeliveryCommand } from "../../adoption/cli/dispatch.mjs";
10
7
  import { handleKfdCommand } from "../../adoption/cli/kfd.mjs";
@@ -1,4 +1,4 @@
1
- import { spawn, spawnSync } from "node:child_process";
1
+ import { spawnSync } from "node:child_process";
2
2
  import path from "node:path";
3
3
  import { root } from "../../contracts/cli/context.mjs";
4
4
 
@@ -20,7 +20,7 @@ export const BUILDCHAIN_USAGE = `Usage:
20
20
  [--cold-fallback-status not-run|passed|failed]
21
21
  [--output <file>] [--json]
22
22
  buildchain candidate timeline --input <file-or-json> [--output <file>] [--json]
23
- buildchain init [--cwd <dir>] [--type package|native|web-surface|infra-contract|publication-artifact|anchored-package] [--force]
23
+ buildchain init [--cwd <dir>] [--type npm|binary|paper|package|native|publication-artifact|anchored-package] [--force]
24
24
  [--package-manager pnpm|npm|yarn] [--runner-preset <preset>]
25
25
  [--artifact-name <name>]
26
26
  buildchain validate [--cwd <dir>] [--require-version-state]
@@ -253,7 +253,7 @@ export const BUILDCHAIN_USAGE = `Usage:
253
253
  [--output <file>] [--promote]
254
254
  [--no-toolchain-pull]
255
255
  [--allow-unpinned-toolchain] [--json]
256
- buildchain paper scaffold --package <name> --repository <owner/repo> [--write] [--json]
256
+ buildchain paper scaffold --repository <owner/repo> [--package <name>] [--write] [--json]
257
257
  buildchain paper migrate [--cwd <dir>] [--write] [--json]
258
258
  buildchain paper work start <topic> [--cwd <dir>] [--branch <branch>] [--execute] [--json]
259
259
  buildchain paper work submit [--cwd <dir>] [--title <title>] [--body <body>] [--execute] [--json]
@@ -261,13 +261,7 @@ export const BUILDCHAIN_USAGE = `Usage:
261
261
  buildchain paper fleet update [--root <dir>] [--write] [--json]
262
262
  buildchain paper agent verify [--cwd <dir>] [--offline] [--json]
263
263
  buildchain paper preflight [--cwd <dir>] [--offline] [--json]
264
- buildchain paper bootstrap npm [--cwd <dir>] [--execute]
265
- [--confirm-public-package <name>] [--json]
266
- buildchain paper build [--cwd <dir>] [--execute] [--json]
267
- buildchain paper alpha [--cwd <dir>] [--source-ref <ref>] [--target-ref <ref>]
268
- [--execute] [--json]
269
264
  buildchain paper status [--cwd <dir>] [--json]
270
- buildchain paper resume [--cwd <dir>] [--runtime-ref <ref>] [--execute] [--json]
271
265
  buildchain release-propagation <plan|write-lock|work|entry|pickup> ...
272
266
  buildchain badges readme [--cwd <dir>] [--readme <path>] [--check] [--write] [--json]
273
267
  buildchain badges bundle [--cwd <dir>] [--readme <path>] [--claims <csv>] [--check] [--write] [--json]
@@ -52,7 +52,7 @@ export function executeBootstrapConformance(
52
52
  const source = fs.readFileSync(path.join(runtimeRoot, relative), "utf8");
53
53
  if (
54
54
  relative !== architecture.bootstrap.publicWorkflow &&
55
- !/(?:\.\/)?\.github\/workflows\/public-ops-bootstrap\.yml/u.test(source)
55
+ !/(?:\.\/)?\.github\/workflows\/\.ops-bootstrap\.yml/u.test(source)
56
56
  )
57
57
  fail(`candidate Bootstrap facade is not governed: ${relative}`);
58
58
  }
@@ -3,12 +3,15 @@ import path from "node:path";
3
3
  import { execFileSync } from "node:child_process";
4
4
  import { createHash } from "node:crypto";
5
5
  import { bindConsumerSource } from "../../consumer/contract/identity.js";
6
+ import { inspectConsumerContract } from "../../consumer/contract/inspection.js";
7
+ import { validateConsumerWiring } from "../../consumer/contract/local-validation.js";
6
8
  import { recordDigest } from "../../release/discussion/envelope.js";
7
9
  import { consumerCommandSession } from "../../runtime/consumer-shell.js";
8
10
  import { createNativeChildEnvironment } from "../../dev-delivery/native/execution.js";
9
11
 
10
12
  function inspectTrackedBytes(cwd, tree) {
11
13
  const root = fs.realpathSync(cwd);
14
+ const files = Object.create(null);
12
15
  const entries = execFileSync(
13
16
  "git",
14
17
  ["-C", root, "ls-tree", "-r", "-z", tree],
@@ -48,7 +51,13 @@ function inspectTrackedBytes(cwd, tree) {
48
51
  throw new Error(
49
52
  `Build tracked source bytes differ from the admitted tree: ${file}`,
50
53
  );
54
+ Object.defineProperty(files, file, {
55
+ enumerable: true,
56
+ get: () =>
57
+ link ? fs.readlinkSync(absolute) : fs.readFileSync(absolute, "utf8"),
58
+ });
51
59
  }
60
+ return files;
52
61
  }
53
62
 
54
63
  export function inspectPipelineSource(cwd, expected) {
@@ -82,7 +91,18 @@ export function inspectPipelineSource(cwd, expected) {
82
91
  "Build source has tracked modifications at its verification boundary",
83
92
  );
84
93
  // Index flags and local Git filters cannot qualify different product bytes.
85
- inspectTrackedBytes(cwd, expected.tree);
94
+ const files = inspectTrackedBytes(cwd, expected.tree);
95
+ const { channel } = validateConsumerWiring(cwd, expected.configPath);
96
+ const inspection = inspectConsumerContract(files, {
97
+ channel,
98
+ configPath: expected.configPath,
99
+ });
100
+ if (inspection.controlIssues.length)
101
+ throw new Error(
102
+ `Consumer control wiring is invalid: ${inspection.controlIssues.join("; ")}`,
103
+ );
104
+ // Unresolved product language/tool edges are not a static safety proof.
105
+ // Execution remains confined to the runtime's read-only product jobs below.
86
106
  return plan;
87
107
  }
88
108
 
@@ -65,9 +65,13 @@ export async function observePipelineWorker(session, current, queue, host) {
65
65
  run,
66
66
  };
67
67
  }
68
+ // Retained executions keep the workflow identity that actually produced them.
69
+ // The old path is read-only evidence, never a new dispatch or consumer alias.
68
70
  const entries = (run.referenced_workflows || []).filter((entry) =>
69
- entry.path?.startsWith(
70
- "kungfu-systems/buildchain/.github/workflows/public-ops-dev-auto-merge.yml@",
71
+ [".ops-dev-auto-merge.yml", "public-ops-dev-auto-merge.yml"].some((file) =>
72
+ entry.path?.startsWith(
73
+ `kungfu-systems/buildchain/.github/workflows/${file}@`,
74
+ ),
71
75
  ),
72
76
  );
73
77
  if (entries.length !== 1) return null;
@@ -64,13 +64,12 @@ function validateEntries(policy, errors) {
64
64
  if (
65
65
  entry.path &&
66
66
  !(
67
- [".build", "build", "buildchain", "buildchain-recover"].includes(
68
- entry.id,
69
- ) && entry.path === `.github/workflows/${entry.id}.yml`
67
+ [".build", "buildchain", "buildchain-recover"].includes(entry.id) &&
68
+ entry.path === `.github/workflows/${entry.id}.yml`
70
69
  )
71
70
  )
72
71
  errors.push(
73
- `${entry.id}: explicit path is reserved for build APIs and the generated consumer pair`,
72
+ `${entry.id}: explicit path is reserved for the internal build engine and generated consumer pair`,
74
73
  );
75
74
  const file = workflowPath(entry);
76
75
  if (!WORKFLOW.test(file) || paths.has(file))
@@ -82,6 +81,33 @@ function validateEntries(policy, errors) {
82
81
  );
83
82
  validateEntryOwnership(entry, errors);
84
83
  }
84
+ const publicEntries = policy.entries.filter(
85
+ (entry) => entry.role === "public",
86
+ );
87
+ if (
88
+ policy.entries
89
+ .filter((entry) => entry.role === "self")
90
+ .map((entry) => entry.id)
91
+ .sort()
92
+ .join(",") !== "buildchain,buildchain-recover"
93
+ )
94
+ errors.push(
95
+ "repository event roots must be exactly the generated consumer pair",
96
+ );
97
+ if (
98
+ publicEntries.length !== 2 ||
99
+ ["pipeline", "recover"].some(
100
+ (purpose) =>
101
+ !publicEntries.some(
102
+ (entry) =>
103
+ entry.id === purpose &&
104
+ entry.category === "ops" &&
105
+ entry.purpose === purpose &&
106
+ entry.invocation === "reusable",
107
+ ),
108
+ )
109
+ )
110
+ errors.push("consumer public entries must be exactly pipeline and recover");
85
111
  return policy.entries;
86
112
  }
87
113
 
@@ -100,11 +126,9 @@ export function discoverWorkflowFiles(root) {
100
126
  return visit(directory).sort();
101
127
  }
102
128
 
103
- function validateWorkflow(root, entry, declared, errors) {
129
+ function validateWorkflow(entry, text, declared, errors) {
130
+ if (typeof text !== "string") return;
104
131
  const file = workflowPath(entry),
105
- absolute = path.join(root, file);
106
- if (!fs.existsSync(absolute) || !fs.lstatSync(absolute).isFile()) return;
107
- const text = fs.readFileSync(absolute, "utf8"),
108
132
  document = parseWorkflowDocument(text);
109
133
  if (
110
134
  (entry.invocation === "reusable") !==
@@ -258,23 +282,41 @@ function validateGateIntegration(root, errors) {
258
282
 
259
283
  export function checkWorkflowTaxonomy(
260
284
  root,
261
- { integration = true, documentation = true } = {},
285
+ { integration = true, documentation = true, files } = {},
262
286
  ) {
263
287
  const errors = [],
264
- policy = readWorkflowTaxonomy(root),
288
+ policy = files
289
+ ? JSON.parse(files[TAXONOMY_PATH] || "null")
290
+ : readWorkflowTaxonomy(root),
265
291
  entries = validateEntries(policy, errors);
266
292
  if (errors.length) return { ok: false, errors };
293
+ files ??= Object.fromEntries(
294
+ discoverWorkflowFiles(root).map((file) => {
295
+ const absolute = path.join(root, file);
296
+ return [
297
+ file,
298
+ fs.lstatSync(absolute).isFile()
299
+ ? fs.readFileSync(absolute, "utf8")
300
+ : null,
301
+ ];
302
+ }),
303
+ );
267
304
  const declared = new Set(entries.map(workflowPath)),
268
- observed = new Set(discoverWorkflowFiles(root));
305
+ observed = new Set(
306
+ Object.keys(files).filter((file) =>
307
+ /^\.github\/workflows\/.*\.ya?ml$/iu.test(file),
308
+ ),
309
+ );
269
310
  for (const file of observed) {
270
311
  if (!declared.has(file)) errors.push(`unregistered workflow: ${file}`);
271
- if (!fs.lstatSync(path.join(root, file)).isFile())
312
+ if (typeof files[file] !== "string")
272
313
  errors.push(`workflow must be a regular file: ${file}`);
273
314
  }
274
315
  for (const file of declared)
275
316
  if (!observed.has(file))
276
317
  errors.push(`registered workflow missing: ${file}`);
277
- for (const entry of entries) validateWorkflow(root, entry, declared, errors);
318
+ for (const entry of entries)
319
+ validateWorkflow(entry, files[workflowPath(entry)], declared, errors);
278
320
  if (integration) validateGateIntegration(root, errors);
279
321
  if (documentation) {
280
322
  const file = path.join(root, TAXONOMY_DOC);
@@ -324,9 +366,9 @@ export function renderWorkflowCatalog(policy) {
324
366
  "",
325
367
  "Generated from `architecture/workflow-taxonomy.json`. Every workflow has one canonical implementation; alternate paths and historical forwarding aliases are rejected.",
326
368
  "",
327
- "Public workflows own the consumer API. Component workflows own reusable multi-job topology. Self workflows own Buildchain repository automation. Actions own execution steps; JS adapters and Rust/WASM own implementation.",
369
+ "The two public workflows own normal pipeline execution and exact-attempt recovery. Component workflows are internal runtime implementation, including once-only setup and the dispatch signing service; consumers do not wire these components. Self workflows are the generated consumer pair. Actions own execution steps; JS adapters and Rust/WASM own implementation.",
328
370
  "",
329
- "Names use `public-<category>-<purpose>.yml`, `.<category>-<purpose>.yml`, and the generated self callers `buildchain.yml` and `buildchain-recover.yml`, with categories `build`, `release`, and `ops`. The primary build API and backbone use `build.yml` and `.build.yml`.",
371
+ "Names use `public-ops-pipeline.yml`, `public-ops-recover.yml`, internal `.<category>-<purpose>.yml`, and the generated self callers `buildchain.yml` and `buildchain-recover.yml`. Categories are `build`, `release`, and `ops`; the internal build engine retains `.build.yml`.",
330
372
  "",
331
373
  "Register ownership before adding a workflow. `pnpm run check:workflows` validates source, calls, required CI integration and independent review ownership. `pnpm run generate:workflows` regenerates this catalog.",
332
374
  "",
@@ -366,6 +408,8 @@ function validateEntryOwnership(entry, errors) {
366
408
  errors.push(`${entry.id}: invalid invocation`);
367
409
  if ((entry.role === "self") !== (entry.invocation === "repository"))
368
410
  errors.push(`${entry.id}: role and invocation disagree`);
369
- if (entry.role === "component" && entry.invocation !== "reusable")
370
- errors.push(`${entry.id}: component must be reusable`);
411
+ if (entry.invocation === "dispatch-service" && entry.role !== "component")
412
+ errors.push(
413
+ `${entry.id}: dispatch services must remain internal components`,
414
+ );
371
415
  }
@@ -204,6 +204,8 @@ export function inspectPublicActionNodes(actions, publicNodes) {
204
204
  const issues = [];
205
205
  if (!Array.isArray(publicNodes))
206
206
  return ["public Action registry must be an array"];
207
+ if (publicNodes.length)
208
+ issues.push("Actions are internal runtime nodes; consumers use pipeline and recovery workflows");
207
209
  const known = new Set(
208
210
  actions.map((action) => action.directory.replace(/^actions\//u, "")),
209
211
  );
@@ -34,15 +34,24 @@ function registrySurfaceIds(root) {
34
34
  (entry) => `cli:${entry.id}`,
35
35
  );
36
36
  const workflows = loadJson(root, "dist/site/workflow-registry.json");
37
- const workflowIds = workflows.workflows.flatMap((entry) => [
38
- `workflow:${entry.id}`,
39
- ...(entry.taxonomy ? [`workflow:${entry.taxonomy.id}`] : []),
37
+ const workflowIds = workflows.workflows.flatMap((entry) =>
38
+ [entry.id, ...(entry.taxonomy ? [entry.taxonomy.id] : [])].map((id) => [
39
+ `workflow:${id}`,
40
+ entry.apiRole === "public" ? "public" : "internal",
41
+ ]),
42
+ );
43
+ const actionIds = workflows.actions.map((entry) => [
44
+ `action:${entry.id}`,
45
+ entry.apiRole === "public" ? "public" : "internal",
40
46
  ]);
41
- const actionIds = workflows.actions.map((entry) => `action:${entry.id}`);
42
47
  const exports = Object.keys(loadJson(root, "package.json").exports).map(
43
48
  (entry) => `export:${entry}`,
44
49
  );
45
- return new Set([...cli, ...workflowIds, ...actionIds, ...exports]);
50
+ return new Map(
51
+ [...cli, ...exports]
52
+ .map((id) => [id, "public"])
53
+ .concat(workflowIds, actionIds),
54
+ );
46
55
  }
47
56
 
48
57
  function listFiles(root, relativeRoot) {
@@ -99,12 +108,12 @@ function validateOwnership(mechanism, ownedSources, issues) {
99
108
  }
100
109
 
101
110
  function validateSurfaces(mechanism, surfaces, issues) {
102
- for (const surface of mechanism.publicSurfaces || []) {
103
- if (!surfaces.has(surface))
104
- issues.push(
105
- `${mechanism.id}: public surface is absent from generated/package registries: ${surface}`,
106
- );
107
- }
111
+ for (const role of ["public", "internal"])
112
+ for (const surface of mechanism[`${role}Surfaces`] || [])
113
+ if (surfaces.get(surface) !== role)
114
+ issues.push(
115
+ `${mechanism.id}: ${role} surface is absent or has a different role in generated/package registries: ${surface}`,
116
+ );
108
117
  }
109
118
 
110
119
  function validateGitRefStore(root, mechanism, issues) {
@@ -140,12 +149,15 @@ function validateReverseScanReferences(root, reverseScan, issues) {
140
149
  function validateSurfaceKinds(inventory, issues) {
141
150
  const surfaceKinds = new Set(
142
151
  (inventory.mechanisms || []).flatMap((mechanism) =>
143
- (mechanism.publicSurfaces || []).map((surface) => surface.split(":")[0]),
152
+ [
153
+ ...(mechanism.publicSurfaces || []),
154
+ ...(mechanism.internalSurfaces || []),
155
+ ].map((surface) => surface.split(":")[0]),
144
156
  ),
145
157
  );
146
158
  for (const kind of ["action", "cli", "export", "workflow"]) {
147
159
  if (!surfaceKinds.has(kind))
148
- issues.push(`reverse scan has no ${kind} public surface coverage`);
160
+ issues.push(`reverse scan has no ${kind} surface coverage`);
149
161
  }
150
162
  return surfaceKinds;
151
163
  }
@@ -329,6 +341,10 @@ function checkCoreMechanismInventory({
329
341
  (sum, entry) => sum + entry.publicSurfaces.length,
330
342
  0,
331
343
  ),
344
+ internalSurfaces: inventory.mechanisms.reduce(
345
+ (sum, entry) => sum + (entry.internalSurfaces || []).length,
346
+ 0,
347
+ ),
332
348
  dependencyCycles: inventory.maintainability.dependencyCycles,
333
349
  ...reverseScan,
334
350
  };