@kungfu-tech/buildchain 4.1.3 → 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.
- package/AGENTS.md +11 -13
- package/CONTRIBUTING.md +32 -9
- package/README.md +56 -140
- package/actions/release/promotion/ref/README.md +1 -1
- package/architecture/action-taxonomy.json +1 -1
- package/architecture/agent-change-map.md +32 -45
- package/architecture/build-orchestration.json +1 -1
- package/architecture/capability-state-machine-manifest.json +5 -5
- package/architecture/ci-lane-change-budget.json +92 -92
- package/architecture/code-layout.json +2 -12
- package/architecture/core-mechanisms.json +38 -39
- package/architecture/cross-platform-adopter-qualification.json +1 -1
- package/architecture/dev-delivery-orchestration.json +2 -2
- package/architecture/floating-consumer-policy.json +3 -3
- package/architecture/internal-capabilities.json +27 -28
- package/architecture/maintainability-debt.json +60 -94
- package/architecture/maintainability-policy.json +7 -13
- package/architecture/minimal-consumer-migration.json +43 -5014
- package/architecture/platform-stage-checkpoints.json +1 -1
- package/architecture/release-tail-contract.json +2 -2
- package/architecture/release-topology.json +31 -25
- package/architecture/stage-capsule-qualification.json +1 -1
- package/architecture/universal-workflow-bootstrap.json +60 -60
- package/architecture/universal-workflow-capability-policy.json +3 -3
- package/architecture/universal-workflow-fault-campaign.json +7 -7
- package/architecture/workflow-taxonomy.json +59 -60
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
- package/dist/site/buildchain-contract.json +138 -66
- package/dist/site/buildchain-site.json +257 -331
- package/dist/site/capability-registry.json +4 -4
- package/dist/site/cli-registry.json +6 -142
- package/dist/site/controller-registry.json +19 -19
- package/dist/site/kfd-claims.json +481 -529
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +22 -22
- package/dist/site/node-api-registry.json +82 -339
- package/dist/site/page-registry.json +229 -304
- package/dist/site/public-surface-audit.json +544 -754
- package/dist/site/publication-authority-registry.json +316 -316
- package/dist/site/publication-registry.json +1 -1
- package/dist/site/site-manifest.json +23 -23
- package/dist/site/workflow-registry.json +1071 -1027
- package/docs/MAP.md +28 -20
- package/docs/auditable-demo.md +17 -49
- package/docs/bootstrap-recovery.md +46 -37
- package/docs/cli-reference.md +2 -46
- package/docs/cli.md +97 -186
- package/docs/code-organization.md +7 -5
- package/docs/dev-alpha-candidate-patrol.md +19 -42
- package/docs/dev-delivery-orchestration.md +15 -11
- package/docs/dev-delivery-qualification-landing-adr.md +10 -9
- package/docs/dev-delivery-warrant.md +17 -16
- package/docs/dev-qualification-patrol.md +25 -20
- package/docs/getting-started.md +80 -139
- package/docs/github-artifact-attestation.md +31 -81
- package/docs/install.md +66 -30
- package/docs/lifecycle-protocol.md +19 -57
- package/docs/migration-inventory.md +17 -45
- package/docs/next-development-transition.md +13 -13
- package/docs/node-api-reference.md +122 -138
- package/docs/oci-publication.md +13 -10
- package/docs/publication-artifacts.md +128 -486
- package/docs/publication-authority.md +15 -45
- package/docs/publish-transaction.md +13 -11
- package/docs/release-candidate.md +126 -355
- package/docs/release-discussions.md +36 -67
- package/docs/release-flow.md +80 -339
- package/docs/release-governance.md +114 -962
- package/docs/release-promotion-request.md +45 -43
- package/docs/release-propagation.md +13 -27
- package/docs/release-tail-provider-plane.md +38 -65
- package/docs/reusable-build-surface.md +78 -196
- package/docs/runtime-train-validation.md +8 -6
- package/docs/stable-candidate-patrol.md +13 -66
- package/docs/v4-adopter-delivery.md +15 -15
- package/docs/v4-declarative-release-tail-migration.md +19 -17
- package/docs/v4-production-release.md +11 -6
- package/docs/v4-publication-rehearsal.md +12 -27
- package/docs/v4-stage-capsule.md +14 -20
- package/docs/v4-tail-reseal.md +34 -20
- package/docs/web-surface-deployments.md +26 -264
- package/docs/workflow-catalog.md +31 -31
- package/docs/workflow-path-migration.md +10 -4
- package/package.json +5 -4
- package/packages/core/adoption/buildchain-kfd-claims.js +7 -7
- package/packages/core/adoption/cli/output.mjs +1 -9
- package/packages/core/adoption/cli/product-gate.mjs +1 -15
- package/packages/core/adoption/cli/project.mjs +9 -10
- package/packages/core/adoption/cli/standards.mjs +1 -14
- package/packages/core/adoption/cli/support.mjs +0 -2
- package/packages/core/adoption/cli/surface-register.mjs +0 -2
- package/packages/core/adoption/commands/init-repo.mjs +77 -485
- package/packages/core/adoption/consumer-init.js +279 -0
- package/packages/core/adoption/qualification/admission.js +1 -1
- package/packages/core/build/cli/cache.mjs +0 -2
- package/packages/core/build/cli/facts.mjs +0 -3
- package/packages/core/build/cli/homebrew.mjs +0 -4
- package/packages/core/build/cli/lifecycle.mjs +0 -3
- package/packages/core/build/github-artifact-attestation.js +2 -2
- package/packages/core/build/platform-stage-checkpoints.js +1 -1
- package/packages/core/build/signing/dispatch.js +1 -1
- package/packages/core/consumer/buildchain-config.js +9 -0
- package/packages/core/consumer/contract/inspection.js +351 -9
- package/packages/core/consumer/contract/javascript-syntax.js +439 -0
- package/packages/core/consumer/contract/javascript-values.js +61 -0
- package/packages/core/consumer/contract/javascript.js +555 -0
- package/packages/core/consumer/contract/local-validation.js +84 -0
- package/packages/core/contracts/buildchain-contract.js +39 -8
- package/packages/core/contracts/cli/introspection.mjs +1 -9
- package/packages/core/contracts/public-surface-cli.js +0 -1
- package/packages/core/dev-delivery/dev-delivery-contract-surface.js +2 -2
- package/packages/core/governance/buildchain-publication-authority.js +24 -24
- package/packages/core/governance/cli/doctor.mjs +58 -42
- package/packages/core/governance/commands/architecture.mjs +6 -1
- package/packages/core/governance/commands/audit-publication-control-plane.mjs +1 -1
- package/packages/core/governance/commands/workflow-friction-report.mjs +1 -1
- package/packages/core/governance/github-governance-authority.js +2 -2
- package/packages/core/governance/publication/collection.js +1 -1
- package/packages/core/index.js +1 -3
- package/packages/core/observability/cli/candidate.mjs +0 -2
- package/packages/core/observability/cli/context.mjs +0 -5
- package/packages/core/observability/cli/diagnostics.mjs +0 -7
- package/packages/core/observability/cli/events.mjs +2 -10
- package/packages/core/paper/commands/paper-work-fleet-cli.mjs +1 -1
- package/packages/core/paper/commands/paper.mjs +33 -422
- package/packages/core/paper/consumer-status.js +72 -0
- package/packages/core/paper/operations/identity.js +0 -3
- package/packages/core/paper/operations/migration.js +460 -0
- package/packages/core/paper/operations/preflight-checks.js +8 -68
- package/packages/core/paper/operations/scaffold.js +16 -326
- package/packages/core/paper/operations/status.js +27 -53
- package/packages/core/paper/paper-agent-entry.js +36 -147
- package/packages/core/paper/paper-fleet.js +24 -39
- package/packages/core/paper/paper-repository.js +16 -0
- package/packages/core/paper/paper-runtime-channels.js +1 -1
- package/packages/core/paper/paper-scaffold-content.js +153 -162
- package/packages/core/paper/paper-work.js +3 -10
- package/packages/core/paper/paper.js +43 -5
- package/packages/core/providers/github/artifact-attestation.js +1 -1
- package/packages/core/providers/github/pipeline-context-artifacts.js +172 -0
- package/packages/core/publication/authority/control-plane.js +2 -2
- package/packages/core/publication/authority/seal.js +1 -1
- package/packages/core/publication/cli/dispatch.mjs +1 -12
- package/packages/core/publication/pipeline/actions.js +16 -9
- package/packages/core/publication/pipeline/apply.js +17 -9
- package/packages/core/publication/pipeline/context.js +29 -0
- package/packages/core/publication/pipeline/prepare.js +15 -6
- package/packages/core/publication/pipeline/recovery-materials.js +63 -1
- package/packages/core/publication/pipeline/recovery-prepare.js +21 -9
- package/packages/core/publication/pipeline/stable-entry.js +12 -7
- package/packages/core/publication/pipeline/stable-products.js +21 -19
- package/packages/core/publication/pipeline/version-actions.js +15 -6
- package/packages/core/publication/publication-rehearsal-projection.js +0 -9
- package/packages/core/release/cli/dispatch.mjs +1 -4
- package/packages/core/release/cli/inspection-handlers.mjs +1 -33
- package/packages/core/release/cli/release-handlers.mjs +2 -19
- package/packages/core/release/cli/verification-handlers.mjs +4 -25
- package/packages/core/release/next-development-projection.js +13 -13
- package/packages/core/release/passport/locations.js +13 -8
- package/packages/core/release/release-passport.js +70 -5
- package/packages/core/web/cli/badges.mjs +0 -4
- package/packages/core/web/publication-admission.js +1 -1
- package/packages/core/web/publication-capability.js +1 -1
- package/packages/core/web/readme-badges.js +1 -1
- package/packages/core/workflow/cli/main.mjs +1 -4
- package/packages/core/workflow/cli/process.mjs +1 -1
- package/packages/core/workflow/commands/buildchain-cli-help.mjs +2 -8
- package/packages/core/workflow/engine/conformance.js +1 -1
- package/packages/core/workflow/pipeline/build.js +21 -1
- package/packages/core/workflow/pipeline/delivery-observation.js +6 -2
- package/packages/core/workflow/workflow-taxonomy.mjs +61 -17
- package/scripts/check-code-layout.mjs +2 -0
- package/scripts/check-core-mechanism-inventory.mjs +29 -13
- package/scripts/check-floating-consumer-policy-contract.mjs +3 -3
- package/scripts/check-inventory.mjs +27 -27
- package/scripts/check-maintainability.mjs +28 -5
- package/scripts/check-public-dogfood-contract.mjs +3 -3
- package/scripts/check-release-topology.mjs +1 -1
- package/scripts/check-self-consumer-contract.mjs +7 -7
- package/scripts/check-universal-workflow-bootstrap.mjs +1 -1
- package/scripts/generate-channel-promotion-workflow.mjs +1 -1
- package/scripts/generate-minimal-consumer-contract.mjs +21 -1
- package/scripts/generate-site-bundle.mjs +2 -1
- package/scripts/generate-tail-reseal-fixture.mjs +3 -3
- package/scripts/inventory/promotion.mjs +1 -1
- package/scripts/next-development-self-dogfood-harness.mjs +1 -1
- package/scripts/next-development-self-dogfood.mjs +4 -4
- package/scripts/site-capability-metadata.mjs +2 -6
- package/scripts/source-metric-lineage.mjs +62 -7
- package/scripts/verify-golden-path.mjs +31 -35
- package/templates/native-dev-delivery.yml +1 -1
- package/templates/universal-buildchain-bootstrap.yml +1 -1
- package/packages/core/paper/operations/bootstrap.js +0 -75
- package/packages/core/paper/operations/plans.js +0 -213
- package/packages/core/paper/operations/provisioning.js +0 -113
- package/packages/core/paper/operations/scaffold-config.js +0 -77
- package/packages/core/paper/operations/scaffold-workflows.js +0 -116
- package/packages/core/paper/operations/workspace.js +0 -60
- 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
|
-
|
|
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
|
-
|
|
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
|
|
107
|
-
|
|
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
|
-
|
|
113
|
-
lockText
|
|
114
|
-
|
|
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
|
-
"
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
189
|
-
|
|
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
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
112
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
- \`
|
|
140
|
-
-
|
|
141
|
-
-
|
|
142
|
-
- \`.buildchain/
|
|
143
|
-
- \`.github/workflows/
|
|
144
|
-
- \`.github/workflows/
|
|
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
|
-
|
|
148
|
-
release
|
|
149
|
-
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
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
|
-
"
|
|
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 =
|
|
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:
|
|
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
|
|
344
|
-
const target =
|
|
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: "
|
|
374
|
-
command: `buildchain
|
|
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
|
-
|
|
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
|
-
|
|
439
|
-
?
|
|
440
|
-
: current === content
|
|
485
|
+
content === null
|
|
486
|
+
? current === undefined
|
|
441
487
|
? "unchanged"
|
|
442
|
-
: "
|
|
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
|
-
"
|
|
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:
|
|
562
|
+
writePaperMigration: applyPaperMigration,
|
|
572
563
|
writePaperScaffold: (plan) => writePaperScaffold(runtime, plan),
|
|
573
564
|
};
|
|
574
565
|
}
|