@kungfu-tech/buildchain 3.0.5-alpha.8 → 3.0.6-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/contracts/auditable-demo-scenario-v1.schema.json +11 -0
  2. package/dist/site/buildchain-contract.json +42 -22
  3. package/dist/site/buildchain-site.json +73 -27
  4. package/dist/site/capability-registry.json +2 -2
  5. package/dist/site/cli-registry.json +5 -3
  6. package/dist/site/controller-registry.json +19 -3
  7. package/dist/site/kfd-claims.json +58 -14
  8. package/dist/site/kfd-upstream-aggregate.json +1 -1
  9. package/dist/site/manual-registry.json +7 -6
  10. package/dist/site/node-api-registry.json +335 -8
  11. package/dist/site/page-registry.json +63 -17
  12. package/dist/site/public-surface-audit.json +94 -11
  13. package/dist/site/publication-authority-registry.json +21 -1
  14. package/dist/site/publication-registry.json +4 -4
  15. package/dist/site/site-manifest.json +10 -10
  16. package/dist/site/workflow-registry.json +53 -4
  17. package/docs/MAP.md +4 -1
  18. package/docs/auditable-demo.md +19 -3
  19. package/docs/cli-reference.md +15 -4
  20. package/docs/dev-alpha-candidate-patrol.md +14 -5
  21. package/docs/dev-qualification-patrol.md +108 -0
  22. package/docs/node-api-reference.md +42 -9
  23. package/docs/release-propagation.md +93 -0
  24. package/docs/reusable-build-surface.md +44 -12
  25. package/docs/stable-candidate-patrol.md +5 -2
  26. package/package.json +1 -1
  27. package/packages/core/buildchain-publication-authority.js +1 -0
  28. package/packages/core/release-propagation-agent-entry.js +185 -0
  29. package/packages/core/release-propagation-push.js +293 -0
  30. package/packages/core/release-propagation-stage-evidence.js +36 -0
  31. package/packages/core/release-propagation-work.js +1 -1
  32. package/packages/core/release-propagation.js +15 -0
  33. package/scripts/artifact-signing-controller-core.mjs +525 -0
  34. package/scripts/artifact-signing-controller.mjs +302 -0
  35. package/scripts/artifact-signing-delegation.mjs +51 -3
  36. package/scripts/auditable-demo-platform.mjs +59 -1
  37. package/scripts/auditable-demo-transport-smoke.mjs +176 -0
  38. package/scripts/build-standalone-binary.mjs +3 -1
  39. package/scripts/buildchain-cli-help.mjs +1 -1
  40. package/scripts/check-inventory.mjs +1 -0
  41. package/scripts/compiler-cache-evidence.mjs +90 -7
  42. package/scripts/dev-alpha-candidate-patrol.mjs +80 -5
  43. package/scripts/dev-pr-auto-merge.mjs +4 -4
  44. package/scripts/dev-qualification-patrol.mjs +594 -0
  45. package/scripts/dispatch-artifact-signing-authority.mjs +312 -61
  46. package/scripts/generate-site-bundle.mjs +3 -0
  47. package/scripts/inspect-artifact-signing-requests.mjs +12 -0
  48. package/scripts/release-propagation.mjs +73 -0
  49. package/scripts/run-lifecycle-core.mjs +25 -0
  50. package/scripts/site-capability-metadata.mjs +1 -1
  51. package/scripts/stable-candidate-patrol.mjs +30 -4
@@ -1,3 +1,21 @@
1
+ ---
2
+ status: active
3
+ period: ongoing
4
+ theme: buildchain-release-propagation
5
+ doc_type: technical-reference
6
+ source_level: local-files
7
+ confidence: high
8
+ sensitivity: public
9
+ evidence_grade: A
10
+ review_state: unreviewed
11
+ last_reviewed: 2026-08-03
12
+ ai_provenance:
13
+ model_family: GPT-5
14
+ product: Codex
15
+ generated_at: 2026-08-03
16
+ invisible_context: not asserted
17
+ ---
18
+
1
19
  # Release Propagation
2
20
 
3
21
  Release propagation lets a finalized upstream release open a downstream update
