Undo bake-off: copy the folder wins (09 §3 decisions 19-20, §6.1a)
gates / gates (push) Successful in 26s

- 09 §3: decision 19 (the copy method is chosen by a bake-off) and 20 (the
  full-system backup waits for the update leg, inside its window; built later).
- Bake-off on 9202, docmost / romm / vikunja: both methods pass every case;
  the folder copy wins because an app with no database server gets no dump,
  so dump-and-load would need the folder copy anyway. 1-5 s extra downtime,
  ~420 MB/s, disk = the volumes.
- R-645 filed: lifting an update hold by hand lets the recovery unit be
  re-captured with the failed definition within seconds.

Documents and evidence only; product code follows in the controller.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-23 10:28:56 +02:00
parent 4c92beab8f
commit 5a349d9884
37 changed files with 2390 additions and 0 deletions
@@ -265,6 +265,21 @@ builds them (`audits/update-rulings-2026-09-23/`).
18. **Fleet view** (Q7). The report carries, per compose service (so the database too), the installed
reference, the catalog reference and the badge state. **Built later**, when the fleet grows.
### 2026-09-23 (afternoon) — two more operator rulings
19. **The undo's copy method is chosen by a bake-off, not by assumption.** Two methods are measured on
the same apps — *dump and load* (the database as a text file, loaded back) and *copy the folder*
(the app's named volumes copied with its containers stopped, put back on failure). The simpler one
that passes every case is built; if both pass, the folder copy wins on simplicity unless its
downtime or disk cost fails the bake-off's limits. **Why:** the morning spike found two traps in the
dump route (a cut-off file loads as success; a failed MariaDB load is half old, half new) and the
folder route had not been measured at all. Result: §6.1a.
20. **On update nights, the full-system backup waits for the update leg, inside its own window**
(answers R-643 / §6.4 part 7's open point). The leg stops starting new steps at **W+5h**, so the
full-system backup keeps at least one hour of its [W+2h, W+6h) window. **Built with §6.4 part 7,
not before.**
**RomM follow-ups, operator-agreed the same day:** the test bench watches memory after an update
(`upgrade-test.py`, 2026-09-23); a version move checks the memory limit (gate or checklist — §6.4);
R-636's louder repeated alarm.
@@ -798,6 +813,19 @@ product path that loads a safety dump back exists (`rollbackSafetyDump`), but on
restore calls it. The eight things the build must add are listed in the audit; §6.4 part 1 prices
them.
**THE COPY METHOD, chosen by the bake-off of 2026-09-23 afternoon (decision 19):
COPY THE FOLDER.** `audits/undo-bakeoff-2026-09-23/README.md`. Both methods passed every case on all
three apps (seeds before and after the backup, ledger equal, a cut-off copy caught before anything is
swapped or loaded). The folder copy wins because an app with no database server gets no dump at all,
so the dump route would have needed the folder copy anyway. **Shape:** after the pull and just before
`up` — where the app is stopped anyway to be recreated — each NAMED volume the app owns is copied with
`cp -a` into a sibling volume `<volume>.pre-update-<stamp>` by a helper container, which writes a
finished-marker last; a bind-mounted user folder is never copied and never touched. On a failed health
check the copy is validated (marker present) and put back, the old definition and pin are restored
from the journal's own copies, and the old version is checked with the OLD `.felhom.yml` probe.
Measured cost: ≈ 1–5 s extra downtime for the three apps, ≈ 420 MB/s, disk = the volumes' size (the
update refuses before moving anything when the copy would breach the 2 GB floor).
**The release could not reach the fleet by floor — R-472.** The hub holds a controller floor above the
vouched golden (publish-train rule 1), so under the weekly golden cadence (R-468) v0.237.0 and v0.238.0
were hand-deployed to the demo guests. **RESOLVED by §3 decision 7 (hub v0.112.0):** v0.239.0 reached