v0.120.0 — one data volume (R-165, decision D-a, variant V-c)
gates / gates (push) Successful in 5s

build-golden.sh 2.1.0 -> 3.0.0: a layout change is a major. The golden ships
ONE data volume at a NEUTRAL path (/var/lib/felhom); both /var/lib/docker
and /mnt/sys_drive are binds of subdirectories of it. mp1 is gone.

The variant was chosen on measurement. Three candidates were built and
rebooted (SPIKE-r165-phase0-2026-08-03.md); all three boot, reboot 3/3, give
ONE df figure and keep a container's statfs(/) on the merged volume — the
ordering worry that motivated the probe did not materialise. They differ
only in which guarantee they break: volume-at-docker puts customer backups
inside Docker's data-root; volume-at-sys_drive puts Docker's ENTIRE
data-root under /mnt, which the controller container mounts wholesale
(measured: it then sees /mnt/sys_drive/docker). V-c breaks neither.

The four assertions were RETARGETED, never deleted, and each was RUN against
a deliberately wrong shape — a real split guest and a real archive of it:
8 checks, 8 passed. A new 2b asserts both paths are ONE filesystem, which
catches the S2 shape the spike ranked worse than the split. Assertion 5
replaces the old "was mp1 excluded?" guard, whose pattern could no longer
match — a guard that cannot match has silently stopped guarding.

Provisioning: one volume, one grow. SysDataGrowGB is FOLDED IN rather than
dropped, because a census established that felhom-host-install.sh passes
-sysdata-grow and the two do not upgrade in the same instant; dropping it
would silently shrink every appliance by 42 of 250 GiB. The flags stay
accepted for the same reason. The existing test was retargeted to pin the
fold, and it caught the change before I did.
This commit is contained in:
2026-08-03 06:43:38 +02:00
parent 587dbb43fe
commit cd6e26785a
5 changed files with 241 additions and 90 deletions
+63
View File
@@ -1,3 +1,66 @@
## v0.120.0 — one data volume (2026-08-03, R-165 · decision D-a · variant V-c) — `build-golden.sh` 2.1.0 → **3.0.0**
**The dedicated backup partition stops existing.** A golden built by `build-golden.sh` v3.0.0 ships a
**single** data volume; `mp1` is gone. An app whose local recovery unit outgrew the old 20 G area
stopped being backed up even with free space next door — D-a removed that wall rather than moving it.
**A layout change is a major**, hence the script's 3.0.0.
### The shape: V-c, a neutral mount — chosen on measurement, not on reading
```
mp0 -> /var/lib/felhom (one volume, backup=1)
├─ docker/ --bind--> /var/lib/docker
└─ sys_drive/ --bind--> /mnt/sys_drive
```
Three candidates were **built and rebooted**, not reasoned about
(`felhom.eu/documentation/audits/SPIKE-r165-phase0-2026-08-03.md`). All three boot, reboot 3/3, give
ONE `df` figure, keep both paths as real mountpoints, and keep a container's `statfs("/")` reporting
the merged volume. **The ordering worry that motivated the probe did not materialise** — an
`/etc/fstab` bind is ordered under `local-fs.target`, which precedes `docker.service`.
They differ only in which documented guarantee they break, and that is what decided it:
- volume at `/var/lib/docker` → customer backups sit **inside Docker's data-root**; the ordinary
"clear `/var/lib/docker` to fix Docker" reflex would destroy every local recovery unit on the box;
- volume at `/mnt/sys_drive` → Docker's **entire data-root** lands under `/mnt`, which the controller
container mounts wholesale (`-v /mnt:/mnt:rslave`). **Measured: the container then sees
`/mnt/sys_drive/docker`**, making the bootstrap's own claim that `/mnt` holds only Felhom's
namespace mounts false.
- **V-c breaks neither**, for one extra path and one extra fstab line.
### The four assertions were RETARGETED, never deleted — and each was proven to fire
They exist because a volume silently falling out of the archive is invisible until a restore, which is
the worst moment to learn it. All were re-pointed at the merged invariant and then **run against a
deliberately wrong shape** (a real split-layout guest and a real archive of it): **8 checks, 8 passed.**
| # | now asserts | proven to reject |
|---|---|---|
| 1 | `/var/lib/docker` is a real mount (the V-c bind) | a plain directory |
| 2 | `/mnt/sys_drive` is a real mount | a plain directory |
| **2b (new)** | both paths are **ONE** filesystem | two volumes — the S2 shape the spike ranked *worse* than the split |
| 4 | the archive's `mp0` is mounted at `/var/lib/felhom` | an `mp0` at the wrong path |
| 5 | the archive carries **no** `mp1` | a leftover `mp1` (the merge-did-not-take case) |
Assertion 5 replaces the old "was `mp1` excluded?" guard, whose pattern could no longer match after the
merge — **a guard that cannot match is a guard that has silently stopped guarding.**
### Provisioning: one volume, one grow — and the retired knob is FOLDED IN, not dropped
`SysDataGrowGB` no longer drives a second resize; its GiB are **added to** the single volume's grow.
**A census established why this matters** — `felhom.eu/scripts/felhom-host-install.sh` computes and
passes `-sysdata-grow`, and an installer and an agent do not upgrade in the same instant. Dropping the
value would silently shrink every appliance an older installer builds by the user-data share (42 of
250 GiB on the standard branch). `-sysdata-grow` / `-sysdata-mount` stay **accepted** for the same
reason; removing them would make every install fail on an unknown flag. `DefaultSysDataMount` now
points at nothing on purpose, so a stale caller is loud at review.
**§8.2 — the single volume's size IS derived from the physical disk, and already was.** The installer's
`step_grows` reads the thin pool's real free space; the merge only collapsed its 80/20 docker-vs-sysdata
split into one total (`226` = the previous `184+42`, so a standard appliance keeps the same capacity —
250 G, no longer split by a wall). An unflagged install does **not** get the golden's 24 G.
## CI — the gate entry point runs on every push (2026-08-02, R-168) — NO VERSION BUMP
**No version bump, no build, no deploy** — this adds a workflow file only. Stated explicitly so the