Files
felhom.eu/REPORT.md
T

3.8 KiB
Raw Blame History

felhom.eu — task reports

Overwrite this file with a summary of the most recent task only (uniform with the other repos; not cumulative). The cumulative hub history lives in hub/CHANGELOG.md; the scripts history lives in scripts/CHANGELOG.md.

SPIKE — referential-coupling backup classification — 2026-07-14

controller 0.130.0 (demo 9201) / agent 0.88.0 · findings-only, no production code · full audit: documentation/audits/SPIKE-backup-classification-2026-07-14.md

Empirical ground-truth pass for the userdata-backup-classification redesign (mandatory=COUPLED / optional=DECOUPLED-precious / excluded=DECOUPLED-bulk).

What was established

  • SQ1 — offsite carries no userdata today, no exception (source + live). All 12 restic snapshots are backups/primary/<app> units only; a full restic ls of the newest immich snapshot shows compose + immich-postgres.sql + manifest — immich is offbox-toggled and its photo library is in none of its snapshots (the latent broken-restore gap, now live-proven).
  • NEW F-S1: tier-2 does not copy bulk userdata — RunTier2 rsyncs only the unit + appdata/<stack>; the tier2.go:17 "recovery unit + bulk userdata" header and the main.go:1360 "namespace wholesale" comment are stale. Browsable HDD userdata has zero automated off-drive protection today (live: secondary/{radarr,jellyfin} hold only recovery-unit/).
  • NEW F-S2: tier-2's appdata leg keys on the stack name → paperless-ngx (appdata/paperless) is silently skipped (live contrast: secondary/nextcloud has appdata/, secondary/paperless-ngx doesn't) — its document originals get no tier-2 copy.
  • SQ3 — the coupling model is VALIDATED (scratch Immich, catalog images v2.5.5). DB-present / library-absent restore: the server refuses to boot (its own .immich folder-check, with the mount state remembered in the DB); with the skeleton recreated it boots into a lying gallery — timeline reports all 3 assets, every thumbnail/original fetch is HTTP 500. No repair/ re-import path. Restoring the files → all 200 again. Worse-than-empty: confirmed.
  • SQ2 — full per-bind classification for all 55 catalog apps (13 hdd + 42 volume-only); shared-media-tree consistency resolved by the "class belongs to the bind; the writing app is the authority; :ro readers back up nothing" rule.
  • SQ4 — size split measured live (state 0.5 M933 M vs bulk tree ~100 MB demo / TB-scale prod); the two-number estimate reuses the existing estimate.go per-mount du + container-view volume sizer — zero new measurement plumbing.
  • SQ5 — round-trip verdict: EXCLUSION scoping (tar the userdata root minus excluded subtrees). Per-bind nested tars cannot ride the v1 manifest (HDDSubdirs basenames; CTRL-001 forbids path separators); exclusion scoping needs no manifest/import change and stays backward-compatible. Proposed backup: block schema + two-level default (no block → legacy per-tier behavior; block present → unlisted writable binds mandatory) — the task's single-level mandatory-default premise would have shipped unmigrated media trees offsite (quota blow-up) and was corrected.
  • SQ6.fab over-capture quantified on the live tree (radarr bundle carries ~1.6× its own data even on the small demo tree, unbounded in prod); the live marker-file export leg is blocked on the customer-owned dashboard login (same blocker as the open Viktor full-circle test).

Cleanup

Scratch Immich fully removed (containers/volumes/network/files/images; verified 0 spike containers, controller healthy). Restic inspection read-only (--no-lock), 12 snapshots before and after. No drive namespace, tier-2 target, or deployed app touched.