@@ -205,6 +223,53 @@ The receipt keeps four machine states separate:
205
223
 
206
224
  Package publication or alpha completion never implies either visibility state.
207
225
 
226
+ ## Unified Site agent entry
227
+
228
+ An Agent begins every Site upstream update through one policy-reporting entry:
229
+
230
+ ```bash
231
+ buildchain release-propagation entry plan \
232
+ --source-id <paper|kfd|buildchain|kungfu-core> \
233
+ --channel <alpha|release> \
234
+ --json
235
+ ```
236
+
237
+ The entry does not blur content and code release policies:
238
+
239
+ | Upstream | Trigger policy | Entry result |
240
+ | ----------- | ------------------------- | -------------------------------------------------- |
241
+ | Paper | automatic release handoff | requires or resumes the exact captured Work |
242
+ | KFD | automatic release handoff | requires or resumes the exact captured Work |
243
+ | Buildchain | explicit Site intent | resolves an exact published package before capture |
244
+ | Kungfu Core | explicit Site intent | resolves an exact published package before capture |
245
+
246
+ Paper and KFD releases keep automatic capture-only handoff. Buildchain and
247
+ Kungfu Core releases remain inert until a downstream Agent receives explicit
248
+ Site-update intent. In all four cases, the entry reports the selected policy,
249
+ exact release coordinate when one has been admitted, Work root and recovery
250
+ cursor when one exists, and one machine-readable next action. A GitHub PR is a
251
+ delivery stage inside that Work; it is not the handoff unit.
252
+
253
+ For an automatic handoff, bind the exact artifact rather than resolving a
254
+ floating tag again:
255
+
256
+ ```bash
257
+ buildchain release-propagation entry plan \
258
+ --source-id kfd \
259
+ --handoff-work work.json \
260
+ --json
261
+ ```
262
+
263
+ The deterministic recovery table is available without repository mutation:
264
+
265
+ ```bash
266
+ buildchain release-propagation entry fault-matrix --json
267
+ ```
268
+
269
+ It classifies current and duplicate Work as successful no-ops, supersession as
270
+ an explicit decision boundary, stale base/expected-old and operational failures
271
+ as retryable, and package/schema disagreement as a hard safety gate.
272
+
208
273
  ## Agent-native work envelope
209
274
 
210
275
  Setting `agent-work-mode: capture-only` makes a finalized release emit a
@@ -372,6 +437,34 @@ buildchain release-propagation work repair ... --output successor.json --json
372
437
  buildchain release-propagation work complete ... --output successor.json --json
373
438
  ```
374
439
 
440
+ The `push-branch` stage has an executable, fail-closed entrypoint:
441
+
442
+ ```bash
443
+ buildchain release-propagation work push-plan \
444
+ --work work.json \
445
+ --expected-work-root sha256:<64-hex> \
446
+ --cwd downstream-worktree \
447
+ --remote origin \
448
+ --json
449
+
450
+ buildchain release-propagation work push-branch \
451
+ --work work.json \
452
+ --expected-work-root sha256:<64-hex> \
453
+ --cwd downstream-worktree \
454
+ --remote origin \
455
+ --execute \
456
+ --json
457
+ ```
458
+
459
+ The executor checks the exact GitHub repository, current managed branch,
460
+ captured downstream base, and expected-old Work root. It pushes only the current
461
+ commit with `HEAD:refs/heads/<managed-branch>`, never a bare branch or wildcard,
462
+ never a force option, then reads that exact remote ref back. Its typed branch
463
+ reconciliation evidence records the argv, source SHA, destination ref, prior
464
+ remote SHA, observed remote SHA, and whether a mutation occurred. A wrong
465
+ repository, unrelated branch, stale base, concurrent writer, or non-fast-forward
466
+ target fails closed without mutating another branch.
467
+
375
468
  Known operational races (`stale-branch`, `expected-old-mismatch`,
376
469
  `lockfile-drift`, `failed-check`, `interrupted-execution`, and `ci-delay`) return
377
470
  a retryable repair action. Semantic ambiguity, missing credentials, policy
@@ -8,11 +8,11 @@ confidence: high
8
8
  sensitivity: public
9
9
  evidence_grade: A
10
10
  review_state: unreviewed
11
- last_reviewed: 2026-07-31
11
+ last_reviewed: 2026-08-03
12
12
  ai_provenance:
13
13
  model_family: GPT-5
14
14
  product: Codex
15
- generated_at: 2026-07-30
15
+ generated_at: 2026-08-03
16
16
  invisible_context: not asserted
17
17
  ---
18
18
 
@@ -105,6 +105,8 @@ jobs:
105
105
  artifact-paths: |
106
106
  dist
107
107
  build/stage
108
+ pre-upload-transport-smoke-scenario-path: .buildchain/auditable-demo.json
109
+ pre-upload-transport-smoke-artifact-root: .
108
110
  expected-artifacts-json: >-
109
111
  {"minFiles":2,"requiredPaths":["dist/libnode.tar.gz","dist/checksums.txt"]}
110
112
  process-summary-path: .buildchain/diagnostics/process-summary.json
@@ -113,6 +115,15 @@ jobs:
113
115
  publish-source-ref: publish-gate/release/v22/v22.22/22.22.3-kf.0
114
116
  ```
