# REPORT — Cleanup bundle: email-wipe guard + carried hygiene — controller v0.137.0 ## Summary Four closing-the-loop items from the backup-redesign arc + 6D. One code fix (Part 1, shipped v0.137.0), three operational/doc items executed inline. ## Part 1 — empty-email notification save guard (CODE, v0.137.0) — SHIPPED **Problem:** `settingsNotificationsHandler` dropped a trimmed-empty `notification_email` into the prefs and pushed it to the hub (`SyncPreferences`), overwriting the customer's provisioning-seeded alert address — a customer saving any notification change with a blank email field silently wiped their own hub-side alert delivery (the 2026-07-15 demo incident, restored by hand in 6D P3-DELIVERY). **Fix:** after computing the trimmed email + enabled events, refuse the save when `email == "" && len(enabledEvents) > 0` — return **before** `SetNotificationPrefs` and any hub sync, re-render with the Hungarian error `"Adj meg egy értesítési e-mail címet – bekapcsolt értesítésekhez szükséges egy cím, ahova küldhetjük őket."`, and repaint the just-submitted checkboxes (render-only overlay on `notificationsPageData`'s `NotificationPrefs`). The legitimate empty-email + **zero** events clear-all still proceeds. `SyncPreferences` / the hub / the seed-migration are untouched. Deliberately **no** HTML `required` attr (it is unconditional and would block the legitimate clear-all — the server-side guard is the precisely-conditional floor). **Tests + red-proof (`web/notifications_guard_test.go`, real temp-file Settings):** guard-fires (stored email survives the refused save), legitimate clear-all proceeds, normal save persists. Red-proof: neutering the guard → the stored email is wiped to `""` (the incident) → the test fails. Full `go build/vet/test ./...` green. **Deploy + live:** built + pushed `felhom-controller:0.137.0`, deployed to guest 9201 (Up, healthy; `selfupdate: Current version 0.137.0 is up to date`). The protected asset is confirmed present — the demo customer's notification email `nagyfenyvesi.viktor@gmail.com` is set. The authenticated UI click-through needs the customer-owned claim password (CC does not hold it), so the server-side guard is validated by the endpoint-equivalent unit test + red-proof (the CLAUDE.md live-validation proxy). ## Part 2 — duplicate recovery-unit cleanup (HYGIENE) — 1 removed, 3 STOPPED Recovery units are `/backups/primary//`; the controller's tie-break selects the newest by manifest `CreatedAt`, else dir mtime (`backup/offbox.go:558-607`, first-in-order wins on a CreatedAt tie). On `felhom-flash`: - **Removed** `/mnt/felhom-drives/felhom-flash/backups/primary/immich` (44M) — CreatedAt `2026-06-23T10:02:35Z` vs the live `felhom-usb` copy `2026-07-15T17:41:20Z` → **confirmed older**, never selected. Prefix asserted (`*/felhom-flash/backups/primary/*`) before `rm -rf`. - **STOPPED** (not deleted): `felhom-flash` **audiobookshelf, komga, romm** — their manifest CreatedAt is **identical** to the `felhom-usb` copy (`2026-06-23T10:02:35Z`), so the controller's tie-break is drive-order-dependent and I cannot confirm the flash copy is the non-selected/older one. Per the STOP discipline, left for a manual byte-identity check / disposition (not this micro-task). ## Part 3 — campaign6 orphaned autofs (OPERATOR ACTION) — safe clear attempted, left for Viktor `/mnt/felhom-drives/campaign6` is a bare empty leftover directory (`nobody:nogroup`) — **not** a live mount (not a mountpoint, absent from the mount table, no autofs config / systemd unit / fstab entry). A safe non-disruptive `rmdir` (refuses non-empty dirs + mountpoints) was **refused with Permission denied** even as root (an autofs-ghost / immutable artifact). No live mount was disturbed (mount count 89→89; all 8 drive mounts intact). Not escalated to `chattr`/force (beyond a safe clear). **Left for Viktor's demo-host reboot window** — CC did not reboot. ## Part 4 — 6D audit doc tag (DOC) — committed Added the matching track-only disposition line to the campaign6 autofs LOW finding in `felhom.eu/documentation/audits/CAMPAIGN-6D-2026-07-15.md` (consistency with the duplicate-recovery LOW). Commit `dee72cd`. ## Queue after this bundle - **Pending operator (Viktor):** campaign6 autofs clears on the next demo-host reboot; the tied-CreatedAt `felhom-flash` audiobookshelf/komga/romm duplicates await a manual disposition. - **Deliberately not here** (correctly deferred): Peti-return runbook (hardware-gated); P4-DEEP timing + P-TIER2 deep-4 (pre-broad-launch resilience); agent 0.88 publish (6D P-DAY0 shows the manifest already vouches 0.88/golden-0.136 — likely closeable, verify separately).