R-645: the night backup skips an app whose pinned version is not the one it runs (09 decision 142)
Every night leg (DB dump, volume dump, recovery-unit capture, Tier-2 mirror) now leaves alone an app whose app.yaml pin (pinned_images) differs from its running record (installed_images) - the state a failed update leaves behind. A hold lifted by hand (--clear-restore-hold + restart) no longer lets the capture write the just-failed definition over the good unit. Unknown (no pin, no record, a service not observed) never skips. The log says it per leg; the backups page shows one amber line, hu + en (backup.status.version_skip). Seam: backup.Manager.SetVersionCheck <- stacks.Manager.PinNotRunning. Tests: TestR645_HandLiftedHoldKeepsTheGoodUnit (whole night run + Tier 2, unit tree fingerprint), TestR645_VersionSkipSentence, TestR645_PinNotRunning_*, TestR645_BackupRowSaysTheNightBackupSkipsIt, TestR645_VersionCheckIsWiredAtStartup. 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:
@@ -458,6 +458,17 @@ func (m *Manager) captureAllRecoveryUnits(dataRun bool) {
|
||||
if m.isHeld(stack.Name) {
|
||||
continue
|
||||
}
|
||||
// R-645 (09 §3 decision 142): the unit of an app that is not running its pinned version stays
|
||||
// as it is — the measured case wrote a just-failed definition over the good unit within seconds
|
||||
// of a hand-lifted hold. Said at WARN on a data run; the periodic refresh repeats it only at DEBUG.
|
||||
if why, skip := m.versionSkip(stack.Name); skip {
|
||||
if dataRun {
|
||||
m.logger.Printf("[WARN] [backup] Recovery unit NOT captured for %s — it is not running its pinned version (%s); the last good unit is kept (R-645)", stack.Name, why)
|
||||
} else if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [backup] recovery-unit refresh skipped for %s — not running its pinned version (%s)", stack.Name, why)
|
||||
}
|
||||
continue
|
||||
}
|
||||
m.noteAttempted(stack.Name)
|
||||
// The reserve, checked BEFORE anything is written. Per app, and the loop continues.
|
||||
if !m.admitApp(stack.Name) {
|
||||
|
||||
Reference in New Issue
Block a user