@kungfu-tech/buildchain 3.0.2 → 3.0.3-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/AGENTS.md +1 -1
  2. package/CONTRIBUTING.md +1 -1
  3. package/README.md +27 -1
  4. package/actions/promote-buildchain-ref/README.md +90 -19
  5. package/actions/report-buildchain-issue/README.md +20 -2
  6. package/actions/run-lifecycle/README.md +5 -0
  7. package/actions/validate-config/README.md +19 -1
  8. package/bin/buildchain.mjs +56 -2
  9. package/bin/internal/command-registry.mjs +82 -0
  10. package/bin/internal/trust-release-cli.mjs +1 -0
  11. package/contracts/auditable-demo-media-profiles-v1.json +116 -1
  12. package/contracts/buildchain-v2-residuals-v1.json +146 -0
  13. package/contracts/evidence/auditable-demo-responsive-web-delivery-v1.json +143 -0
  14. package/contracts/evidence/auditable-demo-web-delivery-v1.json +7 -3
  15. package/contracts/fixtures/auditable-demo-responsive-web-delivery-v1/complete-transcript.txt +2 -0
  16. package/contracts/fixtures/auditable-demo-responsive-web-delivery-v1/public-projection.json +16 -0
  17. package/contracts/fixtures/auditable-demo-responsive-web-delivery-v1/scene.json +12 -0
  18. package/dist/site/buildchain-contract.json +188 -46
  19. package/dist/site/buildchain-site.json +181 -90
  20. package/dist/site/capability-registry.json +5 -5
  21. package/dist/site/cli-registry.json +860 -98
  22. package/dist/site/controller-registry.json +118 -5
  23. package/dist/site/kfd-claims.json +233 -19
  24. package/dist/site/kfd-upstream-aggregate.json +1 -1
  25. package/dist/site/manual-registry.json +20 -20
  26. package/dist/site/node-api-registry.json +374 -59
  27. package/dist/site/page-registry.json +156 -65
  28. package/dist/site/public-surface-audit.json +231 -22
  29. package/dist/site/publication-registry.json +4 -4
  30. package/dist/site/release-provenance.json +3 -0
  31. package/dist/site/site-manifest.json +24 -24
  32. package/dist/site/workflow-registry.json +575 -79
  33. package/docs/MAP.md +22 -4
  34. package/docs/auditable-demo.md +54 -13
  35. package/docs/aws-us-elastic-runner-burst-plane.md +381 -0
  36. package/docs/cli.md +119 -12
  37. package/docs/consumer-issue-reporting.md +20 -2
  38. package/docs/dev-alpha-candidate-patrol.md +24 -10
  39. package/docs/github-governance-authority.md +24 -31
  40. package/docs/lifecycle-protocol.md +20 -2
  41. package/docs/migration-inventory.md +24 -5
  42. package/docs/observed-evidence-patrol.md +28 -12
  43. package/docs/ownership.md +19 -1
  44. package/docs/publication-artifacts.md +158 -18
  45. package/docs/publication-authority.md +4 -4
  46. package/docs/publish-transaction.md +78 -31
  47. package/docs/release-candidate.md +24 -0
  48. package/docs/release-flow.md +50 -32
  49. package/docs/release-governance.md +39 -32
  50. package/docs/release-passport.md +4 -0
  51. package/docs/release-propagation.md +57 -12
  52. package/docs/reusable-build-surface.md +218 -90
  53. package/docs/runtime-train-validation.md +20 -2
  54. package/docs/shifu-gate-profiles.md +7 -1
  55. package/docs/stable-candidate-patrol.md +6 -6
  56. package/docs/toolkit-observability.md +22 -0
  57. package/docs/versioning.md +46 -24
  58. package/docs/web-surface-deployments.md +82 -1
  59. package/package.json +7 -5
  60. package/packages/core/README.md +60 -4
  61. package/packages/core/artifact-signing.js +1 -0
  62. package/packages/core/buildchain-contract.js +9 -4
  63. package/packages/core/cache-evidence.js +1 -0
  64. package/packages/core/controller-evidence.js +2 -0
  65. package/packages/core/diagnostics.js +105 -30
  66. package/packages/core/github-governance-authority.js +25 -17
  67. package/packages/core/index.js +40 -0
  68. package/packages/core/paper.js +3226 -0
  69. package/packages/core/public-surface-audit.js +3 -0
  70. package/packages/core/publication-artifact.js +1 -6
  71. package/packages/core/publication-authority.js +1 -0
  72. package/packages/core/publication-control-plane-audit.js +28 -0
  73. package/packages/core/publication-reproducibility.js +947 -0
  74. package/packages/core/publication-sealed-bundle.js +190 -0
  75. package/packages/core/publish-transaction.js +147 -17
  76. package/packages/core/release-candidate.js +234 -0
  77. package/packages/core/release-passport.js +519 -228
  78. package/packages/core/release-propagation.js +175 -1
  79. package/packages/core/stable-release-gate.js +4 -1
  80. package/scripts/artifact-signing-delegation.mjs +268 -0
  81. package/scripts/audit-github-governance.mjs +32 -13
  82. package/scripts/audit-publication-control-plane.mjs +17 -8
  83. package/scripts/auditable-demo.mjs +266 -7
  84. package/scripts/aws-codebuild-toolchain.mjs +285 -0
  85. package/scripts/aws-macos-jit-core.mjs +378 -0
  86. package/scripts/aws-macos-jit.mjs +123 -0
  87. package/scripts/aws-runner-burst-core.mjs +248 -0
  88. package/scripts/aws-runner-burst.mjs +79 -0
  89. package/scripts/aws-windows-jit-core.mjs +374 -0
  90. package/scripts/aws-windows-jit.mjs +121 -0
  91. package/scripts/build-contract-core.mjs +69 -6
  92. package/scripts/build-standalone-binary.mjs +23 -0
  93. package/scripts/buildchain-contract-lock.mjs +1 -1
  94. package/scripts/buildchain-patrol.mjs +1 -1
  95. package/scripts/check-internal-architecture.mjs +69 -2
  96. package/scripts/check-inventory.mjs +70 -2
  97. package/scripts/check-javascript-syntax.mjs +31 -0
  98. package/scripts/check-maintainability.mjs +371 -0
  99. package/scripts/compiler-cache-evidence.mjs +221 -0
  100. package/scripts/dev-alpha-candidate-patrol.mjs +288 -43
  101. package/scripts/dispatch-artifact-signing-authority.mjs +7 -1
  102. package/scripts/finalize-native-artifact-signing-result.mjs +185 -31
  103. package/scripts/gate-profile-core.mjs +6 -1
  104. package/scripts/generate-channel-promotion-workflow.mjs +3 -12
  105. package/scripts/generate-release-candidate-passport.mjs +4 -0
  106. package/scripts/generate-site-bundle.mjs +84 -18
  107. package/scripts/import-artifact-signing-results.mjs +64 -5
  108. package/scripts/inspect-artifact-signing-requests.mjs +52 -14
  109. package/scripts/maintainability-metrics.mjs +339 -0
  110. package/scripts/npm-publish-transaction.mjs +57 -6
  111. package/scripts/observed-evidence.mjs +151 -33
  112. package/scripts/paper.mjs +645 -0
  113. package/scripts/promotion-channel-router.mjs +16 -4
  114. package/scripts/publication-reproducibility.mjs +62 -0
  115. package/scripts/reconcile-github-governance.mjs +8 -1
  116. package/scripts/release-propagation.mjs +39 -0
  117. package/scripts/resolve-artifact-signing-upload-route.mjs +55 -0
  118. package/scripts/resolve-build-contract.mjs +6 -0
  119. package/scripts/route-offline-runners.mjs +236 -0
  120. package/scripts/run-candidate-body-prefix-renderer.mjs +187 -0
  121. package/scripts/run-lifecycle-core.mjs +62 -1
  122. package/scripts/runtime-ref-core.mjs +36 -4
  123. package/scripts/seal-artifact-signing-requests.mjs +64 -12
  124. package/scripts/stable-candidate-qualification.mjs +50 -0
  125. package/scripts/verify-artifact-signing-results.mjs +26 -1
  126. package/scripts/web-surface-core.mjs +272 -86
  127. package/scripts/web-surface-production-decision.mjs +19 -3
