docs(v0.232.0): CHANGELOG, three CONTEXT rulings, README (R-411/408/407, R-414, R-412a)
gates / gates (push) Successful in 14s

This commit is contained in:
2026-09-01 10:36:52 +02:00
parent 8b55de734c
commit 62c6a8a98a
3 changed files with 114 additions and 3 deletions
+3 -2
View File
@@ -1114,8 +1114,9 @@ restores cleanly, and gives the customer nothing back. Measured on `demo-hp` 202
| where the expectation comes from | the unit's **own** `compose/docker-compose.yml`, never the live box — the snapshot may predate the app's current shape. Database: `DBServiceNames` (the same discriminator the restore path uses). Volumes: `ParseComposeNamedVolumes`, as an **existence** check, not a name match |
| outcomes | **three:** pass, fail (readable and empty), and **cannot judge**. An app that legitimately has no database and no named volumes **passes** |
| repository writes | **none.** `--no-lock`, no `unlockStale`, and the exec seam rather than `resticStep`, so the `unlock --remove-all` escalation is unreachable. Asserted on the argv as a non-effect |
| guard | takes the single-writer flag itself and **SKIPS rather than waits** (`RestoreOffboxScratch` does not take it — R-408) |
| scratch | `backups/offsite-proof/<app>` — a **separate root** from the customer's `backups/offsite-restore/`, so the nightly delete can never reach a copy the customer made, and a proof copy can never be offered for placement |
| guard | takes the single-writer flag itself and **SKIPS rather than waits**. **Since v0.232.0 every off-site entry point takes it** — `RestoreOffboxScratch`, `OffboxRestorePrepareFull`, `RestoreSharesScratch` and `RestoreOffbox` were all missing it (R-411/R-408), and the invariant is now pinned by an AST walk rather than asserted in a comment |
| scratch | `backups/offsite-proof/<app>` — a **separate root** from the customer's `backups/offsite-restore/`, so the nightly delete can never reach a copy the customer made, and a proof copy can never be offered for placement. **On a box with NO registered data drive it falls back to the system data path** (v0.232.0, R-414), because that is where a driveless app's unit already lives; the customer's FULL restore does not fall back and still refuses |
| if it cannot run at all | it records **`cannot_run`**, not silence (v0.232.0, R-414). A proof that never started is a standing property of the machine, not a transient failure, so it is written where the hub can read it — `last_proof_result` is never ABSENT, because absent already means *a controller too old to have the feature*. Per-snapshot due-ness is NOT advanced, so the app is retried once a drive is registered |
| timeout | 10 min (`proofRestoreTimeout`) — ~150x the slowest single app measured |
| cost, measured on demo-hp | **one app 2.3–4.0 s**, all eight back to back **25 s**, peak scratch = that app's logical size (213 MB largest). The weekly check beside it takes 40.3 s |
| result | persisted on `settings.OffboxTarget` (`proved_snapshots`, `last_proof_*`) and published on `OffboxReportStatus`. `last_proof_result` absent = **NOT RECORDED** (a pre-0.231.0 controller), never "failed" |