# REPORT — slice 10: external user-data drive passthrough (P1 spike + P2) **Agent v0.25.0** (+ controller v0.48.0, golden rebaked). P1 spike PASSED (gate); P2 BUILT + validated live on guest 9201. P3 (self-heal) + P4 (dual-role) are the next phases. ## PHASE 1 — SPIKE (GATE PASSED), four proofs on 9201 - **1A host→guest bind:** `pct set 9201 -mp0 /mnt/felhom-usb,mp=/mnt/felhom-usb` — **bind form** (host path), never `storage:size`. Propagation `shared:49` host↔guest automatic. - **1B write — chown, not idmap:** idmap not clean (mixed host ownership 1000+0, container-wide, restart, subuid). Decision (refined with Viktor): chown only a fresh **`/felhom-data`** namespace to `100000:100000`; the customer's existing data is never touched. Guest-root r+w confirmed. - **1C guest→controller-container:** `-v /mnt:/mnt:rslave` + `/mnt` rshared in the guest → newly-mounted drives propagate into the running container (proven). The de-priv `/mnt` gap, reopened scoped. - **1D app-container:** busybox bind read+write; bytes land on `/dev/sdb1`. ## PHASE 2 — passthrough (Model A: the felhom-data namespace is the in-guest mount) - **P2A agent — `POST /disks/guest-attach`** (`internal/localapi`, `GuestBinder`): self-scoped; creates `/felhom-data`, chowns it to the guest base (not -R), and `pct set -mpN /felhom-data,mp=/mnt/` (RW bind). Idempotent; lowest free `mpN`; `where` validated. Only Felhom's namespace crosses into the guest — the customer's other on-drive data never does. Tests: `TestGuestAttach_*` (slot select, idempotency, bad-path, not-configured). - **P2B golden — `configs/build-golden.sh`:** controller `docker run` gains `-v /mnt:/mnt:rslave`; the bootstrap makes `/mnt` rshared first. Scoped to `/mnt` (only felhom-data-namespace mounts). - **P2C controller (v0.48.0):** `agentapi.GuestAttach`; `runStorageInit`/`runStorageAttach`/ `handleStorageRegister` call `attachIntoGuest` after register (best-effort; P3 heals a miss). ## Live validation (9201) After `guest-attach` + a guest restart to activate mp0: - mp0 = `/mnt/felhom-usb SOURCE /dev/sdb1[/felhom-data]` (Model A; the `[/felhom-data]` suffix the controller's mount strip already handles). - Controller container mountinfo has `/felhom-data /mnt/felhom-usb … /dev/sdb1`. - An app (busybox bind) writes `proof.txt` → present on the **host** `/mnt/felhom-usb/felhom-data/...`, `df` device `/dev/sdb1` (NOT the rootfs). - Banner cleared: **`[PASS] Storage paths: 1 connected, 0 disconnected`**. - `go test ./...` green (both repos). ## KNOWN LIMITATION — live activation (decision needed before P3) `pct set` does **not** hot-apply a mountpoint to a *running* guest when the guest's `/mnt` is rshared (the P2B rbind shadows the live hotplug; the spike's live hot-apply worked only because `/mnt` wasn't yet shared). So a drive enrolled into a **running** guest activates on the **next guest restart** — the end-state is correct, but live enroll isn't seamless. This is a genuine hotplug-vs-propagation fork (like the chown/idmap + Model A decisions) to settle before P3: options are (a) enroll triggers a guest reboot; (b) drop the guest `/mnt` rbind and have enroll do `pct set` (live hotplug works) + a lightweight controller-container restart to capture it; (c) let P3 self-heal reconcile drive activation. Fresh guests from the rebaked golden are unaffected (mp mounts activate at first boot, before the controller starts). ## Not done (next phases) P3 self-heal watchdog reconcile (4-state new/enrolled/ejected/decommissioned) + safety rails; P4 dual-role + backup-aware wipe warning. Cross-drive backup ENGINE remains out of scope.