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
@@ -0,0 +1,43 @@
package backup
import (
"io"
"log"
"os"
"path/filepath"
"testing"
"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
)
// R-668 (v0.269.0) — a registered storage path whose folder does not exist is NOT a second drive.
// Measured on 9202 2026-09-24: `scratch_hdd/userdata/romm` (removed that morning) was chosen as
// nextcloud's Tier-2 target — the stat in the same-disk check failed, which read as "another disk" — and
// the copy was written into a re-created folder on nextcloud's OWN disk. Runs the PRODUCTION same-disk
// check (no seam).
//
// COMPANION RED-PROOF (REPORT): remove the fail-closed stats in Manager.sameDevice — this test then fails
// at "chose the missing path".
func TestR668_MissingStoragePathIsNotASecondDrive(t *testing.T) {
tmp := t.TempDir()
live := filepath.Join(tmp, "drive")
missing := filepath.Join(tmp, "drive-gone")
if err := os.MkdirAll(live, 0o755); err != nil {
t.Fatal(err)
}
sett, err := settings.Load(filepath.Join(tmp, "settings.json"), log.New(io.Discard, "", 0))
if err != nil {
t.Fatal(err)
}
if err := sett.AddStoragePath(settings.StoragePath{Path: missing, Label: "gone", Schedulable: true}); err != nil {
t.Fatal(err)
}
m := &Manager{logger: log.New(io.Discard, "", 0), settings: sett, systemDataPath: filepath.Join(tmp, "no-sys")}
tgt, err := m.selectTier2TargetFrom("app", live, 1, 1)
if err == nil && tgt != nil && tgt.NamespaceRoot == NamespaceRoot(missing, true) {
t.Fatalf("chose the missing path %s as the second drive", missing)
}
if !m.sameDevice(live, missing) {
t.Fatal("an unreadable path must count as the SAME disk")
}
}