@kungfu-tech/buildchain 4.0.8 → 4.0.9-alpha.1

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 (57) hide show
  1. package/AGENTS.md +12 -19
  2. package/CONTRIBUTING.md +6 -9
  3. package/README.md +11 -1
  4. package/architecture/agent-change-map.md +11 -4
  5. package/architecture/build-environments.json +71 -0
  6. package/architecture/build-orchestration.json +18 -0
  7. package/architecture/ci-lane-change-budget.json +51 -2
  8. package/architecture/internal-capabilities.json +17 -4
  9. package/architecture/maintainability-debt.json +37 -126
  10. package/architecture/maintainability-policy.json +19 -210
  11. package/architecture/release-topology.json +9 -7
  12. package/architecture/universal-workflow-bootstrap.json +5 -4
  13. package/architecture/universal-workflow-train-admission.json +2 -2
  14. package/architecture/workflow-taxonomy.json +13 -0
  15. package/bin/buildchain.mjs +1 -1
  16. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
  17. package/dist/site/buildchain-contract.json +41 -1131
  18. package/dist/site/buildchain-site.json +48 -153
  19. package/dist/site/capability-registry.json +2 -2
  20. package/dist/site/cli-registry.json +1 -1
  21. package/dist/site/controller-registry.json +30 -868
  22. package/dist/site/kfd-claims.json +148 -396
  23. package/dist/site/kfd-upstream-aggregate.json +1 -1
  24. package/dist/site/manual-registry.json +7 -7
  25. package/dist/site/node-api-registry.json +37 -37
  26. package/dist/site/page-registry.json +36 -141
  27. package/dist/site/public-surface-audit.json +93 -402
  28. package/dist/site/publication-authority-registry.json +22 -1
  29. package/dist/site/publication-registry.json +4 -4
  30. package/dist/site/site-manifest.json +11 -11
  31. package/dist/site/workflow-registry.json +165 -391
  32. package/docs/MAP.md +5 -4
  33. package/docs/cli-reference.md +1 -1
  34. package/docs/getting-started.md +8 -7
  35. package/docs/node-api-reference.md +85 -85
  36. package/docs/release-governance.md +19 -18
  37. package/docs/reusable-build-surface.md +160 -1430
  38. package/docs/runtime-train-validation.md +45 -172
  39. package/docs/workflow-catalog.md +1 -0
  40. package/package.json +1 -1
  41. package/packages/core/build-configuration.js +117 -0
  42. package/packages/core/buildchain-config.js +2 -0
  43. package/packages/core/buildchain-contract.js +14 -44
  44. package/packages/core/buildchain-publication-authority.js +1 -0
  45. package/packages/core/controller-evidence.js +2 -9
  46. package/scripts/buildchain-cli-help.mjs +1 -1
  47. package/scripts/check-floating-consumer-policy-contract.mjs +4 -7
  48. package/scripts/check-inventory.mjs +91 -77
  49. package/scripts/check-maintainability.mjs +23 -8
  50. package/scripts/check-universal-workflow-bootstrap.mjs +12 -2
  51. package/scripts/generate-channel-build-workflow.mjs +50 -410
  52. package/scripts/generate-site-bundle.mjs +2 -1
  53. package/scripts/generate-universal-workflow-facades.mjs +1 -0
  54. package/scripts/init-repo.mjs +25 -26
  55. package/scripts/resolve-build-configuration.mjs +105 -0
  56. package/scripts/universal-workflow-self-dogfood.mjs +8 -1
  57. package/scripts/verify-golden-path.mjs +3 -3
@@ -6,183 +6,56 @@ doc_type: technical-reference
6
6
  source_level: local-files
7
7
  confidence: high
8
8
  sensitivity: public
9
- evidence_grade: A
9
+ evidence_grade: B
10
10
  review_state: unreviewed
11
- last_reviewed: 2026-07-31
11
+ last_reviewed: 2026-09-08
12
12
  ai_provenance:
13
- model_family: GPT-5
13
+ model_family: GPT-6
14
14
  product: Codex
15
- generated_at: 2026-07-31
15
+ generated_at: 2026-09-08
16
16
  invisible_context: not asserted
