R-699: a unit that holds no data is never an update-precondition copy (found live on 9202)
gates / gates (push) Successful in 25s
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:
@@ -46,6 +46,9 @@ type Tier2RestorePoint struct {
|
||||
// DataDate (v0.275.0, R-696) — the mirrored unit's DATA time (unitNewestArtifact on the mirror): when
|
||||
// the data the copy holds was written, which a mirror run copies but never makes newer. "" = unknown.
|
||||
DataDate string
|
||||
// DataUnproven (R-699) — the mirrored unit is only a captured definition (no `data`, no data file):
|
||||
// never a copy the update may lean on.
|
||||
DataUnproven bool
|
||||
}
|
||||
|
||||
// restorePointFromCoverage is the pure half of the predicate.
|
||||
@@ -58,6 +61,7 @@ func restorePointFromCoverage(cov Tier2Coverage) Tier2RestorePoint {
|
||||
PackagePreserved: preserved,
|
||||
CopyLastSuccess: cov.CopyLastSuccess,
|
||||
DataDate: cov.UnitDataDate,
|
||||
DataUnproven: cov.UnitDataUnproven,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +90,7 @@ func (m *Manager) Tier2UnitRestorePoint(stackName string) (Tier2RestorePoint, er
|
||||
// actually mirrored the unit — EXCEPT when the run preserved an older package (R-403), in which case
|
||||
// the package date is the honest one, because that is what the copy really holds.
|
||||
func (p Tier2RestorePoint) ProvenCopyTime() (time.Time, bool) {
|
||||
if !p.Restorable || !p.CopyDateProven {
|
||||
if !p.Restorable || !p.CopyDateProven || p.DataUnproven {
|
||||
return time.Time{}, false
|
||||
}
|
||||
src := p.CopyLastSuccess
|
||||
@@ -269,6 +273,11 @@ func (m *Manager) updateTierPoint(ctx context.Context, stackName string, tier in
|
||||
}
|
||||
pts, _ := list(stackName)
|
||||
for _, rp := range pts {
|
||||
if !rp.DataProven {
|
||||
// R-699: a unit that is only a captured definition is not a copy of the app's data.
|
||||
m.logger.Printf("[INFO] [backup] update precondition for %s: the own unit holds no data yet (no backup run has confirmed it) — not a copy", stackName)
|
||||
continue
|
||||
}
|
||||
if at, err := time.Parse(time.RFC3339, rp.Time); err == nil {
|
||||
return UpdateTierPoint{Tier: tier, At: at}, true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user