docs: record the two silent no-ops the end-to-end restore run found

Both were checks whose failure mode was to not run, and both produced output
indistinguishable from a healthy report. Worth writing down as a shape rather
than as two bugs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
librelad 2026-08-27 12:16:48 +01:00
parent 647b19cf4a
commit 5b2d824aac
2 changed files with 44 additions and 0 deletions

View File

@ -88,6 +88,28 @@ Output is a verdict list, then one confirmation:
Continue? [Y/n]:
```
### 3.1 — Two silent no-ops, and what they have in common
Both were found by running the installer's restore path end to end against a
real repository, not by reading the code — which is the point of doing that.
1. **The manifest is pretty-printed.** `"size_bytes": 123` carries a space, so
a `"key":[0-9]*` pattern missed it. Size came back empty, and the fit check
is guarded by `[[ -n "$size_bytes" ]]` — so it was skipped for every app.
2. **The manifest was never read at all.** `storageSnapshotSourcePath` passed a
snapshot id into an app-tag filter (see storage-locations §9), so it returned
1 every time and the preflight fell back to a `?` size.
The shared shape: **a check whose failure mode is to not run.** Neither printed
an error, and the report they produced — thirteen green ticks — is exactly what
a healthy run looks like. The only visible tell was the `?` in a column nobody
had a reason to distrust.
So the regression test (`scripts/dev/lp-preflight-test`) asserts the *negative*
cases: an app too big for the disk must be refused, an app this version no
longer ships must be refused, an app whose location is gone must be marked as
moved. Reintroducing either historical bug fails it.
## 4. The password problem, stated plainly
**An encrypted repository cannot be opened with anything inside itself.** `CFG_BACKUP_LOC_<idx>_PASSWORD` lives in the system config — which is *inside the backup*. So on a fresh machine the user must supply the repository password by hand. There is no way around this and it is not a bug; it is what encryption means.

View File

@ -349,6 +349,28 @@ The fix is needed for this feature and is worth doing on its own: restore into `
Also worth noting: an app's restic snapshot paths change when it moves. Snapshot *history* stays intact and restorable (each snapshot knows its own path), but path-based filters in the snapshot browser need to accept either.
**Built — and then found not to work, which is the part worth remembering.**
`storageSnapshotSourcePath` / `storageRestoreAppTo` landed as described above,
but the resolver asked for a snapshot with
```bash
engineSnapshotsJson "$idx" "$snapshot_id"
```
and that function's second parameter is an app **tag** filter. So it ran
`restic snapshots --tag app=<snapshot-id>`, matched nothing, and returned 1 on
every call. `storageRestoreAppTo` has a fallback for engines that cannot report
paths (borg genuinely cannot), so it took that fallback *always* — restoring in
place, which is exactly the blocker above, reinstated in the code written to
remove it.
It survived because nothing failed: the fallback is a legitimate branch, and the
restore preflight's only symptom was printing every app's size as `?`. Fixed by
`engineSnapshotPaths`, an engine call that takes a snapshot id because that is
what it is for. The lesson generalises — **a check with a fallback needs a test
that the check itself fires**, not just that the command succeeds
(`scripts/dev/lp-preflight-test`).
## 10. Risks, in the order they'll bite
**10.1 — An unplugged drive is the top data-integrity risk.** `crontab_boot_app_reconcile.sh` brings **every** installed app up at boot. If a location's drive isn't mounted yet — or at all — docker cheerfully creates the bind-mount directories on the bare mountpoint and the app boots **empty**. Plug the drive back in and there are now two divergent copies, with the good one hidden underneath the mount. Mitigation is mandatory, not optional: