Getting a PR from open to live in under an hour.
Updated Tue Oct 20, 1:30 PM (3-day close-out written; watch stopped on Fede's call; all times Mountain). Fede's goal: open to live 3.6 h → under 1.5 h by Wed Oct 7, 1 PM, and 1 h by Fri Oct 9. Measured from GitHub and the runner job tables; dollars are estimates, not invoices.
Where we are (Oct 16). The queue is dialed in: 11-minute wait, 94% of PRs merge first try, main green. Merge to live is 60 minutes, tripled since Oct 12 by the 30-minute deploy wait; open to live is 116. Cost per merged PR is about $0.70. The Oct 16 deep dive below has the three opportunities and the three decisions.
Contents
Written Fri Oct 16 from three read-only inspections of the factory store, GitHub, AWS Cost Explorer and Slack, then fact-checked claim by claim (98 claims, 17 corrected). Nothing was changed. Every number traces to a command in the three reports or to the factory's live scorecard; days are UTC days, the factory's bucket, clock times are MT: merge to live · the Oct 14–15 jump · where the dollars go · the fact-check.
The short version. CI is stable: main was red for only 17 minutes in the last three days (Oct 15, 12:39–12:57 PM), the queue wait is 11 minutes against a 30-minute target, and 94% of PRs merge on the first try. Two things did move. Merge to live tripled on Oct 12 because the production deploy wait was switched from 5 back to 30 minutes. The Oct 14–15 cost jump is mostly more work, not more waste: the swarms merged 1.6 times as many PRs, and the cost per merged PR ($0.69–0.72) stayed inside the previous week's range ($0.51–0.77). The yellow reruns are real but small, and three quarters of them came from two flaky tests.
| Number | Before | After | Why |
|---|---|---|---|
| Merge to live, median | 20 min (Oct 7–11) | 60 min (Oct 12–16) | The deploy wait went 5 → 30 min on Oct 11, 8:25 PM. Nothing else in the path changed: waiting for the full test on main 7–8 min, the test itself 9 min, both flat. |
| Open to live, median | 74 min | 116 min | Essentially all of it is the deploy wait. Open to merge stayed at 51–52 min. |
| PRs live within an hour of opening | 32% | 3% | Same cause. |
| Production deploys per day | 79 | 39 (42 on the full days Oct 12–15) | The only thing the 30-minute wait buys: fewer Vercel builds, worth $3–7 a day. |
| AWS cost per day | $91–131 (Oct 10–13, Sat–Tue) | $202–203 (Oct 14–15; Oct 15 not final) | 292 and 280 PRs merged, against 155–202 a day before. The previous Thu–Fri cost $211 and $217. Cost per merged PR: $0.69–0.72, inside the previous week's $0.51–0.77. |
| Yellow: reruns behind a red, machine hours | 0–31 | 262 / 401 | About $9 and $14 a day. Two flaky tests caused 72% (Oct 14) and 78% (Oct 15) of it; see below. |
| # | Hypothesis | Change | Validate before touching anything | Undo | Stability risk | Expected gain |
|---|---|---|---|---|---|---|
| 1 | The 30-minute deploy wait is essentially the whole merge-to-live regression, and it made deploys less stable. Since the wait went back to 30 there have been six “production deploy failed” alerts; five trace to the wait (four machines taken back by AWS while the deploy job sat idle, one job that could not read main while holding). The 5-minute week had one alert, a real build error. Gera's agent set it at 8:25 PM on Oct 11, at his request, to save Vercel builds; no PR, no test, and the decision page still shows it unanswered (the who-said-what is in the merge-to-live report). | Set the wait back to 5 minutes. | Already validated: five days at each setting (the second still running), same deploy code, similar load (246 vs 228 merged PRs a day). Merge to live 20 vs 60, deploys 79 vs 39, full test runs on main 83 vs 83, AWS unchanged. | One setting. | Low and likely a gain | Merge to live 60 → 20 min; open to live 116 → 74. Costs $3–7 a day on Vercel. |
| 2 | Each time a flaky test fails in the queue, GitHub throws away the 6–8 trains behind it. The two flaky tests on Oct 14–15 (each edited by the PR that merged just before) cost 44 and 69 trains, $8 and $13, over 50 minutes and 1 h 45. The red-main check did not stop it: it watches only the full test on main, went red once 73 minutes in, and cleared itself 17 minutes later while trains kept failing. A third episode ($5, 24 trains) was a test whose built-in review date passed. | (a) Stop the line when one test fails for two unrelated PRs within 30 minutes. (b) When a PR edits a test file, run that file several times in its own PR checks. | (a) A read-only card in the factory app for a week, no action. A replay since Oct 8 shows 5 fires: 2 flaky tests, 1 expired-date test, 1 real break, 1 unchecked. (b) A one-time local replay, 20 runs per test version; attempted and stopped because the repo rule caps local test loops at 3 runs per 15 min, so it needs Fede's one-line go. The CI record (same commit passing and failing within minutes) is the primary evidence either way. | (a) Delete the card. (b) One workflow line. | Low for the card and the replay; Medium once it acts | About $6–13 on a bad day ($18.5 over Oct 14–15, estimate), and the trains behind the red. |
| 3 | About $8–11 a day (estimate) could come off a normal day without changing which tests run. Machine labels like “r8g” also pick premium variants that cost 1.5–2.5× the base price (about $2.8 a day extra on normal days, $5.7 a day averaged over Oct 8–15). An unused stopped warm pool costs about $1 a day with zero jobs on it. Runner machine logs cost about $2 a day. PR test shards spend 66 of their 419 seconds pulling full git history. | Name exact machine types and move 2-CPU helper jobs to arm (these two overlap); remove the warm pool; trim runner logs; poll Cost Explorer less often; shallow checkout on test shards. | Machine types: spot placement scores read Oct 16: safe to narrow the PR-only jobs ($3.6 of the $4.4 a day premium cost; keep at least 4 types), hold the two queue job classes (zone scores drop). All 13 reclaims on Oct 14–15 were on a base type that stays. Re-run on a busy afternoon first. Shallow checkout: the read-only replay first, because full history is what makes “a known-red file this PR edits still blocks” work. | One config line each. | Low housekeeping; Low–medium machine types and checkout | About $2.8 + $3 + $2 a day (estimates); about 45 s off every test shard. |
Sat Oct 17, 2:40 PM MT: Fede chose live rollout over shadow mode. Steps 1, 2b, 3 and 5 ship as small PRs with no switch and a 6-hourly watcher for three days; the fold and the deploy-wait change are dropped; batching (2a) is on hold on Fede's yes at 3:10 PM, because GitHub's queue setting tests every PR separately (no saving, up to 15 min slower; tried Sep 13) and the real saving needs our bot to become the merger, a decision for next week with Gera. Savings on the page are also read as percent of the $142 bill: chip 11–13%, precise tests up to 19%, batching 9–14% (held), checks at arm 4–7%, no second full test 4%. The two paid shadows are off; the selector shadow stays until the queue PR lands.
Percent is of the $150 a day the bill averaged Oct 11–15 (m, factory). Watch so far (Sun 12:55 PM): 4 ticks over 18 hours, 0 red main pushes, 0 missed tests, production level with main, sweeps green every 2 hours, big jobs on the newer chip. One train lost its machine to a spot take-back at 1:58 AM; the retry fired, passed, and the PR merged 10 minutes later. Dollars: AWS cost data arrives about a day late, so Saturday still reads as partial ($138, high because the shadows and bot trains ran until 2:40 PM and we merged ~10 PRs); the first clean day with every step live is Monday Oct 19, readable Tuesday morning. Each line is a small PR with no switch; the watcher checks red-main rate, selector misses, machine families, sweep and promotion, and the daily dollars every 6 hours for three days and a fixer acts on a regression.
| Step | What changed | Saves (% of bill) | Status |
|---|---|---|---|
| 5. Chip | Every machine label asks for the newer, cheaper chip first and falls back to the older one (no more all-or-nothing, which broke the queue 3 times before). | ~7% (3–10) | Merged 3:40 PM (#20837). Watch: machine families, launch failures. |
| 1. Precise tests | PR checks run only the test files the change can reach; the queue's full-set machines do the same, and run everything when any changed file is missing from the map. | ~3% measured by the builder ($4–5 a day, e), not the 19% modeled: the selector always pins ~600 tests so small PRs fall back to the full list, and the "any unmapped file runs everything" rule sends 68% of trains (36 of 53, Oct 16–17) to the full set. Replays: 51 of 51 PR failures caught; queue 97 of 109 caught, about 3 likely real misses in 14 days, each caught by the sweep and reverted. | PR side merged 5:10 PM (#20856); queue side merged 7:45 PM (#20867); the selector shadow is off, all four shadows are now off. Decision for Fede: exempt newly added files from the "run everything" rule? Yes = 39 of 53 trains precise, about $1–2 a day more, likely misses ~12 per 14 days instead of ~3. Recommend hold a week, decide on live numbers. |
| 2b. Sweep | The full re-test after every merge becomes a full sweep every 2 hours; production advances only when the queue, the tip's checks and the newest sweep are all green. | ~5% | Merged 4:55 PM (#20851); first sweep green, production moved at 5:27 PM. Watch: sweep reds, release age. |
| CI Checks | Type check with the faster checker on queue trains; the checks machine is 8 cores on the newer chip instead of 16. | ~7% | Merged 5:45 PM (#20858). Watch: train wall time, memory kills. |
| Guard pins | One guard-pin job per train instead of three. | ~1% | Merged 7:40 PM on its third train (#20859). Its first two trains died when AWS took back the spot machine running the checks job, twice in 10 minutes (confirmed in AWS); not this PR's code. |
| Spot-kill retry (fix found by the watch) | When a spot machine is taken back mid-train, the runner is supposed to mark the job so our fail-fast holds and retries it in the same train. The mark was missing on all 3 cancelled trains since Oct 14, so each train died and the PR was thrown out of the queue. Fix: a kill signal (exit 137) with no real test failure now counts as a take-back and gets the one retry. | stability, not dollars (fewer dead trains, fewer re-queues); matters more on the newer chip, whose take-back rate is 2.2% vs 0.26% | Merged 8:35 PM (#20870), no switch; proof is the next machine take-back in a train. Out of scope: a kill that leaves only "canceled" behind (1 of the 3). |
| 3. Checks at arm | PR checks run when the PR is armed to merge, not on every push. | ~3% | Held for Fede: the repo rule says arm only a PR whose checks are already green (Gera's cap counter). Built (#20840), not armed. |
| 2a. Batching | Several PRs tested per train. | 9–14% | Held (Fede, 3:10 PM): GitHub's setting tests each PR anyway; needs our bot as merger, next week with Gera. |
The watch ended early on Fede's call (it was due at 5:52 PM). Twelve ticks over three days: no red push to main caused by a step, every red merge run either rescued by the spot retry or a real PR conflict, sweeps and releases green on schedule, every job got a machine. One regression (the first batch train stalled) was recovered by hand and fixed forward the same morning. All numbers below are measured (m) from the factory cost endpoint (fetched 12:48 PM Tue) unless marked (e). The Tuesday bill is the first full weekday with everything live; it posts Wed Oct 21.
| What | Before (Oct 11–17 avg) | After | Source |
|---|---|---|---|
| Machine hours per merge-queue run | 5.28 | 4.28 Mon, 4.40 Tue so far (−17 to −19%) | factory days[]: usefulH / runs (m) |
| Machine hours per PR check run | 3.50 | 2.07 Mon, 2.41 Tue so far | factory days[]: prH / prRuns (m). Not a clean compare: checks-at-arm adds cheap unarmed runs, so per commit (−14%, Mon morning) is the fair number. |
| Heavy re-test runs on pushes to main | 265 a day | 12 sweeps a day | workflow 371849834 run counts (m) |
| Re-run hours (queue) | 197 a day (Oct 13–16) | 3.8 Mon, 9.5 Tue so far | factory days[]: rerunH (m); cause not separated |
| PRs per merge-queue run | 1 | batch bot live: first train landed 4 PRs in 1 run (Mon 11:32 PM) | train #21369 (m) |
| AWS spend per day | $152 total AWS (Oct 11–17 avg, m, factory spend[]); plan baseline $142 | Fri Oct 17 $137.94 (complete, m), Sun Oct 18 $43.11 (complete, quiet day, m), Mon Oct 19 $110.92 (incomplete, m, factory spend[] 12:48 PM), Tue Oct 20 pending | factory /api/cost spend[] |
Verdict. Per unit of work, CI is about 15–20% cheaper and stable. Measured savings at normal volume: about $22/day (m, table below), before batching and the precise selector, which only went live Mon Oct 19 (selector about $2.6/day, m; batching modeled $14/day, e). The plan's $63–68/day is not proven; the Oct 20–21 bills decide it. Open, owned elsewhere: the Fri Oct 23 merge-queue pass-rate check (bar 95%, was 90.2%) is handed to Smith on the engineering bridge; the batch bot's first real red train has not happened yet, so its break-up path is merged but unproven live.
Everything below is measured (m) unless marked (e). The AWS bill itself cannot show the rollout yet: the last complete billing day is Fri Oct 17, the day before the rollout, and Cost Explorer lags about 24 hours. The first full day with every change live is Tue Oct 20. Rate for every $ line: $0.0253 per vCPU-hour, all-in (Oct 17 AWS CI about $124 for 4,904 vCPU-h, m, next-savings report); at the factory's own EC2 rate ($0.0354) multiply by 1.4. Volume for $/day: the Oct 11–17 average (468 PR runs, 258 trains a day, m, factory). Sunday Oct 18 was quiet (79 PR runs), so a raw $/day compare would flatter us; these are per-unit changes times normal volume. Watch, ticks 7–8 (7 AM and 1 PM Mon): 0 red pushes to main and 0 red trains in the last 6 hours of each tick, sweeps and releases green on schedule, all test jobs on the newer chip. Batching bot live since 9:07 AM after a fix forward (its park step read a field the runner's GitHub CLI lacks); no train formed yet on a quiet Monday. Ticks 9–10 (7 PM Mon, 1 AM Tue): 0 red pushes to main. Every red-looking merge train was a spot machine taken back mid-run; the in-run retry passed and the PR merged on the same train, so none were lost. The spot pool for the checks job was widened to six machine families anyway. The batching bot formed its first real train at 11:57 PM (three PRs). The train caught a genuine conflict between one PR and main, but the bot had no way to break up a train that fails before reaching the queue, so the three PRs sat parked for about an hour. They were put back in the queue by hand and the bot returned to shadow while that gap is fixed.
| Lane | Shipped | Plan $/day (e) | Measured so far (m) | Proof |
|---|---|---|---|---|
| Whole PR side | all PR-side steps | — | 3.88 → 3.33 vCPU-h per pushed commit (−14%), Oct 17 vs Oct 19 so far. About $6/day at normal volume. | factory /api/cost, PR vCPU-h over distinct head commits |
| Whole merge queue | all queue-side steps | — | 5.28 → 4.22 vCPU-h per train (−20%), Oct 11–17 avg vs Oct 19; re-runs excluded. About $7/day at normal volume. | factory usefulH / runs |
| 2b. Sweep instead of re-test after every merge | #20851 Sat 5 PM, #20961 | 6.0 | Heavy re-test runs 265 a day (Oct 11–16) → 12 (Oct 18) → 8 so far Oct 19, −95%. The 12 sweeps cost about $1.9/day. Saving at least $4.9/day; the "before" cost is not settled (two samples 406 and 42 vCPU-min). | workflow 371849834 run counts; sweeps 39236991921, 39223690888 |
| 6. Advisory tests + harnesses nightly | #20996 11 PM | 2.1–2.35 | 0 advisory and 0 harness runs on pushes to main since merge (45 advisory push runs on Oct 18, 40 vCPU-min each, about 30 vCPU-h). At Sunday's 45 push runs that is $0.74/day (m); at the normal 258 merges a day and the measured 40 vCPU-min per run it is about $4/day (e, from the measured per-run cost). Finding: the advisory run still hangs in its mutation-control step until the 20-minute cancel, before and after, so #20983 is a hanging step, not a missing machine. | runs by workflow id 370674800 / 371576146; runs 39194923206, 39218825403 |
| 5. Chip swap, remaining x86 jobs | #20979, #20981 ~10:40 PM | 0.8–0.9 (chip-swap report) | Machine label moved x86 → arm64, durations unchanged (queue re-entry guard 0.3–0.4 min, harness filter 2.0 vCPU-min both sides). Worth about $0.79/day (e) from hourly prices; the billed instance was not pulled. | guard runs 39199751564 / 39199454256 → 39250959217; harness 39194923126 → 39201346424 |
| 3. Checks at arm | #20840 9:29 PM | 11.6 combined | Flat so far. An unarmed push now costs 52 vCPU-min instead of 276 (sec60, n=6 vs 16). But overnight sessions armed every PR at open, so commits got 1.56 runs instead of 1.05 and the arm run added back what the push saved. It pays once more than ~19% of commits are superseded before arming. | jobs API for 30 runs, measure/sample_ids.json |
| 1. Precise test selector | #21014, #21015, #21033 12–1 AM | ~2.6 (re-modeled) | Not separable yet. Indicative: unit-test shard groups per tested PR run 6.8 → 4.6 (n=5 / 7). Queue side is inside the −20% above. | same job samples |
| 2a. Batch trains | #21032, #21048, #21061 1–3 AM, dark | 14.1 combined | $0. First real train Mon 11:57 PM (3 PRs). It went red on a real conflict and stalled about an hour, because the bot could not yet break up a train that fails its own PR checks. Back in shadow while that is fixed. Before that: The bot was off overnight (its arm-triggered check showed red on PRs until the paging fix); set to shadow 6:23 AM; the dry run passed with an empty plan (nothing armed at that minute). Goes live on the first real shadow plan. | run 39251728292; batch-trains report |
| 4. Glue folds | none | 4.4 | $0, nothing shipped: no fold clears $0.5/day without widening a job's token (Fede's call). | glue-fold report |
Sum of what is measurable this morning: about $22/day at normal volume: the two "whole side" rows ($13, which already contain the chip swap, checks at arm and the selector) plus the two push-to-main lanes that sit outside both columns, the re-test sweep (at least $4.9) and the nightly advisory move (about $4, e from the measured per-run cost). The plan modeled $63–68/day. The gap is mostly the lanes that have not had a chance to show yet: batching ($14 e, zero trains so far), checks at arm ($12 e, cancelled by arm-at-open), and the selector. AWS bill, last complete days (m, factory, UTC days, EC2 compute $ / total AWS $): Oct 14 $158 / $202, Oct 15 $155 / $203, Oct 16 $128 / $175, Oct 17 $90 / $138; Oct 11–17 average $111 / $152. Oct 18 and 19 are incomplete and not comparable yet.
Updated Sat Oct 17, 7:05 AM, after the overnight proof fleet (five lanes, five skeptics, one reconciler) and the shadows. Marks: (m) measured, (e) estimate, (r) replay of real records. Evidence, tracking issue #20581. What changed tonight: three dark workflow files and a shadow bot merged to main; the fold shadow was redesigned after a blocking review before it merged. They log only, gate nothing, comment on nothing (the bot creates and deletes its own shadow-batch branches); the required checks on main and the merge guard are untouched; nothing in AWS or GitHub settings changed.
The bill is a PR counter: 239 merged PRs a day (m), each starting about 117 machines (m) and paying for 2.9 complete test runs (m). Together, after tonight's replays: $142 to about $68 a day, 52% off (e, range $59–80) with 15-minute batches, if agents arm their PRs when the work is done. If they arm at PR open, as today's no-local-type-check rule pushes them to, it is $71, right on the 50% line. The evening model's $63 priced step 3 with the bugs per-push checks catch as free (+$4) and batching from a coarser replay (+$1). The $2,000-a-month line, about $53 of CI/CD, is not reached in any case: it needs about 160 merged PRs a day instead of 239, or a rented server.
"Alone" is the swing by itself against today's $142; "stacked" is what it still removes after the earlier steps, which shrink the same machines. Only the stacked column adds up: $74. At 30-minute batches the end is $67 (range $58–79).
| Step | What changes | Alone | Stacked | Bill after | Confidence | Proof status, Sat 7:05 AM MT |
|---|---|---|---|---|---|---|
| Today | 142.0 | |||||
| 1 | Test once + precise test choice (PR and queue) | 27.3 | 27.3 | 114.8 | pending | Shadow live on main since 11:58 PM Fri (#20623): every red train and 1 in 4 green logs the chosen list beside what ran; 11 trains logged by 6:40 AM (10 green, 1 cancelled, no red yet, so 0 misses of 0); on them the precise list would have run 21% of the test CPU (606 of 2,872 CPU-minutes, e) and 810 files at the median against 3,438 ran. Replay of 99 red trains: 83 caught, 24 of 29 real failures; 14 of the 16 misses sit on 4 files that also failed with main already red (hindsight: 44 trains used a map built after them). Bar: 0 misses on 10+ real failures, about Tue Oct 20 Final shadow tally (Tue Oct 20): 37 trains logged, 0 real failures in the window, so 0 misses proves nothing; bar (0 misses on 10+ real failures) not met. The precise list was 13–58% of the full set’s machine time (5 samples). Shipped live Oct 19 on the 14-day replay instead; measured ~$2.6/day (m). |
| 2a | Batch PRs per queue run (3 at 15-minute windows, 5–6 at 30) | 20.3 | 12.8 | 102.0 | replay, in part | Replay of 16 days of real merges: $17.4 a day at 15-minute batches, $22.4 at 30 (r, machine cost only). On the model's all-in basis that is $20.3 / $26.0 alone, so v2's $25.5 holds only at 30 minutes; the stacked figure is modeled. Shadow bot live since 12:17 AM (#20617, #20616): groups real armed PRs each 30-minute window, dispatches dark trains (cap 24 a night), bisects reds, merges nothing. Its first batch caught a defect in our own dark train (checkouts without credentials, 4 false reds), fixed 2:01 AM (#20659). Since then 5 dark trains finished, all green: 7 PRs in 5 batches, 7.6–8.5 min each (m); the real queue ran 18 trains in those windows, because many PRs enqueue without arming Final shadow tally (Tue Oct 20): 22 dark trains; the first 6 were false reds from a defect in the shadow itself (fixed, #20659), then 16 of 16 green. 41 PRs in 18 batches (median 2, max 5) against 61 real trains in the same windows: about half the trains at Oct 17 volume. Real bot live Oct 19; first train landed Mon Oct 19, 11:32 PM (4 PRs, one queue run). |
| 2b | Drop the post-merge re-test; full sweep every 2 h | 6.0 | 5.9 | 96.1 | modeled | Replay of the record: in 9 days of today's setup, 1 real break the queue passed (#19094) and the re-test kept out of production; the other 13 red spells were flakes, a clock test or a dead machine, held deploys ~180 min and caught nothing. Since Sep 30: 8 real misses in 35 spells (r). The dollars are the model's prices on measured volume; no sweep has run |
| 2c | Ship the batch's build; main's run becomes a trigger | 1.3 | 3.2 | 92.9 | modeled | Measured: the train's build cannot ship as-is (test build, arm64, never uploaded), so the Vercel part stays Gera's. A thin trigger alone is $1.3 and 1 minute; with 2b, merges reach production 13 minutes sooner (r) |
| 3 | PR checks only when armed, not on every push | 9.6 | 6.4 | 86.5 | modeled | Replay of 2,155 merged PRs: runs per merged PR 2.09 → 1.30 mechanically, 1.53 once each caught bug costs a re-run (r). Worth $9.6 alone only if agents arm when the work is done; arming at open gives $1.8; Option B (type check and build every push, tests at arm) $5.3 alone, $2.0 stacked. v2's $15.5 counted the up to 55 bugs a day per-push checks catch as free |
| 4 | Fold the glue machines | 6.9 | 4.7 | 81.8 | pending | Fold shadow #20628 live on main since 2:16 AM Sat. Its first version re-ran PR code inside a run that carries main's context (a cache-poisoning path the repo's rule 9 forbids) and was blocked; the merged version re-runs only main's own commits, 1 in 2 push runs, folded on one 8-CPU machine, paired with the merge-queue run that tested the same commit. 7 samples by 6:40 AM: 6 agree on every verdict, 1 shows a guard-pin red only in the folded run: diagnosed, the fold ran 103 bookkeeping pins the queue skips (fixed, #20736 merged 7:20 AM) and one test-runner timeout fired after every file had passed, a load effect of one process doing three shards' work, which the samples keep counting; 6 machines become 1, $0.103 becomes $0.050 per sampled run on the covered jobs (e, lane 1 rates), 6.6 min becomes 13.8 on the one machine. About 50–60 samples a day; the bar is 500 samples with every verdict agreeing and no more load reds than the real shards get, about Oct 26, when the shadow stops itself Final shadow tally (Tue Oct 20): 29 samples, 22 agree, 7 false reds from one cause (guard pins scanning a temp copy in parallel). One machine instead of six, $0.097 → $0.027 per run (m, shadow artifacts), but slower (median 7.2 → 11.1 min). Bar not met; stays dropped. Only 2 newer-vs-older chip pairs (ratio 0.74), too few to judge. |
| 5 | Chip swap: Graviton4 first, x86 helpers to ARM | 25.4 | 13.6 | 68.3 | pending | 7-day spot prices support a $19.4–19.6 ceiling (m prices, e speed ratio; chip part only); the lane's $14.1 "realistic" is 75% of it and unmeasured, and the skeptic's $12.8 adds a take-back cost 5× higher. Take-backs, not launches, are the risk: 2.2% on Graviton4 vs 0.26% on Graviton3 (m, 9 days). The fold shadow records the chip each leg got: one cross-generation pair so far, Graviton4 at 0.81 of Graviton3's time (m, one pair); only a 48 h canary measures the rest |
| Swing | Fence it crosses | Tried before → what is different now | Proof (zero stability risk) · undo |
|---|---|---|---|
| 1. Test once + precise choice | "Never red main" and the rule that no pre-merge guard goes until the post-merge net catches a real break (it did, Oct 6). Switch only after the shadow shows 0 misses; Fede and Gera's call. | A tree-hash cache (Oct) skipped 1 run in 141. Per-test result keys were approved Oct 5 and never built because the test-read map did not exist. The map merged Oct 13; a chooser on it caught 83 of 99 red trains replayed tonight, 24 of 29 real failures (hindsight: 44 trains used a map built after them). | Shadow on every real train logs the chosen list beside what ran; pass bar 0 misses over 10+ real failures. Result keys logged as "would skip" on main; pass bar 0 real failures on a passed key. Undo: revert the selection PR. |
| 2a. Batch PRs per train | GitHub's merge queue, which cannot batch builds, and "the queue is the only way onto main": our bot (or Trunk, free tier, or Mergify at ~$2–4 a day) becomes that way. "Don't slow shipping" if batches wait to fill. | Five native batching tries Jul–Oct 1 never batched; the Sep 13 one died in 42 min because required checks never reported. Trunk and Mergify were researched Oct 2–4, never tried. Planned: the bot reports its own check; the ruleset requires one job ("Nested Gate"), classic protection also names Build, Type Check, Lint, Unit Tests, the leasing gate and review; test jobs would retry once on a spot reclaim (35 of 132 queue reds were reclaims; queue jobs run with retry off today). | The shadow bot is live: groups real armed PRs each 30-minute window, pushes a batch branch, dispatches a dark train, bisects on red, merges nothing. Plus the 16-day replay of real merges as 15- and 30-minute batches. Undo: stop the bot; GitHub's queue never left. |
| 2b. Drop the post-merge re-test | Production ships only commits the post-merge run proved. The sweep every 2 h keeps that: red sweep bisects and reverts first; a break the queue misses could run live up to about 2.5 h (1 such case in 9 days). | "Ship on queue-green, heavy run as alarm" was proposed Oct 6 and waited on Fede. Trinity's Oct 6 look-back: 42 reds, 0 production reverts in 14 days; since Sep 30 the run went red 95 times, and before the gate 2 of 3 real misses shipped. A clock-dependent test gave 4 main reds on Oct 10, which is why the sweep is hours, not nightly. | Replay of the heavy run's record (done); the sweep runs beside it for two weeks. Undo: turn the heavy run back on. |
| 2c. Ship the batch's build | The merge-guard code and the Vercel build audit are Gera's. The deploy trigger moves to a thin run on main; it is not deleted. | "Build once" was raised Sep 13 and never started. Vercel's billing for prebuilt deploys is unconfirmed. | One throwaway prebuilt deploy (Gera). Undo: a Vercel setting. |
| 3. PR checks only when armed | Gera's rule that a push gets a verdict in the cloud (ADR-0040). Agents iterate with the cloud-test command, live since Oct (208 runs a day). | "Test each change once" was proposed three times and blocked by the rulings. Now cloud-test exists and the train still gates main. | Replay of 2,155 merged PRs (done): runs if only the arm run counted, and where their red catches surface. Then a 1-in-4 sampled live trial. Undo: re-enable the per-push trigger. |
| 4. Fold the glue | Required-check names and the merge guard (Gera); one folded job gains read permissions (Fede). | The Sep 9 fold combined real work, so one lost machine failed three required checks. Smith's Oct 5 "tiny jobs together" was never built. The one-machine trial's second version never ran. Now: fold only the small helper jobs; none of the Oct 14–15 reclaims hit them. | Shadow live: main's own commits re-run folded, trusted code only; pass bar: same verdicts across 500 samples. Undo: Revert button. |
| 5. Chip swap | None. 48 h canary, one job class at a time, PR side first, queue after 7 clean days. | Graviton4-only on Sep 29 was reverted after 3 h 42 min when its spot pools ran dry (or hit the 512-vCPU spot limit; unresolved); on Sep 30 all ARM pools ran dry and small jobs went to x86. Now: Graviton3 stays in the list as fallback, and the six-zone fleet landed Sep 30. 42% of machine spend still runs on the older chip, which bills ~60% more per hour (m) and runs ~29% slower (e, job medians). | The fold shadow records which chip each leg got; cross-generation pairs give the speed ratio, same-chip pairs the noise floor. Then the canary with an automatic revert if queue-to-start grows 30 s, on-demand passes 2%, take-backs pass 5%, or any launch fails. Undo: Revert button. |
| Reserve: rent servers | No self-hosting (Jul 30), spot only, no persistent runners, a purchase; Gera: "only if we need the bill under ~$40/day". | A Mac mini runner ran 1 h 54 min on Jul 30, nothing broke, reverted. Alone it is the biggest lever ($40–60 for 2–3 servers, e); after the five swings it is worth $15–18 (e). GitHub's postponed per-minute fee would hit it too. | Two weeks of one rented box taking only the folded glue jobs. Undo: remove the label. |
| Bucket | Today (m) | After (e) | Range (e) | After, as a bar |
|---|---|---|---|---|
| Testing a change | 60.0 | 26.1 | 21.8–31.7 | |
| Per-machine overhead (boot, public IP, disk, logs, data transfer) | 46.2 | 24.2 | 20.7–28.3 | |
| Everything else | 20.9 | 16.3 | 15.7–17.7 | |
| Waste around tests | 14.9 | 1.6 | 1.2–2.4 | |
| AWS CI/CD | 142 | 68 (−52%) | 59.4–80.1 |
Measured (speed lane, Oct 7–16): a merged PR takes 61 minutes to go live, an opened PR 116 (medians, m). about 40 of those minutes are the 30-minute deploy window set Oct 11; the days before it sat at 20 and 72.
| Minutes, medians | Merge → live | Open → live | Basis |
|---|---|---|---|
| Today (deploy window 30 min) | 61 | 116 | m, store, Oct 12–16 |
| Where it goes (open → live) | re-pushes 14 · last PR check 19 · waiting to be queued 7 · queue and train 12 · merge → live 61 (main's run 7 + heavy re-test 8.5 + window wait and build 46) | m, middle-band means that add to the median | |
| Per step | 1: 0 / −4.5 (e) · 2a: 0 / +8 at 15-min batches, +17 at 30 (r) · 2b: −5 (r) · 2c: −7.5 with 2b (r), about −1 alone (e) · 3: 0 / +4 (e; −6 to +24 by when agents arm) · 4: 0 / −1.7 (e) · 5: 0 / −1.1 (e) | reconciler tally | |
| After the staircase, window kept at 30 | 49 (−13) | 108 (−8) | r + e; at 30-minute batches open → live is +1 instead |
| Window back to 5 only | 20 (−42) | 72 (−44) | m, Oct 7–11 vs 12–16; +$3–7 a day of Vercel builds (Gera's bill page) |
| Window 5 + staircase | 12 | 72 | r + e |
| Free speed moves, ranked | Minutes per PR | Money | Owner |
|---|---|---|---|
| 1. Deploy window 30 → 5 (delete one repo variable) | −42 merge → live, −44 open → live (m) | +$3–7 a day Vercel (Gera's bill page); also ends the spot-reclaim deploy failures seen since Oct 12 | Fede + Gera |
| 2. Gera's sessions arm auto-merge when the work is done (Fede's already do: 0.1 min from green to queued vs 6.8) | −7 per Gera PR (m), ~1,100 PR-minutes a day (e) | $0; arming at PR open instead would erase most of step 3's money | Gera |
| 3. If the window stays at 30: ship release's newest commit when the window closes | −29 (r) | $0, same build count | Gera (deploy path) |
| 4. Prefer 15-minute batches over 30 when 2a ships | +8 instead of +17 (r) | about $1.7 a day less saved (e) | Fede |
| Checked, no free gain | shards already balanced (0.2–0.4 min apart), runner wait 0.3 min flat under load, review bot lands 12 min before checks finish, cache hits in all sampled logs (m) | ||
The shadows log through the weekend: the selector's bar lands about Tuesday, the fold's about Oct 26, the bot runs up to 24 dark trains a night. The first night already paid off twice: the bot exposed a defect in the dark train, and the fold shadow found one guard-pin disagreement, explained and its fix merged by 7:20 AM. On a yes: Monday the chip canary and Gera's step-3 pick. At zero misses: switch test selection, then the bot takes the queue, then 2b with 2c.
GitHub has announced and postponed, with no date, a $0.002-per-minute charge on every Actions minute, self-hosted included: $99–136 a day today (m, market lane), $58–73 after the swings (e, on the evening model). Two hub files are loaded by about 4,000 tests each, so 41% of commits select over 200 test files; splitting them is Gera's. Shadows that run after CI appear as checks on main's newest commit; nothing reads those for a merge or deploy decision at today's window.
Not ours: Gera's open CI PRs, the Vercel build audit (prebuilt deploys possible per Vercel's docs, build-minute billing unconfirmed), ADR-0040, the ruleset, the merge guard.
Written Fri Oct 16 from six read-only lanes: a census of every CI step and machine (Oct 7–15), the graveyard of every attempt since Sep 9 (the factory Log's 112 entries, 48 of them CI attempts from Oct 6–13; 14 session transcripts), Smith's bridge answer, a test compute study, outside references, dedicated-server pricing, and a paired re-read of the Oct 1 one-machine trial. Nothing was changed. Corrected Fri ~3:30 PM: Move 1 re-sized from the trial's paired runs (the first version said $25–35); 3:32 PM: a line-by-line number check applied (72 cells, 11 corrected). Evidence folder. Days are UTC; clock times MT.
The short version. The two busy days were 12% of the two-week bill. The steady state is the problem: about $160 a day of AWS, $0.51–0.77 per merged PR, 239 merges a day. Two moves that change how CI runs, not what it tests, plus housekeeping, take about a quarter off. Coverage trades reach 32–38%. Nothing inside the stability fence reaches half; that takes a different machine model, and the decision is whether to shadow one now.
| Line | $/day | $/month | Note |
|---|---|---|---|
| AWS, everything (the factory's number) | 160 | 4,800 | Oct 7–15 mean; median 171 |
| product, not CI | 14 | 420 | DynamoDB reads, Lambda, backups |
| one-off | 4 | — | CloudTrail spike Oct 8–9, stopped |
| AWS CI/CD | 142 | 4,270 | What this plan halves |
| Vercel build minutes | 7–9 | 220–270 | After Gera's cuts; the $60 platform fee is not CI |
| GitHub Actions, metered AI in CI | 1.5 | 45 | The review bot is on the subscription |
| Half of AWS CI/CD | −71 | −2,130 | First target |
| Budget, read as the AWS bill | 67 | 2,000 | “$200 a day is $6,000” was the AWS number. Half is a waypoint. |
| Bucket | $/day | Share | Inside it |
|---|---|---|---|
| Testing a change | 60 | PR first pass 25.7 · queue re-test 27.4 · main's full test, push CI 6.9 | |
| Per-machine overhead | 46 | Boot, shutdown 16.9 · public IPs 6.7 · bytes leaving AWS 6.8 · logs 6.3 · disks 5.4 · webhooks 3.5 (1.2 of it may be product) · CPU credits 0.6. 27,900 machines a day; 63% work under a minute | |
| Everything else | 21 | Glue, bots 3.4 · extras, nightlies 3.9 · deploys 2.4 · other repos 2.8 · Config, GuardDuty 4.3 · control plane 4.1 | |
| Waste around tests | 15 | Re-pushes 10.4 · trains rebuilt behind reds 3.6 · never merged 1.0 |
| Move | Saves $/day | What changes | Tried before → different now | Prove first · undo · risk |
|---|---|---|---|---|
| 1. Fold the glue, not the tests | 5–8 and up to ~1.7 min off every push (estimate) | The ~11 one-to-two-CPU helper jobs in every PR run (plan, gates, verdict posters) become steps or one job; the same on queue trains and the follow-up workflows. Test shards stay. In the Oct 1–2 trial the verdict chain finished 1.7 min (median) after the last real check, on every push. About $4.5 of this is the PR runs (trial re-read, Oct 15 count: 10.9 glue machines per run; the first deep dive put all glue at $5–6); the rest, queue trains and the follow-up workflows, is an uncounted estimate. | One machine per push, shadow Oct 1–2 (308 pushes, 39 paired): 1 machine vs 22, same time at the median (8.1 vs 8.0 min), ~5 CPU-min saved, $9–15 a day, nearly all per-machine overhead. The 16-core re-run (merged Oct 6) never ran: switched off Oct 2, never re-enabled. One box is wrong today: 44% of runs need the 8-core shards. | Store count of glue machines per run (Oct 15: 10.9), then 48 h before vs after · Revert button · Medium: 100+ tests and scripts key on job names; names agreed with Gera first. |
| 2. Build once, ship what the queue tested, wait back to 5 | AWS ~0 Vercel 7–9 merge→live 60 → ~20 min | The queue already production-builds every train (310 s on 16 vCPU). Keep that output in-region; on promote, ship it prebuilt instead of Vercel building again. The 30-minute wait loses its reason. | Raised Sep 13, never started. “Ship the exact commit the queue tested” open since Oct 6 (Gera's call). Wait 30 → 5 (Oct 6) → 30 (Oct 11). | One throwaway prebuilt deploy: $0 build minutes? env vars? Output leaves AWS only on promote (about 79 a day at a 5-minute wait, not 286 trains) · Vercel setting · Low–medium; Gera's Vercel lane. |
| 3. Housekeeping | 22–27 | Shallow checkout on the test shards 3 · in-region caches with per-job isolation ~4 (bytes out cost 6.8 today) · single runner logging 2.5–3.2 · Config trim 1–2 · one runner stack 2–3 (Smith: ~$8 for three) · dead steps ~2 (the push-to-main CI run stays: it triggers every deploy; its test work, the advisory harnesses and red nightlies can go) · main's duplicate guard pass 1.5 · empty test-choice job 0.8 · PR machine types 2.5 · rule: no push while checks run unless red ~5 (re-pushes cost 10.4). All estimates from the store. | S3 cache dropped Sep 13 (security) → per-job isolation since RunsOn v3.2. Stacks unanswered since Oct 5. Logs “Fede's call”. Config “smallest set”. Cancel groups rejected Sep 18 → the lever left is how sessions push. | Each from the store, read-only · one step each · Low: only checks that never block or never fail stop running. |
| 4. Owner trades (not asked) | 13–22 | Hub trains run their own list, up to 7–10 (ceiling; list sizes not measured) · test files share a process, opt-in 3.5–7 · queue build on 8 vCPU 3–5 · two PRs per train: GitHub's own queue cannot batch (its docs), so it needs a third-party queue; ceiling ≤6.9, not counted | Thin queue (Oct 4): fails per 100 trains 15.8 → 21.7. Shared process (Oct 3): 49 files failed. The 16-vCPU box came from out-of-memory deaths. | Replay the 8 full-set reds at the higher cap; 5× A/B on one shard · one value each · Medium–high: misses reach main; flakes. |
| 5. Platform change | 100+ on paper | Dedicated servers (4 × Hetzner AX162-R ≈ $30 a day, 384 x86 threads; unverified third-party price, setup fees excluded) or long-lived nodes with a micro-VM per job (Actuated, $150 + $125 per server a month) | Gera, Oct 14: “only if we need the bill under ~$40/day”; the budget leaves about $53 for AWS CI/CD if the $2,000 is the AWS bill. No self-hosted (Jul 30); spot only. Demand peaks 401–477 cores vs p90 171–205: a fixed fleet queues at busy hours. x86 not ARM; agent code on shared hosts; patching. | Two-week shadow fleet on a copy of the test lane, no required checks · switch off · High until shadowed. |
| Bucket | Today | Move 1 | Housekeeping | After |
|---|---|---|---|---|
| First pass on the PR | 25.7 | −0.8 | −5.5 | 19.4 |
| The queue's re-test | 27.4 | −0.5 | −0.8 | 26.1 |
| Full test on main, push CI | 7.0 | −1.3 | 5.7 | |
| Re-pushes | 10.4 | −5.0 | 5.4 | |
| Rebuilds behind reds, never merged | 4.6 | 4.6 | ||
| Boot and shutdown | 16.9 | −3.0 | 13.9 | |
| IPs, bytes out, disks, logs, Config, GuardDuty | 30.4 | −1.5 | −7.5 | 21.4 |
| Runner control plane | 7.6 | −0.7 | −2.5 | 4.4 |
| Glue and bots | 3.4 | −0.8 | 2.6 | |
| Extras, nightlies, deploys, other repos | 9.1 | −2.2 | 6.9 | |
| AWS CI/CD | 142 | −7 | −25 | 110 (−23%) |
Move 2 saves Vercel dollars and 40 minutes, not AWS dollars. Owner trades would take the line to $88–97 (32–38% off). After Moves 1–3 the dashboard would read about $124 a day with product ($102–111 with owner trades), against $160 today and a $67 budget.
Moves 1–3 keep every blocking check and its timing, and land at about a quarter off. Coverage trades reach 32–38% in all and still fall short (the hub trains' full set is the biggest, up to $7–10, and it caught 4–5 real breaks in nine days). Half, and the $67 budget, take the machine model: dedicated or long-lived servers, about $30 a day of rent (unverified price) plus per-job isolation, at the risks in row 5. Gera's Oct 14 line was “only if we need the bill under ~$40/day”; the budget leaves about $53 for AWS CI/CD if the $2,000 is the AWS bill.
Not ours: Gera's open CI PRs #20417, #20397, #20365, #20450, #18891; the Vercel build audit; the product DynamoDB read load (~$6 a day of reads, ~$10 of DynamoDB in all).
| Number | Baseline 24 h to Oct 6, 2:06 PM | Now (last 6 h, Tue 8 AM MT) | Now (last 6 h, Tue 2 PM MT) | 8 PM (Oct 7) last 6 h, 75 PRs merged | 2 AM (Oct 8) last 6 h, 118 PRs merged | Wed 1 PM (24 h) | Target | |
|---|---|---|---|---|---|---|---|---|
| PRs kicked out of the queue, per day | 100 | 16 | 24 2 of 6 were the queue’s 30-min timeout | 56 | 16 | 20 9 sibling merge conflicts, 9 red checks, 2 timeouts | under 10 | better, still 2× target on the 24 h window |
| Earlier check (24 h to Oct 6, 7:16 PM): 101 a day; 63 failed checks, 35 merge conflicts, 3 timeouts. · 2 AM–8 AM Tue: 4 kick-outs, 2 red checks on the train, 2 merge conflicts, zero infrastructure. | ||||||||
| Queue runs per merged PR | 3.35 | 1.14 | 1.57 just over | 1.79 | 1.01 | 1.20 | under 1.5 | at target |
| Wait for a queue slot, median | 17.8 min | 0.3 min | 0.3 min at target | 0.3 min | 0.3 min | 0.3 min | under 10 min | at target |
| Open to merge, median | 128.6 min | 55 min | 76 min freeze hour inside the window | 54 min | 47 min | 50 min | under 60 min | at target (barely) |
| Merge to live, median | 72.7 min | 20 min | 26 min at target | 21 min | 20 min | 22 min | under 30 min | at target |
| Cost per merged PR (priced estimate, not invoices) | $1.01 / 523 runner-min | $0.44 / 307 runner-min | $0.68 / 459 runner-min real bill ≈ $0.77, see note | $0.59 | $0.41 | $0.49 (priced estimate, not invoices) | under $0.70 | at target (priced estimate, not invoices) |
| Merged PRs in the window | 282 | — | — | 75 | 118 | — | — | |
| Production deploys, Tue 2 PM: 13 in the last 6 h, 67 in the last 24 h. | ||||||||
Rows at target, Wed 1 PM (24 h window): 5 of 6. PRs kicked out of the queue are 20 a day against a target of under 10; the 6-hour readings were 0.
Real AWS compute bill per merged PR: Mon $0.77, Tue $0.35 (Tue still settling).
Real dollars (new, Tue 2 PM). The Factory dashboard (factory.propflowai.co) carries the actual AWS bill. Monday: EC2 $225.92 / 295 PRs = $0.77 of real EC2 per merged PR (Cost Explorer revised it down from the $258 first read): $0.77 against a $0.44 priced estimate (Monday). The estimate counts runner minutes at spot rates only; the bill also carries the runners' disks, boot and idle time, orchestration and other EC2. From this report on, the dollar row shows both, and the $0.70 target is read against the real bill. At the 2 AM (Oct 8) column, five of six rows are at target on the priced estimate; PRs kicked out of the queue (16 a day against under 10) is the one still above the line. Tuesday’s real bill is still settling, so the real dollars row is not called yet.
Real EC2 bill per merged PR (Oct 8). Oct 6: $225.92 / 295 PRs = $0.77 (Cost Explorer revised it down from $258.62). Oct 7: $85.91 so far / 243 PRs = $0.35, still settling.
The window for "now" closed 90 minutes after tonight's fixes merged, so it barely includes them. Merge to live cannot reach 30 minutes while production waits for the second full test run; that is Gera's call (decisions).
A PR now goes from opened to live in about 67 minutes (median), down from 3.6 hours a week ago, and the machine bill per merged PR is roughly a third of what it was. This section is the plain-English week summary; the scoreboard above has the six-hourly ticks.
| Number | Tue Oct 6 (before) | Wed Oct 8, 8 AM | Target |
|---|---|---|---|
| PRs kicked out of the queue per day | 66 | 0 in the last 6 h (16 overnight) | under 10 |
| Queue runs per merged PR | 3.5 | 1.03 | under 1.5 |
| Wait for a queue slot, median | 40 min | 0.3 min | under 10 min |
| Open to merge, median | 102 min | 45 min | under 60 min |
| Merge to live, median | 45 min | 22 min | under 30 min |
| Dollars per merged PR (priced estimate, not invoices) | $1.04 | $0.45 | under $0.70 |
Source: factory.propflowai.co/cost for hours, AWS Cost Explorer for dollars.
| Day | Useful machine-hours | Wasted machine-hours (re-runs after a kicked-out train) | Real EC2 bill | PRs merged | Real bill per PR |
|---|---|---|---|---|---|
| Thu Oct 2 | 7,443 | 11,629 | $216 | 438 | $0.49 |
| Fri Oct 3 | 6,735 | 4,255 | $209 | 468 | $0.45 |
| Sat Oct 4 | 3,009 | 2,030 | $91 | 152 | $0.60 |
| Sun Oct 5 | 6,205 | 5,044 | $245 | 343 | $0.71 |
| Mon Oct 6 | 2,583 | 2,626 | $226 | 295 | $0.77 |
| Tue Oct 7 | 1,632 | 190 | $86 (still settling) | 243 | $0.35 |
| Wed Oct 8, to 8 AM | 1,143 | 51 | — | — | — |
| Week of Oct 1–7: $1,293 of EC2 for 2,521 merged PRs, about $0.51 per PR. Wasted hours fell from more than the useful hours on Thursday to about 3% of them on Tuesday. The whole AWS account for the week was about $1,930, which includes the database, logs and one tax line. | |||||
caution Caution on the dashboard: the cost page's dollar figures for Oct 2–6 are stale first reads and run two to three times above what Cost Explorer shows today (Oct 2: $638 there, $216 in AWS). This summary uses the AWS numbers. The fix is handed to the dashboard's owner.
Close-out, Wed Oct 8. The lane closed Wednesday at about 1 PM as good enough. Open to live went from 3.6 hours to about 72 minutes. Both CI workflow changes merged today: sharded tests start about 8 minutes sooner, and a reclaimed spot machine no longer re-runs a finished train. Two small follow-ups were filed: shard handoff for small PRs, and a daily cost alarm above $0.70.
We checked every number on the Factory dashboard against GitHub and the AWS bill. Counts are good; the timings and dollars Fede would act on are not.
| Page | Verdict | The one number not to trust | What it should be |
|---|---|---|---|
| Now | wrong | “Merged → live 8 min” | About 22 min. It credits the next deploy even when that deploy does not carry the PR. |
| Also: clock times are Central with no label. “Ready, not queued 8” are 8 blocked PRs. “Conflict 0” is really 14. | |||
| Cost | misleading | “$66 yesterday” | A day AWS has only ~60% posted, shown as complete. The drop is real (usage fell ~49% on Oct 7), just smaller. |
| Also: priced at $0.014 per vCPU-hour, about half the real ~$0.032, so “$57/day waste” is nearer $130. Hours count queue runs only; PR checks (28–46% of runner time) are missing. | |||
| Health | wrong | “Merged → live”: its rule gives 4.8 min on the audited PRs | 19.75 min. And there is no open → live number at all; the real median is ~84 min. |
| Also: the 7d and 30d arrows compare against Sep 29–30. “Full test on main 85%” counts skipped runs as passes (~80%). | |||
| Log | misleading | “9 not merged yet” | 2. Seven of the 38 links point at the wrong repo; one PR is logged twice. |
| Reds | misleading | Who broke it | Only the first culprit in a failed batch, not every PR in it. The clock-bug test (now fixed) is blamed on 4 PRs. |
| Also: the Oct 7 red main, its auto-revert and the 85-min release hold are absent. Range buttons do nothing (data starts Sep 30). The flaky list is wrong. | |||
| Tests | misleading | “Full set on main” | Nearly empty: only 5 main runs read since Oct 4. |
| Also: “3 look flaky” with no file flagged. “▲70555%” is unreadable (it means 32 ms → 21 s). Slowest-file timings check out. | |||
Method: headless render at 1440 and 390 px; every number cross-checked against GitHub and AWS by four independent passes. Evidence is in the lane's scratchpad.
| Fix merged tonight | What changes | Proof |
|---|---|---|
| #17277 · 5:43 PM | Adding a label to a PR no longer starts a test run. That removes one whole class of stuck entries. | merged |
| #17231 · 5:44 PM | When a Spot machine is taken back mid-test, that test slice is retried inside the same run instead of removing the PR. | proof pending on trains now, no machine taken back yet |
| #17227 · 5:46 PM | A PR removed from the queue gets a comment saying why, and re-queues itself when the machine was at fault. | merged |
If the Spot retry works, most of the 63 failed-check removals a day should go away. The 35 conflict removals need a different fix: fewer shared files that every PR edits (plan).
| Time | What broke | Fix | State |
|---|---|---|---|
| 5:50 PM | A test broken by a review-bot change (#17001) | #17283 | merged 6:08 PM |
| 5:57 PM | A voice change (#17175) changed the fingerprint a voice test compares against | #17287 re-stamps it | merged 6:52 PM |
| later | A test that picks a date three days out landed on Columbus Day (a bank holiday) in UTC | #17293 (Gera, urgent): pins the date | merged 7:27 PM |
| 7:16 PM | Production restored: the urgent tours fix merged and its tests went green. The release branch moved to it at 7:21 PM, the web deploy finished at 7:20 PM, and the 33 waiting changes shipped with it. Lambdas and the renewal worker ship from the same release commit. The manual "promote now" was not used. | #17285 | live |
| 7:21 PM | The tours merge moved a voice fingerprint again. The voice harness check is red on main; it does not hold deploys. | re-stamp PR | pending |
| follow-up | That voice check only runs after merge | #17289: run it on PRs too | issue open |
| follow-up | The local pre-push check fails on one Mac for tests that pass in CI | #17298 | issue open |
| Mon 9:48 PM | Production deploy window cut from 30 to 5 minutes (#17354). First deploys after: 6 and 13 min from release move to live, vs 37 when batched. | #17354 | merged |
| Mon 11:11 PM | Post-merge full unit suite split into 4 shards instead of 2 (#17379). Unit shards 11 → 5–6 min; full post-merge run 71 → 22 min. | #17379 | merged |
| Tue 12:23 AM | Post-merge guard-pin shards moved to 8-core arm64 runners (#17397). Guard-pin shards 11–12 → 3–4 min; first full post-merge run after it: 10 min wall, 38 runner-min. | #17397 | merged |
| Tue 2 AM | Six-number check-in: nothing moved the wrong way; no revert. Production deploys in the 6 h: 25 release moves, 21 promoted. | no revert | checked |
| finding | Verified: merge-queue trains already run the full unit suite and guard pins on the exact tree, and the post-merge lane recognises that and skips its own full run (proven-head path). The 'extra full run per PR' only happens for direct pushes or unproven trees. | — | verified |
| Tue 2:29 AM | Voice harness red on main again: the third voice PR of the night changed the leasing agent's prompt without re-stamping the fingerprint. Follow-up #17423 asks for the check to run on the PR itself. | re-stamped (#17424) | merged, main green |
| Tue 3:00 AM | Weekly "Schedule Drift" check had been red two Tuesdays running: an hourly workflow was never declared in the automations registry. | declared (#17434), then the check ran on main: 91 jobs in sync, zero findings | merged, proven |
| Tue 7:50 AM | Proof: Semgrep checkout fix (#17264). On the 10 PR scans since it merged, the scan takes 1.1 min (was 2.2), checkout 16 s (was 94–146 s), no failures, retry never needed. | — | proven |
| Tue 7:50 AM | Proof: post-merge shards (#17379, #17397). Eight full runs this morning: 8–11 min wall, longest unit shard 8.5 min of a 16-min cap, longest guard-pin shard 4.1 min of a 20-min cap, nothing cancelled or timed out. | — | proven |
| Tue 8 AM | Six-number check-in: nothing moved the wrong way; no revert. Production deploys in the 6 h: 21 release moves, 20 promoted. | no revert | checked |
| finding | Next lever for merge → live (already at target): the post-merge lane paces itself to one run per 12 minutes, sized when a full run took 71 minutes; at 10 minutes a 6-minute pace would take ~3 minutes off the median for ~1% more runner time. Parked for Thursday. | — | parked |
| Tue 9:01 AM | Main's test run on a Gera-side merge ended “failure” with no failed job: GitHub created 37 of the usual 59 jobs. One rerun: green, 59 jobs. GitHub-side; nothing to revert. | rerun | green |
| Tue 9:09 AM | A heavy-lane run for that same commit sat “queued” with zero jobs and could not be cancelled (GitHub refused both cancel paths). The lane's pacing rule counted it as busy, so every heavy run after it waited and production froze an hour behind main. | — | froze |
| Tue 9:55 AM | Manual heavy run unfroze production (release = main at 10:13). | manual run | unfrozen |
| Tue 10:11 AM | Fix opened: a queued run older than 20 minutes no longer counts as busy. The first cut touched only the workflow file, which the review bot cannot review while the comment-driven reviewer is switched off (since Sep 30); reshaped so the rule lives in a small script with nine tests, including a planted control. | fix PR | opened |
| Tue 11:24 AM | Second manual run; production caught up again. | manual run | caught up |
| Tue 11:42 AM | Fix merged. 12:05 PM: proof in production. With the ghost record still present, the next scheduled heavy run went ahead and release advanced on its own. | merged | proven |
| Tue 11:30 AM–1:30 PM | Waste audit against the new dashboard: about $85/day of re-run compute (priced estimate), 71% of it merge-queue trains discarded behind a red. Half of last week's queue-only reds were whole-repo “drift” tests PRs never ran; fixed since Monday evening, and that cost is near zero today. Re-run waste: 50% of compute Monday, about 7% so far Tuesday. | — | measured |
| Tue 12:30 PM | Decided NOT to build a pre-queue gate (Fede, Mon: red main is caught in testing, never by a gate before the queue; saving would be ~$4/day net and it adds minutes to every PR). The remaining ~7 queue-only reds a day are mostly tests the PR never selected: fix selection instead. | follow-up | decided |
| Tue 1:00 PM | Spot reclaims no longer turn a train red (fixed Monday; 10 of 10 trains since recovered in-run). Two things found instead, both sent to Gera's side via the bridge: the queue's 30-minute check timeout ejects big trains (one PR twice today), and the automatic merge guard has been off since Oct 1, so Fede-side arms skip the pre-queue type check. | bridge | with Gera |
| Tue 1:15 PM | The runner provider's bot re-runs a merged train after our in-run retry already recovered it (9 times in 19 h, ~20 jobs each). Builder finding the trigger; a repo-side fix ships today if it is a label of ours. | in progress | open |
| Oct 7, 10 PM | Proven live: guard pins (fence tests) now run on PRs. Merged. First 21 PR runs after the merge: the Guard pins step picked between 1 and 79 fence tests per PR (median 6), all in one shard, and on one PR it failed a leasing fence test that is green on main, so the author saw the defect on the PR instead of being ejected from the queue later. | — | proven |
The lesson: a red run after merge holds production without telling anyone. Either it pages someone, or production stops waiting for it (decision 3).
| Cause | Share of re-run waste (priced estimate, not invoices) |
|---|---|
| Queue trains discarded because a PR ahead went red | 71% |
| PR runs replaced by a newer push | 10% |
| Post-merge heavy run re-testing what the queue proved | 9% |
| Spot machines reclaimed mid-run | 8% |
| Manual re-runs and main re-tests | 2% |
The biggest slice is already shrinking (drift tests now run on PRs); the next cuts, in order, are the provider re-runs, superseded PR runs, and the heavy-lane re-test.
| Change | Why, measured | Proof |
|---|---|---|
| Every PR runs every boundary-guard test, whatever it touched | 36 of 93 PR-caused queue failures were guard tests the PR had skipped | #15807 merged |
| Big PRs run the always-run test set too | 24 of 47 sampled big-PR runs skipped about 650 tests; 13 of 93 failures | #15811 merged #15808 open |
| Delete a dead "already passed" shortcut | Unreachable today; stops a future skip | #15806 merged |
| Stale-base PRs and file-reading tests | 13 and 8 of 93 failures | no PR yet |
| Shared lists every PR edits become one row per item, so unrelated PRs stop conflicting | Four lists touched by 299, 124, 82 and 96 PRs in 30 days; 18 collisions | #15789 #15795 #15790 #15793 #15796 merged #15794 open |
| Measuring tools, so every change has a baseline | Read-only | #15804 #15805 #15809 #15792 #15797 #15799 #15800 #15801 #15810 merged |
| Share one install cache across helper workflows; delete a dead schedule | About 580 runner-min a day, about $1 a day (estimate) | measured in #15799, #15810 |
| Change | Why, measured | Proof |
|---|---|---|
| Cancel a queue run once its group is thrown out | 43% of queue compute (558,184 vCPU-min in 34.7 h) ran after the group was already doomed; only 20% went to groups that merged. GitHub let 196 of 227 such runs finish. | #15805, #15800 |
| Stop the early-failure watcher idling after every verdict is in | Up to 26,002 runner-min a day | #15799 |
| Pause the queue by disarming PRs, not pulling entries out | 155 manual and 53 conflict removals against 86 failed checks in 34.7 h. Model: no removals lifts 15.2 to 20.2 merges an hour. | #15805, #15800 |
| The next three shared lists | 25, 21 and 8 collisions | #15801 |
| Log which PRs a classifier calls independent, next to real outcomes | 4 known collisions; a safe call needs 60 | #15792, #15797 |
| Change | Why, measured | Proof |
|---|---|---|
| Untangle the shared test files that tie every PR together | All 177 open PRs form one group; exit test is the largest group at 50% or less (today 98–99%) | #15797 |
| Split the code into packages | 1,114 and 874 imports cross the two main code trees. Sizing only. | #15797 |
| A second merge lane | Needs 60 collisions predicted with zero misses over two weeks. "Different files" missed 1 of 4 real collisions. | #15797 |
| Browser tests against main after merge | 6 preview probes exist; 0 of 61 sampled runs completed one | #15810 |
The "now" list was built from Oct 1–3 data, before removals were understood as the main cost. Tonight's three fixes are the new first priority.
| Decision | Options | Recommendation | Who |
|---|---|---|---|
| 1. Queue depth (8 build at once now) | A. keep 8 B. 10: the model's knee (15.4 an hour at 6, 19.7 at 10, flat after) C. 16 or more: real days ran 23.0 an hour at 16 but 11.5 at 24 | A until the Spot retry is proven, then B for one measured day | Fede, Gera |
| 2. Remove checks from the queue | A. keep all B. drop the duplicate guard step inside the full set (about $41 a day; move one test first) C. drop the 6 guard slices (about $99 a day, but they disagreed with the full set 5 of 85 times; the earlier attempt, #15231, was closed) | B | Gera |
| 3. Release re-check after merge | A. ship the exact commit the queue tested; the after-merge run alerts instead of holding B. keep the hold, add an alert when it goes red C. no change | A: main is already the queue's tested commit. Saves the roughly 25-minute re-check and ends silent holds like tonight's. | Gera |
| 4. The arm64 runner pool in the private org repo | A. delete it B. keep it | A, once a check shows no job targets it | Smith, Gera |
| 5. Ten AI test suites nothing runs | A. run weekly B. delete | B for any replaced by newer evals; A for the rest | owner lanes |
Dollar figures are estimates from runner prices (#15799). Depth numbers come from a model that says it runs optimistic, and depth was changed 24 times in a day, so no real day is a clean test.
| Per day | Mon Oct 5 (baseline) | Estimate for Tue | Tue Oct 6, to 1 PM |
|---|---|---|---|
| PRs merged | 343 | same | 213 so far (afternoon 2x Monday's) |
| CI machine minutes | 180,700 | about half | 112,500 so far; pace 140,000 |
| Machine minutes per merged PR | 527 | about 260 | 528 flat |
| Machine dollars (estimated) | $281 | $110–150 | $221 so far; pace $275 |
| Dollars per merged PR | $0.82 | about $0.40 | $1.04 worse |
| Queue runs per merged PR | 2.3 | not estimated | 3.5 worse |
| Full-price machines | $12 | $0 | $100 spike, reversed; $34 now |
| Median open to merge | not measured | not estimated | 102 min (27 to first green, 52 waiting in line) |
The real bill (Cost Explorer) lags a day: Monday was $245 of compute.
| What happened | How we know | |
|---|---|---|
| worked | Each queue run got cheaper | Guard jobs per run 6.0 → 2.9; full-set jobs 1.9 → 0.65; queue check 11.5 → 4.9 min |
| worked | Tests that never ran now run, including big PRs that went green with zero tests | 44 of 66 train failures and 7 of 22 red-main incidents came from that gap. First afternoon live, it caught a real violation. |
| worked | The queue stopped punishing Spot kills on re-entry | 14 PRs in 48 h had been re-pushed for nothing |
| worked | The review bot stopped dying on token limits | 49 of 53 reviews had failed since Oct 1; pool back to 9 accounts |
| worked | Outside CI: the Western Slope guest-card sync stopped writing for nothing | 64 rows a minute → 0, from the sync's own write meter |
| did not | Cheaper runs, but more runs per PR, so cost per PR did not fall | Runs per merged PR 2.3 → 3.5. Nobody had this number in the plan. |
| did not | Two red mains overnight from our own CI PRs | 6 h and 1.7 h of held deploys; the fix landed 18 h later than it should have |
| did not | A cost change moved the queue onto full-price machines | $12 → $100 a day for 8 h, then reversed |
| did not | One bad PR failed every train behind it | 12:34–1:02 PM: 8 failed trains, about 20 cancels, nothing merged for 53 min |
| did not | Nothing targeted time. The queue run is 12 min; the rest of open to merge is waiting for a slot. | Merge to live added 45 min, 25 of it a re-check the queue already did |
| tonight | A red run after merge held production silently | First noticed when deploys were about two hours behind (above) |
What this changes: the lane is now judged on minutes and dollars per merged PR, and open to live. The next levers are runs per merged PR, the release re-check, and telling owners when the queue removes their PR (now #17227).
| Number | Meaning | Window | Source |
|---|---|---|---|
| 16.3–17.75 / h | PRs merged per hour | Oct 1–2 | #15804, #15805 |
| 12% | PRs whose first queue run failed on its own (52 of 432) | Oct 2 | #15800 |
| 93 / 21 / 70 | PR-caused queue failures / test had passed on the PR / test never ran on the PR | Sep 30–Oct 2 | #15809 |
| 13 | Median groups thrown out behind one failure | Oct 1–2 | #15805 |
| 355 | Runner-min per merge | Oct 1–2 | #15799 |
| 20% / 43% | Queue compute on groups that merged / after the group was doomed | 34.7 h, Oct 1–2 | #15805 |
| 0–60% | Share of groups that merged, from position 1 (60%) to past 20 (0%) | Oct 1–2 | #15805 |
| 5 / 85 | Runs where the guard slices and the full set disagreed | 24 h sample | #15799 |
| 4 of 2,450 | Real two-PR collisions in merged history | Sep 25–Oct 2 | #15797 |
| 17 of 18, 10 of 13 | Rebuild waves that were removals; removals that were Spot kills | Oct 6 | queue-jump study |
Still open: the depth model's second part is not in a PR yet; the early-failure watcher's idle time is unmeasured; whether disarming survives sessions that re-arm PRs is unconfirmed. Out of scope: runner pool sizing and the deploy ordering wait.