17
17
  ---
18
18
 
19
19
  # Runtime Train Validation
20
20
 
21
- Buildchain consumers should keep stable workflow refs such as `@v3` in
22
- committed workflow YAML. Runtime trains provide a temporary validation pointer
23
- for Buildchain changes that are ready for downstream testing but not yet
24
- promoted through the normal `dev -> alpha -> release` chain.
25
-
26
- Official floating channels are not runtime overrides. A consumer that
27
- deliberately follows `@v3-alpha` gets the matching runtime on pull requests and
28
- pushes because the reusable workflow reads the called workflow identity from
29
- `job.workflow_ref`. Passing `buildchain-ref: v3-alpha` explicitly is also
30
- accepted when the caller wants the channel binding visible in its input set.
31
- The caller's `github.workflow_ref` is not used for this inference because it
32
- identifies the caller workflow during reusable calls.
33
-
34
- ## Train refs
35
-
36
- A train ref is a branch in the Buildchain repository:
37
-
38
- ```text
39
- train/v3/v3.0/<capability>
40
- ```
41
-
42
- It is a validation pointer, not a release channel:
43
-
44
- - it does not move `v3`, `vX.Y`, `vX.Y-alpha`, exact tags, npm dist-tags, or
45
- production refs;
46
- - it must not be pinned as a long-term production dependency;
47
- - it should point at the Buildchain commit that downstream maintainers are
48
- expected to validate;
49
- - it is not a pending merge target or a delivery state;
50
- - the final durable path is still a pull request into the active `dev/*`
51
- channel, followed by the requested alpha or release promotion.
52
- - it may remain for a retention window after release so initiating repositories
53
- have a stable fast-use and rollback channel while stable refs, caches, or
54
- rollout windows settle.
55
-
56
- ## Buildchain contributor requirement
57
-
58
- When a Buildchain change needs downstream validation before stable refs move,
59
- publish a train ref before asking consumers to test it:
60
-
61
- ```sh
62
- git push origin HEAD:refs/heads/train/v3/v3.0/<capability>
63
- ```
64
-
65
- Use a capability slug that names the behavior being validated, for example:
66
-
67
- ```text
68
- train/v3/v3.0/runtime-loader
69
- train/v3/v3.0/toolkit-diagnostics
70
- train/v3/v3.0/site-source-of-truth
71
- ```
72
-
73
- The pull request or validation request should include the train ref, the exact
74
- commit SHA it points to, and the downstream evidence expected from consumers.
75
- If the train is refreshed, state the new SHA in the validation thread.
76
-
77
- After downstream validation succeeds, close out through the normal release
78
- path. Merge the Buildchain pull request into the active `dev/*` mainline, run
79
- the requested alpha or release promotion, and record the final mainline commit
80
- plus release ref or tag in the delivery thread. Do not leave the train as the
81
- item that still needs to be merged; it is only a temporary fast-use,
82
- diagnostic, and rollback channel for initiating repositories. Retained trains
83
- are cleaned up by a separate periodic Buildchain cleanup task.
84
-
85
- ## Formal artifact-signing authority ref
86
-
87
- Artifact signing uses a durable, channel-neutral authority ref after its
88
- runtime has passed downstream validation:
89
-
90
- ```text
91
- authority/v3/v3.0/artifact-signing
92
- ```
93
-
94
- Unlike a train, this ref is a protected execution boundary. Alpha and stable
95
- release intent use the same authority ref and the same
96
- `buildchain-artifact-signing` environment; channel promotion never selects a
97
- different certificate environment. Updates to the authority ref require a
98
- reviewed pull request, the normal `check` and `verify` status contexts, and a
99
- fast-forward-safe protected branch policy. Deletion and non-fast-forward
100
- updates are forbidden.
101
-
102
- The temporary `train/v3/v3.0/artifact-signing-authority` ref remains a bounded
103
- rollback and diagnostic pointer during migration. It is not the production
104
- identity and must not regain credential ownership.
105
-
106
- ## Consumer workflow requirement
107
-
108
- Consumers keep their reusable workflow pinned to the stable shell:
109
-
110
- ```yaml
111
- jobs:
112
- build:
113
- uses: kungfu-systems/buildchain/.github/workflows/.build.yml@v3
114
- ```
115
-
116
- To validate a train without committing temporary workflow refs, expose a
117
- trusted manual pass-through once:
118
-
119
- ```yaml
120
- on:
121
- workflow_dispatch:
122
- inputs:
123
- buildchain-ref:
124
- description: "Temporary Buildchain runtime ref for trusted manual validation"
125
- required: false
126
- default: ""
127
-
128
- jobs:
129
- build:
130
- uses: kungfu-systems/buildchain/.github/workflows/.build.yml@v3
131
- with:
132
- buildchain-ref: ${{ inputs.buildchain-ref || '' }}
133
- ```
134
-
135
- Buildchain initializes new package workflows with this pass-through. Existing
136
- consumers that do not have it should add it once before validating a train.
137
-
138
- ## Validation request
139
-
140
- Use this short request when a train is ready:
141
-
142
- ```text
143
- Buildchain train ready: buildchain-ref=train/v3/v3.0/<capability>.
144
- Keep uses: ...@v3; run workflow_dispatch with that buildchain-ref and report the runtime evidence summary.
145
- ```
146
-
147
- The consumer should run a trusted `workflow_dispatch`, paste the train ref into
148
- `buildchain-ref`, and report the workflow summary or aggregate Buildchain
149
- summary. The evidence should include:
150
-
151
- - workflow shell ref;
152
- - requested runtime ref;
153
- - resolved runtime ref;
154
- - resolved runtime SHA;
155
- - stability class;
156
- - trust decision;
157
- - rollback ref.
158
-
159
- ## Trust and limitation
160
-
161
- Official floating channel refs such as `v3` and `v3-alpha` may be selected on
162
- pull requests and pushes. Train refs and arbitrary exact-SHA overrides still
163
- fail closed unless the event is `workflow_dispatch` and the actor has write,
164
- maintain, or admin permission on the caller repository. Pull requests,
165
- including fork-originated pull requests, cannot use train or exact-SHA
166
- overrides.
167
-
168
- That permission does not create a third channel. A train, authority ref, or
169
- exact SHA must be bound to an alpha or stable shell lane, and the consumer lock
170
- must prove that same lane and major. Trusted overrides can replace the runtime
171
- coordinate for validation; they cannot combine a stable shell or lock with an
172
- alpha runtime, or the reverse.
173
-
174
- Runtime train validation covers Buildchain runtime scripts, CLI code, local
175
- actions, configuration parsing, and lifecycle behavior. It cannot validate
176
- changes that require the outer reusable workflow YAML itself to change, such as
177
- new jobs, permissions, workflow outputs, or matrix topology. Those changes need
178
- a canary workflow path or a temporary explicit workflow ref.
179
-
180
- ## v4 persisted-selector boundary
181
-
182
- For v4 consumers, never commit a train or exact SHA in a `uses` node. Keep the
183
- caller on `@v4` or `@v4-alpha`, retain both stable and alpha contract locks, and
184
- pass a temporary train/SHA only through the trusted `workflow_dispatch`
185
- `buildchain-ref` input. Consumer admission binds the selected lock to the exact
186
- workflow-shell commit while recording the separately resolved runtime SHA.
187
- Therefore a train can exercise candidate runtime code without weakening the
188
- durable floating-selector policy or masquerading as a channel promotion.
21
+ Ordinary builds use the public `build.yml@v4` or `build.yml@v4-alpha`
22
+ workflow and select all project settings from `buildchain.toml`. The called
23
+ workflow SHA also selects the runtime; there is no second runtime selector.
24
+ See [Reusable Build Surface](reusable-build-surface.md) for configuration,
25
+ zero-input calls and the optional nested-project locator.
26
+
27
+ ## Alpha qualification
28
+
29
+ Buildchain changes enter the protected development branch after review and
30
+ checks. Publish an alpha through the protected release workflow, then exercise
31
+ that public alpha on the exact consumer source. Record the called workflow SHA,
32
+ source SHA, channel-matching contract lock, configuration root and artifact
33
+ manifests. Promote stable only after the required alpha evidence succeeds.
34
+
35
+ For a breaking build-interface change, publish the producer before changing
36
+ its own public consumers. Retain the callers and locks for the currently
37
+ published interface while creating the first alpha from a successful PR-stage
38
+ candidate. Then migrate the callers and accept the published alpha contract,
39
+ qualify that public interface, and publish the completed alpha and stable.
40
+ This ordering adds no compatibility inputs to the new build workflow.
41
+
42
+ Source checks verify each consumer lock against the immutable source contract
43
+ at its accepted SHA. Hosted consumer admission separately verifies the actual
44
+ called floating workflow; unpublished producer code is not that dependency.
45
+
46
+ A train branch is a temporary diagnostic pointer, never a release channel or a
47
+ persisted consumer dependency. Ordinary builds do not accept train, SHA or
48
+ `buildchain-ref` inputs. Initialization does not create a runtime pass-through.
49
+
50
+ ## Specialized release and recovery
51
+
52
+ Release and recovery entry points retain their own bounded runtime admission
53
+ contracts. Their runtime override capability does not extend to ordinary builds.
54
+ Follow [Release Flow](release-flow.md) and the particular entry point's contract;
55
+ a diagnostic train does not authorize publication, signing, or floating-ref
56
+ movement. Preserve existing source locks, exact candidate lineage and terminal
57
+ receipts when recovering a release.
58
+
59
+ The Buildchain self-build callers exercise the public floating channels using
60
+ root or fixture TOML. They do not commit a private runtime selector to qualify
61
+ that channel.
@@ -130,6 +130,7 @@ all related declarations. Run `pnpm run generate:workflows` and
130
130
  | [self-build-public-consumer-dogfood.yml](../.github/workflows/self-build-public-consumer-dogfood.yml) | build | repository | active | V4 Public Consumer Dogfood | — |
