R-899: a daytime press never cancels the night's whole-guest backup (operator ruling 2026-10-08, option A); press sends trigger=manual
gates / gates (push) Successful in 1m3s

Unreleased; ships with tomorrow's release.

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-08 07:34:03 +02:00
parent 4d3a0246df
commit 6d07ca2be4
11 changed files with 504 additions and 15 deletions
+14
View File
@@ -137,6 +137,9 @@ type dueTier struct {
// primary is the agent's Primary flag (the local tier). Set on the manual path, which backs up
// only the primary (`09` §3 decision 156).
primary bool
// owed (R-899) marks a tier the agent called „not due" only because of a household press. It runs inside the
// window and never fires the safety valve (nightowed.go).
owed bool
}
// resolveDueTiers answers "what must this cycle back up?" — the dedup rule above, in one place.
@@ -175,6 +178,7 @@ func (l *Loop) resolveDueTiers(ctx context.Context) (due []dueTier, degraded boo
l.logger.Printf("[WARN] [quiesce] agent advertised ZERO backup tiers — falling back to the untargeted path")
return l.resolveUntargeted(ctx)
}
led := l.loadLedger() // R-899: read once per cycle
for _, t := range tiers {
isDue, age, wireState, derr := tb.DueFor(ctx, t.Target)
if derr != nil {
@@ -190,6 +194,12 @@ func (l *Loop) resolveDueTiers(ctx context.Context) (due []dueTier, degraded boo
l.logAgeStateDegradeOnce()
}
due = append(due, dueTier{target: t.Target, ageSecs: age, state: st})
continue
}
if l.pressOwesNight(led, t.Target) {
// R-899: the agent says „not due" only because of a household press — tonight still takes its own.
l.logger.Printf("[INFO] [quiesce] tier %s: not due by the agent, but its newest copy is a manual press and tonight's scheduled backup has not run — due tonight (R-899)", tierLabel(t.Target))
due = append(due, dueTier{target: t.Target, ageSecs: age, state: ageStateFromWire(wireState), owed: true})
}
}
return due, false, nil
@@ -202,6 +212,10 @@ func (l *Loop) resolveUntargeted(ctx context.Context) ([]dueTier, bool, error) {
return nil, true, err
}
if !isDue {
if l.pressOwesNight(l.loadLedger(), "") {
l.logger.Printf("[INFO] [quiesce] not due by the agent, but its newest copy is a manual press and tonight's scheduled backup has not run — due tonight (R-899)")
return []dueTier{{target: "", ageSecs: age, owed: true}}, true, nil
}
return nil, true, nil
}
return []dueTier{{target: "", ageSecs: age}}, true, nil