SAFETY-52: a battery that refuses is asked for 0 W, with a 200 W probe every 15 min
At the BMS cut-out the saturation freeze held the last request for hours (+5000 W for 11.87 h on 09-06, +1940 W for 3 h 55 m on 09-19) until the grid error changed sign. compute() now carries a refused direction: after SETTLE_CYCLES of a ~0 W reading against a larger ask it holds that direction at 0 W, probes 200 W (below the gate's 250 W) every 15 minutes, and lets go on charge, an answered probe, stop/start or another writer. A stale-reading trip on a frozen ~0 W reading seeds the same hold, which ends SAFETY-59's ~70 s cycle. One inverter only; no SoC in the loop (SAFETY-25 Option A). test_refusal.py drives the real Controller and gate; tools/replay_refusal.py replays the 16-day capture. test_clamp.py and test_delivery.py re-baselined where they asserted the old hold. DECISIONS/SAFETY-52 has the record and what SAFETY-58/59 must take into account. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d1f7e3336e
commit
1f97c7652f
@@ -1399,6 +1399,7 @@ import logging # noqa: E402
|
||||
from app import hass as _hass, p1 as _p1, validate as _validate, web as _web # noqa: E402
|
||||
from app.arbiter import Claim # noqa: E402
|
||||
from app.main import Controller, why_key # noqa: E402
|
||||
from app import control as _control # noqa: E402
|
||||
from app import main as _main # noqa: E402
|
||||
|
||||
|
||||
@@ -1585,6 +1586,11 @@ for _f in sorted(APP.glob("*.py")):
|
||||
_keys = {why_key(s, [Claim.set(s, 0, 0.0, r)]) for s, r in _SOURCES}
|
||||
_keys |= {why_key("failsafe", []),
|
||||
why_key("failsafe", [Claim.set("loop", 0, 1.0, "tracking")])}
|
||||
# SAFETY-52: the loop's claim reason is computed, so the scan cannot see it.
|
||||
_keys |= {why_key("loop", [Claim.set("loop", 0, 0.0, _r)])
|
||||
for _r in (_control.REFUSED, _control.PROBING)}
|
||||
check("...including the loop's two battery-refuses reasons, which get words of "
|
||||
"their own", {_control.REFUSED, _control.PROBING} <= _keys)
|
||||
check(f"the scan found the claims ({len(_SOURCES)}), including the latched "
|
||||
f"per-inverter stop the 2d test saw as 'Other'",
|
||||
("failsafe", "sign disagreement") in _SOURCES and len(_SOURCES) >= 8)
|
||||
|
||||
Reference in New Issue
Block a user