131
131
  | [self-build-release-verify-compat.yml](../.github/workflows/self-build-release-verify-compat.yml) | build | repository | compatibility | Release - Verify | — |
132
132
  | [self-build-stable-candidate-qualification.yml](../.github/workflows/self-build-stable-candidate-qualification.yml) | build | repository | active | Buildchain Stable Candidate Qualification | — |
133
+ | [self-build-stable-dogfood.yml](../.github/workflows/self-build-stable-dogfood.yml) | build | repository | active | Buildchain Stable Self-Dogfood | — |
133
134
  | [self-build-verify.yml](../.github/workflows/self-build-verify.yml) | build | repository | active | Verify | — |
134
135
  | [self-ops-bootstrap-dogfood.yml](../.github/workflows/self-ops-bootstrap-dogfood.yml) | ops | repository | active | Universal Bootstrap Train-First Self-Dogfood | — |
135
136
  | [self-ops-dev-delivery.yml](../.github/workflows/self-ops-dev-delivery.yml) | ops | repository | active | Buildchain Dev Delivery | — |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kungfu-tech/buildchain",
3
- "version": "4.0.8",
3
+ "version": "4.0.9-alpha.1",
4
4
  "private": false,
5
5
  "description": "Buildchain Release Passport, release governance, CLI toolkit, and site facts.",
