R-356: the off-site restore refused every app that has no data drive
gates / gates (push) Failing after 12s
gates / gates (push) Failing after 12s
ReconstituteFromOffsite and PlaceOffsiteRestore both resolved the restore destination with the RAW HDD_PATH and read an empty answer as "the app is not installed". For 40 of the 53 catalogue apps that answer is correctly empty and permanent, so both actions refused forever for a running, healthy app — and told the customer to reinstall it "in the same place", which those apps never offer. Separate the two questions. "Installed?" is asked of ListDeployedStacks via a new Manager.isStackDeployed that fails CLOSED on a nil provider. "Where?" is answered by GetAppDrivePath — the same resolver CaptureRecoveryUnit wrote the snapshot with, so the restore aims at the place the backup came from. The 13 drive apps are unchanged: own drive, mismatch check, ack still required. A third refusal, with its own sentence, covers installed-but-no-resolvable-root. Fixtures that marked an app "installed" by giving it an HDD path now state deployment as its own fact. No assertion weakened.
This commit is contained in:
@@ -1,3 +1,53 @@
|
||||
## v0.219.0 — the off-site restore refused every app that has no data drive (2026-08-22, R-356)
|
||||
**MinAgent: 0.129.0** (unchanged — no new agent coupling)
|
||||
|
||||
**What broke.** Forty of the fifty-three catalogue apps could not be restored from the off-site copy
|
||||
at all. The customer opened the restore page, pressed the button, and was told the app **"nincs
|
||||
telepítve"** — while it was running in front of them — and instructed to reinstall it "ugyanerre a
|
||||
helyre", a place those apps never offer. The instruction could not be followed, so the restore never
|
||||
started.
|
||||
|
||||
**Why.** `ReconstituteFromOffsite` and `PlaceOffsiteRestore` both resolved the restore destination
|
||||
with the RAW `HDD_PATH` (`stackProvider.GetStackHDDPath`) and read an empty answer as "the app is not
|
||||
installed". One predicate was answering two questions. Measured in the catalogue at `459766cb1639`:
|
||||
**53 templates, 13 declare `needs_hdd: true`, 40 declare `false`** — and for those 40 the answer is
|
||||
*correctly* empty, permanently. The capture side never had this defect: `CaptureRecoveryUnit` resolves
|
||||
via `GetAppDrivePath`, which falls back to the system data path — which is why the 2026-08-21 refusal
|
||||
was able to print `/mnt/sys_drive`, a destination the backup had recorded and the restore refused to
|
||||
use.
|
||||
|
||||
**The fix separates the two questions.** *Installed?* is now asked directly, of
|
||||
`ListDeployedStacks()`, through a new `Manager.isStackDeployed` that fails CLOSED on a nil provider —
|
||||
"cannot tell" must not become "go ahead" when the caller's next act is a write. *Where?* is then
|
||||
answered by `GetAppDrivePath`, the same resolver the capture side wrote the snapshot with, so the
|
||||
restore aims at the place the backup came from.
|
||||
|
||||
**The 13-class behaviour is unchanged.** A drive app still resolves to its own drive, the placement
|
||||
mismatch check still fires when the recorded drive differs, and `ackPlacementChange` is still required
|
||||
to pass it. That claim is not an absence claim: the red-proof plants the system-data fallback into the
|
||||
drive path, and three tests convict it.
|
||||
|
||||
**A third refusal now exists, with its own sentence.** Installed, driveless, and the box cannot name
|
||||
its own data root ⇒ refuse and name the storage page. Widening `nincs telepítve` to cover this would
|
||||
send a customer to reinstall a running app and hide the real fault.
|
||||
|
||||
**Why now.** v0.218.0 (R-354) taught the reconstitution to replay an app's named volumes. Those forty
|
||||
apps keep **all** of their data in exactly those volumes, so that fix could not reach the apps that
|
||||
need it most until this one shipped.
|
||||
|
||||
**Changed:** `internal/backup/backup.go` (`isStackDeployed`), `internal/backup/offbox_reconstitute.go`,
|
||||
`internal/backup/offbox_restore.go`. **Not changed, deliberately:** `offboxCaptureSet`'s raw
|
||||
`GetStackHDDPath` call — capture resolves an app's declared `userdata`/`import` file legs against that
|
||||
value, and a system-data fallback there would write a snapshot claiming to hold files it does not.
|
||||
|
||||
**Tests:** `internal/backup/r356_hot_only_restore_test.go` (Scenarios A–E, both entry points, and the
|
||||
positive/negative control on the deployment predicate) and `cmd/controller/r356_deployed_seam_test.go`
|
||||
(AST walk over the production adapter wiring). Five companion red-proofs, each SEEN failing.
|
||||
|
||||
**Fixture correction in the same commit:** several existing fixtures marked an app "installed" by
|
||||
giving it an HDD path. That is the conflation this change removes, so they now state deployment as its
|
||||
own fact. No assertion was weakened.
|
||||
|
||||
## v0.218.0 — the database nobody backed up, and the restore that returned most apps nothing (2026-08-22, R-354/R-355)
|
||||
**MinAgent: 0.129.0** (unchanged — no new agent coupling)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user