2f8ff2414c
gates / gates (push) Successful in 17s
R-537 — the contents label is now PER TIER. One string computed from the app's shape was rendered on all three tier rows; a Tier-1 unit has no file-copy step, so for the four class-A apps it was claiming „Adatok" for files it does not hold. R-538 — a unit restore REFUSES before anything is touched when the unit cannot return the app's drive-side files, and names the route that can. It runs before the stack is stopped because the measured harm included the app's own wastebasket going unreachable, which still held every byte. R-536 — „Alkalmazás telepítve" moved from the deploy's acceptance to its completion, with app_deploy_started and app_deploy_failed as the honest pair. Each fix red-proofed: seen failing with its own sentence, passing when restored. Requires hub v0.116.0 for the two new event types. MinAgent unchanged (0.131.0). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
58 lines
3.5 KiB
Markdown
58 lines
3.5 KiB
Markdown
# REPORT — controller v0.244.0: the backup page stops promising what it does not hold
|
|
|
|
**2026-09-16.** Three defects the 2026-09-16 drill measured on a fresh box, all in the same family:
|
|
the product said a thing that was not true about a customer's data.
|
|
|
|
## What shipped
|
|
|
|
**R-537 — the label is now per tier.** `BackupContents` was one string, computed from the app's shape
|
|
(`HasHDDData || HasVolumeData → "Adatok"`) and rendered on the Tier-1, Tier-2 and Tier-3 rows alike.
|
|
One string cannot be true for three tiers that capture different things: a Tier-1 unit holds compose
|
|
+ app.yaml + DB dumps + volume tars and has **no file-copy step at all** (`CaptureRecoveryUnit`;
|
|
`RecoveryManifest` has no field for one), so for the four class-A apps the customer's own files are
|
|
carried by Tier 2 and Tier 3 and by nothing else. The row now carries `Tier1Contents`,
|
|
`Tier23Contents` and `DriveFilesNote`, and the template renders the right one per row.
|
|
|
|
**R-538 — the restore refuses instead of lying.** `RestoreFromRecoveryUnitAt` now returns
|
|
`*ErrUnitLacksFileLegs` **before the lock, before the stack is stopped and before any volume is
|
|
replaced**, when the app declares drive-side file legs the unit cannot hold. The web handler turns
|
|
that into a Hungarian sentence naming the route that CAN return the files — the off-site wizard's
|
|
„Teljes visszaállítás (fájlok + adatbázis)", or the second drive's „Fájlok visszaállítása" — and says
|
|
plainly when no copy exists. `UnitRestoreOptions{AcceptMissingFiles}` is the explicit, separately
|
|
worded second step; it is a per-call argument and never a field on the Manager.
|
|
|
|
*Why the refusal runs that early:* in the measured failure the replayed database also stopped
|
|
referencing the app's own wastebasket, which still held every byte on the drive. A refusal that has
|
|
already stopped the app would have destroyed the customer's last route while declining to help.
|
|
|
|
**R-536 — „telepítve" now means installed.** The API emits `app_deploy_started` beside its 202;
|
|
`app_deployed` moved to the async path's own end via `stacks.SetDeployDoneHook`, and
|
|
`app_deploy_failed` (warning) replaces the silence an interrupted install used to get. The
|
|
accept-time `app.yaml` is deliberately kept on failure: it is the crash-safe record written with
|
|
`Deployed:false`, it holds the settings the customer typed, and the state every surface reads is
|
|
`not_deployed`.
|
|
|
|
Also folded in: the pending „0 B" whole-system tile fix (R-517 follow-up).
|
|
|
|
## Red-proofs — each seen failing, then passing
|
|
|
|
| fix | break | what failed |
|
|
|---|---|---|
|
|
| R-537 label | restore the app-shaped label | „the Tier-1 label claims it holds the app's data: `Konfig + Adatok`" |
|
|
| R-538 refusal | disable the guard | „a restore that cannot return the files must refuse; got err=`<nil>`" |
|
|
| R-536 accept-time | put `NotifyAppDeployed` back beside the 202 | „the deploy handler announces an INSTALLED app at accept time" |
|
|
| R-536 completion | remove the success-path hook | „the deploy ended and nothing was told about it" |
|
|
|
|
Each test also carries a negative control: an app whose data really is in the captured volumes keeps
|
|
its „Adatok" and is not refused.
|
|
|
|
## Gates
|
|
|
|
`go build ./... && go vet ./... && go test ./...` — green. `controller_gates.py --fast` — all 15 OK.
|
|
|
|
## Requires
|
|
|
|
Hub **v0.116.0**, which registers `app_deploy_started` / `app_deploy_failed` in `allowedEventTypes`
|
|
and `customerMessages`. Against an older hub those two POSTs 400 and the events are simply absent;
|
|
`app_deployed` keeps working. MinAgent unchanged at **0.131.0**.
|