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
+6 -1
View File
@@ -21,6 +21,10 @@ type RestorePoint struct {
ShortID string `json:"short_id"` // opaque label; POST /backup/restore uses it for logging only
Tier int `json:"tier"` // always 1 (see above)
DriveLabel string `json:"drive_label"` // registered storage label; empty for the SSD fallback
// DataProven (R-699, v0.275.0) — the time is a PROVEN data time (a data run confirmed the unit, or it
// holds data files). False for a unit that is only a captured definition: listed, never a copy the
// update's precondition may lean on. Not part of the page payload.
DataProven bool `json:"-"`
}
// restorePointShortID is the single keep-side restore point's identifier. Hungarian ("local"),
@@ -60,7 +64,7 @@ func (m *Manager) ListRestorePoints(stackName string) (points []RestorePoint, fo
}
// v0.275.0 (R-696): the unit's DATA time (unitNewestArtifact), never the manifest's refresh time.
newest, ok := unitNewestArtifact(RecoveryUnitPath(nsRoot, stackName))
newest, proven, ok := unitDataTime(RecoveryUnitPath(nsRoot, stackName))
if !ok {
return []RestorePoint{}, true // no recovery unit yet — "no backup" is a valid answer
}
@@ -70,6 +74,7 @@ func (m *Manager) ListRestorePoints(stackName string) (points []RestorePoint, fo
ShortID: restorePointShortID,
Tier: 1,
DriveLabel: m.sysDriveLabelFor(stackName),
DataProven: proven,
}}, true
}