package nightchain import ( "context" "sync" "testing" ) // R-1189 (d): the after-catch-up checks run once, AFTER every leg of the catch-up (the off-site proof and the // integrity check are daily jobs the scheduler never runs late; the catch-up is where a box off at 05:30–06:00 comes // back). A box with nothing missed never runs them from here (its 05:30/06:00 jobs do). // RED-PROOF: with the After call removed from run(), the first assertion fails — seen failing 2026-10-22. func TestR1189d_TheChecksRunAfterTheCatchUpLegs(t *testing.T) { h := newHarness(t, at(1, 12, 0), at(5, 9, 0)) h.l.MarkEnded(LegDBDump, at(4, 2, 31)) h.l.MarkEnded(LegTier2, at(4, 3, 31)) h.l.MarkEnded(LegOffsite, at(4, 4, 20)) var mu sync.Mutex var after []int // how many legs had run when After was called h.c.After = func(context.Context) { mu.Lock() after = append(after, len(h.ran)) mu.Unlock() } if legs := h.c.Evaluate(context.Background(), "start"); len(legs) != 3 { t.Fatalf("no catch-up scheduled: %v", legs) } h.wait(t) mu.Lock() defer mu.Unlock() if len(after) != 1 || after[0] != 3 { t.Fatalf("After calls %v, want exactly one, after all 3 legs", after) } h2 := newHarness(t, at(1, 12, 0), at(5, 11, 0)) h2.l.MarkEnded(LegDBDump, at(5, 2, 31)) h2.l.MarkEnded(LegTier2, at(5, 3, 31)) h2.l.MarkEnded(LegOffsite, at(5, 4, 20)) called := false h2.c.After = func(context.Context) { called = true } h2.c.Evaluate(context.Background(), "start") if called { t.Fatal("no catch-up ran, so the after-catch-up checks must not run") } } // C5 (review 2026-10-22 night): while the after-catch-up checks run, the catch-up no longer reports Running() — the // scheduled whole-guest backup (quiesce.go, R-871) waits only for the backup legs, not for the off-site proof and the // integrity check, which take long on a big store. RED-PROOF: with the `c.running = false` before After removed, // this fails — seen failing 2026-10-22 night. func TestC5_TheWholeGuestBackupDoesNotWaitForTheChecks(t *testing.T) { h := newHarness(t, at(1, 12, 0), at(5, 9, 0)) h.l.MarkEnded(LegDBDump, at(4, 2, 31)) h.l.MarkEnded(LegTier2, at(4, 3, 31)) h.l.MarkEnded(LegOffsite, at(4, 4, 20)) var mu sync.Mutex runningDuringAfter := []bool{} h.c.After = func(context.Context) { r := h.c.Running() mu.Lock() runningDuringAfter = append(runningDuringAfter, r) mu.Unlock() } h.c.Evaluate(context.Background(), "start") h.wait(t) mu.Lock() defer mu.Unlock() if len(runningDuringAfter) != 1 || runningDuringAfter[0] { t.Fatalf("Running() during the after-catch-up checks = %v, want [false]", runningDuringAfter) } }