# DIAGNOSIS — post-F9 storage-registration gap (read-only; no system changes made)

**Date:** 2026-06-14. **Scope:** why the HDD (`felhom-usb`) is attached + written-to by RomM yet badged
"Nem regisztrált" and absent from the deploy dropdown. **Method:** live SSH (read-only) + controller
source. **No state changed** — no registration, deploy, restart, or edits. Diagnosis only; fix to be specced next.

## TL;DR
F9 attached the HDD at the **agent/guest layer** (the `pct set -mpN` bind). The controller's **storage
registry** (`settings.json → storage_paths`) is a **separate layer** that F9 never touched. The controller
registers a drive only through its own enroll flows (`runStorageInit` / `runStorageAttach` /
`handleStorageRegister`), each of which calls `registerStoragePath`. In the F9 session the drive was
attached by calling the **agent's `/disks/guest-attach` directly** (and RomM got `HDD_PATH=/mnt/felhom-usb`
via a manual `deploy` value) — both bypass the controller's registry. Auto-discovery can't backfill it
(it's a one-time seed that only scans deployed-app `HDD_PATH`s, never the agent's attached-drive list).
Result: attached + in use, but unregistered → not selectable for a new app. **F9 is NOT closed.**

## Q1 — Real storage topology (what each path maps to)
| Name (UI) | Host path | Device | Size / free | What it is |
|---|---|---|---|---|
| `Tárhely (felhom-data)` ★ (registered) | `/mnt/sys_drive/felhom-data` | `/dev/mapper/pve-vm--9201--disk--0` | 32 G / **~29 G** | the **internal OS-disk volume** (rootfs disk-0). The "28.7 GB szabad" in the dropdown = this. |
| `felhom-usb` (NOT registered) | `/mnt/felhom-usb` | `/dev/sdb1` | **916 G / 870 G** | the **HDD**, guest-attached (mp1), 2.1 MB used |

Evidence: `pct config 9201` → `mp1: /mnt/felhom-usb/felhom-data,mp=/mnt/felhom-usb`; guest `df` → `/mnt/sys_drive`
on `…disk--0` (32 G, 29 G avail) vs `/mnt/felhom-usb` on `/dev/sdb1` (916 G, 870 G avail). The registry
(`settings.json`) lists only `{"path":"/mnt/sys_drive/felhom-data","label":"Tárhely (felhom-data)","is_default":true,"added_at":"2026-06-13T22:22:50Z"}`.
**Confirmed: the "28.7 GB" option is the internal volume, not the HDD.**

## Q2 — Where RomM's data is + how it got an HDD path
- RomM's `app.yaml` (`/opt/docker/stacks/romm/app.yaml`): `env.HDD_PATH: /mnt/felhom-usb`, `deployed: true`,
  `locked_fields: [HDD_PATH]`. Its data dirs live under `/mnt/felhom-usb/felhom-data/appdata/romm/…` (the HDD).
- **How it got set:** the `HDD_PATH` deploy field was filled with `/mnt/felhom-usb` when RomM was (re)deployed
  onto the HDD during the F9 P3/restore test. The deploy path validates `os.Stat(HDD_PATH)` exists
  (`stacks/deploy.go` path-field check) — it does, because F9 had bound `/mnt/felhom-usb` into the guest — but
  **the deploy does NOT register the path** in `storage_paths`. So RomM references the HDD path *directly*,
  entirely independent of the registry. That's how "RomM uses the HDD" coexists with "HDD unregistered."

## Q3 — Why `felhom-usb` is "Nem regisztrált"
The registry (`settings.json storage_paths`) contains **only** `/mnt/sys_drive/felhom-data`; `/mnt/felhom-usb`
is absent. Nothing registered it, at any layer:
- **F9's attach is agent-layer only.** `ReassertGuestBinds` / `handleDiskGuestAttach` → `guestbind.go AttachBind`
  do `pct set -mpN` (the bind). They never call the controller's `registerStoragePath`. In the F9 session the
  drive was attached by calling the agent `/disks/guest-attach` **directly**, bypassing the controller enroll flow.
- **Deploy doesn't register.** Setting `HDD_PATH` on RomM only validates existence (above), no registry write.
- **Auto-discovery can't backfill it** — two reasons in `settings.AutoDiscoverStoragePaths` (`internal/settings/settings.go:584`):
  1. **One-time seed:** `if len(s.StoragePaths) > 0 { return // already configured }` (≈:592). The registry already
     holds `sys_drive` (seeded 2026-06-13), so discovery is now **permanently inert** on every restart.
  2. **Wrong source even if it ran:** it's fed by `discoverHDDPaths(StacksDir)` (`cmd/controller/main.go:1337`,
     called once at startup, `main.go:126`), which scans **deployed apps' `HDD_PATH`** — never the agent's
     `/disks` attached-drive list. A drive attached out-of-band (or whose app was deployed after startup) is invisible.

So: **registration is decoupled from attach; auto-discovery is a one-shot startup seed of app `HDD_PATH`s; the
agent-layer F9 bind and the manual deploy both bypass registration** → the HDD stays unregistered.

