SAFETY-119: re-pin test_safety84/87 digests (log only); prove it
checks / unit (pull_request) Successful in 41m47s
infra-pin / fresh (pull_request) Successful in 1s

The re-pinned digests differ only in OUTPUT_CLAMP log rows; every command
and claim is the same as without the fix (test_safety119.py part 5).
DECISIONS: the delay at a 5 s meter and the open swap case.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
glenn schrooyen
2026-10-19 15:30:18 +02:00
co-authored by Claude
parent c4e15ec4cd
commit b0c2e5977d
4 changed files with 83 additions and 25 deletions
@@ -5,23 +5,33 @@
**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's
last-seconds step went from -2000 W to +429 W. The next cycle'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; the cap held.
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.** On the cycles 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 same window SAFETY-85 grades a battery on). After that it
**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) always counts. No command
changes, and no text was added or changed.
**Kept.** The loop in charge at its rail warns on the same cycle as before. A
loop still at its rail after the window warns then (about 22 s later): delay,
not loss. The start and a restart after a stop are not hand-backs.
**Kept.** The loop in charge at its rail warns on the same cycle as before.
A loop still at its rail after a hand-back warns once the window has passed:
22 s at a 2 s meter, 55 s at 5 s. Delay, not loss. The start and a restart
after a stop are not hand-backs.
**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 5).
**Open.** If another owner and the loop swapped the wire every few cycles,
each swap restarts the window and the loop's bound would not be counted.
A loop at its rail beats a floor or ceiling on its own side, so it keeps the
wire; a swap needs a claim that keeps outranking 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 about
1700 Ws more charge (2 W on that quarter's average) at the next one's start.
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.