agent v0.33.0: C1 net — pre-start self-heal hook + decommission mp-delete

Pre-start PVE hookscript (internal/guesthook) creates host-root placeholders for
absent bind-mount sources so the guest always boots (fail-closed); decommission
now pct set --delete's the dead mp (GuestBinder.DetachBind) so a missing source
can't brick the next reboot (B3 C1 bug). Non-hollow tests + companions. Installed
+ registered per-guest by the provision back-half. Transitional ahead of the
intermediary-mount re-architecture which makes C1 structural.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-15 16:11:10 +02:00
parent 2a4affc3a8
commit 44cdf82631
11 changed files with 490 additions and 3 deletions
+26
View File
@@ -3,6 +3,32 @@
All notable changes to **felhom-agent** are recorded here. Update on every code
change that gets pushed.
## v0.33.0 — C1 net: pre-start self-heal hook + decommission mp-delete (2026-06-15)
The transitional defense for the C1 brick (B3 critical bug) ahead of the intermediary-mount
re-architecture (which makes C1 structural). Two independent nets:
- **Pre-start self-heal hook** (`internal/guesthook`): a PVE `pre-start` hookscript runs
`felhom-agent guest-hook <vmid> <phase>` which, for every BIND mountpoint whose source path is
missing, creates an empty **host-root-owned** placeholder dir so the bind succeeds and the guest
always boots — fail-closed (host uid 0 is unmapped in the unprivileged-LXC userns, so the guest
can't write to the placeholder; a returning drive shadows it). It CREATES rather than DELETEs
because `pct set --delete` in pre-start would take the config lock the start task already holds
(dead-times-out → still bricks); the heal logic is in unit-tested Go, the wrapper just delegates.
Installed + registered per-guest by the provision back-half (`InstallSnippet`/`Register`).
- **Decommission mp-delete** (`GuestBinder.DetachBind` + `handleDiskDecommission`): decommission now
runs `pct set <vmid> --delete mpN` on the slot binding the drive (lock-safe on the running guest),
so its now-missing source can't brick the next reboot. The old handler unmounted but left the dead
`mpN` in config — the exact B3 C1 bug. Eject keeps its mp (temporary; the hook covers a
reboot-while-ejected).
Tests (non-hollow, each with a companion that fails the pre-fix/trivial impl):
`internal/guesthook/heal_test.go` (selector ignores storage volumes + present binds, heals only the
absent one; "return nothing"/"return all" both fail) and `TestDecommission_DeletesGuestMount`
(asserts the correct slot is `--delete`d; pre-fix never calls DetachBind → fails).
Sudoers: new `FELHOM_GUESTHOOK` alias (snippet install, `pct set --hookscript`, `pct set --delete mpN`).
## v0.32.0 — self-serve decommission + intent-aware re-assert (B2a) (2026-06-14)
Customer-self-serve storage decommission (no operator signature; non-destructive — never formats),