6
6
  "repository": "https://github.com/kungfu-systems/buildchain",
@@ -0,0 +1,117 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ // Project choices only. Provider endpoints, roles, runner labels and cache
5
+ // transport authority belong to the selected, runtime-owned environment.
6
+ const sections = {
7
+ tools: { node: "24", rust: "", go: "" },
8
+ artifacts: {
9
+ name: "buildchain-artifact", paths: ["dist", "build/stage"],
10
+ required_paths: [], min_files: 0, max_files: Number.MAX_SAFE_INTEGER,
11
+ min_total_bytes: 0, retention_days: 14, compression_level: 0,
12
+ release_candidate: false,
13
+ },
14
+ diagnostics: {
15
+ sample_process_tree: true, sample_interval_ms: 15000,
16
+ requested_parallelism: 0,
17
+ },
18
+ verification: { substage_evidence_path: "" },
19
+ finalization: { command: "", on_platform: false },
20
+ transport_smoke: { scenario_path: "", artifact_root: "." },
21
+ attestation: { subject_path: "", platform: "linux-x64" },
22
+ macos_signing: { app_path: "", platform: "macos-arm64" },
23
+ contract: {
24
+ compatibility_policy: "major-compatible",
25
+ drift_issue_mode: "compatible-and-breaking",
26
+ },
27
+ evidence: { gate_profile_path: "", candidate_family_path: "" },
28
+ };
29
+ const choices = {
30
+ "contract.compatibility_policy": ["major-compatible", "allow-additive", "exact"],
31
+ "contract.drift_issue_mode": ["off", "breaking-only", "compatible-and-breaking"],
32
+ };
33
+ const ranges = {
34
+ timeout_minutes: [1, 360],
35
+ "artifacts.retention_days": [1, 90],
36
+ "artifacts.compression_level": [0, 9],
37
+ "artifacts.min_files": [0, Number.MAX_SAFE_INTEGER],
38
+ "artifacts.max_files": [0, Number.MAX_SAFE_INTEGER],
39
+ "artifacts.min_total_bytes": [0, Number.MAX_SAFE_INTEGER],
40
+ "diagnostics.sample_interval_ms": [100, 3600000],
41
+ "diagnostics.requested_parallelism": [0, 1024],
42
+ };
43
+
44
+ function table(value, label) {
45
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
46
+ throw new Error(`${label} must be a table`);
47
+ }
48
+ return value;
49
+ }
50
+
51
+ function fields(value, defaults, prefix) {
52
+ table(value, `build.${prefix}`);
53
+ for (const key of Object.keys(value)) {
54
+ if (!Object.hasOwn(defaults, key)) throw new Error(`Unknown build.${prefix}${key}`);
55
+ }
56
+ return Object.fromEntries(Object.entries(defaults).map(([key, fallback]) => {
57
+ const label = `${prefix}${key}`;
58
+ const selected = value[key] === undefined ? structuredClone(fallback) : value[key];
59
+ const valid = Array.isArray(fallback)
60
+ ? Array.isArray(selected) && selected.every((item) => typeof item === "string" && item.trim())
61
+ : typeof selected === typeof fallback;
62
+ if (!valid || (typeof selected === "string" && /\0/u.test(selected))) {
63
+ throw new Error(`Invalid build.${label} type or multiline value`);
64
+ }
65
+ if (ranges[label] && (!Number.isInteger(selected) || selected < ranges[label][0] || selected > ranges[label][1])) {
66
+ throw new Error(`build.${label} must be an integer in ${ranges[label].join("..")}`);
67
+ }
68
+ if (choices[label] && !choices[label].includes(selected)) throw new Error(`Invalid build.${label}: ${selected}`);
69
+ return [key, selected];
70
+ }));
71
+ }
72
+
73
+ export function normalizeBuildConfiguration(value = {}) {
74
+ table(value, "build");
75
+ const { environment = "github-hosted", fail_fast = false, timeout_minutes = 120, ...groups } = value;
76
+ const result = fields({ environment, fail_fast, timeout_minutes }, { environment: "github-hosted", fail_fast: false, timeout_minutes: 120 }, "");
77
+ if (!/^[a-z][a-z0-9-]*$/u.test(result.environment)) throw new Error("Invalid build.environment profile name");
78
+ for (const name of Object.keys(groups)) {
79
+ if (!Object.hasOwn(sections, name)) throw new Error(`Unknown build.${name}`);
80
+ }
81
+ for (const [name, defaults] of Object.entries(sections)) {
82
+ result[name] = fields(groups[name] === undefined ? {} : groups[name], defaults, `${name}.`);
83
+ }
84
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/u.test(result.artifacts.name)) throw new Error("Invalid build.artifacts.name");
85
+ if (result.artifacts.min_files > result.artifacts.max_files) throw new Error("build.artifacts.min_files exceeds max_files");
86
+ return result;
87
+ }
88
+
89
+ export function containedBuildPath(root, relative) {
90
+ if (typeof relative !== "string" || !relative || path.isAbsolute(relative) || relative.includes("\\") || /[\r\n\0]/u.test(relative) || relative.split("/").includes("..")) {
91
+ throw new Error("Build configuration paths must remain repository-relative");
92
+ }
93
+ const resolved = path.resolve(root, relative);
94
+ const realRoot = fs.realpathSync(root);
95
+ // Reject symlink escape through any existing parent, including a missing leaf.
96
+ let ancestor = resolved;
97
+ while (!fs.existsSync(ancestor)) ancestor = path.dirname(ancestor);
98
+ const realAncestor = fs.realpathSync(ancestor);
99
+ if (realAncestor !== realRoot && !realAncestor.startsWith(`${realRoot}${path.sep}`)) {
100
+ throw new Error(`Build configuration path escapes repository: ${relative}`);
101
+ }
102
+ return resolved;
103
+ }
104
+
105
+ export function discoverBuildConfiguration(root, locator = "") {
106
+ const candidates = locator ? [locator] : [".buildchain/buildchain.toml", "buildchain.toml"];
107
+ const found = candidates.filter((candidate) => fs.existsSync(containedBuildPath(root, candidate)));
108
+ if (found.length !== 1) throw new Error(`Expected one buildchain.toml; found ${found.length}. Use config-path for a project outside the repository root.`);
109
+ const configPath = found[0];
110
+ if (path.basename(configPath) !== "buildchain.toml") throw new Error("config-path must locate a project's buildchain.toml");
111
+ const directory = path.posix.dirname(configPath);
112
+ const cwd = path.posix.basename(directory) === ".buildchain" ? path.posix.dirname(directory) : directory;
113
+ // Lifecycle and planning must discover the same file, never a second config.
114
+ const projectConfigs = [".buildchain/buildchain.toml", "buildchain.toml"].filter((candidate) => fs.existsSync(containedBuildPath(root, path.posix.join(cwd, candidate))));
115
+ if (projectConfigs.length !== 1) throw new Error("Ambiguous project configuration");
116
+ return { configPath, cwd };
117
+ }
@@ -8,6 +8,7 @@ import {
8
8
  resolveBuildchainConfigPath,
9
9
  } from "./buildchain-layout.js";
