MAINT-13 round 3: provider site, hourly fixed-tariff check, faster tests
checks / unit (pull_request) Successful in 34m52s
infra-pin / fresh (pull_request) Successful in 1s

- A price-provider site with no fixed tariff is not a gate (its plan never
  sets `cheap`); DECISIONS §3 says so and a test pins it.
- The fixed-tariff check is worked out once an hour, not every tick.
- test_maint13: run() steps really are `step` minutes; the long loops use
  5-minute steps (the per-tick cap); wall backstop checked "not before".
- test_safety93: the drain bound is the rig's configured drain rate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
glenn schrooyen
2026-10-08 12:03:55 +02:00
co-authored by Claude Opus 5.5
parent f7b83cc75c
commit 6836f61bd4
4 changed files with 67 additions and 16 deletions
+14 -3
View File
@@ -1189,6 +1189,7 @@ class Controller:
self.peak_fc = None
self.cheap = False
self._price_gated = False # MAINT-13: is a price gate set up
self._gated_key = None # MAINT-13: (options, hour) of the cache
# TARIFF-03. One line of prose for the status page saying WHICH tariff
# window we are in and why it is or is not cheap - so "Cheap window:
# no" is an evidenced answer rather than a bare no.
@@ -3337,9 +3338,9 @@ class Controller:
# ⚠️ AND IT CANNOT BE BOTH. validate.py refuses static_profile
# alongside the two Home Assistant entities, because this `if` picks
# one and the loser is silent.
self.cheap, self.tariff_words = static_status(
o, datetime.now(timezone.utc))
self._price_gated = static_gated(o, datetime.now(timezone.utc))
_now = datetime.now(timezone.utc)
self.cheap, self.tariff_words = static_status(o, _now)
self._price_gated = self._static_gated(o, _now)
# ⚠️ TARIFF-11. THE PROVIDER PLAN REACHES THE *Tariff* ROW HERE, AND
# THIS IS THE ONLY PLACE THE TWO SOURCES MEET. Everything above is the
@@ -3878,6 +3879,16 @@ class Controller:
inv.refusal_note())]
if n]
def _static_gated(self, o: dict, now: datetime) -> bool:
"""`static_gated()`, worked out once an hour: it builds the same
month-long plan as `static_status()` (about 20 ms with a profile), and
whether a fixed tariff is set up does not change from tick to tick
(options change only with a restart)."""
key = (id(o), now.strftime("%Y-%m-%d %H"))
if key != self._gated_key:
self._gated_key, self._gated = key, static_gated(o, now)
return self._gated
def _charge_gate_open(self, inv) -> bool:
"""MAINT-13: may this pack charge now, for the maintenance timeout?