SAFETY-79 review: margin under a banked month peak too; identity harness reaches headroom and maintenance
checks / unit (pull_request) Successful in 11m50s
infra-pin / fresh (pull_request) Successful in 1s

- quarter_target_w() is now the margin under quarter_ceiling_w(): a peak
  banked between cap - margin and the cap was aimed at exactly, so one
  overshoot crossed the cap; above the cap the same overshoot raised the bill.
- safety79_identity.py hashes charge_headroom_w() and the shaping suspension,
  and adds n1_maint/n2_maint (cheap window, forecast across cap - 50 .. cap).
  Digests re-printed on ed739d4 and pinned; margin 0 still identical.
- test_margin_under_banked_peak; DECISIONS and DOCS updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Review Agent
2026-09-29 00:49:16 +02:00
co-authored by Claude Opus 5.5
parent e6096d3e17
commit ce0aea30b6
5 changed files with 130 additions and 50 deletions
@@ -4,36 +4,38 @@
## Decision
The peak guard aims at `peak_cap_w - peak_margin_w`, not at `peak_cap_w`.
`peak_margin_w` is a setting: default 50 W, range 0-500 W, whole watts. An
install without the key gets 50.
The peak guard aims `peak_margin_w` under the limit it holds: under
`peak_cap_w`, or under a month peak already banked above it
(`quarter_target_w()`). `peak_margin_w` is a setting: default 50 W, range
0-500 W, whole watts. An install without the key gets 50.
**Why (owner):** the guard aimed exactly at the cap, and in the OPT-11 P1 test
a quarter banked 3501.9 W against a 3500 W limit (OPT-11-P1-test-report.md,
check 4). A peak even 1 W over still sets the billed peak. It is a setting and
not a constant because the add-on is sold to several sites.
**Banked peak (review, 2026-09-29):** the PR first aimed at a banked month
peak as it stood. That can bank a few W over it, which raises the bill the
same way; and a peak banked between cap - margin and the cap (common in the
month an install upgrades, since the old guard held quarters at the cap) was
aimed at exactly, so one overshoot went over the cap. The margin now applies
under it too. Cost: up to `peak_margin_w` of a peak already paid for goes
unused (more discharge, less charge headroom); no bill cost. Undo is one line
in `quarter_target_w()`.
## What uses which number
- **cap - margin (the aim):** `peakguard.decide()` (the claim's floor, and so
arbitrage's `charge_headroom_w()` and OPT-11's give-way, which read it),
`shaping_suspended()` and `maintenance_charge_floor()` (the forecast checks,
via `Controller.peak_aim_w()`).
- **the aim:** `peakguard.decide()` (the claim's floor, and so arbitrage's
`charge_headroom_w()` and OPT-11's give-way, which read it), and, as cap -
margin, `shaping_suspended()` and `maintenance_charge_floor()` (the forecast
checks, via `Controller.peak_aim_w()`).
- **the real cap (reporting and billing):** `PeakTracker` (month peak,
headroom, 80 % warning), the decision's `ceiling_w` and every notice and
status row built from it, Home's limit, and `validate.config_notes()`.
A month peak already banked above cap - margin is aimed at as it stands
(`quarter_target_w()` is `quarter_ceiling_w()` on the lowered cap), so the
margin never holds a quarter below a peak that is already paid for.
## Checks
`peak_margin_w: 0` is byte-identical to ed739d4 (test_peak_margin.py part 1,
digests from tools/safety79_identity.py). validate.py rule 12 refuses a value
outside 0-500, not whole, or not below `peak_cap_w`.
## Open
Whether the margin should also apply below a banked month peak above the cap
is not decided here; today it does not.
digests from tools/safety79_identity.py, which also runs a maintenance charge
with a forecast). validate.py rule 12 refuses a value outside 0-500, not
whole, or not below `peak_cap_w`.