R-1252 (P2): a rejected or absent backup block never deletes second-drive copies — reconcile only on a valid classification; a rejected block is said on the app's status and once a day to the operator (backup_run_failures); kept copies stay kept (H2); Remove drops the kept records it deleted (H9). Commit only.
gates / gates (push) Successful in 1m18s

This commit is contained in:
2026-10-24 20:07:16 +02:00
parent 062f9b41d9
commit 518a13592d
16 changed files with 400 additions and 6 deletions
+8 -4
View File
@@ -40,14 +40,18 @@ func tier2DestRel(root appbackup.BindRoot, rel string) string {
// footprint promise), mapped into the same v2 layout so restore has ONE reader. Missing/refused
// mandatory paths are stat-filtered + surfaced loudly (§7-H).
func (m *Manager) tier2CaptureSet(stack, nsRoot string) (legs []tier2Leg, warns []string) {
legs, _, warns = m.tier2CaptureSetFull(stack, nsRoot)
legs, _, warns, _ = m.tier2CaptureSetFull(stack, nsRoot)
return legs, warns
}
// tier2CaptureSetFull is tier2CaptureSet plus the DECLARED legs that are missing on disk (mandatory and optional).
// D25 / R-1181 (2026-10-21): a missing declared folder keeps its second-drive copy — RunTier2 adds these to the
// reconcile's keep set and lists them as kept, instead of pruning the copy that may be the only one left.
func (m *Manager) tier2CaptureSetFull(stack, nsRoot string) (legs, missing []tier2Leg, warns []string) {
//
// classified (R-1252) reports whether the legs come from a VALID backup classification. Only then may the run
// reconcile (delete) dest dirs the legs no longer name: the legacy set is a fallback, and a block that was rejected
// or could not be read falls back to it too — reconciled, that deleted the household's file copies (measured on 9202).
func (m *Manager) tier2CaptureSetFull(stack, nsRoot string) (legs, missing []tier2Leg, warns []string, classified bool) {
// Classified path.
if m.stackProvider != nil {
if binds, has := m.stackProvider.GetStackClassifiedBinds(stack); has {
@@ -75,7 +79,7 @@ func (m *Manager) tier2CaptureSetFull(stack, nsRoot string) (legs, missing []tie
warns = append(warns, fmt.Sprintf("Figyelmeztetés: a(z) %s alkalmazás egyes adatmappái nem kerültek a másodlagos mentésbe: %s.",
stack, strings.Join(gaps, ", ")))
}
return legs, missing, warns
return legs, missing, warns, true
}
}
// Legacy path: the resolver appdata dir(s) → hdd/appdata/<name> legs (mandatory-equivalent for SSD
@@ -98,5 +102,5 @@ func (m *Manager) tier2CaptureSetFull(stack, nsRoot string) (legs, missing []tie
Class: appbackup.ClassMandatory,
})
}
return legs, missing, warns
return legs, missing, warns, false
}