docs: REPORT for v0.32.0 self-serve decommission + intent-aware re-assert
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,40 +1,51 @@
|
||||
# REPORT — live-drive disk fixes F9 + F20-BUG2 + F20-BUG3 → agent v0.31.0 (2026-06-14)
|
||||
# REPORT — self-serve decommission + intent-aware re-assert → agent v0.32.0 (2026-06-14)
|
||||
|
||||
The last live-drive findings, all agent disk/`localapi`-side. Implemented trunk-based on `main`, each
|
||||
its own commit + regression tests; built v0.31.0, deployed to `felhom-pve`, and **validated live** on
|
||||
guest 9201 + the 916 GB felhom-usb. Supervised, phased; every phase verified. Controller side reflected
|
||||
in v0.63.0 (two passthrough fields).
|
||||
Agent half of TASK B2 (the controller half ships as felhom-controller v0.65.0). Implemented trunk-based
|
||||
on `main` against the locked spike design
|
||||
(`felhom.eu/documentation/audits/SPIKE-decommission-migration-2026-06-14.md`). Built on 192.168.0.180,
|
||||
deployed + restarted on demo host `felhom-pve`.
|
||||
|
||||
## Phase 0 (gate) — approach
|
||||
- 9201 ran controller **v0.62.0** (not v0.61.0 — stale premise); no golden template exists; `build-golden.sh`
|
||||
bakes controller **0.43.0** by default ⇒ a re-provision would REGRESS the controller + lose apps.
|
||||
- F9's bind is **agent runtime** `pct set -mpN` (`guestbind.go AttachBind`), NOT golden-baked ⇒ **no golden
|
||||
rebake needed**. Operator-confirmed approach: **attach-to-existing 9201** (no re-provision), with the
|
||||
bind auto-re-assert validated via a **real trigger** (agent restart), not unit-tests + a manual call.
|
||||
> Validate against pushed source, not this report.
|
||||
|
||||
## Fixes (each a commit + tests)
|
||||
| Finding | Commit | What | Live proof |
|
||||
|---|---|---|---|
|
||||
| **F9** | `4cd1d02` (+`a2a76e7` reporting) | `GuestBindStore` + `ReassertGuestBinds` (startup, durable-id-matched) restore a bind a re-provision dropped; `GuestAttached` reporting | dropped bind → agent restart auto-re-attached (no manual call) → reboot activated → HDD app deployed, data on `/dev/sdb1`; `guest_attached=True` end-to-end |
|
||||
| **F20-BUG2** | `a2a76e7` | shared `deviceDurableID` seam → `/disks` `WipeDurableID` is the gate's scheme; one id for the wipe-confirm | confirmed wipe with `/api/disks`'s `wipe_durable_id` accepted (no `binding_mismatch`) |
|
||||
| **F20-BUG3** | `4777f8a` | mkfs detached off `baseCtx` + persisted `formatJob` + `GET /disks/format/status` + `RecoverFormatJob` startup recovery (anti-retarget) | 2 s client timeout left a ~30 s mkfs running to a clean ext4; agent restart mid-format recovered + completed clean — **the live-drive corruption is gone** |
|
||||
## Baseline → shipped
|
||||
- `main` was `8e6d00a` = **v0.31.0** → shipped **v0.32.0** (commit `f43697c`).
|
||||
|
||||
## Verification (per phase)
|
||||
- **P1**: `go build/vet/test ./...` green on the build server incl. new tests (BUG2 scheme + gate-binding; F9 re-assert restores/skips-absent/skips-bound + store persist; BUG3 detached-persist + status + recover re-runs/skips-blank/skips-unresolvable).
|
||||
- **P2**: agent v0.31.0 active; local API reachable; 9201 controller online; **AGENT-001 refusals still hold** (no-confirmation → 409; wrong durable_id → 409).
|
||||
- **P3 / P4**: as above — all live-proven on 9201 + felhom-usb.
|
||||
## What shipped
|
||||
- **`POST /disks/decommission`** (`internal/localapi/disks.go` `handleDiskDecommission`, route in
|
||||
`server.go`) — self-serve, NO operator signature, NON-destructive. Mirrors `handleDiskEject` exactly:
|
||||
`withGuest` self-scoping, `scopedFromBody`, and the same **user-data role gate** (`roleForMountPath` must
|
||||
be `RoleUserData`, else 403; fail-safe-to-protected). It records a PERMANENT `IntentDecommissioned`,
|
||||
prunes the `GuestBindStore` entry, and unmounts. It **NEVER** calls any format/mkfs path — the data stays
|
||||
on the drive. A compromised controller gains nothing beyond eject/customer-confirmed-wipe; the hub can't
|
||||
reach the local API at all.
|
||||
- **`ReassertGuestBinds` is now intent-aware** (the load-bearing F9-reconnect correctness fix): the
|
||||
startup re-assert skips any durable-id whose intent ≠ `enrolled`, so a decommissioned- (or ejected-)
|
||||
but-still-present drive is never auto-rebound into the guest on agent restart. Nil intent store → legacy
|
||||
bind-all (matches the watchdog's nil-intent rule). Covers both the self-serve and the operator-signed
|
||||
decommission paths (both land on `IntentDecommissioned`).
|
||||
- **`GuestBindStore.Remove(vmid, durableID)`** — idempotent (absent = no-op), atomic tmp+rename; drops the
|
||||
vmid key when its set empties. Re-enroll re-`Record`s via the existing `recordGuestBind`, so Remove
|
||||
doesn't break re-commission.
|
||||
- `IntentRecorder` extended with `SetDecommissioned` + `Get`. The operator-signed `DecommissionExecutor` +
|
||||
`reconcile.Classify` classification are **untouched** (the absent-drive/DR route).
|
||||
|
||||
## Backward-compat + safety notes
|
||||
- BUG3 keeps the **synchronous** format response (the live v0.62.0 controller's `agentapi.FormatDisk` is sync) — the detached mkfs just can't be killed by a dropped request; `/disks/format/status` is additive.
|
||||
- The controller has **no automated SSD↔HDD data-migration feature** (removed in de-privileging) — F9 unblocks HDD-app deployment + data-on-HDD, which is proven; an app-data mover would be a separate feature.
|
||||
- The `GuestBindStore`/intent durable-id is the storage-view `uuid:` (fs UUID), which CHANGES on a reformat — so after a wipe a drive must be re-enrolled (auto-re-assert won't match a new fs identity). Correct for the F9 re-provision case (drive unchanged); noted for the reformat edge.
|
||||
## Tests (`go build && go vet && go test ./...` green)
|
||||
`internal/localapi/decommission_test.go`: role-gate refuses system/backup (403, no unmount); decommission
|
||||
sets intent + removes the bind + unmounts + never formats (all three asserted); **intent-aware re-assert
|
||||
does NOT rebind a decommissioned-but-present drive** (companion: enrolled DOES rebind — and the guard was
|
||||
mutation-proven: removing it makes the test FAIL with the drive re-bound); re-commission re-records;
|
||||
`GuestBindStore.Remove` idempotency + persistence.
|
||||
|
||||
## Rollback
|
||||
Baseline preserved at `/usr/local/bin/felhom-agent.bak-0.30.0`. Not needed — all verifications passed.
|
||||
## Deploy / verify
|
||||
- Built v0.32.0 on 192.168.0.180 (`go build -ldflags "-X main.version=0.32.0"`); installed on felhom-pve
|
||||
at `/usr/local/bin/felhom-agent` (prior backed up to `.bak-0.31.0`); `systemctl restart felhom-agent` →
|
||||
**active**, `--version` 0.32.0.
|
||||
- **Live-proven on restart:** the new intent-aware re-assert logged
|
||||
`F9 re-assert: skipping non-enrolled drive (intent-gated) vmid=9201 durable_id=uuid:ce9d1d81-… intent=ejected`
|
||||
— the exact drive that lingered in `guest-binds.json` (B0 spike finding) is now correctly skipped (it
|
||||
would have been re-bound on the pre-fix code). Clean startup, no errors.
|
||||
|
||||
## Follow-up queued (separate task — NOT folded into this)
|
||||
**Bump the golden's default controller tag (`build-golden.sh:43`, currently `:0.43.0`, 20 versions stale) to current + validate the full destroy→provision→first-boot path.** That path *does* warrant a supervised destroy+re-provision (it's the real customer-onboarding flow).
|
||||
|
||||
## Final demo state
|
||||
Agent v0.31.0; controller v0.63.0; 9201 healthy. felhom-usb wiped clean by the BUG3 test, then re-enrolled
|
||||
+ re-attached (`guest_attached=True`); romm redeployed onto the HDD (`/dev/sdb1`); all apps healthy.
|
||||
## NOT yet live-validated — awaiting supervised B3
|
||||
The endpoint's full effect via the real UI flow (customer decommission → drive un-enrolled → does not
|
||||
auto-mount/re-bind on physical reconnect, with real data on the drive) is deferred to the operator-present
|
||||
B3 session. The intent-gate itself is already proven live by the restart log above.
|
||||
|
||||
Reference in New Issue
Block a user