Files
felhom-controller/REPORT.md
T

3.8 KiB

REPORT — most recent implementation

v0.142.0 — offsite repo continuity: orphaned-repo guard (A) + run-status auto-refresh (C) — 2026-07-17

Baseline: v0.141.0 (1452dd2) → v0.142.0 (deployed live on demo 9201, healthy). Green: go build ./... && go vet ./... && go test ./... + template/emoji/native-confirm gates. Closes the reinstall-orphaned-repo incident class (diagnosed 2026-07-17; documentation/audits/DIAGNOSE-offbox-repo-orphaned-2026-07-17.md). Pairs with hub v0.60.0 (Part B).

Part A — orphaned-repo guard (Scenarios A/B/C)

  • Classification (internal/backup/offbox.go classifyResticProbe): restic cat config failure → wrong password or no key found = ORPHANED (the definitive 07-17 signature) · no-repo = init · other (network/SFTP-auth) = unchanged error handling. ensureOffboxRepo acts on it.
  • State + card: OffboxTarget.RepoState="orphaned" (+ OrphanedAt, OrphanedRenamedTo); on the transition only, offbox_repo_orphaned fires and scheduled runs then SKIP (no nightly spam). The remote page shows a calm Hungarian exception-color card (backups_remote.html), NOT the raw restic banner (LastError is cleared for this case); the "Távoli mentés most" button is routed to the card.
  • Reset — move-aside, never delete: UNCLAIMED box auto-resets on detection (Scenario B); CLAIMED box gets an explicit reveal-then-confirm reset (Scenario C, /backup/offbox/reset + confirm=1). Both do mv <repo> <repo>.orphaned-<date> (collision-suffixed -2/-3, over an ssh-exec seam) + restic init + offbox_repo_reset. Restore paths never auto-reset (the auto-reset is run-only).
  • Red-proofs (run-fail-revert): TestOffbox_OrphanDetection_Claimed (pre-fix = the incident: the raw wrong password error surfaces, no state → FAIL; fixed: clean skip, one event, no nightly re-fire, no raw banner) + TestOffbox_OrphanDetection_UnclaimedAutoReset (move-aside + both events, un-orphaned) + TestOffbox_ConfirmedReset + TestClassifyResticProbe.

Part C — run-status auto-refresh (Scenario E)

GET /backup/offbox/status (JSON: status/snapshots/last_error/orphaned) + a poll on backups_remote.html: while a run shows "Fut…" the page polls every 3 s and reloads once at the terminal state (Rendben/Hiba + fresh numbers) — no manual reload; polling stops at terminal. Does not touch the scheduled-run rendering. Test TestOffboxStatusHandler + TestOffboxRun_RefusedWhenOrphaned.

Live leg (§13) — fallback taken, staged for the rehearsal

The scratch-target live leg CANNOT run without disturbing live state: configuring a scratch offsite target resets EscrowState to pending (the offsite config carries the escrow state + the escrowed password), the offbox RUN gates on EscrowState=="escrowed" (a scratch target needs its own customer-driven ceremony), and the live repo (customer zero's first snapshot) is untouchable (rule 2). Per §13's explicit fallback: the mechanism is covered by the fake-based tests above (the classification uses the EXACT restic stderr matched in the real 07-17 diagnosis), and the live leg is STAGED for Viktor's planned delete/re-create rehearsal. Deploy verified: controller 0.142.0 live+healthy on 9201; the demo's healthy live repo was NOT spuriously flagged (settings repo_state absent = normal).

Observations

  • Orphaned bytes vs quota: counted honestly in the usage bar; the card notes the set-aside copy; a purge affordance is NOT built (Viktor purges the .orphaned-<date> dir manually — as in the 07-17 fix).
  • Other backup pages' refresh behavior unchanged (Part C is scoped to the remote-run status only).
  • The controller cannot know the hub's superseded-blob count without cross-repo plumbing, so the card's "recoverable with the recovery code" phrasing is unconditional (true going forward — Part B retains).