49 lines
3.8 KiB
Markdown
49 lines
3.8 KiB
Markdown
# 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).
|