@kungfu-tech/buildchain 4.1.3-alpha.5 → 4.1.3-alpha.6

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 (78) hide show
  1. package/AGENTS.md +41 -75
  2. package/CONTRIBUTING.md +19 -26
  3. package/architecture/agent-change-map.md +7 -12
  4. package/architecture/capability-state-machine-manifest.json +1 -4
  5. package/architecture/ci-lane-change-budget.json +35 -1026
  6. package/architecture/core-mechanisms.json +3 -6
  7. package/architecture/internal-capabilities.json +1 -5
  8. package/architecture/maintainability-debt.json +43 -36
  9. package/architecture/maintainability-policy.json +8 -8
  10. package/architecture/minimal-consumer-migration.json +80 -1977
  11. package/architecture/platform-stage-checkpoints.json +31 -7
  12. package/architecture/release-topology.json +64 -84
  13. package/architecture/stage-capsule-qualification.json +3 -1
  14. package/architecture/universal-workflow-bootstrap.json +3 -1
  15. package/architecture/universal-workflow-capability-policy.json +4 -4
  16. package/architecture/universal-workflow-fault-campaign.json +3 -1
  17. package/architecture/workflow-taxonomy.json +24 -341
  18. package/dist/site/buildchain-contract.json +13 -67
  19. package/dist/site/buildchain-site.json +28 -23
  20. package/dist/site/capability-registry.json +2 -2
  21. package/dist/site/controller-registry.json +1 -47
  22. package/dist/site/kfd-claims.json +78 -448
  23. package/dist/site/kfd-upstream-aggregate.json +1 -1
  24. package/dist/site/manual-registry.json +3 -3
  25. package/dist/site/node-api-registry.json +24 -24
  26. package/dist/site/page-registry.json +21 -16
  27. package/dist/site/public-surface-audit.json +31 -347
  28. package/dist/site/publication-authority-registry.json +51 -511
  29. package/dist/site/publication-registry.json +4 -4
  30. package/dist/site/site-manifest.json +7 -7
  31. package/dist/site/workflow-registry.json +259 -1126
  32. package/docs/code-organization.md +9 -6
  33. package/docs/node-api-reference.md +57 -57
  34. package/docs/release-governance.md +10 -12
  35. package/docs/runtime-entry.md +10 -3
  36. package/docs/runtime-train-validation.md +39 -11
  37. package/docs/stable-candidate-patrol.md +6 -5
  38. package/docs/workflow-catalog.md +3 -32
  39. package/package.json +1 -1
  40. package/packages/core/adoption/buildchain-kfd-claims.js +7 -7
  41. package/packages/core/dev-delivery/dev-delivery-provider-heartbeat.js +18 -15
  42. package/packages/core/dev-delivery/native/actions.js +2 -0
  43. package/packages/core/dev-delivery/native/process-entry.js +19 -0
  44. package/packages/core/dev-delivery/queue/landing-action.js +49 -1
  45. package/packages/core/dev-delivery/warrant/failure-settlement.js +8 -6
  46. package/packages/core/dev-delivery/warrant/service.js +7 -0
  47. package/packages/core/governance/buildchain-publication-authority.js +2 -23
  48. package/packages/core/governance/github-governance-authority.js +1 -0
  49. package/packages/core/observability/controller-evidence.js +0 -8
  50. package/packages/core/providers/github/pipeline-entry-runs.js +8 -1
  51. package/packages/core/providers/github/pipeline-events.js +79 -0
  52. package/packages/core/publication/pipeline/pack.js +31 -8
  53. package/packages/core/workflow/pipeline/actions.js +0 -23
  54. package/packages/core/workflow/pipeline/build-evidence.js +123 -5
  55. package/packages/core/workflow/pipeline/build-result.js +1 -0
  56. package/packages/core/workflow/pipeline/channel-control.js +25 -4
  57. package/packages/core/workflow/pipeline/controller.js +9 -1
  58. package/packages/core/workflow/pipeline/delivery-control.js +54 -9
  59. package/packages/core/workflow/pipeline/delivery-observation.js +16 -10
  60. package/packages/core/workflow/pipeline/group-control.js +1 -0
  61. package/packages/core/workflow/pipeline/guard-build.js +37 -0
  62. package/packages/core/workflow/pipeline/guard.js +4 -2
  63. package/packages/core/workflow/pipeline/host.js +23 -1
  64. package/packages/core/workflow/pipeline/integration-status.js +113 -0
  65. package/packages/core/workflow/pipeline/record-action.js +27 -0
  66. package/packages/core/workflow/pipeline/recorder-status.js +69 -0
  67. package/packages/core/workflow/workflow-taxonomy.mjs +67 -47
  68. package/scripts/check-inventory.mjs +7 -70
  69. package/scripts/check-pipeline-publication-topology.mjs +2 -0
  70. package/scripts/check-public-dogfood-contract.mjs +38 -51
  71. package/scripts/check-release-topology.mjs +8 -7
  72. package/scripts/check-self-consumer-contract.mjs +133 -0
  73. package/scripts/check-universal-workflow-bootstrap.mjs +4 -6
  74. package/scripts/generate-minimal-consumer-contract.mjs +1 -1
  75. package/scripts/inventory/binary.mjs +9 -19
  76. package/scripts/inventory/promotion.mjs +2 -13
  77. package/scripts/prepare-product-toolchain.mjs +10 -0
  78. package/scripts/verify-product-platform.mjs +65 -0
@@ -8,27 +8,30 @@ confidence: high
8
8
  sensitivity: public
9
9
  evidence_grade: B
10
10
  review_state: unreviewed
