MAINT-20 part 2 r2: app/main.py comments, lines 3001-3500 (shadow .. cycle)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
6f94944e44
commit
391c4b4411
@@ -3023,25 +3023,15 @@ class Controller:
|
||||
|
||||
def write_refusal(self, value: float, inv=None) -> str | None:
|
||||
"""Why `value` may NOT be written to `inv` right now, or None if it
|
||||
may.
|
||||
|
||||
SAFETY-28: a number reaches the wire only if THE SINGLE ALLOCATOR
|
||||
placed it, on this tick, for THIS unit (`Allocation.authorises()`).
|
||||
specs 1.5 makes two writers on one actuator a non-goal;
|
||||
`len(validate.ACTUATOR_WRITE_KEYS) == 1` is a statement about the
|
||||
options schema, not the writes. A second writer must file a Claim and
|
||||
go through `resolve()`.
|
||||
0 W is ALWAYS authorised and the test for zero is first and reads
|
||||
nothing: the failsafe writes run while the allocator has REFUSED, so a
|
||||
gate asking its permission to command zero would deadlock the failsafe
|
||||
behind the component whose failure it answers; and at S = 0 broadcast
|
||||
and allocation coincide (no over-command). It tests `value == 0.0`, not
|
||||
a `failsafe=True` flag (a flag is an assertion by the caller, which is
|
||||
what a second writer would pass).
|
||||
DEV-02: the unit is an ARGUMENT: the record holds one share per unit,
|
||||
and the first inverter's name at a roster of two would authorise A's
|
||||
share on B's wire. The default is for N=1 callers and REFUSES at N>=2
|
||||
(`_only()`). DECISIONS/MAIN-orchestration.md."""
|
||||
may. SAFETY-28: a number reaches the wire only if THE SINGLE ALLOCATOR
|
||||
placed it, on this tick, for THIS unit (`Allocation.authorises()`); a
|
||||
second writer must file a Claim. 0 W is ALWAYS authorised and tested
|
||||
first, reading nothing: the failsafe writes run while the allocator has
|
||||
REFUSED, so a gate asking permission to command zero would deadlock the
|
||||
failsafe. It tests `value == 0.0`, not a flag the caller sets. DEV-02:
|
||||
the unit is an ARGUMENT (the record holds one share per unit); the
|
||||
default is for N=1 callers and REFUSES at N>=2.
|
||||
DECISIONS/MAIN-orchestration.md."""
|
||||
if value == 0.0:
|
||||
return None
|
||||
inv = self._only() if inv is None else inv
|
||||
@@ -3311,8 +3301,10 @@ class Controller:
|
||||
if n]
|
||||
|
||||
def _provider_gate(self, now: datetime) -> None:
|
||||
"""PRICE-01: `cheap`, the gate and the gap from the standing plan.
|
||||
(DECISIONS/MAIN-orchestration-archive.md)"""
|
||||
"""PRICE-01: `cheap`, the gate and the gap from the standing plan. No
|
||||
price for now is a closed gate, so the charge waits rather than run
|
||||
unpriced; the gap flag stays False until the first refresh has
|
||||
finished. (DECISIONS/MAIN-orchestration-archive.md)"""
|
||||
plan = self.fresh_tariff_plan(now)
|
||||
published = None if plan is None else plan.published
|
||||
if published is not None:
|
||||
@@ -3349,14 +3341,17 @@ class Controller:
|
||||
|
||||
def _charge_gate_open(self, inv) -> bool:
|
||||
"""MAINT-13: may this pack charge now, for the maintenance timeout?
|
||||
(DECISIONS/MAIN-orchestration-archive.md)"""
|
||||
Closed only when a price gate exists, it is shut, and the pack is not
|
||||
really taking charge. (DECISIONS/MAIN-orchestration-archive.md)"""
|
||||
if not self._price_gated or self.cheap:
|
||||
return True
|
||||
batt = inv.batt
|
||||
return batt is not None and float(batt) <= -MAINT_CHARGING_W
|
||||
|
||||
async def cycle(self) -> None:
|
||||
"""Gather claims, resolve precedence, write the winner.
|
||||
"""Gather claims, resolve precedence, write the winner. Nothing here
|
||||
decides who wins (arbiter.py does, by one rule); this method only
|
||||
states what each strategy wants.
|
||||
(DECISIONS/MAIN-orchestration-archive.md)"""
|
||||
now = datetime.now(timezone.utc)
|
||||
# BEFORE the first `return` of this method on purpose (TARIFF-11): it
|
||||
|
||||
Reference in New Issue
Block a user