MAINT-21 round 2: keep the move pure - revert the added DECISIONS text, restore cut comments
Router T241: the comments commit had put new rationale into MAIN-orchestration.md and cut comment lines that the note at56fc41fdid not hold. - DECISIONS/MAIN-orchestration.md is the56fc41ftext plus the one sentence that the Controller is split into app/main.py and app/ctl_*.py. - Comments whose content is not in a DECISIONS note at56fc41fare back in the code verbatim: MAINT-05 one config, the SAFETY-02, SAFETY-42/34, SAFETY-30 site half, SAFETY-31 and SAFETY-18 latch blocks in __init__, the _grade_store_migration docstring and comment, the trade_power_w docstring, the rows.py docstrings. - Kept: cuts of text already in the note, the SMA-10 / SAFETY-137 / SMA-2 pointers, the SAFETY-32 line fix. No code change: maint21_same_ast OK, maint20_same_code -OO same. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
902da3f723
commit
58b6fa35f5
@@ -288,8 +288,12 @@ class Controller(InputsMixin, WritesMixin, TradeMixin, CycleMixin, AlarmsMixin,
|
||||
self.log_event("maintenance history did not move over cleanly: "
|
||||
+ self.maint_migration.explain(),
|
||||
hint=messages.hint("maint_history"))
|
||||
# MAINT-05: one config, N machines: the options describe the
|
||||
# PROCEDURE; the SCHEDULE and HISTORY are per pack, in the store.
|
||||
# MAINT-05: one config, N machines: the `maintenance_*` options
|
||||
# describe the PROCEDURE (same on every pack); the SCHEDULE and HISTORY
|
||||
# are per pack, in the store. A per-entry config block would be a
|
||||
# second shape for CFG-04 and a fifth place for `maintenance_charge_w`
|
||||
# to disagree with config.yaml; two procedures would be a roster-schema
|
||||
# card.
|
||||
_maint_cfg = MaintConfig.from_options(opts)
|
||||
_one_pack = len(self.inverters) <= 1
|
||||
self.maints = [
|
||||
@@ -307,9 +311,12 @@ class Controller(InputsMixin, WritesMixin, TradeMixin, CycleMixin, AlarmsMixin,
|
||||
tz=site_tz) # MAINT-10: the start hour's zone, from amain()
|
||||
for i, inv in enumerate(self.inverters)]
|
||||
|
||||
# SAFETY-02: one watchdog per actuator, restored from ITS OWN
|
||||
# namespaced keys and graded on every start.
|
||||
# DECISIONS/MAIN-orchestration.md.
|
||||
# SAFETY-02: one watchdog per actuator, each restored from ITS OWN
|
||||
# namespaced store keys (a trip on B latches B, A keeps commanding).
|
||||
# Restored, because a latch held only in memory is cleared by the
|
||||
# restart an operator tries first. Graded on every start: a
|
||||
# disagreement with the flat value re-arms by hand and shouts (the
|
||||
# fail-safe direction is ON). DECISIONS/MAIN-orchestration.md.
|
||||
self._grade_store_migration(store)
|
||||
for inv in self.inverters:
|
||||
if inv.sign_wd.tripped:
|
||||
@@ -329,9 +336,12 @@ class Controller(InputsMixin, WritesMixin, TradeMixin, CycleMixin, AlarmsMixin,
|
||||
hint=messages.hint("stop_restored",
|
||||
unit=inv.name))
|
||||
|
||||
# SAFETY-42 + SAFETY-34: a latch that does NOT act, restored so the
|
||||
# ALARM survives; `_delivery_announced` is per process, so a restart
|
||||
# clears the flag and keeps the latch. DECISIONS/MAIN-orchestration.md.
|
||||
# SAFETY-42 + SAFETY-34: a latch that does NOT act, unlike SAFETY-02's
|
||||
# and SAFETY-31's (which command 0 W). It is restored so the ALARM
|
||||
# survives (2026-09-02: an outage unseen for 6 h 25 m with the detector
|
||||
# correct); `delivery.py` argues reporting rather than acting.
|
||||
# `_delivery_announced` is per process (as `_circ_announced`): a
|
||||
# restart clears the flag and keeps the latch.
|
||||
self._delivery_announced = set()
|
||||
for inv in self.inverters:
|
||||
if inv.delivery_wd.tripped:
|
||||
@@ -348,9 +358,12 @@ class Controller(InputsMixin, WritesMixin, TradeMixin, CycleMixin, AlarmsMixin,
|
||||
hint=messages.hint("not_delivering",
|
||||
unit=inv.name))
|
||||
|
||||
# SAFETY-30: the SITE half of the sign check: armed only at N>=2 (at
|
||||
# one inverter it is constructed and never evaluated), restored with
|
||||
# FLAT keys. DECISIONS/SAFETY-30-per-unit-sign.md.
|
||||
# SAFETY-30: the SITE half of the sign check, one per site, armed only
|
||||
# at N>=2: the SUM of the standing commands against P1. At a roster of
|
||||
# one it is constructed and never evaluated (arming it would duplicate
|
||||
# `inverters[0].sign_wd`: two latches, two banners, a false-positive
|
||||
# record spent twice); `cycle()` enforces it. Restored from the store
|
||||
# with FLAT keys (store.py). DECISIONS/SAFETY-30-per-unit-sign.md.
|
||||
self.site_sign_wd = SignWatchdog(
|
||||
self.site_sign_cfg,
|
||||
tripped=bool(store.data.get("site_sign_tripped", False)),
|
||||
@@ -372,12 +385,15 @@ class Controller(InputsMixin, WritesMixin, TradeMixin, CycleMixin, AlarmsMixin,
|
||||
self._arm_sign_watchdogs()
|
||||
|
||||
# SAFETY-18: the frozen-but-fresh meter detector (freeze.py). NOT
|
||||
# restored: it does not act. DECISIONS/MAIN-orchestration.md.
|
||||
# restored from the store: it does not act, so it does not latch; a
|
||||
# restart re-derives it within one `meter_freeze_s`.
|
||||
self.freeze_wd = FreezeWatchdog(
|
||||
FreezeWatchdogConfig(hold_s=float(opts.get("meter_freeze_s", 300))))
|
||||
|
||||
# SAFETY-31: one per site, RESTORED because it acts, with SITE-level
|
||||
# keys. DECISIONS/MAIN-orchestration.md.
|
||||
# SAFETY-31: one per site, RESTORED (unlike SAFETY-18): a trip files a
|
||||
# P_SAFETY SET that stops every inverter, and a cleared latch would
|
||||
# restart straight into the loop it stopped. SITE-level keys, not
|
||||
# namespaced: circulating power is defined over the roster (store.py).
|
||||
self.circ_wd = CirculationWatchdog(
|
||||
CirculationConfig(
|
||||
min_w=float(opts.get("circulation_w",
|
||||
|
||||
Reference in New Issue
Block a user