115
117
 
118
+ For a standalone Linux binary demo, the optional pre-upload transport smoke
119
+ uses the same declarative scenario as the later capture workflow. Buildchain
120
+ copies the distribution containing the scenario metadata, strips file execute
121
+ bits to model GitHub Artifact transport, restores only the declared
122
+ digest-bound executable closure, and runs `transportSmoke` before either the
123
+ GitHub Artifact or S3 relay upload step. The smoke must be non-interactive and
124
+ is hard-capped at 60 seconds. Omitting the input preserves the ordinary build
125
+ surface; enabling it requires a scenario with `transportSmoke`.
126
+
116
127
  `runner-preset` is the stable first-class surface for known runner fleets:
117
128
 
118
129
  | Preset | Platforms |
@@ -520,7 +531,14 @@ the preparation step. Buildchain probes its version, runs `sccache
520
531
  `compiler-cache-preparation.json`. The receipt binds the source commit/tree,
521
532
  Buildchain runtime, platform, cache profile, and any declared dependency,
522
533
  toolchain, or policy roots. It resets counters only; it does not delete cached
523
- compiler outputs.
534
+ compiler outputs. The same preparation exports `RUSTC_WRAPPER`,
535
+ `CMAKE_C_COMPILER_LAUNCHER`, and `CMAKE_CXX_COMPILER_LAUNCHER` so Cargo and
536
+ CMake/Ninja compilation actually passes through the audited tool.
537
+
538
+ After the build lifecycle, Buildchain probes the reset counter set again. When
539
+ `compiler-cache-required` is true, the build fails closed if sccache observed
540
+ zero compiler requests or zero cacheable requests. This prevents an installed
541
+ but unbound sccache binary from being reported as an active compiler cache.
524
542
 
525
543
  Final diagnostics admit sccache hit/miss outcomes as current-run evidence only
526
544
  when that preparation receipt is present and valid. A bare `sccache
@@ -624,7 +642,8 @@ Every native and container build lane reads this declaration after the build
624
642
  lifecycle and before verification. Buildchain binds the exact artifact bytes or directory tree to
625
643
  the caller repository, source commit, source tree, immutable runtime, platform,
626
644
  and requested signature semantics, then publishes a deterministic
627
- `<artifact>-signing-request-<platform>-<source-sha>` request. No consumer
645
+ `<artifact>-signing-request-<platform>-<source-sha>-<run-id>-<run-attempt>`
646
+ request. No consumer
628
647
  workflow step is required. The lifecycle runner automatically adds declarations
629
648
  selected for the current platform to the `build` manifest scan, including
630
649
  subjects outside the caller's ordinary `artifact-paths`; this extends the
@@ -677,14 +696,27 @@ Buildchain-owned signing authority is responsible for credential selection,
677
696
  native signing, notarization where applicable, immutable result delivery, and a
678
697
  receipt bound to the request digest, runtime SHA, output digest, and signature
