OPT-34 round 3: the latch ends on time, with the run, with the mode, and with the night
checks / unit (pull_request) Successful in 20m15s
infra-pin / fresh (pull_request) Successful in 1s

- F1: an expired latch is dropped whatever the run state; plan_targets() and the
  store loader ignore one that has ended (no stale latch after a restart).
- F2: the "charge goes on" line only while a cheap run is on.
- F3: a battery that is off or no longer Leftover solar leaves the latch.
- F4: a run carries the latch on only if it starts by the bell start (06:00
  local) after the latch began (manager's call, 2026-10-31).
Tests: test_opt34 scenarios stale/stale_live and part 5; test_modes_p4 asks at a
moment inside the latch.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
This commit is contained in:
glenn schrooyen
2026-10-31 23:04:36 +01:00
co-authored by Claude
parent 57b0eb2f20
commit bb57a85b35
5 changed files with 191 additions and 30 deletions
+7 -2
View File
@@ -536,8 +536,13 @@ def plan_cover(c, name):
def _latched_below(c) -> bool:
"""OPT-34: no forecast, but a battery is still below the level its night
charge keeps (`Controller.plan_targets()`), so control goes on charging."""
"""OPT-34: no forecast, but a cheap run is on and a battery is still below
the level its night charge keeps (`Controller.plan_targets()`), so control
goes on charging."""
rp = getattr(c, "mode_runs", None)
if rp is None or rp.cheap is None or not rp.cheap.holds(
datetime.now(timezone.utc)):
return False
targets = getattr(c, "plan_targets", lambda: None)() or {}
return any(inv.soc is not None and inv.name in targets
and inv.soc < targets[inv.name] for inv in c.inverters)