package/docs/MAP.md CHANGED
@@ -1,3 +1,21 @@
1
+ ---
2
+ status: active
3
+ period: ongoing
4
+ theme: buildchain-documentation-map
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-07-31
12
+ ai_provenance:
13
+ model_family: GPT-5
14
+ product: Codex
15
+ generated_at: 2026-07-31
16
+ invisible_context: not asserted
17
+ ---
18
+
1
19
  # Documentation Map
2
20
 
3
21
  Start here. Find the question you have; follow it to the document that answers
@@ -10,7 +28,7 @@ running artifact), *use* (consume / extend) - and a **status**:
10
28
  - `stable` - current and holds.
11
29
  - `draft` - exists, rough or incomplete.
12
30
  - `to write` - planned; the material exists but is not yet a single doc.
13
- - `retired` - intentionally not part of the active Buildchain v2 surface.
31
+ - `retired` - intentionally not part of the active Buildchain v3 surface.
14
32
 
15
33
  ## Capability Coverage
16
34
 
@@ -118,7 +136,7 @@ replace them.
118
136
  | How do I automatically qualify alpha candidates and publish the newest non-revoked qualified candidate at a fixed window? | [`stable-candidate-patrol.md`](stable-candidate-patrol.md) | use | preview |
119
137
  | How do I deploy a site/app preview, staging, or production surface? | [`web-surface-deployments.md`](web-surface-deployments.md) | use | stable |
120
138
  | How do I publish observed infrastructure contracts for downstream consumers? | [`infra-contract.md`](infra-contract.md) | use | preview |
121
- | 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), [`../actions/report-buildchain-issue/README.md`](../actions/report-buildchain-issue/README.md) | use | stable |
139
+ | 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), [`../actions/report-buildchain-issue/README.md`](../actions/report-buildchain-issue/README.md), [`../actions/github-artifact-attestation/README.md`](../actions/github-artifact-attestation/README.md), [`../actions/macos-credential-island/README.md`](../actions/macos-credential-island/README.md); `dist/site/workflow-registry.json#actions` is authoritative for the six-entry inventory. | use | stable |
122
140
  | How can a consumer workflow report a Buildchain-owned failure back to Buildchain? | [`consumer-issue-reporting.md`](consumer-issue-reporting.md) + [`../actions/report-buildchain-issue/README.md`](../actions/report-buildchain-issue/README.md) | use | stable |
