v0.231.0: the off-site proof gets a by-hand trigger, like its integrity sibling (R-87)
gates / gates (push) Successful in 12s

Without it the only way to see the job work is to wait for 05:30, which makes live
validation and any future diagnosis a next-day exercise. Same function as the scheduled
job - no second code path.

ONE deliberate difference from the integrity button: due-ness is NOT bypassed. There,
forcing means "check the store again", which is always answerable. Here due-ness IS the
target selection - an app is due when its newest snapshot has not been proved - so
ignoring it would mean inventing a second way to choose an app, exactly what having one
function prevents. When nothing is due the button says so, honestly.

Every other guard intact, including the single-writer flag: a hand-run during a backup
SKIPS exactly as the scheduled one would.

POST /api/debug/backup/offsite-proof, button beside "Restic integritas" on the debug page.
debug_route_gate pairs the two, so a button with no dispatch (R-400's shape) cannot ship.
This commit is contained in:
2026-08-31 21:09:09 +02:00
parent e43b5ec07d
commit 303129e3af
3 changed files with 69 additions and 1 deletions
+6
View File
@@ -1634,6 +1634,12 @@ func main() {
defer cancel()
return runOffsiteIntegrityCheck(ctx, backupMgr, notifier, logger, force)
}
// R-87: the proof button's caller. Same function as the scheduled job — no second path.
dc.RunOffsiteProof = func() backup.ProofResult {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
defer cancel()
return runOffsiteProof(ctx, backupMgr, notifier, logger)
}
dc.HubConnectivityTest = func() (int, int64, error) {
start := time.Now()
client := &http.Client{Timeout: 10 * time.Second}