@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
@@ -1,9 +1,11 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import { planPaperMigration, writePaperMigration } from "./operations/scaffold.js";
4
- import { resolvePaperRuntimeGitSha } from "./operations/runtime.js";
5
3
  import {
6
- PAPER_PATHS,
4
+ planPaperMigration,
5
+ writePaperMigration,
6
+ } from "./operations/scaffold.js";
7
+ import { paperConsumerStatus } from "./consumer-status.js";
8
+ import {
7
9
  PAPER_WORK_BRANCH_PATTERN,
8
10
  paperWorkSource,
9
11
  readJson,
@@ -46,21 +48,6 @@ function plannedManagedSurfaces(options) {
46
48
  }
47
49
  }
48
50
 
49
- function legacyBuildchainWorkflowRefs(cwd) {
50
- const workflowRoot = path.resolve(cwd, ".github", "workflows");
51
- if (!fs.existsSync(workflowRoot)) return [];
52
- return fs
53
- .readdirSync(workflowRoot, { withFileTypes: true })
54
- .filter((entry) => entry.isFile() && /\.ya?ml$/i.test(entry.name))
55
- .filter((entry) =>
56
- /uses:\s*kungfu-systems\/buildchain\/[^\s]+@v2(?:[-.][^\s]+)?/i.test(
57
- fs.readFileSync(path.join(workflowRoot, entry.name), "utf8"),
58
- ),
59
- )
60
- .map((entry) => `.github/workflows/${entry.name}`)
61
- .sort();
62
- }
63
-
64
51
  function paperFleetEntry({
65
52
  cwd,
66
53
  buildchainRoot,
@@ -69,7 +56,6 @@ function paperFleetEntry({
69
56
  }) {
70
57
  const source = paperWorkSource(cwd);
71
58
  const packageJson = readJson(path.resolve(cwd, "package.json")).value || {};
72
- const pinPath = path.resolve(cwd, PAPER_PATHS.versionPin);
73
59
  const lockPath = path.resolve(cwd, "pnpm-lock.yaml");
74
60
  const expected = plannedManagedSurfaces({
75
61
  cwd,
@@ -93,7 +79,12 @@ function paperFleetEntry({
93
79
  const lockText = fs.existsSync(lockPath)
94
80
  ? fs.readFileSync(lockPath, "utf8")
95
81
  : "";
96
- const legacyWorkflows = legacyBuildchainWorkflowRefs(cwd);
82
+ let consumer;
83
+ try {
84
+ consumer = paperConsumerStatus(cwd);
85
+ } catch {
86
+ consumer = null;
87
+ }
97
88
  const checks = [
98
89
  workCheck(
99
90
  "repository.canonical-origin",
@@ -103,23 +94,25 @@ function paperFleetEntry({
103
94
  ),
104
95
  workCheck(
105
96
  "package.buildchain-runtime",
106
- dependency === buildchainVersion && /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(dependency),
107
- "package.json pins the exact Buildchain semantic runtime.",
97
+ !dependency ||
98
+ (dependency === buildchainVersion &&
99
+ /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(dependency)),
100
+ "An optional local Buildchain CLI dependency pins the selected version.",
108
101
  "buildchain paper migrate --write --json",
109
102
  ),
110
103
  workCheck(
111
104
  "package.pnpm-lock",
112
- Boolean(lockText) &&
113
- lockText.includes("@kungfu-tech/buildchain") &&
114
- lockText.includes(buildchainVersion),
105
+ !dependency ||
106
+ (Boolean(lockText) &&
107
+ lockText.includes("@kungfu-tech/buildchain") &&
108
+ lockText.includes(buildchainVersion)),
115
109
  "pnpm-lock.yaml binds the Buildchain dependency.",
116
110
  "pnpm install --lockfile-only",
117
111
  ),
118
112
  workCheck(
119
- "runtime.version-pin",
120
- fs.existsSync(pinPath) &&
121
- fs.readFileSync(pinPath, "utf8").trim() === buildchainVersion,
122
- "The repository version pin equals the exact Buildchain runtime.",
113
+ "consumer.shared-contract",
114
+ consumer?.ok === true,
115
+ "Schema-2 product policy and the shared caller pair are valid.",
123
116
  "buildchain paper migrate --write --json",
124
117
  ),
125
118
  workCheck(
@@ -128,12 +121,6 @@ function paperFleetEntry({
128
121
  "Every Buildchain-owned paper control surface matches the selected runtime.",
129
122
  "buildchain paper migrate --write --json",
130
123
  ),
131
- workCheck(
132
- "workflows.buildchain-v2-absent",
133
- legacyWorkflows.length === 0,
134
- "No workflow calls a Buildchain v2 reusable surface.",
135
- "buildchain paper migrate --write --json",
136
- ),
137
124
  ];
138
125
  return {
139
126
  name: path.basename(cwd),
@@ -146,7 +133,6 @@ function paperFleetEntry({
146
133
  buildchainDependency: dependency,
147
134
  expectedError: expected.error,
148
135
  managed,
149
- legacyWorkflows,
150
136
  checks,
151
137
  ok: checks.every((entry) => entry.status === "pass"),
152
138
  };
@@ -185,9 +171,8 @@ export function collectPaperFleetAudit({
185
171
  root: resolvedRoot,
186
172
  runtime: {
187
173
  version: buildchainVersion,
188
- sha:
189
- buildchainSha ||
190
- resolvePaperRuntimeGitSha(buildchainRoot, buildchainVersion),
174
+ entry: "v4",
175
+ source: "not-observed",
191
176
  },
192
177
  summary: {
193
178
  repositories: entries.length,
@@ -4,6 +4,7 @@ import path from "node:path";
4
4
  import { loadBuildchainConfig } from "../consumer/buildchain-config.js";
5
5
  import { spawnSyncCommand } from "../runtime/spawn-command.js";
6
6
 
7
+ // Retained schema-1 reader coordinates. New callers come only from consumerWorkflows.
7
8
  export const PAPER_PATHS = Object.freeze({
8
9
  config: ".buildchain/buildchain.toml",
9
10
  agentEntry: ".buildchain/paper/agent-entry.json",
@@ -143,6 +144,21 @@ export function resolvePaperRepository(cwd = process.cwd()) {
143
144
  }
144
145
 
145
146
  export function paperDevelopmentRef(cwd) {
147
+ const loaded = loadBuildchainConfig(cwd);
148
+ if (loaded?.config.schema === 2) {
149
+ const targets = [
150
+ ...new Set(
151
+ loaded.config.channels
152
+ .filter((channel) => channel.operation === "develop")
153
+ .map((channel) => channel.to),
154
+ ),
155
+ ];
156
+ if (targets.length !== 1)
157
+ throw new Error(
158
+ "Paper work requires one unambiguous development target in TOML",
159
+ );
160
+ return targets[0];
161
+ }
146
162
  const configResult = paperConfig(cwd);
147
163
  if (configResult.error) throw new Error(configResult.error);
148
164
  const parsed = parsePaperVersion(
@@ -94,7 +94,7 @@ function workflowErrors(cwd, authority, workflow) {
94
94
  if (!fileDigestMatches(cwd, workflow.path, workflow.sourceDigest))
95
95
  return [`paper workflow source digest mismatch: ${workflow.path}`];
96
96
  const refs =
97
- workflow.reusablePath === ".github/workflows/public-release-paper.yml"
97
+ [".github/workflows/public-release-paper.yml", ".github/workflows/.release-paper.yml"].includes(workflow.reusablePath)
98
98
  ? ["v4-alpha", "v4"]
99
99
  : ["v4-alpha"];
100
100
  const text = fs.readFileSync(path.resolve(cwd, workflow.path), "utf8");
@@ -1,3 +1,7 @@
1
+ import {
2
+ applyPaperMigration,
3
+ paperFileTarget as scaffoldTarget,
4
+ } from "./operations/migration.js";
1
5
  import fs from "node:fs";
2
6
  import path from "node:path";
3
7
  import {
@@ -10,12 +14,6 @@ function jsonText(value) {
10
14
  return `${JSON.stringify(value, null, 2)}\n`;
11
15
  }
12
16
 
13
- export function paperDependencyIgnore(current = "") {
14
- return /^(?:\/)?node_modules\/?\s*$/m.test(current)
15
- ? current
16
- : `${current}${current.endsWith("\n") || !current ? "" : "\n"}node_modules/\n`;
17
- }
18
-
19
17
  function texEscape(value) {
20
18
  return String(value || "")
21
19
  .replaceAll("\\", "\\textbackslash{}")
@@ -52,102 +50,95 @@ clean:
52
50
  `;
53
51
  }
54
52
 
55
- export function paperPackageScripts(current = {}) {
56
- return {
57
- ...current,
58
- "buildchain:paper": "buildchain paper",
59
- "paper:preflight": "buildchain paper preflight --json",
60
- "paper:agent:verify": "buildchain paper agent verify --json",
61
- "paper:work:start": "buildchain paper work start",
62
- "paper:work:submit": "buildchain paper work submit",
63
- "paper:status": "buildchain paper status --json",
64
- };
65
- }
66
-
67
- export function managedPaperPackageJson(current, buildchainVersion) {
68
- if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(buildchainVersion)) {
69
- throw new Error(
70
- "paper repositories require an exact Buildchain semantic version",
71
- );
72
- }
73
- const packageManager = current.packageManager || "pnpm@11.7.0";
74
- if (!packageManager.startsWith("pnpm@")) {
75
- throw new Error("paper repositories require a pnpm packageManager");
76
- }
77
- return {
78
- ...current,
79
- private: true,
80
- scripts: paperPackageScripts(current.scripts),
81
- devDependencies: {
82
- ...(current.devDependencies || {}),
83
- "@kungfu-tech/buildchain": buildchainVersion,
84
- },
85
- packageManager,
86
- };
87
- }
88
-
89
53
  export function scaffoldPackageJson({
90
54
  name,
55
+ title,
91
56
  packageName,
92
57
  repository,
58
+ version,
59
+ siteBaseUrl,
93
60
  buildchainVersion,
94
61
  }) {
95
62
  return jsonText({
96
- ...managedPaperPackageJson(
97
- {
98
- name: packageName,
99
- description: `${name} publication source repository.`,
100
- repository: {
101
- type: "git",
102
- url: `git+https://github.com/${repository}.git`,
103
- },
104
- license: "Apache-2.0",
105
- },
106
- buildchainVersion,
107
- ),
63
+ name: packageName,
64
+ version,
65
+ private: true,
66
+ description: title || `${name} publication source repository.`,
67
+ repository: {
68
+ type: "git",
69
+ url: `git+https://github.com/${repository}.git`,
70
+ },
71
+ ...(siteBaseUrl ? { homepage: siteBaseUrl } : {}),
72
+ license: "Apache-2.0",
73
+ scripts: { build: "make pdf", check: "make check" },
74
+ devDependencies: { "@kungfu-tech/buildchain": buildchainVersion },
75
+ packageManager: "pnpm@11.7.0",
108
76
  });
109
77
  }
110
78
 
111
- export function scaffoldReadme({ title, packageName }) {
112
- return `# ${title}
79
+ function paperDocument(body) {
80
+ return `---
81
+ status: draft
82
+ period: ongoing
83
+ theme: paper-consumer
84
+ doc_type: implementation-guide
85
+ source_level: generated-template
86
+ confidence: high
87
+ sensitivity: public
88
+ evidence_grade: B
89
+ review_state: unreviewed
90
+ last_reviewed: 2026-09-20
91
+ ai_provenance:
92
+ model_family: GPT-6
93
+ product: Codex
94
+ generated_at: 2026-09-20
95
+ visible_context: Shared schema-2 Paper source scaffold and caller templates.
96
+ invisible_context_boundary: No hosted build or publication is claimed.
97
+ ---
113
98
 
114
- This repository is a Buildchain-governed publication artifact source.
99
+ ${body}`;
100
+ }
101
+
102
+ export function scaffoldReadme({ title }) {
103
+ return paperDocument(`# ${title}
104
+
105
+ This repository owns the paper source, product build commands and review history.
115
106
 
116
107
  ## Local workflow
117
108
 
118
109
  \`\`\`sh
119
- pnpm paper:preflight
120
- pnpm paper:agent:verify
121
- pnpm paper:work:start -- <topic>
122
- pnpm paper:work:submit
123
110
  make pdf
111
+ make check
112
+ buildchain validate --require-lifecycle-stages build,verify
124
113
  \`\`\`
125
114
 
126
- The public package identity is \`${packageName}\`. Buildchain owns reproducible
127
- artifact generation, sealed publication, npm Trusted Publishing, and recovery;
128
- this repository owns the paper source and review history.
115
+ Open a protected channel PR to request delivery or publication. The published
116
+ Buildchain pipeline builds and publishes the PDF to GitHub Releases. The same
117
+ normal and recovery callers serve npm, binary and Paper products. Recovery takes
118
+ an exact attempt, with an optional temporary repaired runtime.
119
+
120
+ The private package.json identifies this source repository and its version;
121
+ it is not an npm publication target.
129
122
 
130
123
  See [docs/MAP.md](docs/MAP.md) for the repository map.
131
- `;
124
+ `);
132
125
  }
133
126
 
134
127
  export function scaffoldMap() {
135
- return `# Repository Map
128
+ return paperDocument(`# Repository Map
136
129
 
137
130
  - \`paper/main.tex\`: paper source entrypoint.
138
131
  - \`paper/references.bib\`: bibliography source.
139
- - \`AGENTS.md\`: mandatory managed entry instructions for people and coding agents.
140
- - \`.buildchain/paper/agent-entry.json\`: versioned, digest-bound local and CI entry policy.
141
- - \`.buildchain/buildchain.toml\`: publication identity, toolchain, package, and lifecycle contract.
142
- - \`.buildchain/contract-lock.json\`: accepted Buildchain runtime contract.
143
- - \`.github/workflows/build.yml\`: thin read-only build and reproducibility caller.
144
- - \`.github/workflows/verify.yml\`: thin required check that enforces the Paper entry and acceptance policy.
145
- - \`.github/workflows/public-release-paper.yml\`: thin protected sealed-release caller.
132
+ - \`Makefile\`: product PDF build and verification commands.
133
+ - \`package.json\`: source identity, title, version and optional homepage.
134
+ - \`AGENTS.md\`: shared consumer instructions.
135
+ - \`.buildchain/buildchain.toml\`: schema-2 product and channel policy.
136
+ - \`.github/workflows/buildchain.yml\`: shared normal caller.
137
+ - \`.github/workflows/buildchain-recover.yml\`: shared exact-attempt recovery caller.
146
138
 
147
- The repository does not own npm transaction logic, publication authority,
148
- release-state recovery, or site deployment mechanics. Those remain Buildchain,
149
- npm/GitHub, and downstream site responsibilities respectively.
150
- `;
139
+ Tool-maintained contract locks bind the published runtime. Publication,
140
+ provider readback and release recovery belong to that runtime.
141
+ `);
151
142
  }
152
143
 
153
144
  export function scaffoldMainTex(title) {
@@ -175,6 +166,39 @@ Replace this section with the reviewed paper content.
175
166
  \\end{document}
176
167
  `;
177
168
  }
169
+ function scaffoldRoot(cwd) {
170
+ let existing = path.resolve(cwd);
171
+ const missing = [];
172
+ while (!fs.existsSync(existing)) {
173
+ missing.unshift(path.basename(existing));
174
+ const parent = path.dirname(existing);
175
+ if (parent === existing)
176
+ throw new Error("Cannot resolve Paper scaffold parent");
177
+ existing = parent;
178
+ }
179
+ if (!fs.statSync(existing).isDirectory())
180
+ throw new Error("Paper scaffold root must be a directory");
181
+ return path.join(fs.realpathSync(existing), ...missing);
182
+ }
183
+
184
+ function additionalScaffoldWorkflows(cwd, paths) {
185
+ const directory = path.join(cwd, ".github/workflows");
186
+ if (!fs.existsSync(directory)) return [];
187
+ return fs
188
+ .readdirSync(directory, { withFileTypes: true })
189
+ .filter(
190
+ (entry) =>
191
+ !entry.isFile() ||
192
+ (/\.ya?ml$/iu.test(entry.name) &&
193
+ !paths.includes(`.github/workflows/${entry.name}`)),
194
+ )
195
+ .map((entry) => ({
196
+ path: `.github/workflows/${entry.name}`,
197
+ action: "conflict",
198
+ reason: "outside-shared-consumer-pair",
199
+ }));
200
+ }
201
+
178
202
  function planPaperScaffold(
179
203
  runtime,
180
204
  {
@@ -182,7 +206,6 @@ function planPaperScaffold(
182
206
  buildchainRoot = process.cwd(),
183
207
  buildchainVersion = "",
184
208
  buildchainRef = "v4",
185
- buildchainSha = "",
186
209
  name = path.basename(path.resolve(cwd)),
187
210
  title = "",
188
211
  packageName = "",
@@ -191,10 +214,12 @@ function planPaperScaffold(
191
214
  siteBaseUrl = "",
192
215
  } = {},
193
216
  ) {
194
- const resolvedCwd = path.resolve(cwd);
217
+ const resolvedCwd = scaffoldRoot(cwd);
195
218
  const normalizedName = String(name || "").trim();
196
219
  if (!normalizedName) throw new Error("paper scaffold requires --name");
197
- const normalizedPackage = runtime.normalizePackageName(packageName);
220
+ const normalizedPackage = runtime.normalizePackageName(
221
+ packageName || normalizedName,
222
+ );
198
223
  const normalizedRepository = normalizeRepository(repository);
199
224
  if (!normalizedRepository) {
200
225
  throw new Error("paper scaffold requires --repository <owner/repo>");
@@ -209,19 +234,14 @@ function planPaperScaffold(
209
234
  buildchainRoot,
210
235
  buildchainVersion,
211
236
  );
212
- const runtimeSha =
213
- buildchainSha ||
214
- runtime.resolvePaperRuntimeGitSha(buildchainRoot, runtimeIdentity.version);
215
- if (!runtime.GIT_SHA_PATTERN.test(runtimeSha)) {
237
+ if (buildchainRef !== "v4")
216
238
  throw new Error(
217
- "paper scaffold cannot resolve the exact Buildchain runtime SHA; pass buildchainSha or use a published Buildchain package with npm gitHead provenance",
239
+ "Paper scaffold uses the shared published v4 caller; exact runtimes belong in tool-maintained locks",
218
240
  );
219
- }
220
241
  const files = runtime.scaffoldFiles({
221
242
  buildchainRoot,
222
243
  buildchainVersion: runtimeIdentity.version,
223
244
  buildchainRef,
224
- buildchainSha: runtimeSha,
225
245
  cwd: resolvedCwd,
226
246
  name: normalizedName,
227
247
  title: title || normalizedName,
@@ -231,7 +251,7 @@ function planPaperScaffold(
231
251
  siteBaseUrl,
232
252
  });
233
253
  const changes = [...files.entries()].map(([relativePath, content]) => {
234
- const filePath = path.resolve(resolvedCwd, relativePath);
254
+ const filePath = scaffoldTarget(resolvedCwd, relativePath);
235
255
  const exists = fs.existsSync(filePath);
236
256
  if (!exists) {
237
257
  return {
@@ -267,6 +287,7 @@ function planPaperScaffold(
267
287
  content,
268
288
  };
269
289
  });
290
+ changes.push(...additionalScaffoldWorkflows(resolvedCwd, [...files.keys()]));
270
291
  const publicChanges = changes.map(({ content: _content, ...entry }) => entry);
271
292
  const conflicts = publicChanges.filter(
272
293
  (entry) => entry.action === "conflict",
@@ -286,8 +307,7 @@ function planPaperScaffold(
286
307
  },
287
308
  buildchain: {
288
309
  version: runtimeIdentity.version,
289
- ref: runtimeSha,
290
- resolvedSha: runtimeSha,
310
+ ref: "v4",
291
311
  },
292
312
  summary: {
293
313
  create: publicChanges.filter((entry) => entry.action === "create").length,
@@ -337,11 +357,18 @@ function writePaperScaffold(runtime, plan) {
337
357
  };
338
358
  }
339
359
  const resolvedCwd = path.resolve(plan.cwd);
360
+ if (
361
+ fs.lstatSync(resolvedCwd, { throwIfNoEntry: false })?.isSymbolicLink() ||
362
+ scaffoldRoot(resolvedCwd) !== resolvedCwd
363
+ )
364
+ throw new Error("Paper scaffold root changed after planning");
340
365
  const creates = plan._plannedFiles.filter(
341
366
  (entry) => entry.action === "create",
342
367
  );
343
- for (const entry of creates) {
344
- const target = path.resolve(resolvedCwd, entry.path);
368
+ for (const entry of plan._plannedFiles) {
369
+ const target = scaffoldTarget(resolvedCwd, entry.path);
370
+ if (entry.action === "unchanged" && !fs.existsSync(target))
371
+ throw new Error(`paper scaffold race detected at ${entry.path}`);
345
372
  if (fs.existsSync(target)) {
346
373
  const current = fs.statSync(target).isFile()
347
374
  ? fs.readFileSync(target, "utf8")
@@ -354,6 +381,13 @@ function writePaperScaffold(runtime, plan) {
354
381
  continue;
355
382
  }
356
383
  }
384
+ if (
385
+ additionalScaffoldWorkflows(
386
+ resolvedCwd,
387
+ plan._plannedFiles.map((entry) => entry.path),
388
+ ).length
389
+ )
390
+ throw new Error("paper scaffold workflow inventory changed after planning");
357
391
  const written = [];
358
392
  for (const entry of creates) {
359
393
  const target = path.resolve(resolvedCwd, entry.path);
@@ -370,8 +404,8 @@ function writePaperScaffold(runtime, plan) {
370
404
  idempotent: written.length === 0,
371
405
  nextActions: [
372
406
  {
373
- id: "paper-preflight",
374
- command: `buildchain paper preflight --cwd ${JSON.stringify(resolvedCwd)} --json`,
407
+ id: "consumer-validate",
408
+ command: `buildchain validate --cwd ${JSON.stringify(resolvedCwd)} --require-lifecycle-stages build,verify`,
375
409
  description:
376
410
  "Verify the generated repository before any external mutation.",
377
411
  },
@@ -390,7 +424,11 @@ function planPaperMigration(
390
424
  alphaBuildchainRoot = "",
391
425
  } = {},
392
426
  ) {
393
- const resolvedCwd = path.resolve(cwd);
427
+ if (stableBuildchainRoot || alphaBuildchainRoot)
428
+ throw new Error(
429
+ "Paper migration rejects retired channel-root inputs; runtime locks are preserved by the shared setup contract",
430
+ );
431
+ const resolvedCwd = fs.realpathSync(cwd);
394
432
  const repositoryRoot = gitValue(resolvedCwd, [
395
433
  "rev-parse",
396
434
  "--show-toplevel",
@@ -402,6 +440,15 @@ function planPaperMigration(
402
440
  if (!repositoryRoot || repositoryPrefix) {
403
441
  throw new Error("paper migration must target the exact repository root");
404
442
  }
443
+ for (const relative of [
444
+ ".buildchain/buildchain.toml",
445
+ "package.json",
446
+ "AGENTS.md",
447
+ "pnpm-workspace.yaml",
448
+ ".github/workflows/buildchain.yml",
449
+ ".github/workflows/buildchain-recover.yml",
450
+ ])
451
+ scaffoldTarget(resolvedCwd, relative);
405
452
  const source = {
406
453
  head: gitValue(resolvedCwd, ["rev-parse", "HEAD"]),
407
454
  clean: gitResult(resolvedCwd, ["status", "--porcelain"]).stdout === "",
@@ -425,7 +472,7 @@ function planPaperMigration(
425
472
  path: relativePath,
426
473
  action: "conflict",
427
474
  currentSha256: "",
428
- sha256: sha256Text(content),
475
+ sha256: content === null ? "" : sha256Text(content),
429
476
  content,
430
477
  };
431
478
  }
@@ -435,13 +482,17 @@ function planPaperMigration(
435
482
  return {
436
483
  path: relativePath,
437
484
  action:
438
- current === undefined
439
- ? "create"
440
- : current === content
485
+ content === null
486
+ ? current === undefined
441
487
  ? "unchanged"
442
- : "update",
488
+ : "remove"
489
+ : current === undefined
490
+ ? "create"
491
+ : current === content
492
+ ? "unchanged"
493
+ : "update",
443
494
  currentSha256: current === undefined ? "" : sha256Text(current),
444
- sha256: sha256Text(content),
495
+ sha256: content === null ? "" : sha256Text(content),
445
496
  content,
446
497
  };
447
498
  });
@@ -458,6 +509,7 @@ function planPaperMigration(
458
509
  summary: {
459
510
  create: changes.filter((entry) => entry.action === "create").length,
460
511
  update: changes.filter((entry) => entry.action === "update").length,
512
+ remove: changes.filter((entry) => entry.action === "remove").length,
461
513
  unchanged: changes.filter((entry) => entry.action === "unchanged").length,
462
514
  conflict: conflicts.length,
463
515
  },
@@ -486,7 +538,7 @@ function planPaperMigration(
486
538
  id: "write-migration",
487
539
  command: "buildchain paper migrate --write --json",
488
540
  description:
489
- "Write the reviewed Buildchain-owned control files without changing paper content or publication configuration.",
541
+ "Convert product configuration to the shared pipeline and retire the listed verified legacy control files; source content and historical receipts remain untouched.",
490
542
  },
491
543
  {
492
544
  id: "refresh-pnpm-lock",
@@ -503,72 +555,11 @@ function planPaperMigration(
503
555
  return result;
504
556
  }
505
557
 
506
- function writePaperMigration(runtime, plan) {
507
- if (!plan || plan.contract !== runtime.PAPER_MIGRATION_CONTRACT) {
508
- throw new Error("paper migration plan contract mismatch");
509
- }
510
- if (!plan.ok) {
511
- return {
512
- ...plan,
513
- dryRun: false,
514
- written: [],
515
- updated: [],
516
- ok: false,
517
- errorCode: "paper-migration-blocked",
518
- };
519
- }
520
- const written = [];
521
- const updated = [];
522
- for (const entry of plan._plannedFiles) {
523
- if (entry.action === "unchanged") continue;
524
- const target = path.resolve(plan.cwd, entry.path);
525
- const exists = fs.existsSync(target);
526
- const current =
527
- exists && fs.statSync(target).isFile()
528
- ? fs.readFileSync(target, "utf8")
529
- : undefined;
530
- const currentSha256 = current === undefined ? "" : sha256Text(current);
531
- if (
532
- (entry.action === "create" && exists) ||
533
- (entry.action === "update" && currentSha256 !== entry.currentSha256)
534
- ) {
535
- throw new Error(
536
- `paper migration race detected at ${entry.path}; no stale plan was applied`,
537
- );
538
- }
539
- }
540
- for (const entry of plan._plannedFiles) {
541
- if (entry.action === "unchanged") continue;
542
- const target = path.resolve(plan.cwd, entry.path);
543
- fs.mkdirSync(path.dirname(target), { recursive: true });
544
- fs.writeFileSync(target, entry.content, {
545
- flag: entry.action === "create" ? "wx" : "w",
546
- });
547
- (entry.action === "create" ? written : updated).push(entry.path);
548
- }
549
- return {
550
- ...plan,
551
- ok: true,
552
- dryRun: false,
553
- written,
554
- updated,
555
- idempotent: written.length === 0 && updated.length === 0,
556
- nextActions: [
557
- {
558
- id: "paper-preflight",
559
- command: `buildchain paper preflight --cwd ${JSON.stringify(plan.cwd)} --offline --json`,
560
- description:
561
- "Verify the migrated repository before any external mutation.",
562
- },
563
- ],
564
- };
565
- }
566
-
567
558
  export function createPaperScaffoldOperations(runtime) {
568
559
  return {
569
560
  planPaperMigration: (options) => planPaperMigration(runtime, options),
570
561
  planPaperScaffold: (options) => planPaperScaffold(runtime, options),
571
- writePaperMigration: (plan) => writePaperMigration(runtime, plan),
562
+ writePaperMigration: applyPaperMigration,
572
563
  writePaperScaffold: (plan) => writePaperScaffold(runtime, plan),
573
564
  };
574
565
  }