v0.289.0: off-site key cannot delete — append-only rclone transport, box sends only its public key (hub registrar), retention only inside a hub window behind the fake-snapshot guard (decisions 68-69, R-820, R-822)
gates / gates (push) Successful in 27s

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-10-03 17:01:36 +02:00
parent 09453325d1
commit 55bb6c3d32
15 changed files with 1039 additions and 386 deletions
@@ -192,6 +192,19 @@ func (m *Manager) AbandonSweep(ctx context.Context) (bool, error) {
m.CancelAbandon("no set-aside path recorded")
return false, fmt.Errorf("abandonment due with no recorded path")
}
if t.Pinned() {
// Decision 69 (v0.289.0): the box's off-site key is append-only and cannot delete — by design,
// so that a broken-into box cannot erase history. The set-aside copy STAYS; the operator removes
// it (R-823). The schedule is closed so the sweep stops; nothing was deleted.
if uerr := m.settings.UpdateOffboxStatus(func(o *settings.OffboxTarget) { o.AbandonAt = "" }); uerr != nil {
m.logger.Printf("[WARN] [offbox] abandonment: could not close the schedule: %v", uerr)
}
m.logger.Printf("[WARN] [offbox] abandonment DUE for %s, but the off-site key is append-only (decision 69) — NOTHING deleted; the set-aside copy stays until the operator removes it", t.AbandonRepoPath)
if m.offboxOrphanEvent != nil {
m.offboxOrphanEvent("offbox_abandon_deferred", t.AbandonRepoPath)
}
return false, nil
}
port := t.Port
if port == 0 {
port = 22