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.goclassifyResticProbe):restic cat configfailure →wrong password or no key found= ORPHANED (the definitive 07-17 signature) · no-repo = init · other (network/SFTP-auth) = unchanged error handling.ensureOffboxRepoacts on it. - State + card:
OffboxTarget.RepoState="orphaned"(+OrphanedAt,OrphanedRenamedTo); on the transition only,offbox_repo_orphanedfires 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 (LastErroris 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 domv <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 rawwrong passworderror 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).