test(hibernate): #76 checks.hibernate-swapfile — verify swapfile+offset in a VM
All checks were successful
Check / eval (push) Successful in 4m18s

Push #76's swapfile-resume residual into a VM as far as headlessly possible.
A full hibernate→resume from a RUNTIME swapfile turned out not to be
headless-reachable: systemd reports CanHibernate=no for a swap that isn't
declared in the boot config, and a runtime-computed resume_offset can't be
fed into the boot cmdline (the genuine chicken-and-egg). So the check now
verifies, bounded and deterministically, what the partition test
(checks.hibernate) can't and what a VM CAN prove: the installer's btrfs
@swap swapfile is built correctly and its offset is valid — NOCOW
mkswapfile, file-type swapon, a good `map-swapfile -r` offset the kernel
accepts (/sys/power/resume_offset), and zram (prio 100) above it.

The literal encrypted-swapfile power-cycle + LUKS-initrd unlock stays a V3
laptop check (the dev box runs exactly this layout, /proc/cmdline verified).

(First cut had an unbounded wait_for_shutdown that hung on the CanHibernate
refusal; rewritten with a thread-bounded wait + a CanHibernate pre-check,
which gave the clean verdict. Device is /dev/vdb without useNixStoreImage.)

Verification: V2 PASS (nix build .#checks.x86_64-linux.hibernate-swapfile,
fresh, exit 0); flake check --no-build green. #76 residual narrowed in
BACKLOG/ROADMAP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Bernardo Magri
2026-07-11 08:34:17 +01:00
parent 2fa5231215
commit 37615c85a4
4 changed files with 106 additions and 11 deletions

View File

@@ -345,12 +345,16 @@ Design/decision records and a running log of shipped work (items marked
no-swap opt-out; the Power-menu Hibernate row is kept unconditional and
**notifies on failure** (no-swap machines) rather than silently no-op'ing.
Existing machines get an *enable-hibernation* runbook in `docs/MIGRATION.md`
(no tool). Guarded by two VM checks — `checks.zram-swap` (device/algo/
priority) and `checks.hibernate` (a full hibernate→resume→crash cycle that
proves the image round-trips through disk swap and that zram at priority
100 doesn't swallow it). The LUKS-initrd unlock + btrfs-swapfile
`resume_offset` triple is a V3 laptop check (QEMU can't feed a boot-time
offset for a file that only exists after first boot).
(no tool). Guarded by three VM checks — `checks.zram-swap` (device/algo/
priority), `checks.hibernate` (a full hibernate→resume→crash cycle on a swap
*partition* that proves the resume mechanism + that zram at priority 100
doesn't swallow the image), and `checks.hibernate-swapfile` (the installer's
btrfs `@swap` *swapfile* build — NOCOW `mkswapfile`, file-type swapon, a
valid `map-swapfile -r` offset the kernel accepts, zram above it). A full
hibernate from a *runtime* swapfile isn't headless-reachable (systemd
`CanHibernate=no` for undeclared swap; and a runtime-computed `resume_offset`
can't be fed into the boot cmdline), so the literal encrypted-swapfile
power-cycle + LUKS-initrd unlock stays a V3 laptop check.
✓ **Doctor hibernate/sleep section (#77, `VISION § C`):** `nomarchy-doctor`
gained a read-only hibernate row group — resume device on the cmdline
(+ `resume_offset` for a swapfile), disk swap ≥ RAM, zram active, and any