# Failure catalog (each line: symptom -> root cause -> the guard that now prevents it)

1. Reap storm, 169 reaps in 8 min -> junk `{}` rows froze board writes silently -> loud write failure + rollback, writer-token triggers, resync refused without `--i-know`.
2. Board rebuilt from a stale export twice -> reconcile treated the JSONL mirror as truth -> the DB is the SSOT; exports are write-only views.
3. Child CLI calls "succeeded" but wrote nothing -> entry guard compared a resolved argv path to the real file path, so symlinked callers ran nothing -> realpath on both sides; a test greps every entry guard.
4. Stall sweep marked tasks answered but status never changed -> child stderr swallowed in try/catch -> capture stderr, alert on non-zero, never swallow.
5. A quarantined task re-launched every 30 min -> the deadline killer's finish moved it back to todo -> quarantined is terminal to every writer except requeue.
6. `cancel` did not stop a running task -> it only flipped status -> cancel kills the lane, drops the lease, writes a terminal status.
7. Six branches failed on the train, board showed `shipped` -> the reconciler's fix call hit the terminal guard and was silently ignored -> dedicated `landing-failed` verb, requeue to author, escalate on the second failure.
8. Four worktrees lost uncommitted work -> stale leases stolen by the dispatcher; salvage captured tracked files only -> busy protection for any holder the board does not know; salvage via a temp index includes untracked files.
9. A landing deleted 12 files and reverted a module -> a branch built in a salvaged slot carried a stale index -> `landing-scope` guard; every agent runs the diff-stat ship check.
10. Every branch failed the same build guard -> generated outputs stale from earlier landings that skipped regen; scoped regen never catches up -> unscoped catch-up after each pass; the guard's cached-verdict hash now includes the generator's own imports.
11. Train idle 80% of the time, 545 s between landings -> a dangling worktree symlink made each pass re-run a creator whose `sleep 300` watchdog held the stdout pipe -> file-backed stdout with a cap, watchdog killed on EXIT, per-pass timing log.
12. Builders failed on their own sources -> a mass codemod rewrote generator inputs while those builders were dormant -> `builder-sources-parse` light guard; restore from the pre-codemod commit when regenerated output proves identical.
13. Spec runner red everywhere, `X is not a function` -> a generated module stopped importing the engine and bare scripts never assembled the runtime -> one import in the compiler; a fresh-worktree smoke.
14. Nested build deadlocked -> child `heavy()` waited for a slot its parent held -> children inherit the parent's class slot via env.
15. Unit tests wrote fake kills into the live alerts file -> alert path not scoped to the test board -> alerts follow the board dir; tests assert the live file is untouched.
16. Big tasks killed at 40 min while prompts promised 120 -> deadline ignored the prompt -> deadline honors the largest "ship by minute N" plus grace.
17. Tasks waited hours pinned to a runner with no capacity -> no automatic re-pin -> `fit-runners` every 10 min from the supervisor.
18. Canary skipped a slot and went yellow -> exact-minute scheduling -> a 5-minute window keyed by a slot file, skips logged.
19. Lanes spent hours porting into files no build reads -> generators had no liveness filter and "read" was mistaken for "live" -> traced live list; reads that only scan docs are excluded; every source filters on it.
20. Rewire landings collided on one JSON -> a generator rewrote a shared progress file per landing -> union merge for listed append-only paths; everything else still parks.
21. Generator re-emitted the same failed target every 10 min -> prior-attempt gate looked at task status, not attempts -> gate counts reaps/fails in attempts for 24 h.
22. Generator pass took 2 min 20 s -> one board read per candidate -> one snapshot per pass (5 s).
23. The dispatcher launched nothing with room 20 -> transient "database is locked" on readers without a busy timeout -> one read opener with busy timeout; CLI readers pass `.timeout`.
24. Cheap lane re-ran a stalled task three times -> no escalation on repeat reap -> second reap on the same runner moves up the rotation.
25. Caps were "fixed" by lowering them -> the owner wants machines used fully -> ceilings high, admission adaptive, never lower a cap without asking.

26. Owner told to install Homebrew on a machine that had it -> a non-interactive ssh shell's PATH lacked /opt/homebrew/bin, so `command -v` said "missing" for git, node, pnpm and brew; same class as calling a domain free from an empty DNS record and a file live because a build opened it -> rule 11: a negative claim needs two independent methods before it is reported or acted on; `fleet-box check` probes under a login shell and by absolute path and prints the PATH it used.

Postmortem format (twenty whys): symptom, why x N until a design decision appears, the guard added, how it was shown red then green, what the tick now watches.
