Restore-holes run close-out: README, CONTEXT, REPORT; the interrupted-restore log line names a waiting put-back. Commit only.
gates / gates (push) Successful in 1m18s

This commit is contained in:
2026-10-24 21:03:34 +02:00
parent c9b4b82dc7
commit e1613aea8d
5 changed files with 41 additions and 17 deletions
+2
View File
@@ -88,6 +88,8 @@ brief 2026-10-24, Part 4 (commit only; the release rides the next normal train).
over the data the box is about to put back. The restore record (`PutBackWaiting`,
`note.restore.interrupted_put_back_waiting`) and the `restore_interrupted` event say the box puts the data back when
the drive is there. Pinned by `TestR1251_TheRecordSaysThePutBackWaits` (seen failing).
- The interrupted-restore log line says a put-back waits for its drive (it still said „the household is told to run it
again", which the record no longer says).
- A removal clears a waiting put-back (it belongs to the install); a later restore that completes drops it (the
household chose that data; the copy stays on disk).
- Tests (each seen failing with its rule taken out): `TestR1251_DriveCutRestoreWaitsForTheDriveThenPutsBackBeforeAnyStart`
+8
View File
@@ -1,5 +1,13 @@
# CONTEXT.md — Project Memory
> **2026-10-24 night (unattended restore-holes run) — on `main`, NOT released (next v0.343.0, MinAgent 0.158.1 unchanged).**
> R-1251: a pending put-back blocks every start (`backup/appstop_putback_wait.go`: restore hold `putback_pending`, the
> hold store every start path honours; `ResumePutBack` in the boot recreate and `restartStacks`; `ResumeWaitingPutBacks`
> at start and on a drive return; a failed put-back = the D20 hold; the copy's folders synced before `SetUndo`).
> R-1252: `tier2CaptureSetFull` returns `classified`; reconcile only then; `BackupBlockRejected` via the stack adapter.
> R-1253: `AppStopGuard.BusyWith` / `BeginExclusive`; the exporter refuses a stop-first export. Proven on Tester 1
> (R-1251) and 9202 (R-1252, R-1253): felhom.eu `audits/restore-holes-2026-10-24/`. Release: Monday's list (STATUS).
> **2026-10-24 (attended release run) — v0.342.0 gains the TESTED line (operator rulings D41 = 50 %, D42, the iperf3 line
> test; felhom.eu CONTEXT 07:22/07:26).** `agentapi.LineTest` reads the agent's `GET /host/line-test` (agent ≥ 0.164.0 —
> its weekly 10-second iperf3 upload to ep0 inside the tunnel; demo-hp measured 90.7 Mbit/s where the push floor said 10).
+17 -17
View File
@@ -1,21 +1,21 @@
# REPORT — review round 2 (2026-10-24, unattended): two small fixes, commit only
# REPORT — the restore and backup holes (2026-10-24 night, unattended; commit only, NOT released)
**What:** found by the review round's readers and verified at `file:line` by the main session (felhom.eu
`documentation/audits/review-round-2-2026-10-24/`). No release; both ride the next normal train (next v0.343.0).
Brief: fix R-1251, R-1252, R-1253 (and R-1254, R-1257 in their repos); live-prove the recovery-code changes; nothing
released. Full record: felhom.eu `documentation/audits/restore-holes-2026-10-24/README.md`.
1. **A media restart no longer starts an app the household stopped (R-721).** `restartMediaApps` and
`mediaSafeRemoval` recreated every media app (`RestartStack` = `up -d --force-recreate`), skipping only held ones.
Now both take `stacks.MediaAppsToRecreate`, which leaves out an app whose recorded intent is „stopped" (logged). Its
override is already written, so its next start sees the drives. Tests: `TestMediaAppsToRecreate_SkipsAppsTheHouseholdStopped`
(red with the rule off) and `TestR2_MediaRecreateLoopsSkipStoppedApps` (source pin of the two loops; red with
`s.mediaApps()` back in the safe removal).
2. **The file manager's header name file appears whole (R-1100).** `LoadOrCreateFileBrowserSSOHeader` created the file
empty and wrote it after; a parallel caller read "" and got an error. Measured on clean `main` `321df1f`: 44 of 300
runs of the existing parallel-writers check failed (4 of 50 under `-race`). Now: temp file, sync, hard link into place
— 0 of 300, 0 of 50 under `-race`.
| Commit | What | CI |
|---|---|---|
| `bb2809d` | R-1251 (P1): a pending put-back blocks every start; H2 a failed put-back holds; H7 Stop still gets the put-back | 2301 / #482 success |
| `062f9b4` | R-1251: the copy's folders synced before the marker names it (found by the Tester 1 proof: `undo.json.tmp` after a cut); the restore record says the put-back waits | 2302 / #483 success |
| `518a135` | R-1252 (P2): reconcile only under a valid classification; a rejected block is said and signalled; kept copies stay kept; Remove drops kept records | 2303 / #484 success |
| `c9b4b82` | R-1253 (P2): a stop-first export refuses while another operation holds the marker | 2304 / #485 success |
| (close-out) | README, CONTEXT, this report; the interrupted-restore log line names a waiting put-back | final report |
`go vet ./...` and `go test ./...` green. Design docs read: `15-media-library.md` §10–11 (the restart), `01` §5 / `02`
(the file manager sign-in).
**Proofs:** R-1251 on Tester 1 — a local restore of MeTube (1.5 GB volume) cut by powering the VM off, the data disk
taken off and put back: held while away, put back BEFORE the start, the newest data there, a later restart poured
nothing. R-1252 on 9202 — the review's audiobookshelf steps: kept after a bogus path. R-1253 on 9202 — the export refused
during a restore, ran after it. Every rule red-proved (each test names its red-proof).
**Docs (same session):** `REUSE.md` — D22 released in v0.338.0; the `recordInstalledImages` callers; a row for the
stray-copy seams. felhom.eu `documentation/audits/review-round-2-2026-10-24/EDITS.md` lists every edit.
**Images:** dev images `0.343.0-dev.r1251a/b`, `r1252a`, `r1253a` built locally and loaded into the test guests only;
never pushed. **Machines:** Tester 1 and 9202 put back (both: the controller on 0.342.0; leftover anonymous volumes of
the R-1267 class named in the audit). **Release:** Monday — controller v0.343.0 (with R-1250), MinAgent 0.158.1.
+11
View File
@@ -1030,6 +1030,17 @@ Each app can define rich metadata in `.felhom.yml`:
files stay); the operator gets `backup_run_failures` leg `restore-put-back`. Only a put-back that fails — or a
replay AND rollback that both fail — still HOLDS the app (`restore_mixed` / the restore hold, operator-cleared),
and then the copy is kept for support. On success the copy is removed. `offbox_restore_undo.go`.
- **A restore cut by a power loss, on a drive that comes back late (unreleased, R-1251).** The copy of the live
data lives on the app's drive. When it cannot be reached at start because the drive is not bound yet, the app is
HELD (`putback_pending`; „…A visszaállítás előtti adatai egy meghajtón vannak, amely most nem érhető el…") and no
path starts it; when the drive binds, the copy is poured back FIRST, then the app starts. A put-back that fails
holds the app for support („félúton megszakadt"). Stop pressed during the restore still gets the put-back. The
copy's folders are synced before the restore records it. `appstop_putback_wait.go`.
- **An export that stops its app waits for a running restore (unreleased, R-1253):** it is refused (409,
„Egy másik művelet … éppen leállítva tart egy alkalmazást…") while another operation holds the app-stop marker.
- **A broken backup block never deletes a second-drive copy (unreleased, R-1252):** the night copy deletes dest
folders only under a valid classification; a rejected block keeps every copy, says so on the app's status and
tells the operator once a day (`backup_run_failures`, leg `tier2-settings-unreadable`).
- **Where an off-site restore puts the data (v0.219.0, R-356).** `ReconstituteFromOffsite` and
`PlaceOffsiteRestore` resolve the destination with `Manager.GetAppDrivePath` — **the same
resolver `CaptureRecoveryUnit` wrote the snapshot with**: the app's `HDD_PATH` if it declares
@@ -114,6 +114,9 @@ func (m *Manager) LoadRestoreRecordAfterRecovery(putBack, waiting []string) *Res
if res.PutBack {
tail = "the start-up put its data back as it was before the restore (R-1195), and the household is told so"
}
if res.PutBackWaiting {
tail = "its put-back waits for the app's drive (R-1251), and the household is told so — not to run it again"
}
m.logger.Printf("[WARN] [backup] restore of %s (%s, started %s) was INTERRUPTED by a controller stop — recorded as failed; %s",
rec.Stack, rec.Op, rec.StartedAt.Format(time.RFC3339), tail)
}