v0.236.0: "delete my data too" deletes the data, or says that it could not (R-442)
gates / gates (push) Successful in 13s
gates / gates (push) Successful in 13s
Removal resolves the drive from the app's own app.yaml HDD_PATH (the 07 ~L437 rule), never the global cfg.Paths.HDDPath which no box sets. A data removal that cannot be resolved, or whose drive is absent, is refused with a typed RemoveRefusedError -> 409 + exact Hungarian sentence, before compose down, and the app is kept. SSD app -> hdd_paths_removed: [] never null; missing folders stated; backup-path refusals reach the response. 15 tests, two red-proofs run (pre-fix fallback -> C fails with err=nil and the handler 200s; "no drive refuses" -> D fails). Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -1,3 +1,52 @@
|
||||
## v0.236.0 — "delete my data too" deletes the data, or says that it could not (2026-09-13, R-442)
|
||||
|
||||
**The defect.** A customer removes an app and ticks *also delete my data*. The box says it worked;
|
||||
**the data is still on the disk** — measured 2026-09-01 on demo-hp: `HTTP 200` with
|
||||
`hdd_paths_removed: null, hdd_paths_preserved: null` and 128 MB of Nextcloud left at
|
||||
`/mnt/felhom-drives/hdd_1/appdata/nextcloud`. `DeleteStack`, `RemoveStack` and `GetStackHDDData`
|
||||
resolved the drive from the GLOBAL `cfg.Paths.HDDPath`, which has no default and is set on no box, so
|
||||
`ParseComposeHDDMounts` returned nil on its first line and the removal reported, truthfully, that it
|
||||
removed none — as a success.
|
||||
|
||||
**Fix 1 — the source of truth.** The three lookups now read the app's OWN recorded `HDD_PATH` from
|
||||
`app.yaml` (`Manager.appHDDPath`, via `LoadAppConfigByName`) — the rule `07-backup-architecture.md`
|
||||
states (~L437: *"the drive if the app declares one (`HDD_PATH`), the system data path otherwise"*) and
|
||||
that deploy, the start gate and the backup destination already implement. **Deliberately no fallback
|
||||
to the global** when the per-app value is empty: that silent fallback is the exact path this closes.
|
||||
|
||||
**Fix 2 — success is never reported over inaction** (the R-443 class). When the data was asked for and
|
||||
the box cannot resolve where it is, the removal is REFUSED with a typed `stacks.RemoveRefusedError`
|
||||
that the handler maps to **HTTP 409** and the exact sentence
|
||||
„Az alkalmazás adatainak helye nem állapítható meg, ezért semmit nem töröltünk. Az alkalmazás nem
|
||||
lett eltávolítva.” The refusal happens BEFORE `compose down`, so a refused removal has touched nothing
|
||||
— **the app is kept too**: an app gone with its data left behind cannot even be re-run from the UI.
|
||||
A recorded drive that is not mounted right now refuses the same way („A(z) %s tárhely jelenleg nem
|
||||
elérhető — az alkalmazás nem távolítható el, amíg a meghajtó vissza nem csatlakozik.”), via the same
|
||||
`DriveLive` signal the belt and the boot reconciler use.
|
||||
|
||||
**"Declares no drive" ≠ "cannot resolve the drive".** An SSD-resident app (no `HDD_PATH`, no
|
||||
`${HDD_PATH}`/`${USERDATA_PATH}` bind in its compose) is NOT refused: `hdd_paths_removed: []` — an
|
||||
empty list, never `null` — plus `hdd_note` saying the app kept no data on a drive. A recorded folder
|
||||
that is already gone is listed under `hdd_paths_missing` and stated, not refused.
|
||||
|
||||
**The backup half gets the same honesty.** The "outside expected directory" refusal now reaches the
|
||||
response as `backup_paths_refused` (path + reason), not only a WARN line. Its base is resolved by the
|
||||
same rule (the app's namespace root — its own drive, or `<system data>/felhom-data` otherwise), which
|
||||
is what the router's `AppNamespaceRoot` produced the paths from; under the global lookup every backup
|
||||
path of every app on every box was being refused, silently.
|
||||
|
||||
**Tests (15 new, two red-proofs run):** `internal/stacks/delete_r442_test.go` asserts the folder is
|
||||
gone / present on a real tree, the marker-leaving stub compose never ran on a refusal, `[]`
|
||||
serialisation, the userdata root untouched; `internal/api/remove_r442_test.go` drives the real
|
||||
handler → real `Manager` (constructor + `ScanStacks`) → 409 + exact sentence + `app.yaml` still on
|
||||
disk. Red-proof 1 (pre-fix silent fallback): C fails with `err=nil … app.yaml present=false` and the
|
||||
handler test with `HTTP 200 ok=true`. Red-proof 2 ("no drive" refuses): the SSD test fails with the
|
||||
refusal sentence. UI: both success modals render `hdd_note` and „Nem törölt mentések”.
|
||||
|
||||
**Observation:** `cfg.Paths.HDDPath` still has readers outside removal (`report/builder.go`,
|
||||
`monitor/healthcheck.go`, `api/router.go` system-info, `web/server.go`, `main.go` auto-discovery +
|
||||
metrics) — left alone; not deleted here.
|
||||
|
||||
## v0.235.0 — freeze the version, keep the fixes flowing (2026-09-06, update arc slice 3)
|
||||
|
||||
**OPERATOR RULING, 2026-09-06 — Option 1.** R-447 was `BLOCKED` because R-438 established that
|
||||
|
||||
Reference in New Issue
Block a user