v0.275.0: a backup's data and its version travel together (R-696, 07 §6.6, D4 option A); R-695, R-691, R-694
gates / gates (push) Successful in 23s
gates / gates (push) Successful in 23s
The unit's data files are stamped with the versions that wrote them; the capture keeps the definition the data belongs to; a restore never starts data under another version's definition (unit restores refuse a mismatch; the off-site restore writes the snapshot's definition); every tier's time is its data's; the conversion-copy release needs a dump on the new engine. File-browser sync single-flight + no empty kept folder (R-695); the kept view joins the folder's owning group, language switch resyncs (R-691); a restore-generated login is not shown as the password (R-694). Red-proofs in felhom.eu/documentation/audits/version-travel-2026-09-26/. 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:
@@ -66,17 +66,32 @@ func (m *Manager) driveLabelForRoot(root string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// unitNewestArtifact is the unit's data time: the newest of its manifest, .sql dumps and .tar
|
||||
// volume dumps. ONE rule, shared with ListRestorePoints, so the two lists cannot date a unit
|
||||
// differently.
|
||||
// unitNewestArtifact is the unit's DATA time. ONE rule, shared by ListRestorePoints (Tier 1), the Tier-2
|
||||
// copy's date, the removed-app list and kept data, so no two of them can date a unit differently.
|
||||
//
|
||||
// v0.275.0 (R-696) — THE TIME OF THE DATA, NEVER OF THE MANIFEST. It used to be the newest of the
|
||||
// manifest, the .sql dumps and the .tar dumps; a refresh rewrites the manifest when the app's pins move,
|
||||
// so a unit re-captured two minutes after an update read as two minutes old over data from before the
|
||||
// update (9202 2026-09-25 11:06; demo-hp 2026-09-26 02:20, where it released the kept pre-conversion
|
||||
// copy). Now: the manifest's `data.at` when the data is stamped; else the newest DATA file (the undo
|
||||
// copies `pre-restore-*` excluded — an update's own safety dump is not a backup); the manifest's time
|
||||
// only for a unit that holds no data file at all, whose whole content is its definition.
|
||||
func unitNewestArtifact(unitDir string) (time.Time, bool) {
|
||||
fi, err := os.Stat(UnitManifestFile(unitDir))
|
||||
if err != nil {
|
||||
return time.Time{}, false
|
||||
}
|
||||
newest := fi.ModTime()
|
||||
newest = newestArtifact(UnitDBDumpDir(unitDir), ".sql", newest)
|
||||
newest = newestArtifact(UnitVolumeDumpDir(unitDir), ".tar", newest)
|
||||
if man := readManifest(UnitManifestFile(unitDir)); man != nil {
|
||||
if t, ok := man.Data.DataTime(); ok {
|
||||
return t, true
|
||||
}
|
||||
}
|
||||
var newest time.Time
|
||||
newest = newestDataFile(UnitDBDumpDir(unitDir), ".sql", newest)
|
||||
newest = newestDataFile(UnitVolumeDumpDir(unitDir), ".tar", newest)
|
||||
if newest.IsZero() {
|
||||
return fi.ModTime(), true
|
||||
}
|
||||
return newest, true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user