Files
goodwe-addon/goodwe_controller/DECISIONS/SAFETY-79-peak-margin.md
Review AgentandClaude Opus 5.5 ce0aea30b6
checks / unit (pull_request) Successful in 11m50s
infra-pin / fresh (pull_request) Successful in 1s
SAFETY-79 review: margin under a banked month peak too; identity harness reaches headroom and maintenance
- 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>
2026-09-29 00:49:16 +02:00

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'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().

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.