- 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>
2.0 KiB
SAFETY-79 — the peak guard keeps a margin below the peak limit
Status: DECIDED 2026-09-28 (owner decision).
Decision
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
- the aim:
peakguard.decide()(the claim's floor, and so arbitrage'scharge_headroom_w()and OPT-11's give-way, which read it), and, as cap - margin,shaping_suspended()andmaintenance_charge_floor()(the forecast checks, viaController.peak_aim_w()). - the real cap (reporting and billing):
PeakTracker(month peak, headroom, 80 % warning), the decision'sceiling_wand every notice and status row built from it, Home's limit, andvalidate.config_notes().
Checks
peak_margin_w: 0 is byte-identical to ed739d4 (test_peak_margin.py part 1,
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.