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
+5
View File
@@ -497,6 +497,11 @@ func main() {
// sweep could bring up a half-updated app with no record of why. Pin-backs for updates interrupted
// before anything ran happen here too. The resumed health wait itself is launched further down,
// once the backup side is wired, because a resumed update that fails must be able to HOLD.
// R-682: a Remove a restart cut off is finished first (drive data and backups kept) — before the
// boot reconciler, which would otherwise start the half-removed app again.
if names := stackMgr.RecoverInterruptedRemoves(); len(names) > 0 {
log.Printf("[WARN] [stacks] %d remove(s) interrupted by the restart were finished: %v", len(names), names)
}
if resumed := stackMgr.RecoverUpdates(); len(resumed) > 0 {
logger.Printf("[WARN] [update] %d interrupted update(s) will resume after the backup side is wired: %v", len(resumed), resumed)
}