R-699: a unit that holds no data is never an update-precondition copy (found live on 9202)
gates / gates (push) Successful in 25s

A just-installed app's unit, captured by the status refresh before any backup, satisfied
the precondition on its manifest time; tandoor's PostgreSQL was converted with no backup
of its database. Listed still; never a copy on Tier 1 or Tier 2. Red-proof RP6.

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-27 12:04:03 +02:00
parent b6810f14ff
commit 7fcda8f1a4
8 changed files with 89 additions and 11 deletions
@@ -574,3 +574,47 @@ func TestA4_TheOffsiteRunRecordsThePushedDataTime(t *testing.T) {
t.Fatalf("after a successful push the data-time record is %+v ok=%v, want the unit's data time", rec, ok)
}
}
// R-699 (v0.275.0) — a just-installed app's unit, captured by the status refresh before any backup ran,
// holds only the definition. It stays LISTED (restorable as the definition) but is never a copy the
// update's precondition leans on; after a data run it is.
//
// COMPANION RED-PROOF (REPORT.md): drop the DataProven skip in updateTierPoint — the precondition then
// accepts the dump-less unit ("Tier 1 … 0s old"), which is what 9202 logged for tandoor on 2026-09-27.
func TestR699_ADefinitionOnlyUnitIsNotAPreconditionCopy(t *testing.T) {
v := newVTStack(t, "16")
if err := v.m.captureRecoveryUnit("app", false); err != nil { // the refresh, right after the install
t.Fatal(err)
}
pts, _ := v.m.ListRestorePoints("app")
if len(pts) != 1 || pts[0].DataProven {
t.Fatalf("points = %+v, want one listed, NOT proven", pts)
}
any := func(UpdateTierPoint) bool { return true }
if p, ok, _ := v.m.UpdateRestorePoints(context.Background(), "app", any); ok {
t.Fatalf("the precondition accepted tier %d at %s — a unit with no data is not a copy", p.Tier, p.At)
}
// The update's own "back up first" is a data run: afterwards the unit IS a copy.
v.m.discoverDBs = func(context.Context) ([]DiscoveredDB, error) {
return []DiscoveredDB{{StackName: "app", ContainerName: "app-db", DBType: DBTypePostgres}}, nil
}
v.m.dumpOne = func(_ context.Context, db DiscoveredDB, dir string, _ *log.Logger, _ bool) DumpResult {
p := filepath.Join(dir, "app-postgres.sql")
mustWrite(t, p, pgDump(1))
return DumpResult{DB: db, FilePath: p}
}
v.m.perAppTier2 = func(string) error { return nil }
if err := v.m.RunAppBackupNow(context.Background(), "app"); err != nil {
t.Fatal(err)
}
if _, ok, _ := v.m.UpdateRestorePoints(context.Background(), "app", any); !ok {
t.Fatal("after a backup the own unit is still not a copy")
}
}
func TestR699_ADefinitionOnlyMirrorIsNotAPreconditionCopy(t *testing.T) {
p := Tier2RestorePoint{Restorable: true, CopyDateProven: true, CopyLastSuccess: "2026-09-27T09:36:36Z", DataDate: "2026-09-27T09:36:36Z", DataUnproven: true}
if _, ok := p.ProvenCopyTime(); ok {
t.Fatal("a mirror of a definition-only unit counted as a proven copy")
}
}