3.8 KiB
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 fullrestic lsof 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 —
RunTier2rsyncs only the unit +appdata/<stack>; thetier2.go:17"recovery unit + bulk userdata" header and themain.go:1360"namespace wholesale" comment are stale. Browsable HDD userdata has zero automated off-drive protection today (live:secondary/{radarr,jellyfin}hold onlyrecovery-unit/). - NEW F-S2: tier-2's appdata leg keys on the stack name → paperless-ngx
(
appdata/paperless) is silently skipped (live contrast:secondary/nextcloudhasappdata/,secondary/paperless-ngxdoesn'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
.immichfolder-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;
:roreaders back up nothing" rule. - SQ4 — size split measured live (state 0.5 M–933 M vs bulk tree ~100 MB demo /
TB-scale prod); the two-number estimate reuses the existing
estimate.goper-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 (
HDDSubdirsbasenames; CTRL-001 forbids path separators); exclusion scoping needs no manifest/import change and stays backward-compatible. Proposedbackup: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 —
.fabover-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.