679
698
  evidence. Consumer repositories neither receive nor duplicate credential-island
680
- material. The reusable workflow dispatches the sealed request to the
681
- Buildchain repository, waits for its protected authority workflow, verifies the
682
- immutable result, replaces only the declared artifact with the returned final
683
- bytes. The ordinary platform lane completes the consumer's functional
684
- verification before delegation. A GitHub-hosted finalization lane then verifies
685
- the authority result against the sealed request, imports the exact signed bytes,
686
- and recomputes the final manifest before replacing the deterministic artifact.
687
- The signing result is never downloaded back to a self-hosted native runner.
699
+ material. Each platform lane seals and uploads the unsigned request plus a
700
+ run-attempt-bound control request, completes functional verification, and exits.
701
+ It does not dispatch or poll the authority. A separate `ubuntu-24.04` controller
702
+ starts only after the build matrices complete, validates the exact source,
703
+ tree, runtime, request-set root, platform, run attempt, and correlation, then
704
+ dispatches and awaits the protected authority workflow. Its retained receipt
705
+ records two independent immutable identities: the consumer Buildchain runtime
706
+ SHA carried by the control request and the exact authority-ref commit resolved
707
+ immediately before dispatch. The former validates the request-producing
708
+ runtime; the latter must equal the authority workflow run's `head_sha` and is
709
+ retained with the exact authority run and result artifact. If the protected ref
710
+ moves between resolution and dispatch, settlement fails closed. Failure, timeout, or
711
+ cancellation produces a non-qualifying receipt and no finalization delegation.
712
+
713
+ A second GitHub-hosted finalization lane downloads the original control request,
714
+ controller receipt, and delegation, verifies their roots and coordinates agree,
715
+ then verifies the authority result against the sealed request, imports the exact
716
+ signed bytes, and recomputes the final manifest before replacing the
717
+ deterministic artifact. The signing result is never downloaded back to a
718
+ self-hosted native runner, so a macOS caller is released before credential-island
719
+ signing and notarization complete.
688
720
  Platform manifests, KFD evidence, checksums, and Release Passport inputs
689
721
  therefore observe the final signed artifact rather than the pre-signing build
690
722
  output.
@@ -8,7 +8,7 @@ confidence: high
8
8
  sensitivity: public
9
9
  evidence_grade: A
10
10
  review_state: self-reviewed
11
- last_reviewed: 2026-07-31
11
+ last_reviewed: 2026-08-03
12
12
  ai_provenance:
13
13
  model_family: GPT-5
14
14
  product: Codex
@@ -141,7 +141,10 @@ bot, or human service-account token as `approval-token`. The approval identity
141
141
  must differ from the promotion token identity that opens the PR. When no
142
142
  `approval-token` is passed, `auto-approve: true` falls back to the caller
143
143
  `github.token` and therefore requires GitHub Actions approval permission. The
144
- generated PR may use auto-merge, but it never bypasses the target branch checks.
144
+ generated PR may use auto-merge, but it never bypasses the target branch
145
+ checks. Callers can select `merge-method: merge`, `squash`, or `rebase`; the
146
+ default is `merge` for compatibility. Unsupported values fail closed before
147
+ GitHub is called.
145
148
 
146
149
  Before enabling `auto-approve` and `auto-merge`, the caller repository must
147
150
  provide one approval path and enable auto-merge:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kungfu-tech/buildchain",
