From c37ee6d43a39f10e1cb57cfd30227c212c39f2cb Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Sun, 14 Jun 2026 17:40:04 +0200 Subject: [PATCH] docs: REPORT.md for TASK A storage-lifecycle cleanups (v0.64.0) Co-Authored-By: Claude Opus 4.8 (1M context) --- REPORT.md | 124 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 43 deletions(-) diff --git a/REPORT.md b/REPORT.md index 4d7d209..5c97070 100644 --- a/REPORT.md +++ b/REPORT.md @@ -1,56 +1,94 @@ -# REPORT — live-drive Batch 1 (+F17) → controller v0.61.0 (2026-06-14) +# REPORT — TASK A storage-lifecycle cleanups → controller v0.64.0 (2026-06-14) -Implemented the controller-side fixes from `LIVE-DRIVE-FIXSPEC-2026-06-14.md` (Batch 1 + the CRITICAL -F17), shipped as **v0.61.0** to demo guest 9201. Each fix has a regression test that fails on the -pre-fix code; the authoritative `go build && go vet && go test ./...` is green on the Linux build server. +Two settings-layer cleanups (A1, A2) + two doc-only changes (A3, A4) from the F9 storage-registration +diagnosis. Trunk-based, all on `main`, no branches. Each code change has a table-driven test that fails on +the pre-fix code. Built, pushed, and deployed to demo guest 9201; verified `:0.64.0 Up (healthy)` with a +clean startup (`controller_started (0.64.0)`, no errors). -## Fixes (each its own commit) +> Verify against pushed source, not this report. -| Finding | Sev | Change | Test | Live-verified | -|---|---|---|---|---| -| **F17** | CRIT | per-app restore now **replays the captured `.sql` dump** (new `appbackup.ImportDump` + `backup.reimportDBDumps`), AFTER volume restore so the **dump wins**; volume/DB failures now surface | `restore_db_test.go` (injectable seams) | **marker DB round-trip PASSED** on romm | -| **F1** | HIGH | guest RAM cap from `docker info` (daemon runs in LXC); deploy guard "used" = committed memory | `info_cgroup_test.go` (cgroup + docker-info paths) | `total_mem_mb=2048` (was 15771) | -| **F20-BUG1** | HIGH | `agentapi.FormatDisk` surfaces non-2xx/`ok:false` instead of zero-value success | `disks_test.go` (502→err) | unit | -| **F5 (catalog)** | HIGH | uptime-kuma healthcheck → v2 `extra/healthcheck` binary + 180s start_period | — (catalog) | uptime-kuma **healthy → route 302** (was 404) | -| **F5 (dashboard)** | HIGH | `routeUnpublished` helper + distinct indicator for unhealthy/restarting deployed apps | `route_unpublished_test.go` | render test | -| **F8** | LOW-MED | `controller.yaml` persisted 0600 (holds infra tokens) | `config_perms_test.go` | unit (Linux) | -| **F6** | LOW | deploy POST → 202 + "Telepítés elindítva" (was "deployed" before compose) | — | code/UI | -| **F7** | LOW | `status-refresh` 30s → 10s | — | cadence | -| **F4** | TRIV | `GET /api/stacks/rescan` → 405 + `Allow: POST` | — | `→ 405` | +## Pre-flight -## Key implementation notes +`main` is the only branch in felhom-controller; HEAD was `688ba0d v0.63.0` (CHANGELOG top + live container +both `:0.63.0`). Confirmed before starting. -- **F17 reuse decision:** `ImportDump` lives in `internal/appbackup` (the DB-domain package with - `DiscoverDatabases`/`DumpOne`/`getMariaDBPassword`), NOT reusing `appexport`'s unexported copies — - `appexport→appbackup` already exists, so the reverse would import-cycle. `DiscoveredDB` carries the live - container's own creds, so no env threading. Precedence: replay runs after volume restore → `.sql` wins. -- **F1 reroot:** the FIXSPEC's cgroup-limit approach was a **no-op** on the demo (the container's own - cgroup is unlimited; the 2 GB cap is on the LXC ancestor, hidden; no lxcfs in the container). The - working source is `docker info` MemTotal. The deploy guard's "used" switched from host RSS (not - per-guest observable) to the controller's committed-memory accounting. +## Per-item results -## Deploy & verification +### A1 — `AutoDiscoverStoragePaths` made ADDITIVE +- **File:** `controller/internal/settings/settings.go` (the function previously at L584). +- **Change:** removed the `if len(s.StoragePaths) > 0 { return }` early-return. It now registers only + discovered paths NOT already present. Invariants enforced: + - Never removes/modifies a manually-added path. + - SKIPS any path already in the registry IN ANY STATE — including a `Decommissioned` soft-marked entry — + so it is never re-added or reactivated (`if existing[path] { continue }`, keyed on `filepath.Clean`). + - Never flips `IsDefault`: a newly-discovered path becomes default ONLY if the registry currently has no + default at all (and then only the first such new path) — `IsDefault: !hasDefault`, with `hasDefault` + seeded from existing entries and set true after the first new default. +- **Tests:** new `controller/internal/settings/storage_discovery_test.go` + (`TestAutoDiscoverStoragePaths_Additive`, table-driven, + `..._DecommissionedNotReactivated`): + - (a) non-empty registry + a deployed-app path missing from registry → exactly that path registered; + pre-existing entry byte-identical via `reflect.DeepEqual` (IsDefault asserted unchanged); new path not + promoted to default. + - (b) Decommissioned path present + a deployed app still pointing at it → NOT reactivated; entry + byte-identical; path count unchanged. + - extra cases: empty registry (first becomes default), registry-with-no-default (first new becomes + default), fallback path pickup. +- **Non-hollow proof:** temporarily removing the `if existing[path] { continue }` guard makes + `..._DecommissionedNotReactivated` FAIL (`path count changed: got 4 want 2`); restored → green. +- **Commit:** `2d4d432` (shared with A2). **Test result:** `ok internal/settings`. -- Built+pushed `gitea.dooplex.hu/admin/felhom-controller:0.61.0`; deployed via the guest-9201 - golden/bootstrap mechanism (`/etc/felhom-controller-image` + restart bootstrap). Healthy, `/api/health` - + dashboard 200, no startup errors. -- Live-verified: F1 (`total_mem_mb=2048`), F4 (405), F5 (uptime-kuma healthy → route 302), **F17 (marker - row dropped after backup was restored by `/backup/restore`)**. +### A2 — internal-SSD label disambiguation +- **File:** `controller/internal/settings/settings.go` (`InferStorageLabel`). +- **Change:** when `filepath.Base(path) == appbackup.FelhomDataDir` (the `"felhom-data"` namespace dir), the + label is now `Belső SSD (rendszer)` instead of the colliding `Tárhely (felhom-data)`. Imported + `internal/appbackup` for the constant (no import cycle — appbackup only depends on `internal/util`). + Still overridable via `SetStorageLabel`. +- **User-drive safety confirmation:** Model-A user drives register their MOUNT ROOT (e.g. `/mnt/felhom-usb`) + — confirmed live on 9201, where the user drive is registered as `/mnt/felhom-usb`, never + `.../felhom-data` — so the `base == felhom-data` match cannot mislabel a user drive. +- **Untouched:** the separate host-metrics label in `web/agent_host_metrics_handler.go:91` was left as-is + (display-only host-metrics path; A2 is the storage-registry label only). +- **Tests:** `TestInferStorageLabel` covers `/mnt/sys_drive/felhom-data` → `Belső SSD (rendszer)`, a + second felhom-data path, plus the existing hdd/ssd/usb/`Tárhely` branches (note: `felhom-usb` does NOT + start with `usb`, so it correctly labels `Tárhely (felhom-usb)` — pre-existing behavior). +- **Demo seeded-label update (before/after):** the seeded `settings.json` on 9201 had + `"/mnt/sys_drive/felhom-data" → "Tárhely (felhom-data)"`. Updated **through the real UI endpoint** + (`POST /settings/storage/label` → `SetStorageLabel`, the same handler the dashboard form posts to) to + `"Belső SSD (rendszer)"`; verified persisted in `settings.json`. (Note: the public URL + `https://felhom.demo-felhom.eu` returned 200 without applying the change — the Cloudflare/Traefik path + mangled the POST body; posting to the container's own `127.0.0.1:8080` returned 302 success and + persisted. Same handler either way.) Before: `Tárhely (felhom-data)`. After: `Belső SSD (rendszer)`. +- **Commit:** `2d4d432` (shared with A1). **Test result:** `ok internal/settings`. -## Test approach +### A3 — doc: reject auto-register-on-attach (no deploy) +- **File:** `felhom.eu/documentation/backlog/DIAGNOSIS-f9-storage-registration-gap-2026-06-14.md` (the doc + lives in `backlog/`, not `audits/` as the task said). +- **Change:** recommendation #1 annotated **REJECTED (2026-06-14)** — contradicts the new→enrolled + manual-enrollment model; manual enroll is by design. Noted that the "make discovery additive" sub-point + WAS adopted (v0.64.0 A1) but only for paths deployed apps reference, not auto-register of agent-attached + drives. +- **Commit:** `b5a9614` (felhom.eu repo). -Controller code is largely `//go:build linux`; dev host is Windows. Per-commit gate = -`CGO_ENABLED=0 GOOS=linux go build && go vet` locally (compiles code + tests); authoritative -`go test ./...` ran on the Linux build server (all green, incl. the linux `system` tests). +### A4 — doc: live-validation rule (no deploy) +- **Files:** `felhom-controller/CLAUDE.md` and `felhom-agent/CLAUDE.md` — added the verbatim "Live + validation" paragraph to both. +- **Commits:** `e850402` (felhom-controller), `8e6d00a` (felhom-agent). -## Not in this batch (SUPERVISED, next session — agent/golden) +## Build / deploy / verify -**F9** (HDD provisioning/guest-attach + reporting), **F20-BUG2** (durable_id scheme), **F20-BUG3** -(async mkfs). These touch the host agent, golden template, and bring-up (blast radius beyond the -disposable demo). +- `go build ./... && go vet ./internal/settings/ && go test ./...` → all green locally. +- Built + pushed `gitea.dooplex.hu/admin/felhom-controller:0.64.0` on 192.168.0.180. +- Deployed to guest 9201 via the golden/bootstrap mechanism (`docker pull` → write + `/etc/felhom-controller-image` → restart `felhom-controller-bootstrap.service`). +- **Verify:** `docker ps` → `gitea.dooplex.hu/admin/felhom-controller:0.64.0 Up (healthy)`; logs show + `Event pushed: controller_started (info) — Controller elindult (0.64.0)` and no startup errors. No + rollback needed. -## Final state +## Commit hashes (per item) -Demo guest 9201 on `:0.61.0`, healthy; agent unchanged. Apps: actualbudget, gokapi, mealie, privatebin, -romm(+db,+redis), uptime-kuma (now **healthy**), vikunja — all healthy. felhom-usb still not attached to -the guest (F9, deferred). +| Item | Repo | Commit | +|---|---|---| +| A1 + A2 (code + tests + CHANGELOG + README) | felhom-controller | `2d4d432` | +| A4 (CLAUDE.md) | felhom-controller | `e850402` | +| A4 (CLAUDE.md) | felhom-agent | `8e6d00a` | +| A3 (diagnosis annotation) | felhom.eu | `b5a9614` |