58b598b697
The agent cannot create a PVE storage (Datastore.Allocate at /storage) or grant an ACL (Permissions.Modify) -- it holds neither by design, and widening the role would trade the whole blast-radius containment model for one feature. The privileged half therefore lives in a new fenced shim behind a literal FELHOM_BACKUPTARGET sudoers alias, following the mkfs/pbs-apply pattern. The wrapper enforces the two laws E-1 paid for on live hardware so no caller can forget them: F-1 the path must BE the drive's own mountpoint, F-2 is_mountpoint 1 is hardcoded rather than a caller flag. It refuses a root-device target, has NO storage-removal path of any kind (the pbs-apply no-delete law, grep-assertable), is idempotent for the same path, and REFUSES to repoint an existing id. POST /backup/target drives it in a fixed order: create -> grant -> config. Reversed, a config pointing at an ungranted storage 403s every backup on first run -- exactly E-1 finding F-3. A failed grant leaves the config untouched. It deliberately does NOT restart the agent: restarting with a backup in flight cancels the wait and records a spurious tier failure for a backup that actually succeeded (E-1 did this to a real felhom-pbs run). It returns restart_required and the caller restarts behind its own immediate in-flight check. Config rewrite preserves unknown keys verbatim and writes in place, since /etc/felhom-agent is root-owned while agent.json is agent-owned 0600. Green gate: build + vet + test rc=0 (29 packages), run separately from this commit.