3
- "version": "3.0.5-alpha.8",
3
+ "version": "3.0.6-alpha.0",
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",
@@ -30,6 +30,7 @@ const DESCRIPTORS = Object.freeze([
30
30
  [".github/workflows/buildchain-patrol.yml", "governance-write"],
31
31
  [".github/workflows/buildchain-ref-promotion.yml", "governance-write"],
32
32
  [".github/workflows/buildchain-stable-candidate-patrol.yml", "governance-write"],
33
+ [".github/workflows/dev-qualification-patrol.yml", "governance-write"],
33
34
  [".github/workflows/dev-alpha-candidate-patrol.yml", "governance-write"],
34
35
  [".github/workflows/dev-merge-queue-governance.yml", "governance-write"],
35
36
  [".github/workflows/dev-pr-auto-merge.yml", "governance-write"],
@@ -0,0 +1,185 @@
1
+ import {
2
+ assertPlainObject,
3
+ assertString,
4
+ normalizeChannel,
5
+ sha256Json,
6
+ } from "./release-propagation-common.js";
7
+ import { verifyReleasePropagationWork } from "./release-propagation-work.js";
8
+
9
+ export const SITE_UPSTREAM_AGENT_ENTRY_CONTRACT =
10
+ "kungfu-buildchain-site-upstream-agent-entry";
11
+ export const RELEASE_PROPAGATION_FAILURE_MATRIX_CONTRACT =
12
+ "kungfu-buildchain-release-propagation-failure-matrix";
13
+
14
+ const SOURCE_ALIASES = new Map([
15
+ ["buildchain", "buildchain"],
16
+ ["core", "kungfu-core"],
17
+ ["kfd", "kfd"],
18
+ ["kungfu", "kungfu-core"],
19
+ ["kungfu-core", "kungfu-core"],
20
+ ["paper", "paper"],
21
+ ["papers", "paper"],
22
+ ]);
23
+
24
+ const POLICIES = Object.freeze({
25
+ buildchain: Object.freeze({
26
+ mode: "downstream-manual",
27
+ trigger: "explicit-site-intent",
28
+ package: "@kungfu-tech/buildchain",
29
+ }),
30
+ "kungfu-core": Object.freeze({
31
+ mode: "downstream-manual",
32
+ trigger: "explicit-site-intent",
33
+ package: "@kungfu-tech/site",
34
+ }),
35
+ kfd: Object.freeze({
36
+ mode: "automatic-release-handoff",
37
+ trigger: "upstream-release-capture",
38
+ package: "@kungfu-tech/kfd",
39
+ }),
40
+ paper: Object.freeze({
41
+ mode: "automatic-release-handoff",
42
+ trigger: "upstream-release-capture",
43
+ packagePrefix: "@kungfu-tech/paper-",
44
+ }),
45
+ });
46
+
47
+ const FAILURE_ROWS = Object.freeze([
48
+ ["current", "no-op", "none", "retain-current-cut"],
49
+ ["duplicate-work", "no-op", "reuse", "resume-exact-work"],
50
+ ["superseded-work", "stop", "needs-decision", "follow-declared-successor"],
51
+ ["stale-downstream-base", "failure", "retry", "refresh-and-recapture"],
52
+ ["stale-expected-old", "failure", "retry", "refresh-and-recapture"],
53
+ [
54
+ "package-schema-mismatch",
55
+ "failure",
56
+ "hard-safety-gate",
57
+ "repair-upstream-release",
58
+ ],
59
+ ["pull-request-conflict", "failure", "retry", "refresh-and-recapture"],
60
+ ["verification-failure", "failure", "retry", "repair-same-work"],
61
+ ["release-race", "failure", "retry", "read-authoritative-release-and-resume"],
62
+ ["deployment-failure", "failure", "retry", "repair-same-work"],
63
+ ["online-readback-failure", "failure", "retry", "repair-same-work"],
64
+ ]);
65
+
66
+ export const RELEASE_PROPAGATION_FAILURE_MATRIX = Object.freeze({
67
+ schemaVersion: 1,
68
+ contract: RELEASE_PROPAGATION_FAILURE_MATRIX_CONTRACT,
69
+ rows: FAILURE_ROWS.map(([condition, outcome, disposition, recovery]) => ({
70
+ condition,
71
+ outcome,
72
+ disposition,
73
+ recovery,
74
+ })),
75
+ });
76
+
77
+ export function normalizeSiteUpstreamIntent(value) {
78
+ const raw = assertString(value, "site upstream intent").toLowerCase();
79
+ if (raw.startsWith("@kungfu-tech/paper-")) return "paper";
80
+ const normalized = SOURCE_ALIASES.get(raw);
81
+ if (!normalized) {
82
+ throw new Error(
83
+ "site upstream intent must identify paper, kfd, buildchain, or kungfu-core",
84
+ );
85
+ }
86
+ return normalized;
87
+ }
88
+
89
+ function automaticHandoff(sourceId, policy, handoffWork) {
90
+ if (handoffWork === null || handoffWork === undefined) {
91
+ return {
92
+ status: "handoff-required",
93
+ exactRelease: null,
94
+ work: null,
95
+ nextAction: {
96
+ action: "consume-release-handoff",
97
+ command:
98
+ "buildchain release-propagation entry plan --source-id <source> --handoff-work <work.json> --json",
99
+ },
100
+ };
101
+ }
102
+ const status = verifyReleasePropagationWork(
103
+ assertPlainObject(handoffWork, "automatic release handoff Work"),
104
+ );
105
+ const packageFact = status.work.upstream.release.package;
106
+ const packageMatches =
107
+ packageFact?.name === policy.package ||
108
+ (policy.packagePrefix &&
109
+ packageFact?.name?.startsWith(policy.packagePrefix));
110
+ if (!packageMatches) {
111
+ throw new Error(
112
+ `automatic ${sourceId} handoff package disagrees with the selected policy`,
113
+ );
114
+ }
115
+ return {
116
+ status: status.lifecycle === "complete" ? "complete" : "handoff-ready",
117
+ exactRelease: {
118
+ repository: status.work.upstream.release.repository,
119
+ package: packageFact,
120
+ releaseRoot: status.work.upstream.releaseRoot,
121
+ },
122
+ work: {
123
+ workId: status.workId,
124
+ workRoot: status.contentRoot,
125
+ lifecycle: status.lifecycle,
126
+ currentStage: status.currentStage,
127
+ expectedBaseSha: status.work.downstream.expectedBaseSha,
128
+ branch: status.work.downstream.branch,
129
+ },
130
+ nextAction: status.nextAction,
131
+ };
132
+ }
133
+
134
+ export function planSiteUpstreamAgentEntry({
135
+ sourceId: sourceInput,
136
+ channel = "",
137
+ handoffWork = null,
138
+ } = {}) {
139
+ const sourceId = normalizeSiteUpstreamIntent(sourceInput);
140
+ const policy = POLICIES[sourceId];
141
+ const normalizedChannel = channel
142
+ ? normalizeChannel(channel, "site upstream channel")
143
+ : sourceId === "paper" || sourceId === "kfd"
144
+ ? ""
145
+ : "release";
146
+ const route =
147
+ policy.mode === "automatic-release-handoff"
148
+ ? automaticHandoff(sourceId, policy, handoffWork)
149
+ : {
150
+ status: "manual-resolution-required",
151
+ exactRelease: null,
152
+ work: null,
153
+ nextAction: {
154
+ action: "resolve-published-release",
155
+ command: `buildchain release-propagation pickup plan --config <config.json> --source-id ${sourceId} --channel ${normalizedChannel} --current-version <exact-version> --json`,
156
+ },
157
+ };
158
+ const body = {
159
+ schemaVersion: 1,
160
+ contract: SITE_UPSTREAM_AGENT_ENTRY_CONTRACT,
161
+ sourceId,
162
+ channel: normalizedChannel,
163
+ policy,
164
+ automaticTrigger: policy.mode === "automatic-release-handoff",
165
+ ...route,
166
+ faultMatrixRoot: sha256Json(RELEASE_PROPAGATION_FAILURE_MATRIX),
167
+ };
168
+ return { ...body, entryRoot: sha256Json(body) };
169
+ }
170
+
171
+ export function classifyReleasePropagationCondition(condition) {
172
+ const normalized = assertString(condition, "release propagation condition");
173
+ const row = RELEASE_PROPAGATION_FAILURE_MATRIX.rows.find(
174
+ (entry) => entry.condition === normalized,
175
+ );
176
+ if (!row) {
177
+ throw new Error(`unsupported release propagation condition: ${normalized}`);
178
+ }
179
+ return {
180
+ schemaVersion: 1,
181
+ contract: "kungfu-buildchain-release-propagation-condition",
182
+ ...row,
183
+ matrixRoot: sha256Json(RELEASE_PROPAGATION_FAILURE_MATRIX),
184
+ };
185
+ }