# SAFETY-119 - no "not keeping up" when the loop takes the wire back **Status: for review.** Tests: `test_safety119.py`. **Cause.** When another owner (the peak guard, a maintenance charge) has set the wire and the loop wins again, `cycle()` re-seeds the integrator from that owner's command, and `compute()` adds `gain * error` from a meter that does not show that command yet. On the TEST-23 rig (SAFETY-118 I-2) the guard stepped from -2000 W to +429 W with 5 s left. A cycle later the loop's ask crossed the +2500 W rail and beat the guard's floor, so SAFETY-85 rule 1 counted it as the loop's own bound and raised `goodwe_integrator_bound`. The battery gave what it was told, and the cap held. **Decision.** After a hand-back, the loop's integrator bound is not counted until the plant's settle has passed (`SHORT_CYCLES` cycles and `SHORT_SPAN_S`, the window SAFETY-85 grades a battery on). After that it counts as before. An over-rating (`clamped`, a bug) on a cycle the loop decided always counts. No command changes, and no text was added or changed. **A rolling budget (round 3).** The settle above is per hand-back, and losing the wire restarts it. Across all hand-backs the bound is hidden on at most 8 cycles in any 15 minutes (`ROLLING_BOUND_CYCLES`, `ROLLING_S`). A cycle over the budget counts. Round 1 restarted the settle at every hand-back, so a guard and a charge taking turns hid the bound for good (0 warnings in 2 h where 28 were raised before). Round 2 gave each run of hand-backs its own budget; at 10 s and 15 s meters each quarter then started a fresh one and the loop's bound was never counted. A quarter-edge kick is a few bound cycles in one quarter, a real bound that stays is many: a budget per 15 minutes tells them apart. **Why 8.** Measured over 2 h (`goodwe-addon-checks:1`), budgets 3 to 10, the quarter-edge case (house 800 W, cap 2500 W, 1 to 15 s meters) and the case below. 3, 4, 5 and 6 let the false alarm back (at 2 s, for each). 7 let it back on 10 of 30 seeds at 2 s. 8: 1 of 30 seeds at 2 s, none at 1, 5, 10 and 15 s. 9 and 10: none, but the case below then misses quarters at 10 s. So 8 is the largest budget that still warns every quarter at 2, 5 and 10 s, and the margin is narrow: 7 and 9 each fail one side. **What holds with 8.** Single hand-back, the loop at its rail: the first counted bound cycle is the 9th, so 8 cycles after the hand-back (measured, real Controller): 8 s at 1 s, 16 s at 2 s, 40 s at 5 s (default), 80 s at 10 s, 120 s at 15 s, 240 s at 30 s, 480 s at 60 s. Repeated hand-backs (2 x 2500 W, cheap-window charge, no usable forecast, cap 5000 W, house 5050 and 5100 W, 2 h; 20 runs at 2, 5 and 10 s, 8 at 15 s): | meter | warnings in 2 h | quarters warned (of 7 after the first) | without the fix | |---|---|---|---| | 2 s | 51 to 57 | 7 | 54 to 56 | | 5 s | 19 to 25 | 7 | 28 | | 10 s | 7 to 11 | 7 | 14 | | 15 s | 1 to 3 | 1 to 3 | 14 | | 30 s | 0 | 0 | 7 and 11 | At 15 s it warns in some quarters, not all. At 30 s it does not warn in this case. For 60 s the rig's cycle is a different regime (the house is not over the cap there), so nothing is claimed. The cap held at 2 s and 5 s; at 10 s and 15 s the meter's lag puts the highest quarter 20 to 55 W over 5000 W, the same with and without the fix. Quarter-edge case, 15 s meter: the highest quarter is 2327 W to 2680 W, the same with and without the fix. **Accepted limits (owner, 2026-10-20, with N=8).** The owner accepted N=8 knowing that: - at a 2 s meter the quarter-edge false alarm still shows on about 1 of 30 seeds (one notification in 2 h); - at a 15 s meter the case above warns in only 1 to 3 of the 7 quarters (some runs are silent for more than one quarter in a row); - at a 30 s meter and slower it gives no warning in that case (0 in 2 h, against 7 and 11 without the fix): a real bound is suppressed there; - the cap is exceeded at 10 s and slower in that case (and up to 2680 W of 2500 W at 15 s on the quarter edge), the same with and without the fix. A budget that follows the cycle length (10 cycles up to 3.5 s, 8 to 11 s, 6 to 16 s, 4 beyond) met both cases on every swept seed at 1 to 20 s (at 30 s: no false alarm, 3 to 5 of 7 quarters) in the dev round-3 sweep; it was not adopted. Without a monotonic clock the budget never refills, so a bound that stays is counted after 8 hidden cycles. **Kept.** The loop in charge at its rail warns on the same cycle as before. The start and a restart after a stop are not hand-backs. The quarter-edge kick of `test_safety119.py` part 1 stays hidden (0 warnings in 2 h at 1, 2, 5, 10 and 15 s meters). **Re-pinned.** test_safety84 (all six) and test_safety87 (`n1_crossing`, `n1_above`, `n1_charge_low`): only OUTPUT_CLAMP log rows differ; commands and claims are the same (`test_safety119.py` part 6). **Not hidden.** A battery that gives less than another owner told it still alarms through SAFETY-85 rule 2. "Always counts" for an over-rating holds on cycles the loop decided; on others SAFETY-85 rule 1 already dropped it. **Not changed.** The kick itself is control behaviour: for a few seconds at a quarter's edge the loop asks up to its rail. In `test_safety119.py` part 1 that is more discharge than the guard asked at a quarter's end, and a few seconds of up to 500 W more charge at the next quarter's start.