R-682: a Remove cut off by a controller restart is finished at boot

RemoveStack journals itself before compose down and clears on every
return; at start a found journal finishes the remove through the same
RemoveStack (once, before the boot reconciler), keeping drive data and
backups even if the household had asked to delete them (no unattended
deletion at boot; logged).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-05 22:02:03 +02:00
parent 05a447ef02
commit 4347983a72
4 changed files with 177 additions and 0 deletions
+7
View File
@@ -667,6 +667,13 @@ func (m *Manager) RemoveStack(name string, removeHDDData bool, backupPathsToRemo
// 2026-09-30: v0.284.0 wired only DeleteStack, and the household's Remove button runs THIS function.
removedRepos := appImageRepos(stackDir, LoadAppConfig(stackDir))
// R-682: journal the remove before anything is torn down; every return below clears it, so a
// marker found at start means the process died mid-remove (remove_interrupted.go).
if err := markRemovePending(stackDir, removeHDDData, len(backupPathsToRemove)); err != nil {
m.logger.Printf("[WARN] [stacks] RemoveStack %s: cannot journal the remove (a restart mid-remove would leave it half-done): %v", name, err)
}
defer clearRemovePending(stackDir)
// Step 2: Run docker compose down --volumes
env := m.stackEnv(stackDir)
// R-489 (v0.242.0): the volumes are listed BEFORE and AFTER; the difference is what was removed.