# REPORT — any backup tier lets an app update, and the release header must state its MinAgent (2026-09-13) *Overwritten each run. This records the most recent implementation only.* > **Shipped as controller v0.239.0 and delivered to both demo guests by the managed floor alone** (hub > v0.112.0, declared MinAgent). No hand install. Scenarios G–M are tested; K, H, the failed update and > the restore were walked live on demo-hp. Evidence: `felhom.eu/documentation/audits/rulings-r472-r475-2026-09-13/`. ## 1. What changed | Commit | What | |---|---| | `f946b0d` | `controller/scripts/minagent_header_gate.py` (fast, blocking): the newest `## vX.Y.Z` block must hold a line starting `**MinAgent: X.Y.Z**`. Decoy test; registered in GATES, FINGERPRINTS and COVERS. Backfill: v0.233.0–v0.236.0 now read `**MinAgent: 0.129.0** (unchanged)` — v0.232.0's value; zero commits under `internal/agentapi` since 2026-09-01, highest `featureMinAgent` 0.129.0 (R-470). | | `b93c154` | v0.239.0 (R-475): `backup.Manager.UpdateRestorePoints` walks Tier 2 → 1 → 3 and returns the first copy the caller accepts; stacks' `freshRestorePoint` is the one age rule; nothing anywhere → back up first; refused only when no copy AND `CanBackUpApp` is false. `RunAppBackupNow` treats a Tier-2 failure as a WARN and marks the captured unit proven current. The hold stores `copy_tier` and names the tier; old holds keep their sentence. A successful off-site restore now clears an update hold. The backups page still calls `Tier2UnitRestorePoint`. | ## 2. Tests and red-proofs - Go gate green per commit: `go build ./... && go vet ./... && go test ./...` (28 packages ok). - `controller_gates.py --fast` green; `test_controller_gates.py` and `test_gate_decoys.py` green. - New tests: `internal/stacks/update_tiers_test.go`, `internal/backup/update_tiers_test.go`, `cmd/controller/r475_wiring_test.go`, `scripts/test_minagent_header_gate.py`. | Red-proof | Mutation | Result | |---|---|---| | F | gate accepts a body mention | the decoy test fails; 4 tests ran | | M | age checked only for Tier 2 | 3 M sub-cases fail; 5 RUN lines | | L | refuse even with a copy | the L test fails | | tail | the proven-current mark misses | fails on the mtime | | off-site clear | call removed | the hold stays; test fails | The first run of all four Go red-proofs was inert: the harness ran outside the module (`RUN lines=0`). They were rerun from the module folder and each failed as intended. ## 3. Live — demo-hp, endpoint-level | Step | Result | |---|---| | Delivery | floor 0.239.0 + MinAgent 0.129.0 saved 15:19:12Z; demo-hp on 0.239.0 at +14 s, demo-felhom at +15 s | | K | throwaway actualbudget, Tier 2 off, unit removed: `found: none — backing up first`, Tier 2 skipped, Tier 1 chosen, done | | H | gokapi: `precondition met — Tier 1 (own recovery unit)`, no backup, done | | F-shape | never-healthy image: held; text ends „saját meghajtó, 2026-09-13 17:34."; start 409; record `copy_tier: 1` | | Restore | `POST /backup/restore` from „helyi": hold CLEARED, gokapi v1.9.6 healthy | A first K attempt did not test K: the deploy had already written a Tier-1 unit, so Tier 1 was chosen. It is kept as `04a-…`. The restore script's first read polled a 404 path and stopped early; the second read is appended to `08-…`. ## 4. Observations 1. **The Tier-3 lookup pays its full 15 s bound on demo-hp and logs a misleading WARN about another app's snapshot size.** FILED: R-477 2. **A leftover recovery unit from a REMOVED install counted as the fresh Tier-1 restore point of a reinstall.** FILED: R-478 3. **For a bind-data app the Tier-1 unit holds settings only, so the route the hold names does not restore data.** FILED: R-479 4. **After a successful restore the card keeps the failed update's sentence, which says the running app is stopped.** FILED: R-480 5. **Removal with `remove_backups` again left both throwaways' recovery units and their backup prefs.** FILED: R-474