123
141
  | 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), [`../fixtures/publication-artifact-shaped/README.md`](../fixtures/publication-artifact-shaped/README.md) | verify | stable |
124
142
  | What license and contribution terms apply? | [`../LICENSE`](../LICENSE) + [`../LICENSE-POLICY.md`](../LICENSE-POLICY.md) | use | stable |
@@ -129,14 +147,14 @@ replace them.
129
147
 
130
148
  - **ABV / old workflows / old action repositories** -> [`release-governance.md`](release-governance.md)
131
149
  and [`migration-inventory.md`](migration-inventory.md).
132
- - **v2 / v3-alpha / v2.0 / v2.0-alpha / exact tags / floating tags** ->
150
+ - **v3 / v3-alpha / v3.0 / v3.0-alpha / exact tags / floating tags** ->
133
151
  [`release-governance.md`](release-governance.md) and
134
152
  [`release-flow.md`](release-flow.md).
135
153
  - **Buildchain self-dogfood / released alpha canary / stable compatibility lane** ->
136
154
  [`release-governance.md`](release-governance.md#buildchain-alpha-self-dogfood).
137
155
  - **qualified alpha ledger / scheduled stable selection / hold and revoke** ->
138
156
  [`stable-candidate-patrol.md`](stable-candidate-patrol.md).
139
- - **v2.1 vs v2.2 / when to open a new minor line** ->
157
+ - **v3.1 vs v3.2 / when to open a new minor line** ->
140
158
  [`versioning.md`](versioning.md).
141
159
  - **dry-run / what would happen if this channel PR merges** -> [`cli.md`](cli.md)
142
160
  and [`release-flow.md`](release-flow.md).
@@ -8,11 +8,11 @@ confidence: high
8
8
  sensitivity: public
9
9
  evidence_grade: A
10
10
  review_state: self-reviewed
11
- last_reviewed: 2026-07-28
11
+ last_reviewed: 2026-07-31
12
12
  ai_provenance:
13
13
  model_family: GPT-5
14
14
  product: Codex
15
- generated_at: 2026-07-25
15
+ generated_at: 2026-07-31
16
16
  invisible_context_boundary: No hidden model build, parameter count, or private corpus is asserted.
17
17
  ---
18
18
 
@@ -41,6 +41,18 @@ public-projection.json
41
41
  scene.json
42
42
  ```
43
43
 
44
+ It may additionally emit one declared `terminal-capture.json` using
45
+ `kungfu.terminal-capture/v1`. The optional capture is bounded to 60 seconds,
46
+ fixed 80-200 by 24-80 terminal cells, 10,000 events, and 4 MiB of canonical
47
+ base64 bytes. It must contain a passed completion sentinel and an explicitly
48
+ empty authority-grant list. Existing three-file adapters remain valid.
49
+
50
+ Terminal bytes are volatile observations, not Work, Warrant, capability, or
51
+ publication authority. First-party or System identity, KFD compliance, Product
52
+ System metadata, package metadata, scan output, registry history, and
53
+ standalone generation remain non-authoritative unless an exact higher-level
54
+ contract independently admits them.
55
+
44
56
  The adapter must not rebuild or rerun the product. It receives:
45
57
 
46
58
  ```text
@@ -49,6 +61,15 @@ The adapter must not rebuild or rerun the product. It receives:
49
61
  --source-coordinate PATH
50
62
  ```
51
63
 
64
+ Consumers with one shared adapter for several deterministic demos may also set
65
+ `adapter-arguments-json` to a bounded JSON array. Buildchain parses the array,
66
+ rejects malformed values, newlines, NUL bytes, more than 32 arguments, values
67
+ longer than 256 bytes, and attempts to override the three coordinate flags
68
+ above, then appends the accepted strings directly to the adapter argv. It never
69
+ evaluates a shell command. The exact argument vector and its content root are
70
+ retained in `adapter.json`; the Gate receipt binds that root. Adapter arguments
71
+ select consumer-owned capture behavior only and grant no authority.
72
+
52
73
  `--source-coordinate` identifies the caller repository, run, artifact id,
53
74
  artifact name, upload digest, expiry, and exact source SHA. The workflow finds
54
75
  exactly one live artifact with the requested name in the current caller run and
@@ -78,7 +99,8 @@ The Gate:
78
99
  - resolves and downloads one exact same-run GitHub Artifact;
79
100
  - invokes the checked-in adapter by argv, never as an evaluated shell string;
80
101
  - rejects undeclared adapter outputs, symlinks, invalid UTF-8, invalid scene or
81
- projection schemas, out-of-range transcript references, and oversized input;
102
+ projection or terminal-capture schemas, implicit capture grants,
103
+ out-of-range transcript references, and oversized input;
82
104
  - derives a one-second compatibility scene from the consumer projection;
83
105
  - anonymously pulls an immutable `image@sha256:digest` renderer;
84
106
  - runs it as non-root with `--network none`, a read-only root filesystem, and a
@@ -105,6 +127,11 @@ distribution checksums. A web-delivery profile also retains
105
127
  `media-inspection.json`, whose content root is bound into the receipt.
106
128
  `render-media: false` does not weaken or skip the Gate.
107
129
 
130
+ When the Gate bundle contains a qualified terminal capture, the render job
131
+ passes it read-only to the immutable renderer. The renderer manifest binds the
132
+ capture root and terminal-state-machine version, but raw capture bytes remain
133
+ in the Gate bundle rather than being copied into the public media bundle.
134
+
108
135
  ## Media Qualification Profiles
109
136
 
110
137
  The single machine-readable source is
@@ -116,6 +143,7 @@ shell fragments, arbitrary profile paths, or transcoding instructions.
116
143
  | --- | --- |
117
144
  | `archive-v1` | Default compatibility contract. Retains the exact renderer outputs and classifies GIF as README compatibility evidence without making a browser-delivery claim. |
118
145
  | `web-delivery-v1` | Independently qualifies H.264 MP4 and VP9 WebM playback sources, forbids audio, requires exact scene dimensions and bounded duration/frame-rate drift, checks per-rendition byte ceilings, and proves MP4 `moov` precedes `mdat`. PNG remains the lossless evidence poster. |
146
+ | `responsive-web-delivery-v1` | Extends `web-delivery-v1` with exact 1280x720 H.264 MP4 and VP9 WebM responsive sources plus a 1280x720 README GIF while keeping the primary MP4/WebM and evidence poster at the source scene dimensions. Every declared downscale must preserve the scene aspect ratio and may never upscale. |
119
147
  | `site-hero-v1` | Extends `web-delivery-v1` and additionally requires a qualified WebP browser poster. The current Build Images v1 renderer does not emit that member, so selecting this profile fails closed until the producer adds it. |
120
148
 
121
149
  For web-delivery profiles, Buildchain runs its own fixed `ffprobe` invocation
@@ -129,16 +157,22 @@ field remains supporting evidence, never sufficient authority.
129
157
 
130
158
  The default `archive-v1` path preserves the existing v1 media receipt exactly.
131
159
  An explicitly selected web-delivery profile emits a v2 media receipt with a
132
- content-addressed rendition list and explicit roles and MIME types. Agents and
133
- site builds select `primary-video`,
134
- `alternate-video`, `browser-poster`, or evidence-only roles from that receipt;
135
- they do not infer semantics from extensions or filenames. Additional responsive
136
- renditions are accepted only when the immutable renderer manifest declares the
137
- bounded `build-images.auditable-demo-web-delivery/v1` role and MIME metadata and
138
- the selected Buildchain profile supplies the byte ceiling; producer metadata
139
- cannot raise that ceiling. Unbound outputs,
140
- duplicate singleton roles, unknown profiles, or unsupported required versions
141
- fail closed.
160
+ content-addressed rendition list and explicit roles, MIME types, dimensions,
161
+ and dimension policy. Agents and site builds select `primary-video`,
162
+ `alternate-video`, `responsive-primary-video`,
163
+ `responsive-alternate-video`, `browser-poster`, or evidence-only roles from
164
+ that receipt; they do not infer semantics from extensions or filenames.
165
+ Profile-declared responsive renditions must match their exact dimensions,
166
+ remain within the source scene, and preserve its aspect ratio. Additional
167
+ producer-declared renditions remain bounded by the selected profile and cannot
168
+ raise their own byte ceiling. Unbound outputs, implicit upscales, aspect-ratio
169
+ drift, duplicate singleton roles, unknown profiles, or unsupported required
170
+ versions fail closed.
171
+
172
+ The required Gate binds the exact selected media profile and the smoke media
173
+ qualification root before optional full rendering starts. Gate-only validation
174
+ and full rendering therefore exercise the same profile contract; a later media
175
+ job cannot silently switch rendition authority.
142
176
 
143
177
  Initial byte ceilings are derived from the checked-in
144
178
  `auditable-demo-web-delivery-v1` fixture rendered by Build Images
@@ -147,6 +181,12 @@ PNG ceilings are the next power of two above sixteen times the measured member
147
181
  bytes. The not-yet-produced WebP poster uses eight times the measured lossless
148
182
  PNG as its conservative proxy. The path-scoped qualification workflow
149
183
  regenerates the content-addressed evidence and fails on any byte or fact drift.
184
+ Its matrix retains the original 1280x720 web-delivery baseline on the renderer
185
+ that produced it and separately measures the responsive profile against a
186
+ 1920x1080 fixture and the first exact renderer release that emits both
187
+ source-resolution and 720p renditions. This keeps historical budget evidence
188
+ reproducible while giving the responsive contract its own immutable
189
+ qualification root.
150
190
 
151
191
  ## Consumer Example
152
192
 
@@ -183,6 +223,7 @@ jobs:
183
223
  source-artifact-name: ${{ needs.build.outputs.artifact-name }}
184
224
  source-artifact-digest: ${{ needs.build.outputs.artifact-digest }}
185
225
  adapter-path: scripts/auditable-demo-adapter
226
+ adapter-arguments-json: '["--demo-id","agent-work-lab"]'
186
227
  renderer-image: ghcr.io/kungfu-systems/build-images/demo-renderer@sha256:RENDERER_DIGEST
187
228
  render-media: false
188
229
  media-profile: archive-v1
@@ -0,0 +1,381 @@
1
+ ---
2
+ status: draft
3
+ period: 2026-07-28
4
+ theme: aws-us-elastic-runner-burst-plane
5
+ doc_type: design
6
+ source_level: local-files-and-provider-docs
7
+ confidence: high
8
+ sensitivity: public
9
+ evidence_grade: A
10
+ review_state: unreviewed
11
+ last_reviewed: 2026-07-30
12
+ ---
13
+
14
+ # AWS US elastic runner burst plane
15
+
16
+ The local runner fleet remains the normal Kungfu build plane. This AWS US plane
17
+ is an explicit, temporary overflow mechanism with sequential qualification:
18
+
19
+ 1. Linux CodeBuild proof of concept under USD 50.
20
+ 2. Windows EC2 one-job JIT runners.
21
+ 3. One bounded 24-hour EC2 Mac campaign.
22
+
23
+ No later phase can start from design intent alone. The preceding phase must
24
+ produce a qualifying source-bound receipt, actual cost, and zero-resource
25
+ cleanup proof.
26
+
27
+ ## Phase 1 contract
28
+
29
+ `aws-us-codebuild-linux` is a Linux-only runner preset. It requires the exact
30
+ CodeBuild project name and resolves the runner label at workflow evaluation
31
+ time:
32
+
33
+ ```text
34
+ codebuild-<project>-<github.run_id>-<github.run_attempt>
35
+ ```
36
+
37
+ The GitHub-hosted `trust-gate` remains ahead of the matrix job. A fork pull
38
+ request therefore fails or skips before the CodeBuild `runs-on` label exists as
39
+ a queued job. The dedicated consumer workflow is manual-only and does not add
40
+ the preset to dev, alpha, release, signing, notarization, deployment, or
41
+ publication workflows.
42
+
43
+ The CodeBuild project is:
44
+
45
+ - repository-scoped through an AWS CodeConnections GitHub App;
46
+ - one ephemeral runner and one GitHub job per CodeBuild build;
47
+ - outside a VPC, with no idle VM, NAT gateway, public ingress, SSH, or persistent
48
+ workspace;
49
+ - limited to two concurrent builds, 15 queued minutes, and 40 execution
50
+ minutes;
51
+ - allowed to write only its dedicated CloudWatch log group and request a token
52
+ from its dedicated GitHub App connection;
53
+ - forbidden from receiving signing, notarization, package publication, release,
54
+ deploy, static AWS, long-lived GitHub, or SSH credentials.
55
+
56
+ The AWS-managed Ubuntu 24.04 standard image is the immutable base. Before a
57
+ native lifecycle starts, Buildchain installs the distribution's `gcc-14` and
58
+ `g++-14` packages, exposes only per-job `gcc`/`g++` aliases, and downloads the
59
+ pinned Kitware CMake 3.31.6 archive after verifying its reviewed SHA256. The
60
+ resolved package manager, versions, and CMake source digest are retained as
61
+ `aws-native-toolchain.json`; no toolchain state survives the ephemeral
62
+ CodeBuild execution. The toolchain adapter also retains the reviewed Amazon
63
+ Linux 2023 `gcc14` path for compatible projects.
64
+
65
+ ## Cost and kill-switch envelope
66
+
67
+ The 2026-07-28 AWS Price List entry for
68
+ `BUILD_GENERAL1_XLARGE` Linux in `us-east-1` is USD 0.0798 per build minute.
69
+ The contract rounds that rate up to USD 0.08. Twelve fully timed-out accepted
70
+ builds reserve at most USD 38.40. At project concurrency two, the fail-closed
71
+ controller can see at most two over-cap builds. The envelope conservatively
72
+ charges both race builds for their complete 40-minute timeout rather than
73
+ assuming fast EventBridge delivery. The bounded CodeBuild maximum is therefore
74
+ USD 44.80, below the dedicated USD 49 budget and leaving USD 4.20 for the small
75
+ controller, state, notification, and log charges.
76
+
77
+ The controller stores an idempotent build-id ledger, an atomic accepted-build
78
+ counter, and worst-case reservation in DynamoDB. Duplicate EventBridge delivery
79
+ does not consume the bounded build allowance. It deletes the CodeBuild webhook
80
+ and stops the triggering build when:
81
+
82
+ - the accepted-build or reserved-cost cap is reached;
83
+ - actual-cost telemetry is missing or more than six hours old;
84
+ - actual CodeBuild spend reaches the budget;
85
+ - AWS Budgets sends the 80% or 95% actual-spend notification;
86
+ - the kill switch was already set.
87
+
88
+ The stack starts fail closed: it has no cost telemetry item and CloudFormation
89
+ does not create the webhook. Before arming the webhook, the operator must write
90
+ a current Cost Explorer observation to the `COST` item, clear only the dedicated
91
+ controller's killed state, and create the exact workflow-filtered webhook.
92
+ Re-arming after any kill is a separate provider mutation and requires a new
93
+ explicit approval.
94
+
95
+ ## Qualification evidence
96
+
97
+ Each successful job uploads `aws-runner-burst.json`, binding:
98
+
99
+ - consumer repository, exact source SHA and ref;
100
+ - GitHub run id, attempt and job;
101
+ - CodeBuild project, build id, build ARN and initiator;
102
+ - observation timestamp and canonical digest.
103
+
104
+ Linux qualification requires:
105
+
106
+ - at least 10 trusted exact-source successful jobs;
107
+ - observed concurrency of at least two;
108
+ - p95 queue-to-start of at most five minutes;
109
+ - actual incremental AWS spend below USD 49;
110
+ - no idle build and no active cloud residue.
111
+
112
+ `node scripts/aws-runner-burst.mjs verify-linux --input <snapshot.json>` fails
113
+ closed when cost telemetry is missing/stale or any acceptance predicate is
114
+ false.
115
+
116
+ ### Phase 1 recorded outcome
117
+
118
+ The Linux phase passed on 2026-07-29. Ten trusted exact-source Kungfu jobs
119
+ completed successfully, including four overlapping two-job waves. The observed
120
+ CodeBuild queue-to-start p95 was 0.696 seconds. All 16 paid executions,
121
+ including six diagnostic runs, produced a conservative incremental compute
122
+ upper bound of USD 25.798 by rounding every execution up to a whole minute at
123
+ the live AWS Price List rate.
124
+
125
+ The global webhook kill switch was exercised after the tenth qualifying job.
126
+ The project then reported no webhook or in-progress build, and the card-owned
127
+ EC2 inventory was empty. AWS Billing and Cost Explorer still reported an
128
+ estimated zero during their provider ingestion delay; the retained
129
+ execution-derived upper bound is therefore the immediate cost proof and must be
130
+ reconciled with the eventual AWS line item in the final campaign report.
131
+
132
+ The source-bound evidence and deterministic phase receipt are:
133
+
134
+ - `evidence/aws-us-elastic-runner-burst-plane/linux-codebuild-qualification-input.json`
135
+ - `evidence/aws-us-elastic-runner-burst-plane/linux-codebuild-qualification-receipt.json`
136
+
137
+ ## Phase 2 contract
138
+
139
+ The Windows phase uses the explicit `aws-us-ec2-windows-jit` runner preset.
140
+ Its caller supplies one bounded label under
141
+ `aws-us-ec2-windows-jit-<qualification-id>`, and Buildchain resolves exactly
142
+ one Windows x64 native lane. The reusable trust gate still runs on a
143
+ GitHub-hosted runner before the JIT label can select EC2.
144
+
145
+ The provider creates repository-level GitHub JIT configuration for
146
+ `kungfu-systems/kungfu`. Its `labels` request must contain all four scheduling
147
+ labels: `self-hosted`, `Windows`, `X64`, and the card-scoped
148
+ `aws-us-ec2-windows-jit-<qualification-id>` label. GitHub's JIT endpoint does
149
+ not infer the default OS and architecture labels when they are omitted. The
150
+ encoded configuration is never placed in EC2 user data, a tag, a command log,
151
+ or an artifact. The operator writes it to a card-scoped SSM SecureString under
152
+ `/kungfu/burst/windows/`; the instance role can read and delete only that
153
+ prefix. Bootstrap reads the value once, deletes the parameter immediately, and
154
+ passes it only to the pinned runner process.
155
+
156
+ Each runner uses:
157
+
158
+ - Amazon's current Windows Server 2025 Full Base AMI, resolved through the
159
+ public SSM AMI parameter and retained by exact AMI id and name;
160
+ - `c7i.4xlarge`, one instance and one JIT runner per job;
161
+ - GitHub Actions Runner 2.336.0 with the official Windows x64 SHA256;
162
+ - PowerShell 7.6.4 with the official Windows x64 MSI SHA256 and Microsoft
163
+ Authenticode verification;
164
+ - pinned PortableGit 2.55.0.3 with its GitHub release SHA256, exposing only its
165
+ `cmd` directory so POSIX compatibility tools cannot shadow Windows tools;
166
+ - a Microsoft Authenticode-verified Visual Studio 2022 Build Tools bootstrap;
167
+ - IMDSv2, an encrypted root volume with delete-on-termination, no inbound
168
+ security-group rule, no key pair, and no warm Auto Scaling capacity.
169
+
170
+ Runner diagnostics and a redacted lifecycle record are uploaded to the
171
+ provider's encrypted, private evidence bucket. The runner process exits after
172
+ one job, Windows shuts down, and EC2's instance-initiated shutdown behavior is
173
+ set to `terminate`. A five-minute reaper terminates card-owned stopped or
174
+ three-hour-old instances and deletes only their dedicated JIT parameter.
175
+
176
+ At the 2026-07-29 AWS Price List rate of USD 1.45 per Windows
177
+ `c7i.4xlarge` hour, six accepted three-hour instances reserve USD 26.10. The
178
+ two-instance race envelope reserves another USD 8.70, producing a USD 34.80
179
+ worst case below the dedicated USD 40 budget. Budget notifications at 80% and
180
+ 95% invoke the same card-scoped global kill switch.
181
+
182
+ Qualification requires one runner-profile smoke, three trusted exact-source
183
+ full Windows jobs, independent cancellation and timeout cleanup exercises, and
184
+ zero repository runner, EC2 instance, disposable volume, min capacity, and
185
+ desired capacity within 15 minutes of the final job.
186
+
187
+ ## Phase 3 contract
188
+
189
+ The macOS phase uses the explicit `aws-us-ec2-macos-jit` runner preset. Its
190
+ caller supplies one unique label under
191
+ `aws-us-ec2-macos-jit-<qualification-id>`, and Buildchain resolves exactly one
192
+ native macOS ARM64 lane with `self-hosted`, `macOS`, `ARM64`, and the unique
193
+ campaign label. The reusable trust gate remains ahead of the JIT runner.
194
+
195
+ Unlike Windows, the Mac campaign deliberately reuses one instance on one
196
+ `mac2.metal` Dedicated Host. The operator allocates exactly one tagged host,
197
+ launches exactly one tagged instance, and sends three sequential SSM bootstrap
198
+ commands. Each command consumes and immediately deletes a distinct repository
199
+ JIT SecureString under `/kungfu/burst/macos/`, then runs GitHub Actions Runner
200
+ 2.336.0 for exactly one job. The runner archive is pinned to the official
201
+ macOS ARM64 SHA256. No GitHub, signing, notarization, publication, SSH, or
202
+ static AWS credential is admitted to the instance.
203
+
204
+ The instance uses the exact retained Amazon EC2 macOS AMI, IMDSv2, an encrypted
205
+ delete-on-termination root volume, no inbound security-group rule, and the
206
+ AMI's preinstalled SSM Agent and AWS CLI v2. The three accepted jobs must bind
207
+ to the same host id, instance id, AMI id, source SHA, and campaign. At least one
208
+ job must exercise the full native lifecycle.
209
+
210
+ AWS imposes a 24-hour minimum Dedicated Host allocation. The contract therefore
211
+ keeps the one host for at least 24 hours even if all three jobs finish earlier.
212
+ At the recorded USD 0.6498 hourly rate, the minimum commitment rounds to USD
213
+ 15.60. A 30-hour fail-closed ceiling rounds to USD 19.49, below the dedicated
214
+ USD 25 budget. A ten-minute reaper terminates an expired campaign instance and
215
+ retries host release after the minimum allocation and Apple scrub constraints
216
+ allow it. Budget notifications at 80% and 95% invoke the same card-scoped kill
217
+ switch.
218
+
219
+ Qualification requires three trusted exact-source one-job JIT runs on the one
220
+ host, including at least one full run, plus proof that:
221
+
222
+ - the instance terminated and the encrypted disposable volume disappeared;
223
+ - Apple host scrub completed;
224
+ - the Dedicated Host was released between 24 and 30 hours after allocation;
225
+ - the repository has no registered campaign runner;
226
+ - AWS has no active campaign instance or allocated campaign host;
227
+ - actual incremental spend remained below USD 25.
228
+
229
+ ## Provider lifecycle
230
+
231
+ The three infrastructure templates live under
232
+ `infra/aws-us-elastic-runner-burst-plane/`. Creating a change set is the review
233
+ boundary. Executing it, completing the GitHub App connection, creating or
234
+ re-arming a webhook, allocating or releasing a Dedicated Host, writing cost
235
+ telemetry, dispatching paid jobs, operating a kill switch, and deleting a stack
236
+ are all explicit provider mutations.
237
+
238
+ The reviewed Phase 1 provider sequence is below. It deliberately separates
239
+ connection creation, change-set inspection, stack execution, cost observation,
240
+ and webhook arming:
241
+
242
+ ```bash
243
+ burst_profile=us
244
+ burst_region=us-east-1
245
+ burst_stack=kungfu-buildchain-linux-burst-poc
246
+ burst_project=kungfu-buildchain-linux-burst-poc
247
+ burst_connection_name=kungfu-linux-burst-poc
248
+ burst_change_set=phase1-linux-codebuild-poc
249
+
250
+ aws --profile "$burst_profile" --region "$burst_region" \
251
+ codeconnections create-connection \
252
+ --provider-type GitHub \
253
+ --connection-name "$burst_connection_name" \
254
+ --tags Key=kungfu:owner,Value=buildchain \
255
+ Key=kungfu:plane,Value=aws-us-elastic-runner-burst
256
+ ```
257
+
258
+ The returned connection is `PENDING` until an operator completes the GitHub App
259
+ handshake in AWS. Read back `ConnectionStatus=AVAILABLE` before creating the
260
+ change set. Do not put an OAuth token or GitHub token in the shell:
261
+
262
+ AWS CodeConnections connection names are limited to 32 characters, so keep the
263
+ shorter connection name even when the stack and project use the longer
264
+ Buildchain-specific name.
265
+
266
+ ```bash
267
+ burst_connection_arn=REPLACE_WITH_AVAILABLE_CONNECTION_ARN
268
+
269
+ aws --profile "$burst_profile" --region "$burst_region" \
270
+ codeconnections get-connection \
271
+ --connection-arn "$burst_connection_arn"
272
+
273
+ aws --profile "$burst_profile" --region "$burst_region" \
274
+ cloudformation create-change-set \
275
+ --stack-name "$burst_stack" \
276
+ --change-set-name "$burst_change_set" \
277
+ --change-set-type CREATE \
278
+ --template-body \
279
+ file://infra/aws-us-elastic-runner-burst-plane/codebuild-poc.template.yml \
280
+ --capabilities CAPABILITY_IAM \
281
+ --parameters \
282
+ ParameterKey=GitHubConnectionArn,ParameterValue="$burst_connection_arn" \
283
+ ParameterKey=ProjectName,ParameterValue="$burst_project"
284
+
285
+ aws --profile "$burst_profile" --region "$burst_region" \
286
+ cloudformation wait change-set-create-complete \
287
+ --stack-name "$burst_stack" \
288
+ --change-set-name "$burst_change_set"
289
+
290
+ aws --profile "$burst_profile" --region "$burst_region" \
291
+ cloudformation describe-change-set \
292
+ --stack-name "$burst_stack" \
293
+ --change-set-name "$burst_change_set"
294
+ ```
295
+
296
+ Only after the change-set resource list and IAM diff are accepted:
297
+
298
+ ```bash
299
+ aws --profile "$burst_profile" --region "$burst_region" \
300
+ cloudformation execute-change-set \
301
+ --stack-name "$burst_stack" \
302
+ --change-set-name "$burst_change_set"
303
+
304
+ aws --profile "$burst_profile" --region "$burst_region" \
305
+ cloudformation wait stack-create-complete \
306
+ --stack-name "$burst_stack"
307
+ ```
308
+
309
+ Arming requires a fresh, operator-observed CodeBuild cost value. `COST` is the
310
+ only mutable telemetry item and `CONTROL` is the only state cleared:
311
+
312
+ ```bash
313
+ burst_table=$(
314
+ aws --profile "$burst_profile" --region "$burst_region" \
315
+ cloudformation describe-stacks \
316
+ --stack-name "$burst_stack" \
317
+ --query "Stacks[0].Outputs[?OutputKey=='StateTable'].OutputValue" \
318
+ --output text
319
+ )
320
+ burst_observed_at=$(date -u +%s)
321
+ burst_actual_usd=REPLACE_WITH_CURRENT_CODEBUILD_ACTUAL_USD
322
+
323
+ aws --profile "$burst_profile" --region "$burst_region" \
324
+ dynamodb put-item \
325
+ --table-name "$burst_table" \
326
+ --item "{\"pk\":{\"S\":\"COST\"},\"actual_usd\":{\"N\":\"$burst_actual_usd\"},\"observed_at\":{\"N\":\"$burst_observed_at\"}}"
327
+
328
+ aws --profile "$burst_profile" --region "$burst_region" \
329
+ dynamodb delete-item \
330
+ --table-name "$burst_table" \
331
+ --key '{"pk":{"S":"CONTROL"}}'
332
+
333
+ aws --profile "$burst_profile" --region "$burst_region" \
334
+ codebuild create-webhook \
335
+ --project-name "$burst_project" \
336
+ --filter-groups \
337
+ '[[{"type":"EVENT","pattern":"WORKFLOW_JOB_QUEUED"},{"type":"WORKFLOW_NAME","pattern":"^AWS US Linux Burst Qualification$"}]]'
338
+ ```
339
+
340
+ The immediate global kill is idempotent and targets only the dedicated project:
341
+
342
+ ```bash
343
+ aws --profile "$burst_profile" --region "$burst_region" \
344
+ codebuild delete-webhook \
345
+ --project-name "$burst_project"
346
+ ```
347
+
348
+ After preserving the qualification evidence and proving no build is in
349
+ progress, rollback removes only the card-owned stack and connection:
350
+
351
+ ```bash
352
+ aws --profile "$burst_profile" --region "$burst_region" \
353
+ cloudformation delete-stack \
354
+ --stack-name "$burst_stack"
355
+
356
+ aws --profile "$burst_profile" --region "$burst_region" \
357
+ cloudformation wait stack-delete-complete \
358
+ --stack-name "$burst_stack"
359
+
360
+ aws --profile "$burst_profile" --region "$burst_region" \
361
+ codeconnections delete-connection \
362
+ --connection-arn "$burst_connection_arn"
363
+ ```
364
+
365
+ Phase cleanup evidence must include:
366
+
367
+ - CodeBuild batch/list results showing no in-progress build;
368
+ - controller state and accepted-build ledger;
369
+ - CodeBuild actual cost observation and its timestamp;
370
+ - no EC2 instance, volume, launch template, Auto Scaling group, or dedicated
371
+ host created by this phase;
372
+ - the CodeBuild webhook deleted or the whole stack deleted.
373
+
374
+ ## Source boundaries
375
+
376
+ The design follows the current AWS CodeBuild GitHub Actions runner contract:
377
+ `WORKFLOW_JOB_QUEUED` starts an ephemeral runner, the run id maps cancellation,
378
+ and the build terminates after one job. It uses the current GitHub guidance to
379
+ prefer ephemeral autoscaled self-hosted runners and to retain runner logs
380
+ externally. Provider documentation and the live AWS Price List query are the
381
+ authoritative external sources; this document is an auditable cache.