## Q4 — Why the deploy dropdown excludes the HDD
The deploy dropdown is populated from `s.settings.GetSchedulableStoragePaths()` (`internal/web/handlers.go:323`),
i.e. **registered paths only**. `/mnt/felhom-usb` is not in the registry → not schedulable → absent. So a new
app (Calibre) can only be pointed at `sys_drive` (the 31 G internal volume). The "Nem regisztrált" badge is the
storage page (`storageWizardPageHandler`) merging the agent `/disks` (attached, `guest_attached=true`) against
`GetStoragePaths()` (registry) and flagging the difference (`storage_handlers.go` `Registered` field;
`settings.html` `window.__registeredPaths`).

## Q5 — Intended registration-vs-attach behavior (per the code)
The controller's design intends **register + attach as one operator-driven enroll operation**, NOT an automatic
side-effect of an agent bind:
- `runStorageInit` (format a blank/new drive) and `runStorageAttach` (mount an existing-fs drive — the "Csatolás"
  button) both do: assign (host mount) → **`registerStoragePath`** → `attachIntoGuest`→`agent.GuestAttach`
  (`internal/web/storage_handlers.go:83-158`). The comment is explicit: *"the StoragePath **registration is the
  durable intent**, so a transient attach failure is logged (not fatal) — P3 self-heal completes it."*
- For an **already-mounted, unregistered** drive (exactly `felhom-usb`'s state), there is a dedicated action:
  `POST /api/storage/register` → `handleStorageRegister` (`storage_handlers.go:442`, the "Regisztrálás" button),
  commented: *"the natural primary action for a mounted-but-unregistered data drive (e.g. **felhom-usb**): the
  customer's intent is to USE the existing data, not wipe it… registering a host-only mount otherwise leaves it
  guest-invisible (the exact gap that produced the 'nem elérhető' banner)."* It registers + attaches into the guest.

So per the code, registration is meant to come **through these controller flows**. There is **no reconciliation
that auto-registers a drive the agent attached out-of-band** — which is precisely the F9 case (the agent's
re-assert / a direct guest-attach binds the drive without ever invoking the controller's register step).

## Q6 — The "felhom-data" naming collision
Deliberate convention, but genuinely confusing. `felhom-data` is BOTH:
1. the **path tail of the internal volume's registered path** (`/mnt/sys_drive/felhom-data`), surfaced as the
   label `Tárhely (felhom-data)`, and
2. the **per-drive Felhom namespace subdirectory** created on EVERY user-data drive by the agent's `AttachBind`
   (`guestbind.go:29 felhomDataNS = "felhom-data"`, "matches `appbackup.FelhomDataDir`") — hence `/mnt/felhom-usb/felhom-data/…`.
So `felhom-data` denotes both a specific volume and the generic namespace. Risk: the label `Tárhely (felhom-data)`
reads as generic but is specifically the OS-disk volume; meanwhile the HDD also has a `felhom-data` dir. A clearer
label (e.g. "Belső SSD" for the internal volume vs the drive's own name for the HDD) would remove the ambiguity.

## Recommended fix direction (to spec next — NOT implemented here)
1. ~~**Auto-register on attach (primary).**~~ **REJECTED (2026-06-14)** — contradicts the new→enrolled
   manual-enrollment model; manual enroll is by design. A drive becomes usable through the explicit
   enroll/"Regisztrálás" flow (recommendation #2), not by auto-registering whatever the agent attached
   out-of-band. (The "make discovery additive, not return-if-any-path-exists" sub-point WAS adopted —
   shipped in controller v0.64.0, A1 — but only as additive pickup of paths referenced by *deployed apps*,
   NOT as auto-register-on-attach.)
   ~~Make a drive the agent has attached into the guest become a registered
   storage path automatically, so F9's attach is usable end-to-end. Options: (a) the controller's startup/periodic
   storage reconcile consults the **agent `/disks`** and registers any `guest_attached=true` user-data drive missing
   from the registry (extend beyond the app-`HDD_PATH` scan); and/or (b) the enroll/re-assert path that binds a
   drive also performs `registerStoragePath`. Also **remove the one-time-seed gate** (or make discovery additive,
   not "return if any path exists") so it can pick up drives added after the first run.~~
2. **Keep `handleStorageRegister` as the explicit fallback** ("Regisztrálás" button) for the mounted-but-unregistered
   case, and make the "Nem regisztrált" badge clearly actionable. For the **immediate** demo state, this button
   (`POST /api/storage/register {where:/mnt/felhom-usb}`) would register felhom-usb + make it selectable — no fix needed to recover now.
3. **Clarify the `felhom-data` label** (Q6) to disambiguate the internal volume from the per-drive namespace.
Recommended: **both** auto-register-on-attach AND the clearer manual path — auto so the normal flow "just works",
manual for out-of-band/edge cases.

## Verdict on F9 — NOT closed
F9 made the HDD present + writable **inside the guest** (agent layer), but did not make it **usable for new apps
through the UI** (controller registry layer). The deploy dropdown is gated on the registry; the registry is
unaware of the agent-attached drive. **F9 should remain open (or spawn an F9b)** until: attach ⇒ auto-registered
⇒ a NEW app (e.g. Calibre) can be deployed to the HDD through the normal deploy UI with its data landing on
`/dev/sdb1` persistently. Today that round-trip fails at the dropdown.
