# REPORT — FileBrowser no-op recreate fix (F2) + drop restic binary (F1) **Repo:** `felhom-controller` · **Version:** `v0.81.0` → **`v0.82.0`** · **Date:** 2026-06-24 **Baseline:** `main` @ `036a6078b` (CHANGELOG top `v0.81.0`), trunk-based, no branches. Two findings from `TEST-REPORT-stable-path-sysdrive-restart-2026-06-23.md`, both validated at source. ## F2 — gate the FileBrowser recreate on an actual change **Root cause:** `syncFileBrowserMounts` (`internal/web/handlers.go`) ran `docker compose up -d --force-recreate --remove-orphans` **unconditionally**. The existing `sourcesChanged` flag gated only the restore-mode DB reset (`down -v`); the force-recreate fired on every controller restart and every storage sync even when `config.yaml`/compose were byte-identical — bouncing the customer's file-access UI, contradicting the "Vezérlő újraindítása → apps keep running" promise (the 3.4 reproduction in the test report). **Fix:** - Capture `oldConfig`/`oldCompose` from disk **before** the writes. - Re-read `finalConfig`/`finalCompose` **after** the writes — so the integrations' `ReapplyConfigForTarget("filebrowser")` edits to `config.yaml` are included in the comparison. - New pure helper `fbNeedsRecreate(oldCfg, newCfg, oldCompose, newCompose) bool` (byte-equality on both files) drives the decision. `changed` → `up -d --force-recreate --remove-orphans`; otherwise a plain `up -d --remove-orphans` (ensures running, no bounce). - Preserved: the restore-mode DB reset stays gated on `sourcesChanged && resetDBOnChange`; when it runs it sets `changed = true` (a `down -v` removed the container, so it must be recreated). - First-ever run (no old files → empty bytes) differs from generated content → `changed = true` → creates it. **Files:** `internal/web/handlers.go` (helper + gate; added `bytes` import). ## F1 — drop the unused restic binary from the image `controller/Dockerfile`: removed the `restic \` apt line and its `# - restic: …` comment. Disk-tier restic moved to the host agent; no controller code execs the binary. Left **untouched** (still live in the dashboard/UI): `ResticSchedule` config, `migrateResticToRsync` settings migration, and the `Method`/backup-dir-name string references. ## Tests - Added `TestFbNeedsRecreate` (`internal/web/filebrowser_gate_test.go`): unchanged → **false** (no recreate); config differs → **true**; compose differs → **true**; first run (no old files) → **true**. - **Red-proof:** hard-wiring `fbNeedsRecreate` to always return `true` (the old unconditional behaviour) makes the "unchanged → no recreate" case fail; restoring the byte-equality gate turns it green. - Web package top-level tests: +1 (added `TestFbNeedsRecreate`). - Green gate: `go build ./...` ✓ · `go vet ./...` ✓ · `go test ./...` ✓ (all packages ok). ## Deploy & verify (guest 9201 / felhom-pve) Deployed via the golden bootstrap mechanism: `docker pull …:0.82.0` into the guest, set `/etc/felhom-controller-image` → `0.82.0`, `systemctl restart felhom-controller-bootstrap.service`. - `docker ps` → `gitea.dooplex.hu/admin/felhom-controller:0.82.0 Up … (healthy)` ✓ - **F1:** `docker exec felhom-controller command -v restic` → `NO-RESTIC` ✓ - **F2 (no-op):** deploying 0.82.0 restarted the controller; its startup sync logged `FileBrowser sync — no config/compose change, ensured running without recreate (3 storage path(s))`, and FileBrowser `StartedAt` stayed `2026-06-23T18:15:47` (UNCHANGED — not bounced) ✓ - **F2 (change path):** dirtied the on-disk `config.yaml` + restarted the controller → log `FileBrowser mounts synced (recreated) — 3 storage path(s), config updated`, FileBrowser `StartedAt` advanced to `2026-06-24T09:05:53` (recreated on a real change) ✓. The sync regenerated `config.yaml` back to canonical (test line gone), FileBrowser + controller healthy — state restored. Method: invoked the exact server-side sync (controller restart → `syncFileBrowserMounts`) on the live guest; no browser tool needed for this check (it's container-lifecycle, observed via `docker inspect`).