v0.284.0 — a box deletes old app images (decision 53, R-736); an after_install app is held until its known login is replaced (R-741)
gates / gates (push) Successful in 27s

Image retention: after a done/undone guarded Update and at remove, an app's images older than its running
and previous one are deleted — never an image any container, installed compose or installed/previous record
names (box-wide keep set read at delete time); exact id, never forced or pruned; paused while any update runs;
a one-time sweep of catalog app images at the first start. Install hold: an after_install app is installed
behind the setup gate's door and opens when after_install succeeds or the household says it changed the login.
Tests TestImageRetention_* and TestInstallHold_* with red-proofs; parity fixture for the held card.

MinAgent: 0.131.0 (unchanged).

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-09-30 22:29:33 +02:00
parent d48da6c7f3
commit 5a3437669f
23 changed files with 1724 additions and 23 deletions
+1
View File
@@ -564,6 +564,7 @@ func (m *Manager) tryUndo(ctx context.Context, name, dir, why string, entry *upd
m.logger.Printf("[WARN] [stacks] update %s: rescan after the undo failed: %v", name, err)
}
m.finishUpdate(name, UpdatePhaseUndone, "")
m.retainAfterUpdate(name, nil) // decision 53: the app runs its old image again; the attempt's is not kept
m.emitUpdateEvent(UpdateEventUndone, name, entry, UpdateRestorePoint{}, true)
m.logger.Printf("[INFO] [stacks] update %s: UNDONE in %s — the previous version is running on the data from before the update (%s)", name, m.now().Sub(start).Round(time.Second), detail)
return ""