controller v0.241.0: a bind-data app leans on off-site before its own unit; the hold names what the copy holds (R-479)
gates / gates (push) Successful in 13s

Operator ruling 2026-09-13. An app with classified binds walks second
drive -> off-site -> own unit (its unit holds no files); volume apps keep
2 -> 1 -> 3. RestoreHold.CopyHolds records what the chosen copy holds and
the sentence ends with it; older holds keep their tier-only sentence.
Tests on both halves; red-proof: a layout-blind order fails the bind case.
This commit is contained in:
2026-09-13 21:47:33 +02:00
parent 3013a1cc93
commit 3e813307cc
11 changed files with 208 additions and 7 deletions
+2 -1
View File
@@ -3424,5 +3424,6 @@ func (a *updateGuardsAdapter) HoldAfterFailedUpdate(name string, at time.Time, r
if a.b == nil {
return fmt.Errorf("backup is not enabled on this box — the hold cannot be recorded")
}
return a.b.HoldAfterFailedUpdate(name, at, rp.ProvenAt, rp.Tier)
// R-479: the sentence names what the chosen copy holds, decided by the app's data layout NOW.
return a.b.HoldAfterFailedUpdateHolding(name, at, rp.ProvenAt, rp.Tier, a.b.UpdateCopyHolds(name, rp.Tier))
}
@@ -68,4 +68,8 @@ func TestR475_AdapterReadsEveryTier(t *testing.T) {
if h := adapterMethodSelectors(t, "HoldAfterFailedUpdate"); !strings.Contains(h, " Tier ") {
t.Errorf("the hold must be told the chosen TIER, or it cannot name it; selectors:%s", h)
}
// R-479: and WHAT the copy holds, computed from the app's data layout at hold time.
if h := adapterMethodSelectors(t, "HoldAfterFailedUpdate"); !strings.Contains(h, " UpdateCopyHolds ") || !strings.Contains(h, " HoldAfterFailedUpdateHolding ") {
t.Errorf("the hold must carry UpdateCopyHolds through HoldAfterFailedUpdateHolding (R-479); selectors:%s", h)
}
}