11
- last_reviewed: 2026-09-08
11
+ last_reviewed: 2026-09-14
12
12
  ai_provenance:
13
13
  model_family: GPT-6
14
14
  product: Codex
15
- generated_at: 2026-09-08
16
- invisible_context: not asserted
15
+ generated_at: 2026-09-14
16
+ visible_context: Source-bound caller installation, pipeline wake implementation and GitHub event documentation.
17
+ invisible_context_boundary: No unobserved provider execution or publication authority is claimed.
17
18
  ---
18
19
 
19
20
  # Runtime Train Validation
20
21
 
21
22
  A train repairs the execution runtime without changing the consumer's durable
22
23
  public entry. All public workflows, including ordinary builds, use the same
23
- [Runtime entry contract](runtime-entry.md). The transient runtime parameter
24
- wins over the consumer lock. Buildchain dogfood follows this same path.
24
+ [Runtime entry contract](runtime-entry.md). The recovery entry accepts a transient runtime parameter, which wins over the
25
+ consumer lock. The normal minimal pipeline accepts only an optional config path.
26
+ Buildchain dogfood follows the same two-entry contract.
25
27
 
26
28
  ## Validate a runtime change
27
29
 
28
30
  1. Commit the candidate with its action bundles, WASM and runtime contract.
29
31
  2. Publish the candidate at `train/v4/v4.1/<capability>`.
30
- 3. Dispatch the consumer's existing public entry with `runtime-ref` set to that
31
- train. Record the selected runtime, consumer source and resulting evidence.
32
+ 3. Recover the exact retained attempt through `buildchain-recover.yml`, with
33
+ `runtime-ref` set to that train. Record the attempt, selected runtime, consumer
34
+ source and resulting evidence.
32
35
  4. After checks and independent review, merge into protected Dev and publish
33
36
  the requested Alpha. Qualify the published entry before Stable promotion.
34
37
 
@@ -38,13 +41,38 @@ provider credentials, capability constraints and readback requirements.
38
41
 
39
42
  ## Recover a runtime failure
40
43
 
41
- Start a new dispatch through the same public entry with the repaired train.
42
- For builds, supply `resume-run-id`; for release promotion, preserve the original
43
- candidate run and transaction in the typed request. The entry prepares runtime
44
- Y while the task keeps its original source and valid completed evidence.
44
+ Start a new dispatch through `buildchain-recover.yml` with the exact attempt
45
+ and the repaired train. The runtime selects the retained source and completed
46
+ evidence; the consumer does not provide candidate, run or transaction selectors.
45
47
  A GitHub failed-job rerun does not change its inputs and cannot select a new
46
48
  runtime. Do not persist the train into the caller workflow or contract lock.
47
49
 
48
50
  If the public entry itself is defective, publish and adopt the corrected entry
49
51
  and start a full run. Copied consumer recovery packages and alternate recovery
50
52
  workflows are not part of the runtime contract.
