5.2 KiB
REPORT — most recent implementation
v0.141.0 — N100 polish: initialize-to-usable (F6) + Vissza back-routes (F7) — 2026-07-17
Baseline: v0.140.0 (5be2449) → v0.141.0 (deployed live on demo 9201, healthy). Green:
go build ./... && go vet ./... && go test ./... all pass; template/emoji/native-confirm gates pass.
Closes felhom.eu/documentation/tests/VALIDATION-n100-baremetal-2026-07-16.md F6 + F7. (F5 lives in
felhom.eu scripts/; see that repo's REPORT.)
Fork verdict (Part 1 Phase 1, source-grounded)
F6 is controller-side — NO agent change. The detached mkfs lives agent-side
(felhom-agent/internal/localapi/formatjob.go:99 + disks.go:635, crash-safe, mkfs-only), but the
format→mount→register ORCHESTRATION is internal/web/storage_handlers.go runStorageInit and ran on
the REQUEST context; a disconnect cancelled it after FormatDisk (agent mkfs continues detached,
returns errFormatClientGone) → the mount+register leg never ran → device formatted but unusable.
The chain must reach SyncFileBrowserMounts (handlers.go:2011, controller-only), so a single
detached job can only live controller-side. The agent already exposes crash-safe format + assign →
agent v0.90.0 was NOT triggered.
F6 — initialize now ends in a mounted+registered drive, disconnect-safe
POST /api/storage/initstarts a DETACHED single-flight job (internal/web/storage_init_job.go, thenetAddStateshape) oncontext.Background();runStorageInitgained a nil-safe phase callback (formatting → mounting → registering). The wizard pollsGET /api/storage/init/statusand renders the 3-step progress (storage_init.html); confirm/refuse verdicts surface through the same poll. Register is the LAST step (marker-last, Scenario B) + idempotent prior steps (AddStoragePathdedups) → a crash leaves at most an unregistered orphan, never a broken/duplicate registration.- Deeper half (found on the live leg): a slow mkfs (a 64 GB USB) outruns the agentapi client's
15 s
Timeout; the agent runs it DETACHED and records the job, sorunStorageInitnow POLLS the agent'sGET /disks/format/status(newagentapi.Client.FormatStatus→awaitAgentFormat) to the terminal outcome on a client timeout, then continues to mount+register (the F6 root-cause's "mkfs continues detached; poll the status"). - Red-proofs (run-fail-revert):
TestStorageInit_DetachedSurvivesClientDisconnect(pre-fix cancelled-ctx chain fails at mount, NOT registered → FAIL; fixed: detached job registers exactly once) +TestStorageInit_PollsAgentFormatStatusOnTimeout(timeout→done registers; timeout→failed surfaces the error).
F7 — Vissza back-routes
The "Vissza" (Back) anchor on /storage/init and /storage/attach now routes to /storage (was
/settings); the init success link also points to /storage. Test
TestStorageWizardBackAnchors_PointToStorage.
Live validation (F6 Scenario A, on the demo scratch USB)
Method: the REAL controller endpoints (curl against the in-guest controller with the dashboard Host
header + a login session + the CSRF token — the exact calls the UI makes; browser tool not used).
Scratch device /dev/sdd (serial 20120926571200000, 59.5 GB) serial-checked against the enrolled
list FIRST (≠ the enrolled /dev/sdb hdd_1; ≠ OS /dev/sda) and confirmed present in the
agent-proven initialize candidates. Flow: init (no confirm) → needs_confirmation (ext4) via poll →
init (confirmed) → {started} (returns immediately; the client can leave) → detached job
formatting (~27 s mkfs, past the 15 s client timeout → the status-poll fix engaged) → mounting →
done at /mnt/felhom-drives/scratch1. Verified: /dev/sdd mounted at the enrolled stable bind
/mnt/felhom-drives/scratch1 (/dev/sdd[/felhom-data]); the enrolled hdd_1 untouched.
Security-review acknowledgment (background review of the commit)
Flagged a TOCTOU in runStorageInit (format → resolveEnrollUUID(path) → AssignDisk(uuid)).
Assessment: pre-existing (unchanged sequence — F6 only moved it off the request context and added
the timeout status-poll, which widened the window by the poll interval). The DESTRUCTIVE step (format)
is the authorization boundary and is agent-enforced with anti-retarget durable-id binding — the
controller cannot make the agent format the wrong device; the subsequent mount is benign and keyed by
fs-UUID (a moved /dev node resolves to a non-existent UUID → a mount failure, not data loss or an
authz bypass). No new authorization bypass. Left as an Observation (not expanded this batch per the
minimal-changes mandate); a future hardening could bind resolve+assign to the format's durable-id.
Operator sidebar (Viktor — CC does NOT do these; recorded verbatim from the spec)
- BIOS "State After G3" → "Power On"/"Last State" before final sign-off — also added to the
hardware-prep notes in
scripts/iso/README.md. - campaign6 autofs orphan — clears at the next host reboot.
- tied-CreatedAt flash duplicates (audiobookshelf/komga/romm) — standing action item.
NOT live this task
F5 (guest auto-sizing) is validated by harness only; live at the next from-scratch rehearsal (Viktor's planned delete/re-create run) — see felhom.eu REPORT.