10
10
  import { runShellCommandSync } from "./spawn-command.js";
11
+ import { normalizeBuildConfiguration } from "./build-configuration.js";
11
12
 
12
13
  const CONFIG_FILE = BUILDCHAIN_CONFIG_PATH;
13
14
  const RESERVED_LIFECYCLE_KEYS = new Set(["env", "shell"]);
@@ -206,6 +207,7 @@ export function loadBuildchainConfig(cwd = process.cwd()) {
206
207
  export function normalizeBuildchainConfig(config) {
207
208
  assertPlainObject(config, CONFIG_FILE);
208
209
  const normalized = { ...config };
210
+ if (normalized.build !== undefined) normalized.build = normalizeBuildConfiguration(normalized.build);
209
211
  if (normalized.project !== undefined) {
210
212
  normalized.project = normalizeProjectSection(normalized.project);
211
213
  }
@@ -236,24 +236,11 @@ export function createBuildchainContractWorld({
236
236
  "release-candidate-artifact",
237
237
  ],
238
238
  breakingDefaults: {
239
- buildchainRefDefault: "workflow-shell-ref-or-v3",
240
- promoteOnlyHeavyBuildPolicy: "pr-stage-only",
239
+ configurationAuthority: "buildchain.toml",
240
+ runtimeIdentity: "exact-called-workflow",
241
+ projectDiscovery: "unambiguous-root-or-config-path",
241
242
  },
242
- optionalInputs: [
243
- "buildchain-ref",
244
- "runner-preset",
245
- "platforms-json",
246
- "release-candidate",
247
- "github-artifact-attestation-subject-path",
248
- "github-artifact-attestation-platform-id",
249
- "artifact-transfer-mode",
250
- "checkout-cache-mode",
251
- "checkout-cache-fallback",
252
- "checkout-cache-timeout-seconds",
253
- "checkout-cache-fetch-attempts",
254
- "buildchain-contract-lock-path",
255
- "buildchain-contract-drift-issue-mode",
256
- ],
243
+ optionalInputs: ["config-path"],
257
244
  guarantees: [
258
245
  "runtime floating refs are resolved to immutable SHAs before matrix jobs",
259
246
  "publish source locks are verified before heavy build jobs",
@@ -270,26 +257,17 @@ export function createBuildchainContractWorld({
270
257
  requiredInputs: [],
271
258
  requiredOutputs: ["buildchain-channel", "buildchain-runtime-sha", "build-summary-artifact"],
272
259
  breakingDefaults: {
273
- channelDefault: "auto",
274
- developmentDefault: "alpha",
275
- prereleaseDefault: "alpha",
276
- stableReleaseDefault: "stable",
277
- ambiguousReleasePolicy: "fail-closed",
260
+ configurationAuthority: "buildchain.toml",
261
+ runtimeIdentity: "exact-called-workflow",
262
+ projectDiscovery: "unambiguous-root-or-config-path",
278
263
  },
279
- optionalInputs: [
280
- "buildchain-channel",
281
- "buildchain-ref",
282
- "buildchain-alpha-contract-lock-path",
283
- "buildchain-stable-contract-lock-path",
284
- "buildchain-contract-lock-path",
285
- ],
264
+ optionalInputs: ["config-path"],
286
265
  guarantees: [
287
- "consumers declare one build job while Buildchain selects the matching generic major channel",
288
- "development and prerelease intent select vN-alpha",
289
- "stable release intent selects vN",
290
- "ambiguous release-like intent fails before build jobs",
291
- "explicit train and exact-SHA overrides retain the reusable build trust gate",
292
- "alpha and stable channel selections use separate consumer contract locks by default",
266
+ "single-project consumers require no workflow inputs",
267
+ "project settings have one TOML authority and environment profiles own infrastructure",
268
+ "the called floating ref determines channel and exact runtime SHA",
269
+ "stable and alpha select their matching repository contract locks",
270
+ "source, runtime and configuration roots are bound before the build matrix",
293
271
  ],
294
272
  }),
295
273
  surface(root, devDeliveryWorkflowContractSurface(pkg, majorLine)),
@@ -837,7 +815,7 @@ export function createBuildchainContractWorld({
837
815
  requiredStages: descriptor.expected.stages.filter((stage) => stage.required).map((stage) => stage.id),
838
816
  capabilities: descriptor.expected.capabilities,
839
817
  evidenceRequirements: descriptor.expected.evidence,
840
- inputClassificationPolicy: "buildchain-controller-input-policy/v1",
818
+ inputClassificationPolicy: descriptor.id === "build-lifecycle" ? "buildchain-configured-controller-input-policy/v1" : "buildchain-controller-input-policy/v1",
841
819
  },
842
820
  optionalInputs: Object.keys(descriptor.inputs),
843
821
  controllerDescriptor: {
@@ -846,14 +824,6 @@ export function createBuildchainContractWorld({
846
824
  registryDigest: resolvedControllerRegistry.digest,
847
825
  inputClassifications: descriptor.inputs,
848
826
  },
849
- ...(descriptor.id === "build-lifecycle"
850
- ? {
851
- compatibleBreakingDigests: [
852
- "sha256:e264a79f9f399038c2fcfd21e4168c68c2e1485ee5c651c02242a02b622ac2be",
853
- "sha256:30745921541e9b0f70475bb2178c2559f6aef248f6680670ccd44d8c5a69a6b1",
854
- ],
855
- }
856
- : {}),
857
827
  guarantees: [
858
828
  "plans bind exact consumer source SHA, exact Buildchain runtime SHA, and the runtime contract digest",
859
829
  "receipts bind the plan digest and preserve pass, fail, skip, and partial stage outcomes",
@@ -24,6 +24,7 @@ const DESCRIPTORS = Object.freeze([
24
24
  [".github/workflows/build.yml", "non-publication-oidc"],
25
25
  [".github/workflows/bootstrap.yml", "product-publication", true, ["universal-candidate-execution"], "caller-secrets", "none", "fixed", "caller-bound"],
26
26
  [".github/workflows/self-build-alpha-dogfood.yml", "non-publication-oidc"],
27
+ [".github/workflows/self-build-stable-dogfood.yml", "non-publication-oidc"],
27
28
  [".github/workflows/self-ops-dev-delivery.yml", "governance-write"],
28
29
  [".github/workflows/self-ops-patrol-daily.yml", "governance-write"],
29
30
  [".github/workflows/self-ops-patrol-monthly.yml", "governance-write"],
@@ -22,6 +22,7 @@ const CONTROLLER_SPECS = [
22
22
  id: "build-lifecycle",
23
23
  workflowId: ".build",
24
24
  version: 1,
25
+ derivedInputs: { "configuration-root": { classification: "included", source: "resolved-build-plan" } },
25
26
  capabilities: [
26
27
  "source-lock",
27
28
  "lifecycle-build",
@@ -47,15 +48,6 @@ const CONTROLLER_SPECS = [
47
48
  "controller-receipt",
48
49
  ],
49
50
  },
50
- {
51
- id: "build-channel-router",
52
- workflowId: "build",
53
- version: 1,
54
- capabilities: ["channel-selection", "runtime-selection", "build-delegation"],
55
- stages: ["resolve-channel", "override", "alpha", "stable", "aggregate"],
56
- optionalStages: ["override", "alpha", "stable"],
57
- evidence: ["nested-controller-receipt", "controller-receipt"],
58
- },
59
51
  {
60
52
  id: "shifu-gate-profile-envelope",
61
53
  workflowId: ".gate-profile",
@@ -208,6 +200,7 @@ export function createControllerRegistry({ workflows = [] } = {}) {
208
200
  classification: classifyInput(name, secrets),
209
201
  source: secrets.has(name) ? "workflow-call-secret" : "workflow-call-input",
210
202
  }]));
203
+ Object.assign(inputs, spec.derivedInputs || {});
211
204
  for (const [name, policy] of Object.entries(workflow.inputPolicies || {})) {
212
205
  if (!inputs[name]) throw new Error(`controller ${spec.id} input policy references undeclared input ${name}`);
213
206
  inputs[name] = { ...inputs[name], ...policy };
@@ -24,7 +24,7 @@ export const BUILDCHAIN_USAGE = `Usage:
24
24
  buildchain candidate timeline --input <file-or-json> [--output <file>] [--json]
25
25
  buildchain init [--cwd <dir>] [--type package|native|web-surface|infra-contract|publication-artifact|anchored-package] [--force]
26
26
  [--package-manager pnpm|npm|yarn] [--runner-preset <preset>]
27
- [--artifact-name <template>]
27
+ [--artifact-name <name>]
28
28
  buildchain validate [--cwd <dir>] [--require-version-state]
29
29
  [--require-lifecycle-stages <comma-list>]
30
30
  buildchain lifecycle run <stage> [--cwd <dir>] [--required]
@@ -123,15 +123,12 @@ export function checkFloatingConsumerPolicyContract() {
123
123
  ]);
124
124
  const buildWorkflow = read(".github/workflows/.build.yml");
125
125
  if (
126
- !buildWorkflow.includes("Normalize v3 expected identity aliases") ||
126
+ buildWorkflow.includes("Normalize v3 expected identity aliases") ||
127
+ buildWorkflow.includes("buildchain-expected-channel:") ||
127
128
  !buildWorkflow.includes(
128
- "buildchain-contract-expected-channel conflicts with buildchain-expected-channel",
129
+ "BUILDCHAIN_EXPECTED_INVOCATION_CHANNEL: ${{ fromJSON(needs.configure.outputs.plan-json).identity.channel }}",
129
130
  ) ||
130
- !buildWorkflow.includes(
131
- "BUILDCHAIN_EXPECTED_INVOCATION_CHANNEL: ${{ steps.expected-identity.outputs.expected-channel }}",
132
- ) ||
133
- buildWorkflow.indexOf("Normalize v3 expected identity aliases") >
134
- buildWorkflow.indexOf("Enforce v4 floating consumer policy")
131
+ !buildWorkflow.includes("BUILDCHAIN_WORKFLOW_SHA: ${{ job.workflow_sha }}")
135
132
  )
136
133
  fail("channel builds must disambiguate dual-channel caller invocations");
137
134
  assertTrustGatedJobs(read(".github/workflows/.build.yml"), [