53
+
54
+ ## Protected minimal-entry installation
55
+
56
+ Install both generated callers, `buildchain.yml` and `buildchain-recover.yml`,
57
+ on the protected default branch before retiring the previous delivery controller.
58
+ Read back both files at the exact protected commit and verify their provider
59
+ workflow registrations. A workflow registered from a task branch does not prove
60
+ that its event receiver is installed on the default branch. GitHub requires that
61
+ location for [repository dispatch events](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#repository_dispatch).
62
+
63
+ Recovery preserves source and completed artifacts, then emits a repository
64
+ wake for the remaining pipeline work. That wake requires the normal caller on
65
+ the default branch; installing only the manual recovery caller leaves this
66
+ continuation receiver absent. Verify the complete pair before the first recovery.
67
+
68
+ During this bounded migration, pause the normal pipeline before enabling the
69
+ previous protected delivery controller. After the installation merge, wait for
70
+ its runs and Warrant to become terminal, then pause that controller and enable
71
+ the normal pipeline before recovering a current admitted attempt. An installation
72
+ merge advances the protected base, so an older unmerged source attempt must be
73
+ re-admitted on the current base before recovery.
74
+
75
+ Both callers are byte-identical to the generated consumer entries and call the
76
+ published `@v4-alpha` public workflows. Recovery accepts only `attempt` and
77
+ optional `runtime-ref`; the normal caller retains its protected config path.
78
+ This installation order does not qualify the full self cutover or Stable release.
@@ -8,12 +8,12 @@ confidence: high
8
8
  sensitivity: public
9
9
  evidence_grade: A
10
10
  review_state: unreviewed
11
- last_reviewed: 2026-09-12
11
+ last_reviewed: 2026-09-14
12
12
  ai_provenance:
13
13
  model_family: GPT-6
14
14
  product: Codex
15
- generated_at: 2026-09-12
16
- visible_context: Repository stable policy, public build qualification producer, artifact reader and regression tests.
15
+ generated_at: 2026-09-14
16
+ visible_context: User-directed zero-delay self release policy, required provider evidence and regression tests.
17
17
  invisible_context_boundary: No credentials, private logs, or unpublished consumer content were used.
18
18
  ---
19
19
 
@@ -52,7 +52,8 @@ It writes `buildchain-canary/buildchain-zero-input` on the qualified runtime SHA
52
52
  as `github-actions[bot]`. The consumer source SHA may differ from that runtime.
53
53
 
54
54
  The repository Patrol policy requires the alpha Release and this qualification
55
- status. It retains the one-hour soak. The publication transaction still requires
55
+ status. Its minimum soak and stable publication interval are both zero.
56
+ The publication transaction still requires
56
57
  its sealed release candidate and protected branch checks. Qualification produces
57
58
  evidence; it does not publish or merge a candidate.
58
59
 
@@ -78,7 +79,7 @@ Declare the default once in `.buildchain/buildchain.toml`:
78
79
  strategy = "latest-qualified-alpha"
79
80
  timezone = "Asia/Shanghai"
80
81
  publish_at = "03:00"
81
- minimum_soak_seconds = 3600
82
+ minimum_soak_seconds = 0
82
83
  required_checks = [
83
84
  "alpha-release",
84
85
  "workflow:Build",
@@ -23,7 +23,7 @@ Generated from `architecture/workflow-taxonomy.json`. Every workflow has one can
23
23
 
24
24
  Public workflows own the consumer API. Component workflows own reusable multi-job topology. Self workflows own Buildchain repository automation. Actions own execution steps; JS adapters and Rust/WASM own implementation.
25
25
 
26
- Names use `public-<category>-<purpose>.yml`, `.<category>-<purpose>.yml`, and `self-<category>-<purpose>.yml`, with categories `build`, `release`, and `ops`. The primary build API and backbone use `build.yml` and `.build.yml`.
26
+ Names use `public-<category>-<purpose>.yml`, `.<category>-<purpose>.yml`, and the generated self callers `buildchain.yml` and `buildchain-recover.yml`, with categories `build`, `release`, and `ops`. The primary build API and backbone use `build.yml` and `.build.yml`.
27
27
 
28
28
  Register ownership before adding a workflow. `pnpm run check:workflows` validates source, calls, required CI integration and independent review ownership. `pnpm run generate:workflows` regenerates this catalog.
29
29
 
@@ -83,34 +83,5 @@ Register ownership before adding a workflow. `pnpm run check:workflows` validate
83
83
 
84
84
  | Workflow | Category | Invocation | Status | Purpose |
85
85
  | --- | --- | --- | --- | --- |
86
- | [self-build-adopter-dogfood.yml](../.github/workflows/self-build-adopter-dogfood.yml) | build | repository | active | V4 Adopter Delivery Dogfood |
87
- | [self-build-alpha-dogfood.yml](../.github/workflows/self-build-alpha-dogfood.yml) | build | repository | active | Buildchain Alpha Self-Dogfood |
88
- | [self-build-binary-distribution.yml](../.github/workflows/self-build-binary-distribution.yml) | build | repository | active | Binary Distribution |
89
- | [self-build-channel-verify.yml](../.github/workflows/self-build-channel-verify.yml) | build | repository | active | Release - Verify |
90
- | [self-build-demo-dogfood.yml](../.github/workflows/self-build-demo-dogfood.yml) | build | repository | active | Buildchain Declarative Demo Dogfood |
91
- | [self-build-demo-media-qualification.yml](../.github/workflows/self-build-demo-media-qualification.yml) | build | repository | active | Auditable Demo Media Profile Qualification |
92
- | [self-build-fixture.yml](../.github/workflows/self-build-fixture.yml) | build | repository | active | Build Surface Fixture |
93
- | [self-build-public-consumer-dogfood.yml](../.github/workflows/self-build-public-consumer-dogfood.yml) | build | repository | active | V4 Public Consumer Dogfood |
94
- | [self-build-stable-candidate-qualification.yml](../.github/workflows/self-build-stable-candidate-qualification.yml) | build | repository | active | Buildchain Stable Candidate Qualification |
95
- | [self-build-stable-dogfood.yml](../.github/workflows/self-build-stable-dogfood.yml) | build | repository | active | Buildchain Stable Self-Dogfood |
96
- | [self-build-verify.yml](../.github/workflows/self-build-verify.yml) | build | repository | active | Verify |
97
- | [self-ops-bootstrap-dogfood.yml](../.github/workflows/self-ops-bootstrap-dogfood.yml) | ops | repository | active | Universal Bootstrap Train-First Self-Dogfood |
98
- | [self-ops-dev-delivery.yml](../.github/workflows/self-ops-dev-delivery.yml) | ops | repository | active | Buildchain Dev Delivery |
99
- | [self-ops-governance-audit.yml](../.github/workflows/self-ops-governance-audit.yml) | ops | repository | active | GitHub Governance Authority Audit |
100
- | [self-ops-housekeeping-daily.yml](../.github/workflows/self-ops-housekeeping-daily.yml) | ops | repository | active | Engineering Housekeeper Daily |
101
- | [self-ops-housekeeping-monthly.yml](../.github/workflows/self-ops-housekeeping-monthly.yml) | ops | repository | active | Engineering Housekeeper Monthly |
102
- | [self-ops-housekeeping-weekly.yml](../.github/workflows/self-ops-housekeeping-weekly.yml) | ops | repository | active | Engineering Housekeeper Weekly |
103
- | [self-ops-merge-queue.yml](../.github/workflows/self-ops-merge-queue.yml) | ops | repository | active | Dev Merge Queue Governance |
104
- | [self-ops-patrol-daily.yml](../.github/workflows/self-ops-patrol-daily.yml) | ops | repository | active | Buildchain Dogfood Patrol Daily |
105
- | [self-ops-patrol-monthly.yml](../.github/workflows/self-ops-patrol-monthly.yml) | ops | repository | active | Buildchain Dogfood Patrol Monthly |
106
- | [self-ops-patrol-weekly.yml](../.github/workflows/self-ops-patrol-weekly.yml) | ops | repository | active | Buildchain Dogfood Patrol Weekly |
107
- | [self-ops-promotion-recovery.yml](../.github/workflows/self-ops-promotion-recovery.yml) | ops | repository | active | Buildchain Ref Promotion Recovery |
108
- | [self-ops-runner-smoke.yml](../.github/workflows/self-ops-runner-smoke.yml) | ops | repository | active | Self-hosted Runner Smoke |
109
- | [self-ops-stable-candidate-patrol.yml](../.github/workflows/self-ops-stable-candidate-patrol.yml) | ops | repository | active | Buildchain Dogfood Stable Candidate Patrol |
110
- | [self-release-binary-assets.yml](../.github/workflows/self-release-binary-assets.yml) | release | repository | active | Binary Release Assets |
111
- | [self-release-line-open.yml](../.github/workflows/self-release-line-open.yml) | release | repository | active | Release Line Bootstrap |
112
- | [self-release-next-development.yml](../.github/workflows/self-release-next-development.yml) | release | repository | active | Next Development Review |
113
- | [self-release-npm-dry-run.yml](../.github/workflows/self-release-npm-dry-run.yml) | release | repository | active | Publish npm package |
114
- | [self-release-promote.yml](../.github/workflows/self-release-promote.yml) | release | repository | active | Buildchain Ref Promotion |
115
- | [self-release-rehearsal-dogfood.yml](../.github/workflows/self-release-rehearsal-dogfood.yml) | release | repository | active | V4 Publication Rehearsal Dogfood |
116
- | [self-release-tail-dogfood.yml](../.github/workflows/self-release-tail-dogfood.yml) | release | repository | active | V4 Declarative Release Tail Dogfood |
86
+ | [buildchain-recover.yml](../.github/workflows/buildchain-recover.yml) | ops | repository | active | Buildchain recovery |
87
+ | [buildchain.yml](../.github/workflows/buildchain.yml) | ops | repository | active | Buildchain pipeline |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kungfu-tech/buildchain",
3
- "version": "4.1.3-alpha.5",
3
+ "version": "4.1.3-alpha.6",
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",
@@ -58,7 +58,10 @@ const WORKFLOW_AND_ACTION_FILES = Object.freeze([
58
58
  ".github/workflows/.build.yml",
59
59
  ".github/workflows/.release-promote.yml",
60
60
  ".github/workflows/public-release-promote.yml",
61
- ".github/workflows/self-release-promote.yml",
61
+ ".github/workflows/buildchain.yml",
62
+ ".github/workflows/buildchain-recover.yml",
63
+ ".github/workflows/public-ops-pipeline.yml",
64
+ ".github/workflows/public-ops-recover.yml",
62
65
  ".github/workflows/public-release-artifact-attestation.yml",
63
66
  "actions/build/artifact/prepare-attestation/action.yml",
64
67
  "actions/build/artifact/prepare-attestation/index.js",
@@ -75,7 +78,6 @@ const EXTRA_KFD1_FILES = Object.freeze([
75
78
  "packages/core/index.js",
76
79
  "packages/core/build/homebrew.js",
77
80
  "packages/core/build/build-facts.js",
78
- "packages/core/adoption/kfd3-surface-register.js",
79
81
  "packages/core/release/release-propagation.js",
80
82
  "scripts/generate-site-bundle.mjs",
81
83
  "packages/core/release/commands/ensure-github-release.mjs",
@@ -446,7 +448,7 @@ export function createBuildchainKfdSurfaceRegistry({ root = process.cwd() } = {}
446
448
  {
447
449
  name: "Buildchain standalone binary distribution",
448
450
  artifactPath: "dist/binary",
449
- evidencePath: ".github/workflows/self-build-binary-distribution.yml",
451
+ evidencePath: ".github/workflows/.release-pipeline-products.yml",
450
452
  distribution: normalizeKfd3DistributionDeclaration({
451
453
  registrar: "shifu",
452
454
  tasks: ["binary:build"],
@@ -529,7 +531,6 @@ export function createBuildchainKfdClaimRegistry({ root = process.cwd(), sourceS
529
531
 
530
532
  export function createBuildchainKfd1Witness({ root = process.cwd(), sourceSha = "" } = {}) {
531
533
  const registry = createBuildchainKfdClaimRegistry({ root, sourceSha });
532
- const registrySha256 = sha256Json(registry);
533
534
  const paths = uniquePaths([
534
535
  ...publicDocumentationFiles(root),
535
536
  ...SCHEMA_AND_STANDARD_FILES,
@@ -545,7 +546,7 @@ export function createBuildchainKfd1Witness({ root = process.cwd(), sourceSha =
545
546
  contractWorld: {
546
547
  id: "buildchain-runtime-contract-world",
547
548
  schemaId: "kungfu-buildchain-runtime-contract-world",
548
- digest: `sha256:${registrySha256}`,
549
+ digest: `sha256:${sha256Json(registry)}`,
549
550
  owner: "Buildchain maintainers",
550
551
  selfHosted: true,
551
552
  },
@@ -584,7 +585,6 @@ export function createBuildchainKfd3PrebuildWitness({ root = process.cwd(), sour
584
585
  const registry = createBuildchainKfdClaimRegistry({ root, sourceSha });
585
586
  const surfaces = createBuildchainKfdSurfaceRegistry({ root });
586
587
  const reverseAudit = publicSurfaceAuditEvidence(root);
587
- const digest = `sha256:${sha256Json(registry)}`;
588
588
  return {
589
589
  schemaVersion: 1,
590
590
  id: "buildchain-collaboration-interface",
@@ -596,7 +596,7 @@ export function createBuildchainKfd3PrebuildWitness({ root = process.cwd(), sour
596
596
  path: "dist/site/kfd-claims.json",
597
597
  sha256: fileExists(root, "dist/site/kfd-claims.json") ? sha256File(root, "dist/site/kfd-claims.json") : "",
598
598
  },
599
- collaborationInterfaceDigest: digest,
599
+ collaborationInterfaceDigest: `sha256:${sha256Json(registry)}`,
600
600
  collaborationInterface: {
601
601
  schemaVersion: 1,
602
602
  contract: BUILDCHAIN_KFD_COLLABORATION_INTERFACE_CONTRACT,
@@ -207,29 +207,32 @@ export async function runDevDeliveryProviderHeartbeat(
207
207
  const startedAt = timestamp(now(), "provider heartbeat startedAt");
208
208
  let previousStateRoot = initial.stateRoot;
209
209
  const heartbeats = [];
210
+ let untilHeartbeat = 0;
210
211
  let jobs;
211
212
  try {
212
213
  while (true) {
213
- const result = await heartbeat({
214
- expectedOldStateRoot: previousStateRoot,
215
- fencingToken: initial.fencingToken,
216
- leaseGeneration: initial.generation,
217
- leaseSeconds: duration,
218
- });
219
- const entry = heartbeatEntry(result, previousStateRoot);
220
- heartbeats.push(entry);
221
- previousStateRoot = entry.nextStateRoot;
214
+ if (untilHeartbeat === 0) {
215
+ const result = await heartbeat({
216
+ expectedOldStateRoot: previousStateRoot,
217
+ fencingToken: initial.fencingToken,
218
+ leaseGeneration: initial.generation,
219
+ leaseSeconds: duration,
220
+ });
221
+ const entry = heartbeatEntry(result, previousStateRoot);
222
+ heartbeats.push(entry);
223
+ previousStateRoot = entry.nextStateRoot;
224
+ untilHeartbeat = cadence * 1000;
225
+ }
222
226
  jobs = providerJobs(
223
227
  await readJobs(),
224
228
  { nativeJobName, sealJobName },
225
229
  { allowMissingSeal: true },
226
230
  );
227
- if (!jobs) {
228
- await wait(cadence * 1000);
229
- continue;
230
- }
231
- if (terminal(jobs.native) && terminal(jobs.seal)) break;
232
- await wait(cadence * 1000);
231
+ if (jobs && terminal(jobs.native) && terminal(jobs.seal)) break;
232
+ // Terminal detection must not wait for the next durable lease renewal.
233
+ const interval = Math.min(untilHeartbeat, 5000);
234
+ await wait(interval);
235
+ untilHeartbeat -= interval;
233
236
  }
234
237
  } catch (error) {
235
238
  await onHeartbeatLoss({
@@ -6,6 +6,7 @@ import {
6
6
  } from "./transactions.js";
7
7
  import { admitProviderFinalizer } from "./finalizer-admission.js";
8
8
  import { guardPipelineAdmission } from "../../workflow/pipeline/guard.js";
9
+ import { replaceNativeActionProcess } from "./process-entry.js";
9
10
  function request(core, env) {
10
11
  const candidate = JSON.parse(
11
12
  core.getInput("request-json", { required: true }),
@@ -23,6 +24,7 @@ function outputs(core, result) {
23
24
  core.setOutput(name, value);
24
25
  }
25
26
  export async function executeDeliveryNativeAction(core, env) {
27
+ replaceNativeActionProcess();
26
28
  const context = deliveryActionContext(core, env);
27
29
  const input = request(core, env);
28
30
  outputs(
@@ -0,0 +1,19 @@
1
+ // Node Actions receive artifact/OIDC authority even without token inputs.
2
+ // Replace the process before candidate work so the original environment is
3
+ // absent from /proc, memory and ancestry. A scrubbed child would retain it.
4
+ export function replaceNativeActionProcess(host = process) {
5
+ const injected = ["ACTIONS_RUNTIME_TOKEN", "ACTIONS_ID_TOKEN_REQUEST_TOKEN"];
6
+ if (!injected.some((name) => host.env[name])) return;
7
+ if (host.platform !== "linux" || typeof host.execve !== "function") {
8
+ throw new Error("credentialless native action requires Linux execve");
9
+ }
10
+ const environment = { ...host.env };
11
+ for (const name of injected) delete environment[name];
12
+ // Other credential-like variables remain subject to the ancestry guard.
13
+ host.execve(
14
+ host.execPath,
15
+ [host.execPath, ...host.execArgv, ...host.argv.slice(1)],
16
+ environment,
17
+ );
18
+ throw new Error("credentialless native process replacement returned");
19
+ }
@@ -4,12 +4,29 @@ import { admissionPolicyRequest } from "../admission/request.js";
4
4
  import { runAdmissionTransaction } from "../admission/transaction.js";
5
5
  import { enforceLanding } from "./completion.js";
6
6
  import { guardPipelineAdmission } from "../../workflow/pipeline/guard.js";
7
+ import { githubJsonClient } from "../../providers/github/json-client.js";
8
+ import { publishPipelineBuildStatus } from "../../workflow/pipeline/guard-build.js";
9
+ import { publishIntegratedPipelineStatus } from "../../workflow/pipeline/integration-status.js";
10
+ import { githubPipelineIntegration } from "../../providers/github/pipeline-integration.js";
11
+ import { githubPipelineSource } from "../../providers/github/pipeline-source.js";
12
+ import { githubPipelineRuns } from "../../providers/github/pipeline-runs.js";
13
+ import { GitHubClient } from "../admission/github-client.js";
7
14
  export async function admitLandingAction(core, env) {
8
15
  const context = deliveryActionContext(core, env);
9
16
  const request = JSON.parse(core.getInput("request-json", { required: true }));
10
- await guardPipelineAdmission(request, {
17
+ const admitted = await guardPipelineAdmission(request, {
11
18
  repository: env.GITHUB_REPOSITORY,
12
19
  token: core.getInput("token", { required: true }),
20
+ publishBuildStatus: (build) =>
21
+ publishPipelineBuildStatus(
22
+ request,
23
+ build,
24
+ githubJsonClient({
25
+ token: core.getInput("status-token", { required: true }),
26
+ userAgent: "buildchain-qualified-status",
27
+ }),
28
+ env.GITHUB_REPOSITORY,
29
+ ),
13
30
  });
14
31
  const result = await runAdmissionTransaction(
15
32
  {
@@ -45,6 +62,37 @@ export async function admitLandingAction(core, env) {
45
62
  await core.summary.addRaw(result.summary).write();
46
63
  if (!result.ok)
47
64
  throw new Error("Targeted PR was not admitted at its expected head");
65
+ if (admitted) {
66
+ const repository = env.GITHUB_REPOSITORY;
67
+ const token = core.getInput("token", { required: true });
68
+ const read = githubJsonClient({
69
+ token,
70
+ userAgent: "buildchain-integration-status",
71
+ });
72
+ const [owner, repo] = repository.split("/");
73
+ const queue = new GitHubClient({ repository: { owner, repo }, token });
74
+ await publishIntegratedPipelineStatus(
75
+ {
76
+ ...admitted.history.at(-1),
77
+ intent: admitted.intent,
78
+ },
79
+ {
80
+ repository,
81
+ request: read,
82
+ queue: (branch) => queue.getMergeQueueState(branch),
83
+ integration: githubPipelineIntegration(
84
+ read,
85
+ repository,
86
+ githubPipelineSource(read, repository),
87
+ githubPipelineRuns(read, repository),
88
+ ),
89
+ status: githubJsonClient({
90
+ token: core.getInput("status-token", { required: true }),
91
+ userAgent: "buildchain-qualified-integration-status",
92
+ }),
93
+ },
94
+ );
95
+ }
48
96
  }
49
97
  export function completeDeliveryAction(core) {
50
98
  enforceLanding({
@@ -11,13 +11,15 @@ export function verifyFailureSettlement(result, settlement, stateRoot) {
11
11
  result.receipt.evidenceRoot === settlement.evidenceRoot,
12
12
  "Failure settlement receipt does not bind its exact evidence and prior state",
13
13
  );
14
- const candidate = result.observation?.candidates?.find(
15
- (item) =>
16
- item.pullRequestNumber === settlement.pullRequestNumber &&
17
- item.sourceHead === settlement.sourceHead &&
18
- item.terminal?.evidenceRoot === settlement.evidenceRoot,
14
+ const candidate = result.terminalCandidate;
15
+ requireValue(
16
+ candidate?.candidateId === result.receipt.candidateId &&
17
+ candidate?.pullRequestNumber === settlement.pullRequestNumber &&
18
+ candidate?.sourceHead === settlement.sourceHead &&
19
+ candidate?.status === "terminal-failure" &&
20
+ candidate?.terminal?.evidenceRoot === settlement.evidenceRoot,
21
+ "Failure settlement terminal candidate is missing",
19
22
  );
20
- requireValue(candidate, "Failure settlement terminal candidate is missing");
21
23
  for (const key of [
22
24
  "transferRoot",
23
25
  "finalizerBoundaryRoot",
@@ -104,6 +104,13 @@ export async function runDevDeliveryCommand(optionsInput = {}, clientInput) {
104
104
  concurrencyRecovery,
105
105
  receipt: persisted.changed.receipt,
106
106
  receiptRoot: persisted.changed.receiptRoot,
107
+ terminalCandidate:
108
+ options.command === "settle"
109
+ ? persisted.changed.queue.candidates.find(
110
+ (candidate) =>
111
+ candidate.candidateId === persisted.changed.receipt.candidateId,
112
+ ) || null
113
+ : null,
107
114
  warrant:
108
115
  persisted.changed.warrant ||
109
116
  persisted.changed.queue.activeWarrant ||
@@ -4,6 +4,8 @@ import path from "node:path";
4
4
  import { createPublicationAuthorityRegistry } from "../publication/publication-authority.js";
5
5
 
6
6
  const DESCRIPTORS = Object.freeze([
7
+ [".github/workflows/buildchain.yml", "product-publication", true, ["npm-publish", "github-release", "channel-ref"], "trusted-publishing", "none", "fixed", "fixed", ".github/workflows/.release-pipeline-products.yml"],
8
+ [".github/workflows/buildchain-recover.yml", "product-publication", true, ["npm-publish", "github-release", "channel-ref"], "trusted-publishing", "none", "fixed", "fixed", ".github/workflows/.release-pipeline-products.yml"],
7
9
  [".github/workflows/public-release-oci-compose-preview.yml", "product-publication", true, ["oci-compose-preview"], "caller-secrets", "none", "fixed", "caller-bound"],
8
10
  [".github/workflows/.build-demo-adapter.yml", "non-publication-oidc"],
9
11
  [".github/workflows/public-build-demo.yml", "governance-write"],
@@ -16,28 +18,14 @@ const DESCRIPTORS = Object.freeze([
16
18
  [".github/workflows/public-release-web.yml", "product-publication", true, ["web-production"], "oidc", "consumer-defined", "caller-bound", "caller-bound"],
17
19
  [".github/workflows/.build-wheel-verify-compat.yml", "retired-deny"],
18
20
  [".github/workflows/.release-binary-assets.yml", "product-publication", true, ["github-release"], "github-token", "buildchain-release-assets"],
19
- [".github/workflows/self-build-binary-distribution.yml", "evidence-publication"],
20
- [".github/workflows/self-release-binary-assets.yml", "governance-write"],
21
21
  [".github/workflows/public-release-signing-authority.yml", "evidence-publication"],
22
- [".github/workflows/self-build-demo-dogfood.yml", "governance-write"],
23
- [".github/workflows/self-build-fixture.yml", "non-publication-oidc"],
24
22
  [".github/workflows/build.yml", "non-publication-oidc"],
25
23
  [".github/workflows/public-ops-bootstrap.yml", "product-publication", true, ["universal-candidate-execution"], "caller-secrets", "none", "fixed", "caller-bound"],
26
- [".github/workflows/self-build-alpha-dogfood.yml", "non-publication-oidc"],
27
- [".github/workflows/self-build-stable-dogfood.yml", "non-publication-oidc"],
28
- [".github/workflows/self-ops-dev-delivery.yml", "governance-write"],
29
- [".github/workflows/self-ops-patrol-daily.yml", "governance-write"],
30
- [".github/workflows/self-ops-patrol-monthly.yml", "governance-write"],
31
- [".github/workflows/self-ops-patrol-weekly.yml", "governance-write"],
32
24
  [".github/workflows/public-ops-patrol.yml", "governance-write"],
33
- [".github/workflows/self-ops-promotion-recovery.yml", "governance-write"],
34
- [".github/workflows/self-release-promote.yml", "governance-write"],
35
- [".github/workflows/self-ops-stable-candidate-patrol.yml", "governance-write"],
36
25
  [".github/workflows/public-ops-dev-qualification-patrol.yml", "governance-write"],
37
26
  [".github/workflows/public-ops-alpha-candidate-patrol.yml", "governance-write"],
38
27
  [".github/workflows/public-ops-warrant-close.yml", "governance-write"],
39
28
  [".github/workflows/public-ops-warrant-cancel.yml", "governance-write"],
40
- [".github/workflows/self-ops-merge-queue.yml", "governance-write"],
41
29
  [".github/workflows/public-ops-dev-auto-merge.yml", "governance-write"],
42
30
  [".github/workflows/public-ops-pipeline.yml", "product-publication", true, ["npm-publish", "github-release", "channel-ref"], "trusted-publishing", "none", "fixed", "fixed", ".github/workflows/.release-pipeline-products.yml"],
43
31
  [".github/workflows/public-ops-recover.yml", "product-publication", true, ["npm-publish", "github-release", "channel-ref"], "trusted-publishing", "none", "fixed", "fixed", ".github/workflows/.release-pipeline-products.yml"],
@@ -45,13 +33,8 @@ const DESCRIPTORS = Object.freeze([
45
33
  [".github/workflows/.release-pipeline-products.yml", "product-publication", true, ["npm-publish", "github-release", "channel-ref"], "trusted-publishing", "none", "fixed", "fixed"],
46
34
  [".github/workflows/.release-pipeline-version.yml", "governance-write"],
47
35
  [".github/workflows/.ops-pipeline-delivery.yml", "governance-write"],
48
- [".github/workflows/self-ops-housekeeping-daily.yml", "governance-write"],
49
- [".github/workflows/self-ops-housekeeping-monthly.yml", "governance-write"],
50
- [".github/workflows/self-ops-housekeeping-weekly.yml", "governance-write"],
51
36
  [".github/workflows/public-ops-housekeeping.yml", "governance-write"],
52
- [".github/workflows/self-ops-governance-audit.yml", "governance-write"],
53
37
  [".github/workflows/public-release-artifact-attestation.yml", "evidence-publication", true, ["github-artifact-attestation"], "oidc", "consumer-defined", "caller-bound", "caller-bound"],
54
- [".github/workflows/self-release-npm-dry-run.yml", "dry-run-only"],
55
38
  [".github/workflows/public-release-paper.yml", "product-publication", true, ["npm-publish", "github-release"], "trusted-publishing", "none", "fixed", "caller-bound"],
56
39
  [".github/workflows/public-ops-patrol-daily.yml", "governance-write"],
57
40
  [".github/workflows/public-ops-patrol-monthly.yml", "governance-write"],
@@ -59,13 +42,9 @@ const DESCRIPTORS = Object.freeze([
59
42
  [".github/workflows/public-ops-patrol-weekly.yml", "governance-write"],
60
43
  [".github/workflows/public-build-publication.yml", "evidence-publication"],
61
44
  [".github/workflows/public-release-promote.yml", "product-publication", true, ["npm-publish", "github-release", "channel-ref"], "trusted-publishing", "none", "fixed", "caller-bound"],
62
- [".github/workflows/self-release-line-open.yml", "governance-write"],
63
45
  [".github/workflows/public-release-propagation.yml", "governance-write"],
64
46
  [".github/workflows/public-release-tail.yml", "product-publication", true, ["artifact.publish", "signed-channel.commit", "release.activate", "released-evidence.synthesize"], "caller-secrets", "caller-bound", "caller-bound", "fixed"],
65
- [".github/workflows/self-build-release-verify-compat.yml", "governance-write"],
66
47
  [".github/workflows/public-ops-stable-candidate-patrol.yml", "governance-write"],
67
- [".github/workflows/self-ops-bootstrap-dogfood.yml", "product-publication", true, ["universal-candidate-execution"], "caller-secrets", "none", "fixed", "caller-bound"],
68
- [".github/workflows/self-release-tail-dogfood.yml", "product-publication", true, ["artifact.publish", "signed-channel.commit", "release.activate", "released-evidence.synthesize"], "caller-secrets", "none", "fixed", "fixed"],
69
48
  ]);
70
49
 
71
50
  export function buildchainPublicationAuthorityDescriptors({ root = process.cwd() } = {}) {
@@ -1257,6 +1257,7 @@ export function createGithubRulesetGovernanceRolloutPlan({
1257
1257
  dismiss_stale_reviews_on_push: true,
1258
1258
  require_code_owner_review: true,
1259
1259
  require_last_push_approval: true,
1260
+ require_extra_approval_for_unattributed_changes: true,
1260
1261
  required_approving_review_count: requiredApprovals,
1261
1262
  required_review_thread_resolution: true,
1262
1263
  },
@@ -124,14 +124,6 @@ const CONTROLLER_SPECS = [
124
124
  ],
125
125
  evidence: ["propagation-plan", "propagation-lock", "controller-receipt"],
126
126
  },
127
- {
128
- id: "binary-distribution",
129
- workflowId: "binary-distribution",
130
- version: 1,
131
- capabilities: ["standalone-binary-build", "release-evidence-bundle", "artifact-admission"],
132
- stages: ["resolve-runtime", "build", "verify", "bundle", "aggregate"],
133
- evidence: ["release-evidence-bundle", "release-passport", "controller-receipt"],
134
- },
135
127
  ];
136
128
 
137
129
  function stableJson(value) {
@@ -167,8 +167,15 @@ export async function pipelineEntryCheck(run, host) {
167
167
 
168
168
  function exactCheck(checks, run, repository) {
169
169
  const url = `https://github.com/${repository}/actions/runs/${run.id}/attempts/${run.run_attempt}`;
170
+ // Actions may replace details_url with the check's own provider URL. Its
171
+ // exact external execution identity still binds the original native receipt.
170
172
  const matches = checks.filter(
171
- (check) => check.name === "check" && check.details_url === url,
173
+ (check) =>
174
+ check.name === "check" &&
175
+ (check.details_url === url ||
176
+ (check.details_url ===
177
+ `https://github.com/${repository}/runs/${check.id}` &&
178
+ check.external_id?.endsWith(`:${run.id}:${run.run_attempt}`))),
172
179
  );
173
180
  if (!matches.length) return null;
174
181
  const values = matches.map((check) => {
@@ -1,5 +1,84 @@
1
1
  import { readBusinessAttempt } from "../../workflow/attempt/reader.js";
2
2
 
3
+ // The current provider timeline survives webhook/runtime handoff. Compare it
4
+ // with this candidate's lifetime so an earlier removal cannot cancel recovery.
5
+ export function githubPipelineQueueExit(graphql, repository) {
6
+ if (!/^[\w.-]+\/[\w.-]+$/u.test(repository || ""))
7
+ throw new Error("Invalid pipeline queue repository");
8
+ const [owner, repo] = repository.split("/");
9
+ return async (current, candidate) => {
10
+ if (!candidate || candidate.terminal) return null;
11
+ const started = Date.parse(candidate.enqueuedAt);
12
+ if (!Number.isFinite(started))
13
+ throw new Error("Queue candidate timestamp is missing");
14
+ const number = current.intent.source.pullRequest;
15
+ const result = await graphql(
16
+ `
17
+ query ($owner: String!, $repo: String!, $number: Int!) {
18
+ repository(owner: $owner, name: $repo) {
19
+ pullRequest(number: $number) {
20
+ number
21
+ headRefOid
22
+ baseRefName
23
+ state
24
+ mergeQueueEntry {
25
+ id
26
+ }
27
+ timelineItems(
28
+ last: 2
29
+ itemTypes: [
30
+ ADDED_TO_MERGE_QUEUE_EVENT
31
+ REMOVED_FROM_MERGE_QUEUE_EVENT
32
+ ]
33
+ ) {
34
+ nodes {
35
+ __typename
36
+ ... on AddedToMergeQueueEvent {
37
+ id
38
+ createdAt
39
+ }
40
+ ... on RemovedFromMergeQueueEvent {
41
+ id
42
+ createdAt
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+ `,
50
+ { owner, repo, number },
51
+ );
52
+ const pr = result.repository?.pullRequest;
53
+ if (
54
+ pr?.number !== number ||
55
+ pr.headRefOid !== current.generation.source.commit ||
56
+ pr.baseRefName !== current.intent.source.targetBranch
57
+ )
58
+ throw new Error("Queue exit source identity changed; reobserve");
59
+ if (pr.state !== "OPEN" || pr.mergeQueueEntry) return null;
60
+ const nodes = pr.timelineItems?.nodes;
61
+ if (!Array.isArray(nodes) || nodes.length > 2)
62
+ throw new Error("Queue exit timeline readback is missing or ambiguous");
63
+ const event = nodes.at(-1);
64
+ if (event?.__typename !== "RemovedFromMergeQueueEvent") return null;
65
+ const queued = nodes.at(-2);
66
+ if (queued?.__typename !== "AddedToMergeQueueEvent")
67
+ throw new Error("Queue removal has no matching admission readback");
68
+ const removed = Date.parse(event.createdAt);
69
+ const entered = Date.parse(queued.createdAt);
70
+ if (
71
+ !event.id ||
72
+ !queued.id ||
73
+ !Number.isFinite(removed) ||
74
+ !Number.isFinite(entered) ||
75
+ entered > removed
76
+ )
77
+ throw new Error("Queue removal identity or timestamp is missing");
78
+ return entered > started ? event : null;
79
+ };
80
+ }
81
+
3
82
  // Branch/terminal notifications wake existing intents only. They cannot create
4
83
  // historical releases or infer an execution request from an untracked old PR.
5
84
  export function githubPipelineEvents(request, journal, repository) {