Why PRs are not green, not merged, or not worked on at all while nobody is at the keyboard — and what rules replace the ones that cause that.
Decided 2026-09-17 — Fede adopted all of it except the settings registry (section 5, "Hygiene without a flag platform", first bullet), which is deferred: "too much for now".
Contents
CI speed is on its own page → Ship in 15 Minutes.
The machine ships. The problem is the night and the morning baseline, not throughput.
| Fede-authored PRs, 2026-08-18 → 09-17 | |
|---|---|
| Opened / merged / closed unmerged / open now | 1,607 / 1,439 / 161 / 7 |
| Median time to merge | 37 minutes |
| 90th percentile | 4.4 hours |
| Merged within 24 hours | 98.5% |
| Merged outside 7am–7pm Denver | 44% |
So "always shipping" is already mostly true. Three numbers explain the mornings that feel bad:
| Symptom | Number |
|---|---|
| PRs ever held by the auto-merge guard | 512 of 1,607 (32%) |
| Top hold reasons | dangerous-diff path 179 · 🟡 changes suggested 132 · changes-requested standing 50 |
| PRs needing more than 3 review rounds | 33.5% |
| PRs over 600 lines | 613 (38%), median 4 review rounds |
| Nights with a ≥3-hour dead stretch, last 14 | 7 |
| Finished-subagent notifications unanswered for 5+ minutes | 22,581 of 66,931 (34%) |
Read together: a third of PRs get held, a third need four or more rounds, and half the nights the fleet stops before those are cleared. Whatever is unfinished at the dead stretch is what Fede finds at 7 am. Seven open PRs this morning was a normal night, not a bad one.
Timeline (Denver time):
Root cause A, mechanical. Each session is woken by a small waiter process that watches the GitHub event file. Waiters did not die when their turn ended. They lived up to 24 hours holding the session's "I already have a waiter" lock, so the next real waiter could not arm, and the stale one consumed each verdict and woke nobody. Found on the machine: 11 waiters whose Claude process had exited days earlier, some since September 10; the machine-wide duty lock held by a waiter from a turn that ended at 8:57 pm. Fixed today in the waiter script: a waiter exits within five minutes of its session ending, and a lock held by an orphan is taken over.
Root cause B, behavioral. Seven of the last fourteen nights have a three-hour-or-longer dead stretch, always after midnight. In 30 days, one in three "subagent finished" notifications (22,581 of 66,931) went unanswered for more than five minutes. The 25 longest silences were sessions that wrote a done-or-parked summary, or asked Fede a yes-or-hold question and stopped for a day. None were errors or limits.
Root cause C, structural. Thirteen distinct mechanisms can stop a green PR from merging without a person. Each is reasonable alone. Together they mean a PR needs a live session to clear it several times, and a sleeping session clears nothing.
| Hold | Keep? | Change |
|---|---|---|
| Changes-requested review standing | keep | The session that pushes the fix dismisses the stale review in the same turn. Never left for morning. |
| No verdict on current head | keep | Automatic. Nothing to do. |
| 🟡 changes suggested | change | No longer holds. 🟡 = merge, then open one follow-up issue per finding. Only 🔴 blocking holds. |
| Stacked base | keep | Automatic. |
| Dangerous-diff path | keep, narrow | Only auth, IAM, middleware, secrets, the guard itself. Admin routes under /api/admin behind admin auth are not dangerous. |
| Merge-evidence (green with zero tests run) | keep | This is the one hold that catches real risk. |
| Draft | keep | Drafts are not work in progress. A draft older than 24h is closed by its owner. |
| hold-for-review label | keep, Fede-only | Unchanged. Sessions never apply it. |
| Stale approval after push | keep | Automatic. |
| Hand-armed auto-merge disarmed by event | change | The guard re-arms itself on a clean verdict; sessions must not treat "not armed" as a hold. |
| Red main freeze | keep | Driver rule already exists. |
| CI red | keep | Fix. |
| Review workflow self-modify | keep | Rare. |
Fede's constraint: ship aggressively, keep customers stable, no proliferation of forgotten flags.
Rule: there are exactly three places a behavior can be switched, and they are all product configuration, not engineering flags.
| Switch kind | Where it lives | Who flips it | Lifetime |
|---|---|---|---|
Company live switch (claraLive) | customer page | Fede | forever; it is the go-live |
| Company setting (e.g. reminders opt-in, vendor calendar capture, lead source) | customer page, settings card | ops or the customer | forever; it is a product feature |
| Property setting (e.g. per-property reminder recipient) | property page | ops or the customer | forever |
What is banned: environment flags for behavior (*_ENABLED), code-level release toggles, allowlists in code, "temporary" gates. Today there are 5 env flags and 6 org/property settings. The 5 env flags get a removal PR each or become a company setting.
How a risky change ships:
Hygiene without a flag platform:
Decision: A, minus the settings registry.