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>
2.7 KiB
SAFETY-86 - the peak guard outranks the maintenance HOLD
Status: DECIDED 2026-09-30 (owner). Follows SAFETY-83's "Not changed"
list. Tests: test_safety86.py.
The defect. The HOLD (battery resting full after the maintenance charge)
is a SET of 0 W at P_MAINTENANCE (60), above the peak floor (P_PEAK, 50),
so the floor did not bind. At N=1 a 6500 W house banked 6500 W quarters and
'Load too high' fired (SAFETY-83 rig test, check 4). At N=2 only the other
battery gave: 4500 W against a 3950 W aim (SAFETY-84 rig test, check 6).
The fix (main.py, _peak_over_hold()).
- N=1: during a HOLD a peak floor above 0 W is refiled at
P_MAINTENANCE, as for a drain (SAFETY-83). The battery gives the floor; the Why reads "raised for the peak limit". - N>=2: the holding battery's pin is raised to the floor minus what the other
live batteries may place (their hard
hi, or their pin). The others give first, the holding one only the shortfall. Why this split and not the allocator's shares: the hold is maintenance and outranks the others' use (owner order), and the owner rule for an Off battery is the same, "give way only for the shortfall". A battery Off by its mode (P_MODE, below maintenance) therefore still gives before the holding one. - Below the aim nothing changes: the floor is 0 W, the hold is 0 W, the rows are identical to before (test_safety86.py part 2).
- A site stop (a SET above
P_PEAK) decides alone: nothing is raised at N>=2, and the refiled floor at N=1 stays underP_SAFETY. If another battery is pinned to charge (a SAFETY-73 probe) the pin is not raised, so the site is never split both ways. - The hold resumes by itself: the rule is evaluated each cycle, so when the guard lets go the command is 0 W again.
The level dips below the target: the hold finishes anyway. The HOLD does
not read the level; it ends on its clock (maintenance_hold_min). Topping up
would mean going back to CHARGE, which waits for sun or a cheap window (up to
36 h, CHARGE_TIMEOUT_MIN) while the pack keeps the site's one maintenance
slot, so the other battery's cycle waits, and then a new full hold that the
guard can interrupt again. The guard only gives while the quarter is at risk,
and the next monthly cycle balances again. If the owner wants a top-up
instead, it is a change to maintenance.py's HOLD branch, not to this rule.
Not changed.
- The peak guard still grades the emptiest battery (SAFETY-32): at N=2 with
B under
peak_soc_floorthe floor is limited and A holds even when it is full (SAFETY-87). - "Battery is not keeping up" during maintenance (SAFETY-85), the N=2 charge flapping (SAFETY-88) and the N=1 charge headroom sizing are untouched.