@kungfu-tech/buildchain 2.3.1-alpha.0 → 2.3.1-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.
package/AGENTS.md CHANGED
@@ -36,6 +36,10 @@ See [`docs/cli.md`](docs/cli.md), [`docs/lifecycle-protocol.md`](docs/lifecycle-
36
36
  and [`docs/reusable-build-surface.md`](docs/reusable-build-surface.md) for the
37
37
  consumer contract.
38
38
 
39
+ For temporary validation of an unreleased Buildchain runtime, keep the committed
40
+ workflow ref on `@v2` and use the trusted `workflow_dispatch` `buildchain-ref`
41
+ pass-through. See [`docs/runtime-train-validation.md`](docs/runtime-train-validation.md).
42
+
39
43
  ## Building this repo
40
44
 
41
45
  Buildchain is a pnpm workspace running on Node 24:
@@ -52,6 +56,13 @@ and rebuilds every action bundle.
52
56
  ## Proposing changes
53
57
 
54
58
  - Open pull requests against the relevant `dev/*` channel branch.
59
+ - If a Buildchain change needs downstream validation before stable refs move,
60
+ publish a `train/v2/v2.3/<capability>` ref and include the validation request
61
+ described in [`docs/runtime-train-validation.md`](docs/runtime-train-validation.md).
62
+ After validation succeeds, do not leave the train as a pending merge item:
63
+ merge the pull request into the active `dev/*` mainline and run the requested
64
+ alpha or release promotion. The train may remain for a retention window as a
65
+ fast-use and rollback channel; periodic cleanup handles old trains.
55
66
  - Write commit messages and PR descriptions in English, using lightweight
56
67
  [Conventional Commits](https://www.conventionalcommits.org/)
57
68
  (`type(scope): summary`).
package/CONTRIBUTING.md CHANGED
@@ -103,14 +103,24 @@ release/vX/vX.Y -> publish-gate/major
103
103
  ```
104
104
 
105
105
  - Open normal changes against the relevant `dev/*` branch.
106
+ - When a Buildchain change needs downstream validation before stable refs move,
107
+ publish a temporary runtime train ref such as
108
+ `train/v2/v2.3/<capability>` and ask consumers to run trusted
109
+ `workflow_dispatch` with `buildchain-ref` set to that train. Keep the pull
110
+ request against the `dev/*` branch; the train is only a validation pointer,
111
+ not a pending merge target. After validation succeeds, merge into the active
112
+ `dev/*` mainline and run the requested alpha or release promotion. The train
113
+ may remain for a retention window as a fast-use and rollback channel; old
114
+ trains are cleaned by a separate periodic cleanup task.
106
115
  - Merging into `alpha/*`, `release/*`, or `publish-gate/major` expresses a
107
116
  release intent. Buildchain promotion then creates version-state commits,
108
117
  exact tags, floating tags, npm publish evidence, and next-alpha state.
109
118
  - Manual promotion dispatch is dry-run only; non-dry-run promotion follows a
110
119
  successful protected workflow path.
111
120
 
112
- See [`docs/release-governance.md`](docs/release-governance.md) and
113
- [`docs/release-flow.md`](docs/release-flow.md).
121
+ See [`docs/release-governance.md`](docs/release-governance.md),
122
+ [`docs/release-flow.md`](docs/release-flow.md), and
123
+ [`docs/runtime-train-validation.md`](docs/runtime-train-validation.md).
114
124
 
115
125
  ## License
116
126
 
package/README.md CHANGED
@@ -85,6 +85,27 @@ const report = verifyBuildchainLogEvents({
85
85
  The package also ships `dist/site/` as the Buildchain-owned fact source for
86
86
  `buildchain.libkungfu.dev`.
87
87
 
88
+ Native build consumers can import the diagnostics toolkit instead of copying
89
+ repository-local probes:
90
+
91
+ ```js
92
+ import {
93
+ collectBuildchainDiagnostics,
94
+ collectRunnerDiagnostics,
95
+ writeDiagnosticsArtifact,
96
+ } from "@kungfu-tech/buildchain/diagnostics";
97
+
98
+ writeDiagnosticsArtifact(".buildchain/artifacts/diagnostics.json", {
99
+ contract: "consumer-build-diagnostics",
100
+ buildchain: collectBuildchainDiagnostics({ cwd: process.cwd() }),
101
+ runner: collectRunnerDiagnostics(),
102
+ });
103
+ ```
104
+
105
+ `buildchain lifecycle run` writes a small `diagnostics.json` next to the
106
+ platform manifest. It includes lifecycle-wide observability, runner/tool/cache
107
+ snapshots, Git state, and links to the larger manifest and artifact outputs.
108
+
88
109
  ## Use Buildchain
89
110
 
90
111
  Bootstrap a repository:
@@ -101,6 +101,31 @@ trusted channel workflow:
101
101
  ]
102
102
  ```
103
103
 
104
+ For anchored/manual package repositories that build through the reusable
105
+ workflow, keep the publish entrypoint on the `publish-gate/*` source-lock
106
+ contract:
107
+
108
+ ```yaml
109
+ - uses: kungfu-systems/buildchain/actions/promote-buildchain-ref@v2
110
+ with:
111
+ token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}
112
+ sha: ${{ needs.build.outputs.publish-source-sha }}
113
+ target-ref: release/v22/v22.22
114
+ require-publish-source-lock: "true"
115
+ publish-source-ref: ${{ needs.build.outputs.publish-source-ref }}
116
+ publish-source-sha: ${{ needs.build.outputs.publish-source-sha }}
117
+ publish-source-locked: ${{ needs.build.outputs.publish-source-locked }}
118
+ publish-transaction: "true"
119
+ publish-mode: publish-final-version
120
+ publish-auth: trusted-publishing
121
+ ```
122
+
123
+ `target-ref` remains the channel promotion target that must point at `sha`.
124
+ `publish-source-ref` is the reviewed source-lock branch that authorized this
125
+ specific package publication. Direct `alpha/*` or `release/*` channel refs are
126
+ not valid publish source locks when `require-publish-source-lock` is enabled,
127
+ and a mismatched `publish-source-sha` fails before any promotion or publish side effects begin.
128
+
104
129
  When enabled, the action creates or resumes a release transaction keyed by
105
130
  repository, version, source SHA, and target ref. It persists that transaction to
106
131
  a machine-managed branch under `buildchain/release-state/<version>`, with
@@ -144,10 +169,23 @@ BUILDCHAIN_PUBLISH_EVIDENCE
144
169
  The action outputs `transaction-id`, `transaction-state`,
145
170
  `transaction-exact-tag`, `transaction-release-sha`, `transaction-state-ref`,
146
171
  `transaction-state-sha`, `transaction-state-path`, `publish-evidence-path`, and
147
- `finalization-needed`. `transaction-state-ref` is the durable recovery location.
172
+ `release-passport-path`, `release-passport-output-dir`,
173
+ `release-passport-state-sha`, and `finalization-needed`.
174
+ `transaction-state-ref` is the durable recovery location.
175
+ `release-passport-state-sha` is the durable ref commit after the generated
176
+ `release-passport/*` files have been uploaded into that recovery ref.
148
177
  `finalization-needed=true` means publish evidence is valid, but protected branch
149
178
  or ref finalization needs a later promotion run.
150
179
 
180
+ After a publish transaction reaches `complete`, the action generates the unified
181
+ `buildchain-release-passport` in `.buildchain/release-passport` by default and
182
+ persists those files under `release-passport/` in the durable release-state ref.
183
+ When present, the passport includes the aggregate build summary, platform
184
+ artifact manifests, npm publish evidence, dist-tag promotion evidence, the
185
+ release-state ref, trusted publishing metadata, and the Buildchain transaction
186
+ result. Set `release-passport: "false"` only for a controlled recovery run that
187
+ must skip passport generation.
188
+
151
189
  Finalization recovery is anchored to the durable transaction, not to a single
152
190
  workflow run SHA. After a generated version-state PR is merged, the current
153
191
  channel head can be a merge commit that contains or corresponds to the recorded
@@ -39,3 +39,23 @@ with:
39
39
  expected-artifacts-json: >-
40
40
  {"minFiles":2,"requiredPaths":["dist/app.tar.gz","dist/checksums.txt"]}
41
41
  ```
42
+
43
+ For long native builds, set `sample-process-tree: "true"` and pass
44
+ `process-summary-path`. The action wraps either the explicit `command` or the
45
+ configured lifecycle stage with `buildchain sample process-tree`, then embeds
46
+ the produced summary in the lifecycle diagnostics artifact:
47
+
48
+ ```yaml
49
+ with:
50
+ stage: build
51
+ sample-process-tree: "true"
52
+ process-summary-path: .buildchain/diagnostics/process-summary.json
53
+ ```
54
+
55
+ Custom wrappers can still pass an existing sampler report or summary with
56
+ `process-summary-path`; the action reads it after the lifecycle command
57
+ finishes, so commands may generate the file during the same invocation.
58
+ Set `process-summary-required: "false"` when the summary is an optional sidecar,
59
+ for example when a reusable workflow may skip an optional build stage.
60
+ The diagnostics directory also includes `diagnostics-manifest.json`, a compact
61
+ inventory of the diagnostics sidecars with byte counts and sha256 hashes.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { spawnSync } from "node:child_process";
2
+ import { spawn, spawnSync } from "node:child_process";
3
3
  import crypto from "node:crypto";
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
@@ -24,6 +24,14 @@ import {
24
24
  explainReleasePassport,
25
25
  verifyReleasePassport,
26
26
  } from "../packages/core/release-passport.js";
27
+ import {
28
+ BUILDCHAIN_PROCESS_SAMPLE_REPORT_CONTRACT,
29
+ formatDiagnosticsSummaryTable,
30
+ startProcessSampler,
31
+ summarizeDiagnosticsArtifacts,
32
+ summarizeProcessSamples,
33
+ validateAnchoredPackageRelease,
34
+ } from "../packages/core/diagnostics.js";
27
35
 
28
36
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
29
37
  const embeddedPackageVersion = process.env.BUILDCHAIN_EMBEDDED_PACKAGE_VERSION || "";
@@ -39,6 +47,7 @@ function usage() {
39
47
  [--require-lifecycle-stages <comma-list>]
40
48
  buildchain lifecycle run <stage> [--cwd <dir>] [--required]
41
49
  [--artifact-name <name>] [--artifact-path <path>]...
50
+ [--process-summary <json>]
42
51
  buildchain npm dry-run [--cwd <dir>] [--expected-tag <tag>] [--registry <url>]
43
52
  [--dist-tag <tag>] [--skip-npm-publish-dry-run] [--json]
44
53
  buildchain release --dry-run --target-ref <ref> [--sha <sha>] [--source-ref <ref>]
@@ -51,7 +60,17 @@ function usage() {
51
60
  buildchain transaction inspect ...
52
61
  buildchain collect github-release --tag <tag> [--repository <owner/repo>]
53
62
  [--assets-dir <dir>] [--assets-json <json-or-path>]
54
- [--release-json <json-or-path>] [--output-dir <dir>] [--json]
63
+ [--release-json <json-or-path>] [--package-set-json <json-or-path>]
64
+ [--product-name <name>]
65
+ [--publish-evidence-json <json-or-path>]
66
+ [--trusted-publishing-json <json-or-path>]
67
+ [--transaction-json <json-or-path>]
68
+ [--anchor-manifest-json <json-or-path>]
69
+ [--build-summary-json <json-or-path>]
70
+ [--platform-manifest-json <json-or-path>]...
71
+ [--dist-tag-evidence-json <json-or-path>]
72
+ [--release-extra-json <json-or-path>]
73
+ [--publish-json <json-or-path>] [--output-dir <dir>] [--json]
55
74
  buildchain verify release-passport <file-or-url> [--json]
56
75
  buildchain verify observability-log <jsonl> [--min-events <n>]
57
76
  [--require-phase <csv>]
@@ -59,17 +78,23 @@ function usage() {
59
78
  [--require-event <csv>] [--allow-errors] [--json]
60
79
  buildchain explain release --passport <file-or-url> [--for human|agent] [--json]
61
80
  buildchain inspect release --passport <file-or-url> [--json]
62
- buildchain doctor [--cwd <dir>] [--json]
81
+ buildchain doctor [--cwd <dir>] [--require-publish-source-lock] [--json]
63
82
  buildchain log <info|warn|error> --event <name> [--phase <phase>]
64
83
  [--component <name>] [--source <name>] [--attribute key=value]...
65
84
  [--path <jsonl>] [--json]
66
85
  buildchain log summary [--path <jsonl>] [--json]
86
+ buildchain diagnostics summary <diagnostics.json>... [--artifact <file>]...
87
+ [--output <file>] [--json]
88
+ buildchain sample process-tree [--interval-ms <n>] [--label <name>]
89
+ [--output <jsonl>] [--summary-output <json>]
90
+ [--requested-parallelism <n>] [--json]
91
+ -- <command> [args...]
67
92
  buildchain mark --event <name> [--phase <phase>] [--component <name>]
68
93
  [--attribute key=value]... [--path <jsonl>] [--json]
69
94
  buildchain span --event <name> [--phase <phase>] [--component <name>]
70
95
  [--path <jsonl>] -- <command> [args...]
71
96
  buildchain web-surface ...
72
- buildchain publish-source <lock|manifest|verify-lock> ...
97
+ buildchain publish-source <lock|manifest|verify-lock|validate-anchored-release> ...
73
98
  buildchain build-contract ...
74
99
 
75
100
  Examples:
@@ -140,14 +165,15 @@ function checkStatus(ok, id, message, details = {}) {
140
165
  return { id, status: ok ? "pass" : "fail", message, details };
141
166
  }
142
167
 
143
- function runDoctor({ cwd = process.cwd() } = {}) {
168
+ function runDoctor({ cwd = process.cwd(), requirePublishSourceLock = false } = {}) {
144
169
  const resolvedCwd = path.resolve(cwd);
145
170
  const checks = [];
146
171
  checks.push(checkStatus(fs.existsSync(resolvedCwd), "cwd.exists", "working directory exists", { cwd: resolvedCwd }));
172
+ let validation;
147
173
  try {
148
- const validation = validateBuildchainConfig(resolvedCwd);
174
+ validation = validateBuildchainConfig(resolvedCwd);
149
175
  checks.push(checkStatus(true, "config.valid", "buildchain.toml is valid", {
150
- projectType: validation.project.type,
176
+ projectType: validation.project?.type || "",
151
177
  lifecycleStages: validation.lifecycleStages.map((stage) => stage.name),
152
178
  }));
153
179
  } catch (error) {
@@ -168,6 +194,22 @@ function runDoctor({ cwd = process.cwd() } = {}) {
168
194
  checks.push(checkStatus(fs.existsSync(workflowPath), "workflow.build", "reusable workflow caller exists", {
169
195
  path: ".github/workflows/build.yml",
170
196
  }));
197
+ if (validation?.version?.strategy === "anchored" && validation.version.next === "manual") {
198
+ const anchored = validateAnchoredPackageRelease({
199
+ cwd: resolvedCwd,
200
+ requirePublishGateSourceLock: requirePublishSourceLock,
201
+ });
202
+ checks.push(checkStatus(
203
+ anchored.ok,
204
+ "anchored-package-release.valid",
205
+ "anchored package release contract is valid",
206
+ {
207
+ contract: anchored.contract,
208
+ summary: anchored.summary,
209
+ checks: anchored.checks,
210
+ },
211
+ ));
212
+ }
171
213
  return {
172
214
  schemaVersion: 1,
173
215
  contract: "kungfu-buildchain-doctor",
@@ -195,6 +237,61 @@ function printJson(value) {
195
237
  process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
196
238
  }
197
239
 
240
+ function writeJsonFile(filePath, value) {
241
+ if (!filePath) {
242
+ return "";
243
+ }
244
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
245
+ fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
246
+ return filePath;
247
+ }
248
+
249
+ function appendJsonLine(filePath, value) {
250
+ if (!filePath) {
251
+ return "";
252
+ }
253
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
254
+ fs.appendFileSync(filePath, `${JSON.stringify(value)}\n`);
255
+ return filePath;
256
+ }
257
+
258
+ function readIntegerFlag(args, name, fallback = 0) {
259
+ const value = readFlag(args, name, "");
260
+ if (!value) {
261
+ return fallback;
262
+ }
263
+ const parsed = Number(value);
264
+ if (!Number.isInteger(parsed) || parsed < 0) {
265
+ throw new Error(`--${name} must be a non-negative integer`);
266
+ }
267
+ return parsed;
268
+ }
269
+
270
+ function readDiagnosticsArtifactInputs(args) {
271
+ const values = [];
272
+ for (let index = 0; index < args.length; index += 1) {
273
+ const entry = args[index];
274
+ if (entry === "--artifact") {
275
+ const value = args[index + 1];
276
+ if (!value || value.startsWith("--")) {
277
+ throw new Error("buildchain diagnostics summary --artifact requires a file path");
278
+ }
279
+ values.push(value);
280
+ index += 1;
281
+ continue;
282
+ }
283
+ if (entry === "--output") {
284
+ index += 1;
285
+ continue;
286
+ }
287
+ if (entry === "--json") {
288
+ continue;
289
+ }
290
+ values.push(entry);
291
+ }
292
+ return values;
293
+ }
294
+
198
295
  function packageVersion() {
199
296
  if (embeddedPackageVersion) {
200
297
  return embeddedPackageVersion;
@@ -203,6 +300,81 @@ function packageVersion() {
203
300
  return packageJson.version;
204
301
  }
205
302
 
303
+ async function runProcessTreeSample(sampleArgs = []) {
304
+ const separator = sampleArgs.indexOf("--");
305
+ const optionArgs = separator === -1 ? sampleArgs : sampleArgs.slice(0, separator);
306
+ const commandArgs = separator === -1 ? [] : sampleArgs.slice(separator + 1);
307
+ if (commandArgs.length === 0) {
308
+ throw new Error("usage: buildchain sample process-tree -- <command> [args...]");
309
+ }
310
+ const command = commandArgs[0];
311
+ const args = commandArgs.slice(1);
312
+ const label = readFlag(optionArgs, "label", "process-tree");
313
+ const intervalMs = readIntegerFlag(optionArgs, "interval-ms", 15000);
314
+ const requestedParallelism = readIntegerFlag(optionArgs, "requested-parallelism", 0);
315
+ const outputPath = readFlag(optionArgs, "output", ".buildchain/diagnostics/process-samples.jsonl");
316
+ const summaryOutputPath = readFlag(optionArgs, "summary-output", ".buildchain/diagnostics/process-summary.json");
317
+ const startedAt = Date.now();
318
+ const child = spawn(command, args, {
319
+ cwd: process.cwd(),
320
+ env: process.env,
321
+ stdio: "inherit",
322
+ });
323
+ const sampler = startProcessSampler({
324
+ rootPid: child.pid || process.pid,
325
+ intervalMs,
326
+ label,
327
+ command,
328
+ args,
329
+ env: process.env,
330
+ requestedParallelism,
331
+ onSample(sample) {
332
+ appendJsonLine(outputPath, sample);
333
+ },
334
+ });
335
+ const result = await new Promise((resolve) => {
336
+ child.on("error", (error) => resolve({ error, status: 1, signal: "" }));
337
+ child.on("close", (status, signal) => resolve({ status, signal: signal || "" }));
338
+ });
339
+ const samples = sampler.stop();
340
+ const summary = summarizeProcessSamples({
341
+ samples,
342
+ command,
343
+ args,
344
+ env: process.env,
345
+ requestedParallelism,
346
+ });
347
+ const report = {
348
+ schemaVersion: 1,
349
+ contract: BUILDCHAIN_PROCESS_SAMPLE_REPORT_CONTRACT,
350
+ label,
351
+ command: path.basename(command),
352
+ argsCount: args.length,
353
+ exit: {
354
+ status: result.status ?? 0,
355
+ signal: result.signal || "",
356
+ error: result.error?.message || "",
357
+ },
358
+ durationMs: Date.now() - startedAt,
359
+ samplesPath: outputPath,
360
+ summaryPath: summaryOutputPath,
361
+ summary,
362
+ };
363
+ writeJsonFile(summaryOutputPath, report);
364
+ if (readBooleanFlag(optionArgs, "json")) {
365
+ printJson(report);
366
+ } else {
367
+ process.stdout.write(`buildchain process sample: ${summary.sampleCount} samples\n`);
368
+ process.stdout.write(`observed concurrency max: ${summary.observedConcurrency.max}\n`);
369
+ process.stdout.write(`wrote: ${outputPath}\n`);
370
+ process.stdout.write(`wrote: ${summaryOutputPath}\n`);
371
+ }
372
+ if (result.error || result.status !== 0) {
373
+ process.exitCode = result.status || 1;
374
+ }
375
+ return report;
376
+ }
377
+
206
378
  async function main(argv = process.argv.slice(2)) {
207
379
  const [command, ...args] = argv;
208
380
  if (!command || command === "-h" || command === "--help" || command === "help") {
@@ -241,7 +413,10 @@ async function main(argv = process.argv.slice(2)) {
241
413
  }
242
414
 
243
415
  if (command === "doctor") {
244
- const result = runDoctor({ cwd: readFlag(args, "cwd", process.cwd()) });
416
+ const result = runDoctor({
417
+ cwd: readFlag(args, "cwd", process.cwd()),
418
+ requirePublishSourceLock: readBooleanFlag(args, "require-publish-source-lock"),
419
+ });
245
420
  if (readBooleanFlag(args, "json")) {
246
421
  printJson(result);
247
422
  } else {
@@ -285,6 +460,46 @@ async function main(argv = process.argv.slice(2)) {
285
460
  return;
286
461
  }
287
462
 
463
+ if (command === "diagnostics") {
464
+ const [subcommand = "", ...diagnosticsArgs] = args;
465
+ if (subcommand !== "summary") {
466
+ throw new Error("usage: buildchain diagnostics summary <diagnostics.json>...");
467
+ }
468
+ const inputs = readDiagnosticsArtifactInputs(diagnosticsArgs);
469
+ if (inputs.length === 0) {
470
+ throw new Error("buildchain diagnostics summary requires at least one artifact");
471
+ }
472
+ const summary = summarizeDiagnosticsArtifacts(inputs);
473
+ if (summary.count !== inputs.length) {
474
+ throw new Error(`buildchain diagnostics summary read ${summary.count}/${inputs.length} artifacts`);
475
+ }
476
+ const outputPath = readFlag(diagnosticsArgs, "output", "");
477
+ writeJsonFile(outputPath, summary);
478
+ if (readBooleanFlag(diagnosticsArgs, "json")) {
479
+ printJson(summary);
480
+ } else {
481
+ process.stdout.write(`buildchain diagnostics summary: ${summary.count} platforms\n`);
482
+ process.stdout.write(`warnings: ${summary.totalWarningCount} errors: ${summary.totalErrorCount}\n`);
483
+ if (summary.diagnosticsManifestWarningCount) {
484
+ process.stdout.write(`diagnostics manifest warnings: ${summary.diagnosticsManifestWarningCount}\n`);
485
+ }
486
+ process.stdout.write(`${formatDiagnosticsSummaryTable(summary)}\n`);
487
+ if (outputPath) {
488
+ process.stdout.write(`wrote: ${outputPath}\n`);
489
+ }
490
+ }
491
+ return;
492
+ }
493
+
494
+ if (command === "sample") {
495
+ const [subcommand = "", ...sampleArgs] = args;
496
+ if (subcommand !== "process-tree") {
497
+ throw new Error("usage: buildchain sample process-tree -- <command> [args...]");
498
+ }
499
+ await runProcessTreeSample(sampleArgs);
500
+ return;
501
+ }
502
+
288
503
  if (command === "mark") {
289
504
  const eventName = readFlag(args, "event", "");
290
505
  if (!eventName) {
@@ -359,6 +574,7 @@ async function main(argv = process.argv.slice(2)) {
359
574
  artifactPaths,
360
575
  expectedArtifactsJson: readFlag(lifecycleArgs, "expected-artifacts-json", ""),
361
576
  logPath: readFlag(lifecycleArgs, "log-path", process.env.BUILDCHAIN_LOG_PATH || ".buildchain/logs/events.jsonl"),
577
+ processSummaryPath: readFlag(lifecycleArgs, "process-summary", ""),
362
578
  workspace: process.cwd(),
363
579
  });
364
580
  printJson(manifest);
@@ -446,8 +662,19 @@ async function main(argv = process.argv.slice(2)) {
446
662
  assetsDir: readFlag(collectArgs, "assets-dir", ""),
447
663
  assetsJson: readFlag(collectArgs, "assets-json", ""),
448
664
  releaseJson: readFlag(collectArgs, "release-json", ""),
665
+ productName: readFlag(collectArgs, "product-name", "Buildchain"),
449
666
  packageName: readFlag(collectArgs, "package-name", "@kungfu-tech/buildchain"),
450
667
  packageVersion: readFlag(collectArgs, "package-version", packageVersion()),
668
+ packageSetJson: readFlag(collectArgs, "package-set-json", ""),
669
+ publishEvidenceJson: readFlag(collectArgs, "publish-evidence-json", ""),
670
+ trustedPublishingJson: readFlag(collectArgs, "trusted-publishing-json", ""),
671
+ transactionJson: readFlag(collectArgs, "transaction-json", ""),
672
+ anchorManifestJson: readFlag(collectArgs, "anchor-manifest-json", ""),
673
+ buildSummaryJson: readFlag(collectArgs, "build-summary-json", ""),
674
+ platformManifestJsons: readRepeatedFlag(collectArgs, "platform-manifest-json"),
675
+ distTagEvidenceJson: readFlag(collectArgs, "dist-tag-evidence-json", ""),
676
+ releaseJsonExtra: readFlag(collectArgs, "release-extra-json", ""),
677
+ publishJson: readFlag(collectArgs, "publish-json", ""),
451
678
  workflow,
452
679
  });
453
680
  if (readBooleanFlag(collectArgs, "json")) {
@@ -562,6 +789,24 @@ async function main(argv = process.argv.slice(2)) {
562
789
  runScript("verify-publish-source-lock.mjs", publishArgs);
563
790
  return;
564
791
  }
792
+ if (mode === "validate-anchored-release") {
793
+ const report = validateAnchoredPackageRelease({
794
+ cwd: readFlag(publishArgs, "cwd", process.cwd()),
795
+ requirePublishGateSourceLock: true,
796
+ });
797
+ if (readBooleanFlag(publishArgs, "json")) {
798
+ printJson(report);
799
+ } else {
800
+ process.stdout.write(`anchored release source lock: ${report.ok ? "ok" : "failed"}\n`);
801
+ for (const entry of report.checks) {
802
+ process.stdout.write(`- ${entry.status}: ${entry.id}: ${entry.message}\n`);
803
+ }
804
+ }
805
+ if (!report.ok) {
806
+ process.exitCode = 1;
807
+ }
808
+ return;
809
+ }
565
810
  throw new Error(`unsupported publish-source command: ${mode}`);
566
811
  }
567
812
 
@@ -49,6 +49,11 @@
49
49
  "usage": "buildchain log|mark|span|verify observability-log",
50
50
  "purpose": "Emit timestamped build events, summarize logs, and enforce required phases."
51
51
  },
52
+ {
53
+ "id": "diagnostics-summary",
54
+ "usage": "buildchain diagnostics summary <diagnostics.json>...",
55
+ "purpose": "Summarize small diagnostics artifacts into JSON and a cross-platform lifecycle timing table."
56
+ },
52
57
  {
53
58
  "id": "npm-dry-run",
54
59
  "usage": "buildchain npm dry-run --json",
@@ -10,6 +10,7 @@
10
10
  "exports": {
11
11
  ".": "./packages/core/index.js",
12
12
  "./core": "./packages/core/index.js",
13
+ "./diagnostics": "./packages/core/diagnostics.js",
13
14
  "./logging": "./packages/core/logging.js",
14
15
  "./release-passport": "./packages/core/release-passport.js",
15
16
  "./site/buildchain-site.json": "./dist/site/buildchain-site.json",
package/docs/MAP.md CHANGED
@@ -35,6 +35,7 @@ running artifact), *use* (consume / extend) - and a **status**:
35
35
  | How do I add timestamped logs inside build scripts? | [`toolkit-observability.md`](toolkit-observability.md) | use | stable |
36
36
  | What package-owned facts should buildchain.libkungfu.dev render? | [`site-bundle-contract.md`](site-bundle-contract.md) | use | stable |
37
37
  | How do I call the reusable build workflow? | [`reusable-build-surface.md`](reusable-build-surface.md) | use | stable |
38
+ | How do I validate an unreleased Buildchain runtime train while keeping `@v2`? | [`runtime-train-validation.md`](runtime-train-validation.md) | use | stable |
38
39
  | How do I deploy a site/app preview, staging, or production surface? | [`web-surface-deployments.md`](web-surface-deployments.md) | use | stable |
39
40
  | How do I use the active actions directly? | [`../actions/validate-config/README.md`](../actions/validate-config/README.md), [`../actions/run-lifecycle/README.md`](../actions/run-lifecycle/README.md), [`../actions/promote-buildchain-ref/README.md`](../actions/promote-buildchain-ref/README.md) | use | stable |
40
41
  | What do the fixture repositories demonstrate? | [`../fixtures/libnode-shaped/README.md`](../fixtures/libnode-shaped/README.md), [`../fixtures/publish-transaction-shaped/README.md`](../fixtures/publish-transaction-shaped/README.md), [`../fixtures/web-surface-shaped/README.md`](../fixtures/web-surface-shaped/README.md) | verify | stable |
@@ -59,6 +60,9 @@ running artifact), *use* (consume / extend) - and a **status**:
59
60
  - **libnode / native artifacts / self-hosted runner matrix** ->
60
61
  [`reusable-build-surface.md`](reusable-build-surface.md) and
61
62
  [`../fixtures/libnode-shaped/README.md`](../fixtures/libnode-shaped/README.md).
63
+ - **runtime train validation / temporary `buildchain-ref` override** ->
64
+ [`runtime-train-validation.md`](runtime-train-validation.md) and
65
+ [`reusable-build-surface.md`](reusable-build-surface.md).
62
66
  - **standalone binary install / platform archives / GitHub Release bundle** ->
63
67
  [`install.md`](install.md), [`binary-distribution.md`](binary-distribution.md),
64
68
  and [`release-passport.md`](release-passport.md).