Files
goodwe-addon/goodwe_controller/DECISIONS/SAFETY-83-peak-over-drain.md
T
glenn schrooyenandClaude Opus 5.5 ba31e7c8b1
checks / unit (pull_request) Successful in 24m17s
infra-pin / fresh (pull_request) Successful in 1s
SAFETY-86: peak guard outranks the maintenance hold
During a HOLD the holding battery gives what keeps the quarter at the peak
aim. N=1: the peak floor is refiled at P_MAINTENANCE, as for a drain
(SAFETY-83). N>=2: the hold's pin is raised to the floor minus what the
other live batteries may place, so they give first. A site stop still
decides alone. The hold ends on its clock even if the level dipped.
Below the aim nothing changes (rows identical).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:56:34 +02:00

1.9 KiB

SAFETY-83 - the peak guard outranks the maintenance drain at N=1

Status: DECIDED 2026-09-29 (owner go, P1). Follows SAFETY-78's "Not changed" list. Tests: test_safety83.py.

The defect. At N=1 the drain is the site SET at P_MAINTENANCE (60). The peak floor is a limit at P_PEAK (50), and clause 2 applies only limits at or above the winner, so the floor was ignored and the house imported what the drain left. A 5000 W house under a 2500 W limit and a 2000 W drain banked 3000 W quarters; on the owner's settings (limit 3500, drain 2500, margin 50) a breach starts at about 5950 W.

The fix. While a drain owns the setpoint at N=1 and the peak floor asks for more than the drain rate, main.py (_peak_over_drain()) refiles that peak claim at P_MAINTENANCE. The arbiter then applies it: the target is the floor, still inside the safety limits, and a safety SET (100) still parks everything. Where the floor is at or below the drain rate nothing changes.

  • The order in effect is now the same at N=1 and N=2: safety limits and the SAFETY-73 refusal > peak guard (with the SAFETY-79 margin) > maintenance > modes > trade > loop (arbiter.py, beside the priorities).
  • The drain keeps counting: the battery discharges at least the drain rate on every cycle, so the cycle is not reset or stalled; it only ends sooner.
  • Below the drain rate the rest is still exported (owner, 2026-09-29).
  • Identity: tools/safety78_identity.py --diff against 35cdffe changes only cycles where the guard asked for more than the drain; after such an episode the commands are identical again and only the log and the idle loop's integrator differ. N=2 is unchanged.

Not changed.

  • Between the drain rate and the peak aim, the house still imports what the drain leaves (N=1 behaviour kept by the identity). At N=2 the loop covers it.
  • A maintenance HOLD (0 W, 120 min, battery full) still outranked the peak guard at N=1. Fixed by SAFETY-86.