The "before" numbers to compare against once the app is split and CI skips tests a PR can't affect.
Nov 1, 2026 · Oct 18–29 (before Fede's Oct 30 changes) · re-run with bin/ci-baseline
About 84% of the AWS bill is CI. Every CI machine carries a label AWS bills by, so this is measured, not guessed: $5,117 of October's $6,066 in usage before credits. Nearly all of October's $678 credit landed on CI machines, so after credits it is still about 83%.
| Number | Before |
|---|---|
| CI spend per day | $100 |
| CI spend per merged PR | $0.69 |
| PRs merged per day | 145 |
| CI runs per merged PR | 5.6 |
| Merge → live (median) | 54 min |
| Open → live (median) | 123 min |
| PRs that touch no product code | 11% |
What this says about the plan. Splitting off the website would skip almost no CI: no PR in two weeks touched only website files. Tools, evals and docs-only PRs are about 9%, so path-scoped CI can skip at most about a tenth of PRs. The bigger levers are repeat runs (5.6 CI runs for every merged PR: 3.7 on the PR, 1.1 in the merge queue, 0.8 on main after) and a few slow steps.
The rest of the bill: the $411 "on-demand" line is $219 of full-price CI machines (used when cheap spare ones weren't available) plus $192 of data sent out of AWS; the $243 "VPC" line is the public IP address each runner gets. Vercel's bill can't be read from our login.
AWS dollars are usage before credits. "CI $" = everything tagged Purpose=ci. Job-hours are estimated (runs × median machine-minutes per run, from 30 sampled runs of each kind). Grey rows are after Fede's Oct 30 04:14 UTC changes; Oct 31 is still filling in at AWS.
| Day | Spot EC2 $ | On-demand EC2 $ | CI $ | PR runs | Queue runs | Main runs | Job-hrs | Merges | CI $/merge |
|---|---|---|---|---|---|---|---|---|---|
| 10-18 | 13 | 2 | 21 | 79 | 50 | 43 | 86 | 45 | $0.47 |
| 10-19 | 59 | 6 | 83 | 495 | 140 | 111 | 412 | 134 | $0.62 |
| 10-20 | 89 | 8 | 122 | 619 | 204 | 157 | 535 | 184 | $0.66 |
| 10-21 | 33 | 4 | 49 | 232 | 72 | 57 | 197 | 69 | $0.71 |
| 10-22 | 90 | 7 | 121 | 640 | 183 | 123 | 531 | 165 | $0.73 |
| 10-23 | 61 | 10 | 89 | 512 | 137 | 121 | 422 | 137 | $0.65 |
| 10-24 | 41 | 8 | 64 | 395 | 97 | 78 | 318 | 98 | $0.65 |
| 10-25 | 44 | 7 | 68 | 346 | 93 | 83 | 285 | 94 | $0.72 |
| 10-26 | 66 | 10 | 94 | 451 | 165 | 81 | 395 | 125 | $0.75 |
| 10-27 | 115 | 23 | 171 | 866 | 231 | 188 | 711 | 219 | $0.78 |
| 10-28 | 117 | 22 | 172 | 987 | 298 | 210 | 831 | 263 | $0.65 |
| 10-29 | 99 | 16 | 143 | 777 | 234 | 173 | 655 | 211 | $0.68 |
| 10-30 | 133 | 33 | 202 | 1023 | 318 | 203 | 865 | 270 | $0.75 |
| 10-31 | 70 | 10 | 101 | 538 | 205 | 153 | 484 | 183 | $0.55 |
| Total | 1031 | 167 | 1500 | 7960 | 2427 | 1781 | 6724 | 2197 | $0.68 |
Oct 18–29 only: CI $1,197 ($100/day), spot $827 vs on-demand $123, 1,744 merges, 9,728 runs (3.7 PR + 1.1 queue + 0.8 main per merge), ~448 machine-hours a day (estimate, ±30%).
| Window | PRs | Open→merge | Merge→live med / p90 | Open→live med / p90 | Live within 1 h |
|---|---|---|---|---|---|
| Before Oct 30 04:14Z | 942 | 66 | 54 / 77 | 123 / 328 | 2% |
| After (2 days) | 423 | 69 | 22 / 39 | 95 / 348 | 23% |
Minutes. The "before" row matches Fede's own baseline for the week of Oct 26 (125 / 54 / 2%), which checks the method. The "after" row is two days and already shows his changes working.
| Only touches | PRs | Share |
|---|---|---|
| Website (src/app/(public), components/marketing, config/site-paths.json) | 0 | 0% |
| Internal tools (admin/dev, agents, api/agents, api/admin/dev, components/maestro) | 6 | 0.3% |
| Tools (scripts, evals, docs) | 198 | 9.0% |
| CI plumbing (.github, scripts/ci) | 10 | 0.5% |
| A mix of the four above, no product code | 20 | 0.9% |
| Product code plus one of the above | 936 | 42.6% |
| Product code only | 1,027 | 46.7% |
11 commits touched website files in the window, all alongside product code. PRs with 100+ files, or whose file list could not be read, count as mixed.
Median machine-minutes per finished run: PR 38, merge queue 36, main 8. These are the noisiest numbers here (a 30-run sample moved the PR median between 20 and 38), so job-hours above are ±30%. Compare the per-run step medians below, not totals.
| Step | Median min per run that ran it | Runs (of 30) |
|---|---|---|
| PR · Unit Tests: run this shard | 19.6 | 16 |
| Queue · Full set: full unit tests | 28.8 | 7 |
| Queue · Full set: precise unit tests | 9.6 | 9 |
| Queue · fail-fast watcher (a small machine that waits out the whole queue run) | 8.9 | 30 |
| PR · Unit Tests: git checkout (shallow since Oct 31) | 4.3 | 30 |
| Queue · Guard pins | 4.1 | 30 |
| Queue · affected unit tests | 3.2 | 30 |
| Main · Preflight wait-then-cancel | 3.1 | 30 |
| PR · CI Checks: Mutation controls | 2.0 | 29 |
Mutation controls is the step to watch: 2.0 minutes on a typical PR run but 5.4 on average and up to 31, so a few PRs pay most of it (158 machine-minutes across 29 runs).
runs-on-workflow-name billing tag (exists, currently inactive; counts from the day it is switched on).AWS Cost Explorer daily, UnblendedCost, Usage records, pulled Nov 1. GitHub: every ci.yml run by event in 6-hour windows; merged PRs per 2-hour window with file lists; Production deployments by vercel[bot]. Live = first Production deployment containing the merge commit (Fede's definition, ci-two-hours). Re-run: propflow-docs/bin/ci-baseline --from 2026-10-18 --to 2026-10-31 --split-at 2026-10-30T04:14:00Z.