controller v0.269.0: whole restore from the second drive; crash loops stopped; exact image digests; steps judged by their own .felhom.yml (decisions 26-28, R-661 R-666 R-667 R-668 R-664 R-665 R-662, 09 6.4 part 6)
gates / gates (push) Successful in 27s

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-24 12:18:39 +02:00
parent 7c3b3a9694
commit 3c6b49b31c
141 changed files with 3401 additions and 237 deletions
+14
View File
@@ -181,6 +181,8 @@ type Manager struct {
updateTier2PointFn func(stackName string) (Tier2RestorePoint, error)
updateTier1PointsFn func(stackName string) ([]RestorePoint, bool)
updateOffsiteTimesFn func(ctx context.Context) (map[string]time.Time, error)
// freeBytesFn (v0.269.0, decision 26): the whole restore's disk-floor check; nil → statfs.
freeBytesFn func(path string) int64
// R-354 volume-REPLAY seam — the mirror of the F17 DB seams above, so the off-site path's new
// volume leg is unit-testable without Docker. Nil → the real restoreDockerVolumesFrom.
@@ -1264,6 +1266,18 @@ func (m *Manager) sameDevice(a, b string) bool {
if m.samePhysicalDevice != nil {
return m.samePhysicalDevice(a, b)
}
// R-668 (v0.269.0): FAIL CLOSED. system.SamePhysicalDevice answers "different" when either path cannot
// be stat'd, and a Tier-2 target chosen on that answer is written wherever the path gets re-created —
// measured on 9202 2026-09-24: a removed folder on nextcloud's OWN disk became its "second drive". A
// path we cannot read is treated as the SAME disk: no second copy is claimed on it.
if _, err := os.Stat(a); err != nil {
m.logger.Printf("[WARN] [backup] same-disk check: %s cannot be read (%v) — treated as the same disk", a, err)
return true
}
if _, err := os.Stat(b); err != nil {
m.logger.Printf("[WARN] [backup] same-disk check: %s cannot be read (%v) — treated as the same disk", b, err)
return true
}
return system.SamePhysicalDevice(a, b)
}