Scheduler parity: Modbus Bridge vs Direct Connect¶
The two bridges' schedulers, compared behaviour by behaviour, so they can be aligned.
| Behaviours | Tested | Untested | Unclear | |
|---|---|---|---|---|
Modbus Bridge (scheduler pages, test plan at its main f2e9134, PR #217) |
238 | 130 | 93 | 15 |
| Direct Connect (Scheduler, test plan, 0.5.5) | 266 | 106 | 119 | 41 |
Of the Modbus Bridge's 238 behaviours, this bridge has 74 the same, 121 that differ and is missing 55. It has 83 of its own (Direct Connect only). 13 more rows compare
Corrections from the Modbus Bridge's code check (2026-10-17)
This page read the Modbus Bridge side from its doc markers. That bridge's session has since checked them against its code (franklinwh-modbus-bridge PR #233):
- 28 of the 83 "Direct Connect only" rows exist there too: 17 undocumented, 11 documented under other ids. Treat them as same or differs, not missing there.
- Rows TRG-06, TRG-13, TRG-23, HAA-01 and PRI-01 described the Modbus Bridge wrongly; each row carries a note.
- TRG-19 (next fire for long intervals) is the same bug in both (our #208).
The counts on this page have not been rebased on those corrections yet.
whole sections of the dependencies and examples pages, which carry no markers.
How it was built. Each row is one behaviour id. Ids are shared: where this bridge's page documents the counterpart of a Modbus Bridge behaviour, it uses the same id, even when the behaviour differs. Has / tested for the Modbus Bridge comes from its test plan; for this bridge from the markers in the Scheduler pages. The gap is a short note written while reading both bridges' code. The Modbus Bridge's claims are taken from its docs and were not re-verified against its code here; this bridge's side was read from its code, and the less obvious defects were reproduced with a mock (no hardware).
| Column | Meaning |
|---|---|
| # | Behaviour id. "—" for a section-level comparison (no marker). |
| Page · heading | This bridge's page and the heading both bridges share. |
| Modbus Bridge / Direct Connect | yes / tested, yes / untested, yes / unclear or no. |
| Gap | same, differs, missing here (Modbus Bridge only) or Direct Connect only, then the difference. |
| Why missing | Missing here rows only: Not ported, Depends on, Transport limit, Design choice or Unknown, then the source. See Gap reasons and classes. |
| Class | Differs rows only: behavioural (with what it writes) or variance, then why. |
| Issue | The issue in this repository. Issues opened from this review are listed under Issues filed from this review. |
Gap reasons and classes¶
Added to the table below: Why missing for the 55 missing here rows and Class for the 121 differs rows. Each was assigned from the code and docs cited in the row, the BACKLOG and the issues; nothing was run against a gateway or an emulator.
Why missing (55 rows)¶
| Reason | Rows | What it means |
|---|---|---|
| Not ported | 24 | Not built here yet, and recorded as wanted (BACKLOG or an issue). |
| Depends on | 23 | Needs another missing piece first (named in the row): mostly catch-up, release policy, ownership, supervision. |
| Unknown | 8 | No record of why. Questions below. |
| Transport limit | 0 | None. Every missing behaviour can be built on the transports this bridge already uses: the force path is the same WSet model 704 on the Modbus TCP Server (aGate :502) through the Modbus client (this bridge) (battery_control.py:1-7), and the reserve and mode reads it needs are local (PROTOCOL.md). The two transport limits found sit in differs rows (dependency matrix): Direct Connect (:9000) has no battery force, and reserve (1405) is cloud-only. |
| Design choice | 0 | None recorded for a missing row. Run now ignoring conditions is recorded as by design in #162, but that row is a differs row (OUT-20). |
Differs (121 rows)¶
| Class | Rows |
|---|---|
| Behavioural: battery write | 68 |
| Behavioural: other device or HA write | 7 |
| Behavioural: recorded outcome or notification | 18 |
| Behavioural: display only (timeline, Next, Test, buttons) | 11 |
| Implementation variance | 16 |
| Needs owner | 1 |
Rule used. Variance means the same intent gives the same trigger, conditions, action, target, exit and recorded result by different code. Anything that could change a battery write, another device write or a recorded outcome is behavioural. Display-only rows that misstate when or where something runs are behavioural, ranked last.
Behavioural differences, ranked by risk¶
Battery writes first, then other device and HA writes, then the record, then display. Within a group, the order is a judgement of likelihood times effect, not a measurement.
| Rank | Row | Writes | Difference | Issue |
|---|---|---|---|---|
| 1 | EXT-01 | battery | window close releases a force it never sent or does not own | #189 |
| 2 | EXT-05 | battery | never hands over; releases another's force | #189 |
| 3 | § 5. Peak-demand window | battery | overlapping force schedules release each other (#189) | #189 |
| 4 | RST-01 | battery | restart releases only the in-memory force, to the first gateway's host | #192 |
| 5 | OUT-24 | battery | Stop releases via the first gateway's host; no exit HA actions | #192 |
| 6 | EXT-20 | battery | shutdown releases to the first gateway's host | #192 |
| 7 | TGT-09 | battery | Run now forces the top-bar gateway, not the schedule's | #193 |
| 8 | RST-02 | battery | start-up default is notify: a force left by a crash keeps running (there: released) | #199 |
| 9 | RST-04 | battery | release_stale() never called |
#199 |
| 10 | ACT-13 | battery | a refused force is logged fired and never retried | #191 |
| 11 | § An action is refused or does nothing | battery | refused writes logged fired (#191) | #191 |
| 12 | PRI-03 | battery | a later-ready force overrides a running one whatever the priority | #196 |
| 13 | EXT-04 | battery | delete does not release the running force | #195 |
| 14 | TRG-34 | battery | hidden 90 min duration cuts a window force short | #160 |
| 15 | ACT-17 | battery | time limit = duration_min x 60, hidden 90 min in windows | #160 |
| 16 | § 1. Evening top-up | battery | hidden duration ends the force (#160) | #160 |
| 17 | § 2. Evening peak discharge until the minimum SoC | battery | workaround for #160 changes the window | #160 |
| 18 | TRG-16 | battery | weekly with no days fires every day (Modbus Bridge: never) | #198 |
| 19 | TRG-23 | battery | monthly with no day fires every day | #198 |
| 20 | TRG-09 | battery | start = end is open all day: a force runs 24 h | #198 |
| 21 | ACT-04 | battery | empty power is a 0 W force | #209 |
| 22 | TRG-28 | battery | Always fires once ever, but releases on every falling edge | #190 |
| 23 | § An entry never fires | battery | Always fires once ever (#190) | #190 |
| 24 | TRG-27 | battery | Always fires on the rising edge, not continuously | #190 |
| 25 | TRG-29 | battery | stored occurrence never pruned keeps Always from firing again | #190 |
| 26 | TGT-10 | battery | unbound = first registered gateway, which moves | #182 |
| 27 | EXT-17 | battery | Release refused when the Modbus client (this bridge) is off; no read-back | #174 |
| 28 | § Dependency matrix | battery | force needs the Modbus client (this bridge): :9000 has no battery force (transport limit, HYBRID-CAPABILITIES); reserve write never runs (#129): 1405 is cloud-only (PROTOCOL.md) | #129 |
| 29 | CON-02 | battery | name order, priority only within a tick: decides which force runs | #196 |
| 30 | PRI-02 | battery | contest only within a tick, per resource | #196 |
| 31 | PRI-01 | battery | default If busy = override (there: defer); unknown values act as override | |
| 32 | SEN-10 | battery | stale NEM price kept: price-gated forces run on old prices | #207 |
| 33 | SEN-04 | battery | grid.connected reads 0 at exactly 0 W: a grid gate can fire a force |
#206 |
| 34 | § A condition is always true when it should not be | battery | conditions can pass when they should not (#206) | #206 |
| 35 | ACT-14 | battery | no WSetEna read-back check: a force can be recorded as sent when it did not take | #139 |
| 36 | ACT-03 | battery | % sized on 702 or a 5000 W fallback, no trusted rating: different watts written | |
| 37 | ACT-10 | battery | W/kW not capped by the bridge at 702 | |
| 38 | PRI-07 | battery | busy = only dispatch rows of schedules or the widget; mode entries unchecked | |
| 39 | PRI-08 | battery | defer gives up for the day; wait retries each tick | #204 |
| 40 | PRI-10 | battery | after a manual command ends, a deferred entry does not run | |
| 41 | OUT-04 | battery | retry 30 s doubling to 600 s (there: 15, 30, 60 s); no notification | #172 |
| 42 | ACT-02 | battery | invalid actions saved; fail only at run | #202 |
| 43 | OUT-20 | battery | Run now ignores conditions (by design per #162) | #162 |
| 44 | ACT-05 | battery | percent accepted; any unknown unit is read as percent | |
| 45 | TRG-30 | battery | falling edge sends Release (the Modbus Bridge does not re-check) | |
| 46 | CND-27 | battery | a retry waits the whole hold again, delaying the force | #203 |
| 47 | SEN-08 | battery | undefined window is None (fails closed) not False: == 0 gates differ |
|
| 48 | TRG-22 | battery | no range check; day 0 = every day, so an invalid entry fires | #202 |
| 49 | TRG-08 | battery | the after-midnight part follows the opening day's calendar: a force may run on a day the Modbus Bridge skips | |
| 50 | CND-22 | battery | multi-gateway: tariff/billing sensors from each gateway's own meter, so conditions can differ | |
| 51 | CND-06 | battery | case-insensitive text: a condition can pass that fails there | |
| 52 | CND-08 | battery | bracketed lists and text members parse differently: condition result can differ | |
| 53 | CLK-01 | battery | each gateway's aGate clock: fire times differ when the container clock is not site time | |
| 54 | CND-20 | battery | an empty ALL exit group stops the schedule ever starting | |
| 55 | TRG-13 | battery | an overnight one-off keeps forcing past midnight | |
| 56 | IDX-03 | battery | an edited power or action is not re-sent to a running force until the next window | |
| 57 | TRG-11 | battery | stored days still restrict a one-off, so it may not fire | |
| 58 | TGT-01 | battery | a stale or disabled gateway's schedules are not evaluated | |
| 59 | TGT-11 | battery | unbound and bound contend as one group (two groups there) | |
| 60 | ACT-19 | battery | form save keeps API-only keys (the Modbus Bridge drops target_soc): different force end |
|
| 61 | TRG-10 | battery | an unparsable window falls back to Fire at + duration instead of 00:00 | |
| 62 | ACT-15 | battery | WSetRvrtTms not written (the library writes WSetEna/WSetMod/WSetPct only); PICS Issue 4 calls it cosmetic | |
| 63 | CLK-04 | battery | DST change applies up to 10 min late | |
| 64 | EXT-07 | battery | exit already true: no start here; a brief force there | |
| 65 | PRI-06 | battery | a loser does not fire again that occurrence | |
| 66 | RST-03 | battery | stored occurrence: no re-fire after restart (there: re-dispatches) | |
| 67 | PRI-13 | battery | claims per gateway, not per target | |
| 68 | OUT-25 | battery | Stop with nothing running does not block the window; the entry can still fire | |
| 69 | HAA-06 | device/HA | exit HA actions run at every window close, even if never fired | #189 |
| 70 | HAA-07 | device/HA | on-entry HA actions repeat on every retry | #203 |
| 71 | ACT-28 | device/HA | Run now runs HA actions of HA-only schedules | |
| 72 | EXT-09 | device/HA | exit evaluated for every action kind (mode, HA-only) | |
| 73 | EXT-12 | device/HA | restore_on_exit writes the mode back (the Modbus Bridge only audits) |
#162 |
| 74 | ACT-23 | device/HA | missing mode accepted, fails and retries at run | #202 |
| 75 | HAA-01 | device/HA | invalid HA actions saved; skipped at run | #202 |
| 76 | OUT-18 | record | no failure notifications | #172 |
| 77 | OUT-13 | record | dispatch record holds successful forces only | #139 |
| 78 | TRG-40 | record | missed rows come from stale claims, not outages | |
| 79 | TRG-41 | record | a window no tick saw leaves no missed row | |
| 80 | CND-29 | record | gated logged once a day, two leaves | |
| 81 | HAA-08 | record | guard skip leaves no log row | |
| 82 | HAA-12 | record | HA failures folded into the run row; rarely fail the run | |
| 83 | TGT-06 | record | History rows do not name the gateway | #205 |
| 84 | EXT-10 | record | exit row names no condition | |
| 85 | PRI-14 | record | requester only in the dispatches table | |
| 86 | OUT-01 | record | config changes logged as one word; import not logged | |
| 87 | OUT-05 | record | recovery logged as plain fired; no notification | #172 |
| 88 | TRG-24 | record | invalid cron saved instead of rejected; never fires in either | #202 |
| 89 | CND-02 | record | import accepts unknown sensors silently | #202 |
| 90 | CND-26 | record | hold over 86400 s accepted | |
| 91 | CND-35 | record | no warning for an unexposed HA entity | #202 |
| 92 | HAA-02 | record | incomplete rows kept and skipped at run with a reason | |
| 93 | HAA-10 | record | %ha:…% placeholders not substituted |
#169 |
| 94 | IDX-06 | display | timeline omits interval schedules and ignores the gateway | #161 |
| 95 | TRG-19 | display | Next shows a time the engine does not fire at | #208 |
| 96 | TRG-32 | display | Next uses the container clock | #161 |
| 97 | IDX-07 | display | one-off drawn only on its date (the Modbus Bridge draws it every week) | |
| 98 | TRG-33 | display | active_now also needs a fire; changes Stop/Run now |
|
| 99 | CND-30 | display | editor Test evaluates the top-bar gateway, not the schedule's | |
| 100 | CND-31 | display | Test against live: default gateway, container clock, top-level rows only | #161 |
| 101 | TGT-02 | display | site fan-out only through the API | #162 |
| 102 | TGT-15 | display | timeline is one list, not per gateway | #161 |
| 103 | OUT-19 | display | Stop shown on a different rule, container clock | #161 |
| 104 | CLK-02 | display | previews on the container clock | #161 |
Questions for the owner¶
Unknown (missing here, no record of why):
- Legacy format (CON-07, ACT-07, ACT-08, ACT-09; also EXT-16). These describe the Modbus
Bridge's legacy / v2 split and legacy
power_pctentries. This bridge never had either. Mark them not applicable and drop them from the parity count? - API
oneofftrigger (TRG-35). The Modbus Bridge has an API-onlyoneofftype with an ISOfire_at; here a one-off is a date window. Wanted, or not applicable? - Rating trust model (ACT-11, and ACT-12, OUT-17 that build on it). No record says whether a calibrated / peak-confirmed rating gate is wanted here. #162 lists the overshoot guard but not the trust model. Port it?
- Power staging (ACT-16). The Modbus Bridge stages power and re-sends the active command;
here a force is one
BatteryCommand. Not applicable? - Mock warning in the form (TGT-13). Wanted?
Needs owner (differs):
- Storm example (§ 4. Storm forecast). Is
weather.conditionmatching*thunder*right, or should the example useweather.code in 95, 96, 99(and shouldweather.codebe in the picker)?
Behaviours¶
| # | Page · heading | Modbus Bridge | Direct Connect | Gap | Why missing | Class | Issue |
|---|---|---|---|---|---|---|---|
| IDX-01 | index · The entry list | yes / untested | yes / untested | differs: DC shows all by default | variance: list filter default only | ||
| IDX-02 | index · The entry list | yes / untested | yes / untested | differs: DC opens an unsaved 'Copy of' form, disabled | variance: both end with a disabled copy; only the save step differs | ||
| IDX-03 | index · The entry list | yes / tested | yes / untested | differs: DC confirms but does not re-send a running force; change applies next window | behavioural (battery): an edited power or action is not re-sent to a running force until the next window | ||
| IDX-04 | index · Templates, export and import | yes / untested | yes / untested | differs: DC loads disabled, no enable prompt | variance: templates load disabled in both | ||
| IDX-05 | index · Templates, export and import | yes / tested | yes / tested | same: DC also exports/imports its own franklinwh-local-schedules | |||
| IDX-06 | index · Visual timeline | yes / tested | yes / tested | differs: DC: one list, interval/cron/always not drawn, not per gateway | behavioural (display): timeline omits interval schedules and ignores the gateway | #161 | |
| IDX-07 | index · Visual timeline | yes / tested | yes / untested | differs: DC draws a one-off only on its date | behavioural (display): one-off drawn only on its date (the Modbus Bridge draws it every week) | ||
| IDX-08 | index · The entry list | no | yes / tested | Direct Connect only: Turn on/off partial PUT merged (fixed 0.5.2) | #157 | ||
| IDX-09 | index · The entry list | no | yes / unclear | Direct Connect only: PUT without enabled re-enables | #168 | ||
| IDX-10 | index · Templates, export and import | no | yes / tested | Direct Connect only: eleven presets incl. four force presets (MB has four different templates) | |||
| IDX-11 | index · Visual timeline | no | yes / untested | Direct Connect only: timeline ignores gateway and uses container clock | #161 | ||
| IDX-12 | index · Using schedules from Home Assistant (Direct Connect only) | no | yes / unclear | Direct Connect only: Pause/Resume API ineffective (does not hold a run, tick ignores paused) | #200 | ||
| CON-01 | concepts · The tick | yes / untested | yes / tested | same: DC cadence configurable 5-60 s | |||
| CON-02 | concepts · The tick | yes / tested | yes / untested | differs: DC reads all by name; priority only in a same-tick contest | behavioural (battery): name order, priority only within a tick: decides which force runs | ||
| CON-03 | concepts · The tick | yes / tested | yes / tested | same: none | |||
| CON-04 | concepts · The tick | yes / tested | yes / tested | same: DC: per-resource claims (battery, grid, circuit) | |||
| CON-05 | concepts · The tick | yes / untested | yes / untested | differs: DC waits for the next tick (<=15 s) | variance: same write, up to one tick (<=15 s) later | ||
| CON-06 | concepts · The tick | yes / unclear | yes / untested | differs: DC has no module switch | variance: the Modbus Bridge switch hides routes but the engine still runs: same writes | ||
| CON-07 | concepts · Legacy and v2 entries | yes / untested | no | missing here: DC has one format | Unknown: none found; the page states one format, not why | ||
| CON-08 | concepts · The tick | no | yes / tested | Direct Connect only: stale/disabled/never-polled gateway skipped (max(90 s, 3 polls)) | |||
| CON-09 | concepts · Window, activation and run | no | yes / tested | Direct Connect only: stored occurrences: fire once per occurrence, retry while failed | |||
| CON-10 | concepts · What the engine remembers | no | yes / untested | Direct Connect only: last fired occurrence, runs and dispatches survive restart | |||
| TRG-01 | triggers · Fire-based triggers: the active window | yes / tested | yes / tested | same: none | |||
| TRG-02 | triggers · Fire-based triggers: the active window | yes / untested | yes / untested | differs: DC: the one Fire at minute; force has no own timer, released at next tick after | variance: both release about a minute after a zero-duration fire | ||
| TRG-03 | triggers · Fire-based triggers: the active window | yes / tested | yes / untested | same: none | |||
| TRG-04 | triggers · Recurring windows | yes / tested | yes / untested | same: untested in DC | |||
| TRG-05 | triggers · Recurring windows | yes / tested | yes / tested | same: none | |||
| TRG-06 | triggers · Recurring windows | yes / untested | yes / tested | differs: DC: each window is its own occurrence (fires once per window) Modbus Bridge check (their PR #233): separate windows each fire there too; only back-to-back windows merge. | variance: both fire once per window | ||
| TRG-07 | triggers · Recurring windows | yes / tested | yes / untested | same: DC: end <= start wraps | |||
| TRG-08 | triggers · Recurring windows | yes / untested | yes / untested | differs: DC attributes the after-midnight part to the day it opened | behavioural (battery): the after-midnight part follows the opening day's calendar: a force may run on a day the Modbus Bridge skips | ||
| TRG-09 | triggers · Recurring windows | yes / tested | yes / unclear | differs: DC: start == end is a 24-hour window | behavioural (battery): start = end is open all day: a force runs 24 h | #198 | |
| TRG-10 | triggers · Recurring windows | yes / untested | yes / untested | differs: DC: 24:00 = end of day; unparsable window dropped, empty list falls back to fire_at | behavioural (battery): an unparsable window falls back to Fire at + duration instead of 00:00 | ||
| TRG-11 | triggers · One-off date window | yes / tested | yes / tested | differs: DC: stored days still restrict; form shows windows that are ignored | behavioural (battery): stored days still restrict a one-off, so it may not fire | ||
| TRG-12 | triggers · One-off date window | yes / tested | yes / tested | same: DC card has no 'passed' label | |||
| TRG-13 | triggers · One-off date window | yes / untested | yes / untested | differs: DC runs past midnight into the next date Modbus Bridge check (their PR #233): an overnight one-off there also runs from 00:00 on its own date. | behavioural (battery): an overnight one-off keeps forcing past midnight | ||
| TRG-14 | triggers · Daily at time | yes / tested | yes / tested | same: none | |||
| TRG-15 | triggers · Daily at time | yes / untested | yes / untested | same: form max 1440 | |||
| TRG-16 | triggers · Weekly at time | yes / tested | yes / tested | differs: DC: no days = every day | behavioural (battery): weekly with no days fires every day (Modbus Bridge: never) | ||
| TRG-17 | triggers · Every N minutes | yes / tested | yes / tested | same: none | |||
| TRG-18 | triggers · Every N minutes | yes / untested | yes / untested | same: untested in DC | |||
| TRG-19 | triggers · Every N minutes | yes / untested | yes / unclear | differs: DC next_fire disagrees with the window | behavioural (display): Next shows a time the engine does not fire at | #208 | |
| TRG-20 | triggers · Every N minutes | yes / tested | yes / untested | same: none | |||
| TRG-21 | triggers · Monthly / calendar | yes / tested | yes / tested | same: none | |||
| TRG-22 | triggers · Monthly / calendar | yes / tested | yes / untested | differs: DC does not validate; day 0/None = no restriction | behavioural (battery): no range check; day 0 = every day, so an invalid entry fires | ||
| TRG-23 | triggers · Monthly / calendar | yes / untested | yes / untested | differs: DC: no day of month = fires every day Modbus Bridge check (their PR #233): monthly with no day fires on the 1st there. | behavioural (battery): monthly with no day fires every day | #198 | |
| TRG-24 | triggers · Custom cron | yes / tested | yes / untested | differs: DC accepts it; never fires | behavioural (record): invalid cron saved instead of rejected; never fires in either | ||
| TRG-25 | triggers · Custom cron | yes / untested | yes / untested | same: untested in DC | |||
| TRG-26 | triggers · Custom cron | yes / tested | yes / tested | same: none | |||
| TRG-27 | triggers · Always evaluate | yes / tested | yes / tested | differs: DC: window = conditions; fires on rising edge | behavioural (battery): Always fires on the rising edge, not continuously | ||
| TRG-28 | triggers · Always evaluate | yes / untested | yes / unclear | differs: DC: once EVER (stored occurrence, survives restart); falling edges still release | behavioural (battery): Always fires once ever, but releases on every falling edge | #190 | |
| TRG-29 | triggers · Always evaluate | yes / unclear | yes / unclear | differs: DC: stored occurrence row, never pruned | behavioural (battery): stored occurrence never pruned keeps Always from firing again | #190 | |
| TRG-30 | triggers · Always evaluate | yes / untested | yes / tested | differs: DC does release on the falling edge | behavioural (battery): falling edge sends Release (the Modbus Bridge does not re-check) | ||
| TRG-31 | triggers · Quick presets | yes / untested | yes / untested | same: DC preset list differs | |||
| TRG-32 | triggers · Next fire | yes / tested | yes / tested | differs: DC searches 366 days; container clock | behavioural (display): Next uses the container clock | #161 | |
| TRG-33 | triggers · Next fire | yes / untested | yes / tested | differs: DC: inside window AND fired this occurrence | behavioural (display): active_now also needs a fire; changes Stop/Run now |
||
| TRG-34 | triggers · Editing a trigger in the form | yes / untested | yes / unclear | differs: DC: hidden duration_min (default 90) also limits a scheduled force | behavioural (battery): hidden 90 min duration cuts a window force short | #160 | |
| TRG-35 | triggers · Editing a trigger in the form | yes / untested | no | missing here: DC has no API oneoff type | Unknown: none found; no API oneoff type here |
||
| TRG-36 | triggers · After an outage or a restart (catch-up) | yes / tested | no | missing here: DC: stale gateway skipped; no outage record | Not ported: ORCH 2b (catch-up on outage); #162 | #162 | |
| TRG-37 | triggers · After an outage or a restart (catch-up) | yes / tested | no | missing here: no catch-up | Not ported: ORCH 2b (catch-up); #162 | #162 | |
| TRG-38 | triggers · After an outage or a restart (catch-up) | yes / tested | no | missing here: no catch-up | Not ported: ORCH 2b (catch-up after restart); #162 | #162 | |
| TRG-39 | triggers · After an outage or a restart (catch-up) | yes / tested | no | missing here: no catch-up | Depends on: catch-up (TRG-37) | #162 | |
| TRG-40 | triggers · After an outage or a restart (catch-up) | yes / tested | yes / tested | differs: DC: claimed runs whose window ended >120 s ago marked missed | behavioural (record): missed rows come from stale claims, not outages | ||
| TRG-41 | triggers · After an outage or a restart (catch-up) | yes / untested | yes / untested | differs: DC: an unclaimed window leaves no missed row | behavioural (record): a window no tick saw leaves no missed row | ||
| TRG-42 | triggers · After an outage or a restart (catch-up) | yes / untested | no | missing here: no missed policy | Depends on: catch-up missed policy (TRG-37) | #162 | |
| TRG-43 | triggers · After an outage or a restart (catch-up) | yes / tested | no | missing here: no late fire | Depends on: catch-up (TRG-37) | #162 | |
| TRG-44 | triggers · After an outage or a restart (catch-up) | yes / untested | no | missing here: no late fire | Depends on: catch-up (TRG-37) | #162 | |
| TRG-45 | triggers · After an outage or a restart (catch-up) | yes / untested | no | missing here: no late fire | Depends on: catch-up (TRG-37) | #162 | |
| TRG-46 | triggers · After an outage or a restart (catch-up) | yes / untested | no | missing here: no late fire | Depends on: catch-up (TRG-37) | #162 | |
| TRG-47 | triggers · After an outage or a restart (catch-up) | yes / untested | no | missing here: no catch-up | Depends on: catch-up (TRG-37) | #162 | |
| TRG-48 | triggers · After an outage or a restart (catch-up) | yes / untested | no | missing here: no missed policy | Depends on: catch-up (TRG-37) | #162 | |
| TRG-49 | triggers · Summary | no | yes / untested | Direct Connect only: calendar restrictions apply to every trigger type | |||
| TRG-50 | triggers · Recurring windows | no | yes / tested | Direct Connect only: start/end date range restriction with a reason | |||
| TRG-51 | triggers · One-off date window | no | yes / unclear | Direct Connect only: One-off ignores its Time windows; no date = every day | #198 | ||
| TRG-52 | triggers · Next fire | no | yes / unclear | Direct Connect only: next_fire/active_now on container clock | #161 | ||
| TRG-53 | triggers · Editing a trigger in the form | no | yes / untested | Direct Connect only: trigger type change seeds defaults | |||
| TRG-54 | triggers · After an outage or a restart (catch-up) | no | yes / untested | Direct Connect only: no late fire ever | #162 | ||
| TRG-55 | triggers · After an outage or a restart (catch-up) | no | yes / tested | Direct Connect only: stale snapshot skips evaluation | |||
| TRG-56 | triggers · After an outage or a restart (catch-up) | no | yes / tested | Direct Connect only: older open runs coalesced | |||
| CND-01 | conditions · Rules for every condition | yes / tested | yes / tested | same: none | |||
| CND-02 | conditions · Rules for every condition | yes / tested | yes / untested | differs: import does not warn about unknown sensors | behavioural (record): import accepts unknown sensors silently | #202 | |
| CND-03 | conditions · Rules for every condition | yes / tested | yes / untested | differs: same idea, but every gateway tick also fetches each HA instance's whole /api/states | variance: one snapshot per gateway per tick in both; HA read differs | ||
| CND-04 | conditions · Rules for every condition | yes / untested | yes / untested | same: none; on/off sensors are stored as int 1/0 | |||
| CND-05 | conditions · Operators | yes / tested | yes / tested | same: none | |||
| CND-06 | conditions · Operators | yes / tested | yes / untested | differs: DC compares text case-insensitively; untested | behavioural (battery): case-insensitive text: a condition can pass that fails there | ||
| CND-07 | conditions · Operators | yes / tested | yes / untested | same: untested here | |||
| CND-08 | conditions · Operators | yes / tested | yes / untested | differs: brackets not stripped; untested here | behavioural (battery): bracketed lists and text members parse differently: condition result can differ | ||
| CND-09 | conditions · Operators | yes / tested | yes / untested | same: untested here | |||
| CND-10 | conditions · Operators | yes / tested | yes / untested | same: untested here | |||
| CND-11 | conditions · Operators | yes / tested | yes / untested | same: untested here | |||
| CND-12 | conditions · Operators | yes / tested | yes / untested | same: untested here | |||
| CND-13 | conditions · Value and Lookup | yes / untested | yes / untested | same: none | |||
| CND-14 | conditions · Value and Lookup | yes / tested | yes / untested | same: untested here | |||
| CND-15 | conditions · Value and Lookup | yes / untested | yes / untested | differs: Explain prints the Lookup label; Test against live prints an empty RHS | variance: display text of a Lookup only; evaluation is the same | ||
| CND-16 | conditions · Groups and items: ALL / ANY | yes / tested | yes / tested | same: empty top-level block is true even with match any | |||
| CND-17 | conditions · Groups and items: ALL / ANY | yes / tested | yes / tested | same: none | |||
| CND-18 | conditions · Groups and items: ALL / ANY | yes / tested | yes / untested | same: untested here | |||
| CND-19 | conditions · Groups and items: ALL / ANY | yes / untested | yes / untested | differs: empty block saved as [] (same effect) | variance: [] and null have the same effect | ||
| CND-20 | conditions · Groups and items: ALL / ANY | yes / untested | yes / untested | differs: an empty ALL exit group blocks the schedule from starting (exit condition already holds) | behavioural (battery): an empty ALL exit group stops the schedule ever starting | ||
| CND-21 | conditions · Scope: which gateway's values | yes / untested | yes / untested | same: applies to gateway_scope all; untested | |||
| CND-22 | conditions · Scope: which gateway's values | yes / untested | yes / tested | differs: DC measures each gateway against its own meter (better) | behavioural (battery): multi-gateway: tariff/billing sensors from each gateway's own meter, so conditions can differ | ||
| CND-23 | conditions · Hold for (dwell) | yes / tested | yes / untested | same: untested here | |||
| CND-24 | conditions · Hold for (dwell) | yes / tested | yes / untested | same: untested here | |||
| CND-25 | conditions · Hold for (dwell) | yes / untested | yes / untested | same: none | |||
| CND-26 | conditions · Hold for (dwell) | yes / tested | yes / untested | differs: no maximum; untested here | behavioural (record): hold over 86400 s accepted | ||
| CND-27 | conditions · Hold for (dwell) | yes / untested | yes / untested | differs: a retry waits the whole hold again | behavioural (battery): a retry waits the whole hold again, delaying the force | #203 | |
| CND-28 | conditions · When conditions are evaluated | yes / tested | yes / untested | same: none | |||
| CND-29 | conditions · When conditions are evaluated | yes / tested | yes / untested | differs: once per calendar day per gateway, up to two leaves; untested | behavioural (record): gated logged once a day, two leaves | ||
| CND-30 | conditions · Test Verification | yes / tested | yes / tested | differs: editor Test uses the top-bar gateway, not the schedule's | behavioural (display): editor Test evaluates the top-bar gateway, not the schedule's | ||
| CND-31 | conditions · Test Verification | yes / untested | yes / unclear | differs: Test against live reads the default gateway and container clock, top-level rows only, no exit/hold/conflict check | behavioural (display): Test against live: default gateway, container clock, top-level rows only | #161 | |
| CND-32 | conditions · Test Verification | yes / untested | yes / untested | differs: no login on this bridge's HTTP API | variance: no login anywhere on this bridge (LAN trust, BACKLOG); evaluate writes nothing | ||
| CND-33 | conditions · Home Assistant entities | yes / tested | yes / tested | same: since 0.5.4 unavailable/unknown are no reading, as in the Modbus Bridge; before 0.5.4 they read 0 | #167 (fixed in 0.5.4) | ||
| CND-34 | conditions · Home Assistant entities | yes / tested | yes / tested | differs: REST /api/states (whole list) every tick of every gateway; no WebSocket | variance: REST each tick vs WebSocket: same values per tick | ||
| CND-35 | conditions · Home Assistant entities | yes / tested | yes / untested | differs: no such warning | behavioural (record): no warning for an unexposed HA entity | #202 | |
| CND-36 | conditions · Conditions (intro) | no | yes / untested | Direct Connect only: DC evaluates exit conditions for every action kind while the window is open | |||
| CND-37 | conditions · Home Assistant entities | no | yes / tested | Direct Connect only: DC auto-scales $/kWh to c/kWh (tested) | |||
| SEN-01 | conditions · Notes on some sensors | yes / tested | no | missing here: no time.* sensors; use calendar restrictions | Not ported: SENSOR-PARITY §A time.* |
#162 | |
| SEN-02 | conditions · Notes on some sensors | yes / tested | no | missing here: no time.* sensors | Not ported: SENSOR-PARITY §A time.* |
#162 | |
| SEN-03 | conditions · Notes on some sensors | yes / tested | yes / tested | same: none | |||
| SEN-04 | conditions · Grid | yes / tested | yes / tested | differs: DC derives it from grid power != 0, so it reads 0 at exactly 0 W while on grid | behavioural (battery): grid.connected reads 0 at exactly 0 W: a grid gate can fire a force |
#206 | |
| SEN-05 | conditions · Battery | yes / tested | no | missing here: no reserve sensors | Not ported: SENSOR-PARITY §A battery.reserve_*; reserve is readable locally as 1726 reserved_soc (PROTOCOL.md), so not a transport limit |
||
| SEN-06 | conditions · Notes on some sensors | yes / tested | yes / tested | same: capacity is a user constant (no local capacity register); rate falls back to a constant | |||
| SEN-07 | conditions · Constants | yes / tested | yes / tested | same: DC adds default operating mode; capacity/max power not in the picker | |||
| SEN-08 | conditions · Tariff | yes / tested | yes / tested | differs: from the gateway's meter; None when undefined (fails closed) | behavioural (battery): undefined window is None (fails closed) not False: == 0 gates differ |
||
| SEN-09 | conditions · Tariff | yes / tested | yes / untested | same: untested here | |||
| SEN-10 | conditions · Tariff | yes / tested | yes / tested | differs: last good NEM price kept however old | behavioural (battery): stale NEM price kept: price-gated forces run on old prices | #207 | |
| SEN-11 | conditions · Utility Plan | yes / tested | yes / tested | same: none | |||
| SEN-12 | conditions · Utility Plan | yes / tested | no | missing here: no such sensor | Not ported: SENSOR-PARITY §A service.tz_matches_clock |
||
| SEN-13 | conditions · Weather | yes / tested | yes / untested | same: untested here; weather.code not in the picker | |||
| SEN-14 | conditions · Gateway identity | yes / untested | no | missing here: no gateway.* sensors; system.* describe the install | Not ported: SENSOR-PARITY §A gateway.* |
||
| SEN-15 | conditions · Other | yes / tested | no | missing here: no dispatch.* sensors | Not ported: SENSOR-PARITY §A dispatch.* |
||
| SEN-16 | conditions · Other | yes / unclear | no | missing here: no dispatch.* sensors | Depends on: dispatch.* sensors (SEN-15) |
||
| SEN-17 | conditions · Energy | yes / tested | no | missing here: only billing-period import/export cost sensors | Depends on: FEAT-BILLING-SERVICE, per SENSOR-PARITY §B | ||
| SEN-18 | conditions · Every sensor in the picker | no | yes / tested | Direct Connect only: different groups (Gateway, Derived Battery, …, one per HA instance) | |||
| SEN-19 | conditions · Tariff | no | yes / untested | Direct Connect only: DC keeps the last good NEM price with no age limit | #207 | ||
| ACT-01 | actions · Summary | yes / untested | yes / tested | same: none | |||
| ACT-02 | actions · Summary | yes / untested | yes / untested | differs: DC validates no action at save; failures appear only at run | behavioural (battery): invalid actions saved; fail only at run | #202 | |
| ACT-03 | actions · Power and sizing | yes / tested | yes / untested | differs: DC sizes pct against the 702 rating or a 5000 W fallback; no trusted rating | behavioural (battery): % sized on 702 or a 5000 W fallback, no trusted rating: different watts written | ||
| ACT-04 | actions · Power and sizing | yes / tested | yes / unclear | differs: DC empty power = 0 W; form seeds 100 % | behavioural (battery): empty power is a 0 W force | #209 | |
| ACT-05 | actions · Power and sizing | yes / untested | yes / untested | differs: DC offers % and kW in the form, W via API | behavioural (battery): percent accepted; any unknown unit is read as percent | ||
| ACT-06 | actions · Power and sizing | yes / untested | no | missing here: DC has no params validation at all (see ACT-02) | Depends on: save-time validation #202 | ||
| ACT-07 | actions · Power and sizing | yes / tested | no | missing here: no legacy format here | Unknown: none found; legacy power_pct format never existed here |
||
| ACT-08 | actions · Power and sizing | yes / untested | no | missing here: n/a | Unknown: none found; legacy format | ||
| ACT-09 | actions · Power and sizing | yes / untested | no | missing here: n/a | Unknown: none found; legacy format | ||
| ACT-10 | actions · Power and sizing | yes / unclear | yes / unclear | differs: DC does not cap W/kW (library behaviour unverified) | behavioural (battery): W/kW not capped by the bridge at 702 | ||
| ACT-11 | actions · Power and sizing | yes / tested | no | missing here: no trust model | Unknown: none found; #162 does not list a rating trust model | #162 | |
| ACT-12 | actions · Power and sizing | yes / tested | no | missing here: DC refuses only when the Modbus client is not ready (ACT-30) | Depends on: trusted rating (ACT-11) | #162 | |
| ACT-13 | actions · Power and sizing | yes / tested | yes / unclear | differs: DC classifies a capability refusal as OK: logged fired, not retried | behavioural (battery): a refused force is logged fired and never retried | #191 | |
| ACT-14 | actions · What is written | yes / tested | yes / untested | differs: DC sends one BatteryCommand via the library and trusts its return; no read-back | behavioural (battery): no WSetEna read-back check: a force can be recorded as sent when it did not take | ||
| ACT-15 | actions · What is written | yes / untested | yes / untested | differs: DC: bridge watchdog releases; hardware timer called cosmetic in a code comment (unverified) | behavioural (battery): WSetRvrtTms not written (the library writes WSetEna/WSetMod/WSetPct only); PICS Issue 4 calls it cosmetic | ||
| ACT-16 | actions · What is written | yes / unclear | no | missing here: no staging in the scheduler path | Unknown: none found; the force here is one BatteryCommand (battery_control.py:534), no staging |
||
| ACT-17 | actions · Parameters you can set only through the API | yes / tested | yes / untested | differs: DC time limit is always duration_min x 60; hidden 90 min in Recurring windows | behavioural (battery): time limit = duration_min x 60, hidden 90 min in windows | #160 | |
| ACT-18 | actions · Parameters you can set only through the API | yes / untested | yes / untested | differs: DC target SoC is in the form; checked every 5 s from the poller | variance: same release rule at the same 5 s cadence; target in the form here | ||
| ACT-19 | actions · Parameters you can set only through the API | yes / untested | yes / untested | differs: DC form keeps the whole action object | behavioural (battery): form save keeps API-only keys (the Modbus Bridge drops target_soc): different force end |
||
| ACT-20 | actions · Battery actions: Force Standby | yes / tested | yes / untested | same: DC still needs a ready Modbus client (this bridge) | |||
| ACT-21 | actions · Battery actions: Release | yes / untested | no | missing here: no Release action | Not ported: #162 ("a Release action"); SCHEDULE-AND-AUTOMATIONS | #162 | |
| ACT-22 | actions · Non-battery actions: Reserve and Operating Mode | yes / tested | yes / tested | same: DC picker tou/self/backup from gateway work modes | |||
| ACT-23 | actions · Non-battery actions: Reserve and Operating Mode | yes / untested | yes / untested | differs: DC checks nothing; missing mode fails at run | behavioural (device/HA): missing mode accepted, fails and retries at run | ||
| ACT-24 | actions · Non-battery actions: Reserve and Operating Mode | yes / untested | yes / unclear | same: DC also logs a rejected mode or off-grid write as fired | #191 | ||
| ACT-25 | actions · Non-battery actions: Reserve and Operating Mode | yes / tested | no | missing here: no write-lock tracking | Depends on: read-back of command results #139: a 1727 write can be accepted (result:0) and not applied (PROTOCOL.md) |
||
| ACT-26 | actions · Non-battery actions: Reserve and Operating Mode | yes / untested | yes / untested | same: DC: If busy is force-only; same-tick priority still applies | |||
| ACT-27 | actions · No battery action (HA only) | yes / tested | yes / tested | same: none | |||
| ACT-28 | actions · No battery action (HA only) | yes / untested | yes / untested | differs: DC Run now runs the fire-phase HA actions | behavioural (device/HA): Run now runs HA actions of HA-only schedules | ||
| ACT-29 | actions · Summary | no | yes / tested | Direct Connect only: Unknown action kind at run is skipped and logged fired | |||
| ACT-30 | actions · Battery actions: Force Charge and Force Discharge | no | yes / untested | Direct Connect only: Force refused unless a SunSpec read through the Modbus client (this bridge) succeeds | |||
| ACT-31 | actions · Battery actions: Force Charge and Force Discharge | no | yes / tested | Direct Connect only: No host: force skipped | |||
| ACT-32 | actions · Non-battery actions: Reserve and Operating Mode | no | yes / tested | Direct Connect only: reserve_soc always skipped, logged fired | #129 | ||
| ACT-33 | actions · Smart circuits, off-grid and notify (Direct Connect only) | no | yes / tested | Direct Connect only: Smart circuit write with read-back; NOT confirmed retried | |||
| ACT-34 | actions · Smart circuits, off-grid and notify (Direct Connect only) | no | yes / tested | Direct Connect only: On/Off read strictly since 0.5.5; before it, Off ran as on | #188 (fixed in 0.5.5) | ||
| ACT-35 | actions · Smart circuits, off-grid and notify (Direct Connect only) | no | yes / untested | Direct Connect only: Off-grid action with SoC, no confirm | |||
| ACT-37 | actions · Summary | no | yes / tested | Direct Connect only: smart_circuit_schedule listed unavailable with reason | |||
| ACT-38 | actions · Battery actions: Force Charge and Force Discharge | no | yes / untested | Direct Connect only: Force disabled in the form with the reason when the Modbus client (this bridge) is unavailable | |||
| ACT-39 | actions · What is written | no | yes / unclear | Direct Connect only: One in-memory force for the whole bridge; a second gateway's force drops the first's watchdog | #194 | ||
| ACT-40 | actions · What is written | no | yes / untested | Direct Connect only: Up to 5 attempts with sleeps inside one tick; blocks all gateways | #197 | ||
| ACT-41 | actions · What is written | no | yes / unclear | Direct Connect only: UNKNOWN verdict unreachable for scheduler actions | #201 | ||
| ACT-42 | actions · What is written | no | yes / unclear | Direct Connect only: Retry deadline falls to 1 s for Always and zero-duration windows | #209 | ||
| HAA-01 | actions · Home Assistant actions | yes / untested | yes / tested | differs: DC saves anything; skips with a reason at run Modbus Bridge check (their PR #233): its import skips validation too (their #232), so invalid actions can be saved there as well. | behavioural (device/HA): invalid HA actions saved; skipped at run | #202 | |
| HAA-02 | actions · Home Assistant actions | yes / untested | yes / untested | differs: DC form saves incomplete rows | behavioural (record): incomplete rows kept and skipped at run with a reason | ||
| HAA-03 | actions · When they run | yes / tested | yes / untested | same: DC: after the battery action whatever its result (HAA-07) | |||
| HAA-04 | actions · When they run | yes / tested | yes / untested | same: none | |||
| HAA-05 | actions · When they run | yes / tested | yes / untested | same: none | |||
| HAA-06 | actions · When they run | yes / tested | yes / unclear | differs: DC: at every closing edge of the window, even if never fired; not on Stop or an in-window end | behavioural (device/HA): exit HA actions run at every window close, even if never fired | #189 | |
| HAA-07 | actions · When they run | yes / untested | yes / unclear | differs: DC runs them on every attempt | behavioural (device/HA): on-entry HA actions repeat on every retry | #203 | |
| HAA-08 | actions · Guards | yes / tested | yes / untested | differs: DC skips silently, no log; API also accepts a tree | behavioural (record): guard skip leaves no log row | ||
| HAA-09 | actions · Placeholders in notifications | yes / tested | yes / tested | same: DC prints numbers as stored (no .0 trimming) | |||
| HAA-10 | actions · Placeholders in notifications | yes / untested | yes / untested | differs: DC: dotted ids work, ha: ids do not | behavioural (record): %ha:…% placeholders not substituted |
#169 | |
| HAA-11 | actions · Failure alerts | yes / tested | no | missing here: no failure notifications | Not ported: #172 (notifier not passed to the outcome path) | #172 | |
| HAA-12 | actions · What is logged | yes / tested | yes / untested | differs: DC folds results into the fired/exit/manual row; failures rarely fail the run | behavioural (record): HA failures folded into the run row; rarely fail the run | ||
| HAA-13 | actions · Failure alerts | no | yes / untested | Direct Connect only: run_action_outcome called without notifier | #172 | ||
| HAA-14 | actions · Placeholders in notifications | no | yes / tested | Direct Connect only: Placeholders also in service entity_id and data | |||
| HAA-15 | actions · Home Assistant actions | no | yes / tested | Direct Connect only: Raw service with bad JSON is skipped with the reason | |||
| HAA-16 | actions · Home Assistant actions | no | yes / tested | Direct Connect only: Guided entity action calls domain.service with entity and data | |||
| HAA-17 | actions · Placeholders in notifications | no | yes / tested | Direct Connect only: %run.%, %schedule.%, %gateway.id% variables | |||
| HAA-18 | actions · Home Assistant actions | no | yes / untested | Direct Connect only: Notify as a battery action kind | |||
| TGT-01 | targets · Pick a target | yes / untested | yes / tested | differs: DC: bound schedule only on its gateway's tick; not evaluated while stale/disabled | behavioural (battery): a stale or disabled gateway's schedules are not evaluated | ||
| TGT-02 | targets · Pick a target | yes / untested | yes / untested | differs: DC: API-only gateway_scope all; no Site target in the form | behavioural (display): site fan-out only through the API | #162 | |
| TGT-03 | targets · Pick a target | yes / untested | no | missing here: no utility-service target | Not ported: ORCH 2b (Target = Service); #162 | #162 | |
| TGT-04 | targets · How a fan-out works | yes / tested | yes / tested | same: DC: occurrence and resource claim per gateway | |||
| TGT-05 | targets · How a fan-out works | yes / tested | yes / untested | same: DC: per gateway:entry; but see TGT-20 and ACT-39 | |||
| TGT-06 | targets · How a fan-out works | yes / tested | yes / untested | differs: History rows do not name the gateway | behavioural (record): History rows do not name the gateway | #205 | |
| TGT-07 | targets · How a fan-out works | yes / untested | yes / unclear | same: DC: a stale/disabled gateway gets no window-end release either | |||
| TGT-08 | targets · How a fan-out works | yes / untested | yes / tested | same: DC: stale/disabled gateway skipped with a debug log only | |||
| TGT-09 | targets · How a fan-out works | yes / untested | yes / unclear | differs: DC Run now: one gateway, and the top-bar gateway overrides the bound one | behavioural (battery): Run now forces the top-bar gateway, not the schedule's | #193 | |
| TGT-10 | targets · Entries with no target id | yes / untested | yes / untested | differs: DC unbound = first-registered gateway, unstored | behavioural (battery): unbound = first registered gateway, which moves | #182 | |
| TGT-11 | targets · Entries with no target id | yes / unclear | yes / untested | differs: DC: unbound claims the tick gateway, same group as bound | behavioural (battery): unbound and bound contend as one group (two groups there) | ||
| TGT-12 | targets · In the form | yes / unclear | no | missing here: no service select | Depends on: service target (TGT-03) | ||
| TGT-13 | targets · In the form | yes / untested | no | missing here: no mock warning in the form | Unknown: none found | ||
| TGT-14 | targets · In the form | yes / tested | yes / tested | same: none | |||
| TGT-15 | targets · On the timeline | yes / untested | yes / untested | differs: DC timeline ignores gateway; one list | behavioural (display): timeline is one list, not per gateway | #161 | |
| TGT-16 | targets · How a fan-out works | yes / unclear | no | missing here: n/a; see TGT-07 | Depends on: run ownership (EXT-06, #189) and site/service targets | ||
| TGT-17 | targets · Entries with no target id | no | yes / unclear | Direct Connect only: Disabled first gateway: unbound schedules run nowhere | #182 | ||
| TGT-18 | targets · In the form | no | yes / tested | Direct Connect only: Mock gateways skip the 702 ratings read | |||
| TGT-19 | targets · In the form | no | yes / untested | Direct Connect only: Test against live always uses the default gateway | |||
| TGT-20 | targets · How a fan-out works | no | yes / unclear | Direct Connect only: Stop, Pause, shutdown and boot reconcile use the default gateway's host | #192 | ||
| TGT-21 | targets · Pick a target | no | yes / untested | Direct Connect only: Gateway select only with >1 gateway; Default gateway = empty id | |||
| TGT-22 | targets · Pick a target | no | yes / untested | Direct Connect only: Schedule bound to an unknown gateway id never runs, silently | |||
| TGT-23 | targets · Pick a target | no | yes / tested | Direct Connect only: gateway_scope survives a form save (#157 fix) | #157 | ||
| EXT-01 | exit-and-conflicts · How a run ends | yes / tested | yes / tested | differs: DC releases at every force entry's window close, owned or not; logged exit 'window closed' | behavioural (battery): window close releases a force it never sent or does not own | #189 | |
| EXT-02 | exit-and-conflicts · How a run ends | yes / tested | yes / tested | same: none; DC marks the occurrence fired | |||
| EXT-03 | exit-and-conflicts · How a run ends | yes / tested | yes / tested | differs: DC uses per-occurrence keys instead of clearing a mark | variance: per-occurrence keys vs clearing a mark: both fire again next window | ||
| EXT-04 | exit-and-conflicts · How a run ends | yes / tested | yes / untested | differs: DC: disable releases on next tick; delete does not release | behavioural (battery): delete does not release the running force | #195 | |
| EXT-05 | exit-and-conflicts · How a run ends | yes / unclear | yes / unclear | differs: DC never hands over; it always releases, even another's force | behavioural (battery): never hands over; releases another's force | #189 | |
| EXT-06 | exit-and-conflicts · How a run ends | yes / unclear | no | missing here: no ownership hand-over in DC | Not ported: #189 (no ownership: window end releases a force it does not own) | ||
| EXT-07 | exit-and-conflicts · Exit conditions | yes / tested | yes / tested | differs: DC does not start when exit already holds | behavioural (battery): exit already true: no start here; a brief force there | ||
| EXT-08 | exit-and-conflicts · Exit conditions | yes / tested | yes / tested | same: none (DC plain release) | |||
| EXT-09 | exit-and-conflicts · Exit conditions | yes / untested | yes / untested | differs: DC evaluates exit for every action kind while the window is open | behavioural (device/HA): exit evaluated for every action kind (mode, HA-only) | ||
| EXT-10 | exit-and-conflicts · Exit conditions | yes / untested | yes / tested | differs: DC detail names no rows | behavioural (record): exit row names no condition | ||
| EXT-11 | exit-and-conflicts · Release policy | yes / tested | no | missing here: no release policies; always plain release | Not ported: ORCH 2b (on-exit release policy); #162 | #162 | |
| EXT-12 | exit-and-conflicts · Release policy | yes / tested | yes / untested | differs: DC restore_on_exit (API only) writes the captured mode back, set_mode schedules only; end-to-end untested | behavioural (device/HA): restore_on_exit writes the mode back (the Modbus Bridge only audits) |
#162 | |
| EXT-13 | exit-and-conflicts · Release policy | yes / tested | no | missing here: not in DC | Not ported: ORCH 2b (release policy); #162 | #162 | |
| EXT-14 | exit-and-conflicts · Release policy | yes / tested | no | missing here: no policies; DC Stop never restores | Not ported: ORCH 2b (release policy); #162 | #162 | |
| EXT-15 | exit-and-conflicts · Release policy | yes / untested | no | missing here: no field | Depends on: release policy (EXT-11) | ||
| EXT-16 | exit-and-conflicts · Release policy | yes / untested | no | missing here: no such migration | Depends on: release policy (EXT-11); the migration is the Modbus Bridge's own | ||
| EXT-17 | exit-and-conflicts · What a release does on the gateway | yes / tested | yes / untested | differs: DC release has no read-back; refused when Modbus client off | behavioural (battery): Release refused when the Modbus client (this bridge) is off; no read-back | #174 | |
| EXT-18 | exit-and-conflicts · Hold instead of release (API only) | yes / tested | no | missing here: no hold | Not ported: #162 ("hold instead of release") | #162 | |
| EXT-19 | exit-and-conflicts · Hold instead of release (API only) | yes / unclear | no | missing here: no hold | Depends on: hold (EXT-18) | ||
| EXT-20 | exit-and-conflicts · Bridge shutdown | yes / untested | yes / unclear | differs: DC releases the in-memory force to the first gateway's host, not the force's host | behavioural (battery): shutdown releases to the first gateway's host | #192 | |
| EXT-21 | exit-and-conflicts · How a run ends | no | yes / unclear | Direct Connect only: DC: deleting a running schedule does not release its force | #195 | ||
| EXT-22 | exit-and-conflicts · Exit conditions | no | yes / tested | Direct Connect only: nested exit groups (MB also supports; tested here) | |||
| EXT-24 | exit-and-conflicts · How a run ends | no | yes / unclear | Direct Connect only: flapping exit conditions repeat Release and exit HA actions | #189 | ||
| EXT-25 | exit-and-conflicts · How a run ends | no | yes / unclear | Direct Connect only: force watchdog uses hidden duration_min in Recurring windows | #160 | ||
| EXT-26 | exit-and-conflicts · How a run ends | no | yes / untested | Direct Connect only: bridge watchdog enforces duration and target SoC every 5 s | |||
| EXT-27 | exit-and-conflicts · Release policy | no | yes / tested | Direct Connect only: restore_on_exit captures mode before first attempt | |||
| EXT-28 | exit-and-conflicts · Release policy | no | yes / tested | Direct Connect only: PUT merge keeps restore_on_exit | #157 | ||
| PRI-01 | priorities · Priorities and conflicts | yes / untested | yes / untested | differs: DC: any integer, free-text conflict (unknown = override), default override Modbus Bridge check (their PR #233): its import skips validation (their #232); the default and unknown-value handling are as their code, not their old markers. | behavioural (battery): default If busy = override (there: defer); unknown values act as override | ||
| PRI-02 | priorities · Entries on the same target | yes / tested | yes / tested | differs: DC: contest only among entries ready on the same tick, per resource | behavioural (battery): contest only within a tick, per resource | ||
| PRI-03 | priorities · Entries on the same target | yes / untested | yes / untested | differs: DC: later-ready entries judged only by If busy; override (default) pre-empts regardless of priority; mode entries never checked | behavioural (battery): a later-ready force overrides a running one whatever the priority | #196 | |
| PRI-04 | priorities · Entries on the same target | yes / untested | yes / untested | same: none (untested in both) | |||
| PRI-05 | priorities · Entries on the same target | yes / untested | yes / tested | same: DC: mode only claims on its fire tick | |||
| PRI-06 | priorities · Entries on the same target | yes / tested | yes / tested | differs: DC logs deferred, settles the occurrence skipped, no re-fire that occurrence | behavioural (battery): a loser does not fire again that occurrence | ||
| PRI-07 | priorities · Manual control | yes / tested | yes / tested | differs: DC: active dispatches rows of another schedule or _widget; force winners only | behavioural (battery): busy = only dispatch rows of schedules or the widget; mode entries unchecked | ||
| PRI-08 | priorities · Manual control | yes / tested | yes / tested | differs: DC defer marks the day done; wait logs every tick and retries | behavioural (battery): defer gives up for the day; wait retries each tick | ||
| PRI-09 | priorities · Manual control | yes / tested | yes / tested | same: none | |||
| PRI-10 | priorities · Manual control | yes / untested | yes / untested | differs: DC: only wait does; defer gave up for the day | behavioural (battery): after a manual command ends, a deferred entry does not run | ||
| PRI-11 | priorities · What the bridge cannot see | yes / untested | yes / untested | same: none (both dispatch over it) | |||
| PRI-12 | priorities · What the bridge cannot see | yes / unclear | no | missing here: no ownership in DC | Depends on: run ownership (EXT-06, #189) | ||
| PRI-13 | priorities · Entries on different targets | yes / unclear | yes / tested | differs: DC has gateway binding and scope all; claims per gateway on its tick | behavioural (battery): claims per gateway, not per target | ||
| PRI-14 | priorities · Who sent what (requester) | yes / tested | yes / tested | differs: DC records schedule id or _widget in the dispatches table only; no control-log requester | behavioural (record): requester only in the dispatches table | ||
| PRI-15 | priorities · What the bridge cannot see | yes / unclear | no | missing here: no supervision in DC | Depends on: supervision (OUT-07 to OUT-11) | #162 | |
| PRI-16 | priorities · Manual control | no | yes / tested | Direct Connect only: wait retries every tick (MB: wait = defer) | |||
| PRI-17 | priorities · Entries on the same target | no | yes / tested | Direct Connect only: per-resource claims: grid, per-circuit, wildcard merge, unknown kind | |||
| PRI-18 | priorities · Entries on the same target | no | yes / tested | Direct Connect only: notify/none claims nothing (MB: own lane, equivalent) | |||
| PRI-19 | priorities · Manual control | no | yes / unclear | Direct Connect only: defer marks the date, so interval/cron/window#n entries defer and log every tick | #204 | ||
| OUT-01 | outcomes · Activity Log results | yes / tested | yes / untested | differs: DC logs a word only; import writes no row | behavioural (record): config changes logged as one word; import not logged | ||
| OUT-02 | outcomes · Activity Log results | yes / tested | yes / tested | same: DC also filters severity | |||
| OUT-03 | outcomes · Activity Log results | yes / untested | yes / untested | differs: DC History loads 200 rows, chips per status present; fired is used | variance: History view length and chips only | ||
| OUT-04 | outcomes · Retries | yes / tested | yes / tested | differs: DC 30 s doubling to 600 s, plus in-tick resilience retries; no notification | behavioural (battery): retry 30 s doubling to 600 s (there: 15, 30, 60 s); no notification | #172 | |
| OUT-05 | outcomes · Retries | yes / tested | yes / tested | differs: DC logs plain fired; no notification | behavioural (record): recovery logged as plain fired; no notification | #172 | |
| OUT-06 | outcomes · Retries | yes / untested | yes / untested | same: DC settles it skipped | |||
| OUT-07 | outcomes · Supervision of a running command | yes / tested | no | missing here: no supervision | Not ported: #162 ("dispatch verification and re-send") | #162 | |
| OUT-08 | outcomes · Supervision of a running command | yes / tested | no | missing here: no supervision | Not ported: #162; the force uses the same WSet model 704 on the Modbus TCP Server (aGate :502) (battery_control.py:1-7), so not a transport limit |
#162 | |
| OUT-09 | outcomes · Supervision of a running command | yes / tested | no | missing here: no supervision | Not ported: #162 | #162 | |
| OUT-10 | outcomes · Supervision of a running command | yes / tested | no | missing here: no supervision | Not ported: #162 | #162 | |
| OUT-11 | outcomes · Supervision of a running command | yes / tested | no | missing here: no supervision | Not ported: #162 | #162 | |
| OUT-12 | outcomes · Supervision of a running command | yes / untested | no | missing here: no supervision | Depends on: supervision (OUT-07) | #162 | |
| OUT-13 | outcomes · The dispatch record | yes / tested | yes / tested | differs: DC dispatches table: successful forces only (schedule, Run now, widget) | behavioural (record): dispatch record holds successful forces only | #139 | |
| OUT-14 | outcomes · The dispatch record | yes / untested | no | missing here: no verification states | Depends on: supervision (OUT-07) and an outcome record #139 | #162 | |
| OUT-15 | outcomes · The dispatch record | yes / untested | yes / untested | same: none | |||
| OUT-16 | outcomes · The dispatch record | yes / tested | no | missing here: no REST read of dispatches | Not ported: #139 | #139 | |
| OUT-17 | outcomes · Overshoot guard | yes / tested | no | missing here: no overshoot guard | Not ported: #162 ("an overshoot guard") | #162 | |
| OUT-18 | outcomes · Notifications | yes / tested | yes / unclear | differs: no scheduler failure notifications; only boot reconcile notify | behavioural (record): no failure notifications | #172 | |
| OUT-19 | outcomes · Run now and Stop | yes / untested | yes / untested | differs: DC active_now also needs fired this occurrence; container clock | behavioural (display): Stop shown on a different rule, container clock | #161 | |
| OUT-20 | outcomes · Run now | yes / tested | yes / untested | differs: DC Run now ignores conditions entirely | behavioural (battery): Run now ignores conditions (by design per #162) | #162 | |
| OUT-21 | outcomes · Run now | yes / untested | yes / untested | same: DC uses duration_min (hidden 90 for windows) | #160 | ||
| OUT-22 | outcomes · Run now | yes / untested | yes / untested | same: none | |||
| OUT-23 | outcomes · Run now | yes / untested | yes / untested | same: DC also runs disabled entries | |||
| OUT-24 | outcomes · Stop | yes / tested | yes / unclear | differs: DC Stop: plain Release via default gateway host, no exit HA actions, no block needed | behavioural (battery): Stop releases via the first gateway's host; no exit HA actions | #192 | |
| OUT-25 | outcomes · Stop | yes / untested | yes / untested | differs: DC Stop with nothing changes nothing; entry may still fire | behavioural (battery): Stop with nothing running does not block the window; the entry can still fire | ||
| OUT-26 | outcomes · The dispatch record | no | yes / untested | Direct Connect only: scheduled/Run now force writes a dispatches row | |||
| OUT-27 | outcomes · Run now | no | yes / untested | Direct Connect only: Run now force recorded, so Stop and If busy see it (MB: Stop does not see Run now) | |||
| OUT-28 | outcomes · Run now | no | yes / unclear | Direct Connect only: UI Run now uses the top-bar gateway over the bound one | #193 | ||
| OUT-29 | outcomes · Retries | no | yes / tested | Direct Connect only: missed sweep after 120 s grace (MB: catch-up instead) | |||
| OUT-30 | outcomes · Activity Log results | no | yes / tested | Direct Connect only: coalesced backlog runs | |||
| OUT-31 | outcomes · Retries | no | yes / tested | Direct Connect only: unknown outcome settles, not retried | |||
| OUT-32 | outcomes · Retries | no | yes / unclear | Direct Connect only: unknown is unreachable from the action path | #201 | ||
| OUT-33 | outcomes · Retries | no | yes / unclear | Direct Connect only: in-tick resilience retries block the scheduler thread | #183 | ||
| OUT-34 | outcomes · Retries | no | yes / unclear | Direct Connect only: refused force / rejected mode logged fired (text classification) | #191 | ||
| OUT-35 | outcomes · Retries | no | yes / unclear | Direct Connect only: per-attempt audit sink signature mismatch | #201 | ||
| OUT-36 | outcomes · Run now and Stop | no | yes / unclear | Direct Connect only: Pause ineffective | #200 | ||
| OUT-37 | outcomes · Run now and Stop | no | yes / tested | Direct Connect only: Resume only inside the window | |||
| OUT-38 | outcomes · Run now and Stop | no | yes / tested | Direct Connect only: paused runs become stopped at restart | |||
| OUT-39 | outcomes · Where to look | no | yes / tested | Direct Connect only: run queue /runs and /stats | |||
| OUT-40 | outcomes · Activity Log results | no | yes / tested | Direct Connect only: log severity classes with per-class caps | |||
| OUT-41 | outcomes · Activity Log results | no | yes / tested | Direct Connect only: 'nothing to do' still logged | |||
| OUT-42 | outcomes · Retries | no | yes / tested | Direct Connect only: error row names attempt and retry delay | |||
| OUT-43 | outcomes · Run now | no | yes / untested | Direct Connect only: Run now placeholders limited to gateway + HA values | |||
| CLK-01 | restarts-and-clock · The clock | yes / untested | yes / tested | differs: DC: each gateway's aGate clock (site time) | behavioural (battery): each gateway's aGate clock: fire times differ when the container clock is not site time | ||
| CLK-02 | restarts-and-clock · The clock | yes / untested | yes / unclear | differs: DC: previews on container clock, tick on site clock | behavioural (display): previews on the container clock | #161 | |
| CLK-03 | restarts-and-clock · The clock | yes / tested | yes / tested | differs: DC: site timezone setting for mocks; no install check | variance: the tick here uses the aGate clock, so the install timezone check has nothing to guard | ||
| CLK-04 | restarts-and-clock · Daylight saving | yes / unclear | yes / unclear | differs: DC: fixed offset re-read every 10 min; late by up to 10 min | behavioural (battery): DST change applies up to 10 min late | ||
| CLK-05 | restarts-and-clock · The clock | no | yes / tested | Direct Connect only: unreadable gateway falls back to container clock, not UTC | |||
| CLK-06 | restarts-and-clock · The clock | no | yes / tested | Direct Connect only: implausible aGate clock refused | |||
| RST-01 | restarts-and-clock · Bridge restart | yes / tested | yes / untested | differs: DC releases only the in-memory force, to the first gateway's host | behavioural (battery): restart releases only the in-memory force, to the first gateway's host | #192 | |
| RST-02 | restarts-and-clock · Bridge restart | yes / untested | yes / tested | differs: DC: reconcile policy, default notify (battery untouched) | behavioural (battery): start-up default is notify: a force left by a crash keeps running (there: released) | ||
| RST-03 | restarts-and-clock · Bridge restart | yes / tested | yes / tested | differs: DC: a fired occurrence is stored, no re-fire | behavioural (battery): stored occurrence: no re-fire after restart (there: re-dispatches) | ||
| RST-04 | restarts-and-clock · Bridge restart | yes / untested | yes / unclear | differs: DC: release_stale never called; no catch-up | behavioural (battery): release_stale() never called |
#199 | |
| RST-05 | restarts-and-clock · Bridge restart | no | yes / tested | Direct Connect only: paused runs resolved to stopped at start-up | |||
| RST-06 | restarts-and-clock · Bridge restart | no | yes / tested | Direct Connect only: release/resume policies re-arm or re-force | |||
| RST-07 | restarts-and-clock · Bridge restart | no | yes / untested | Direct Connect only: with notify a force outlives a restart; timer lost | |||
| RST-08 | restarts-and-clock · Bridge restart | no | yes / unclear | Direct Connect only: reconcile and shutdown handle only the first gateway | #192 | ||
| DEP-01 | dependencies · Dependency matrix → Actions | no | yes / untested | same: none (untested here) | #128 | ||
| — | dependencies · A Home Assistant action did not run | no | section | Direct Connect only: kept from the old troubleshooting page | #169 #171 | ||
| — | dependencies · A condition is always true when it should not be | section | section | differs: DC: tariff windows read None when unconfigured; grid.connected reads 0 at 0 W; before 0.5.4 an unavailable HA entity read 0 (#167) | behavioural (battery): conditions can pass when they should not (#206) | #206 | |
| — | dependencies · An action is refused or does nothing | section | section | differs: a force refused by the Modbus client path, and a mode/off-grid write with a non-zero result, are logged fired | behavioural (battery): refused writes logged fired (#191) | #191 | |
| — | dependencies · An entry never fires | section | section | differs: DC Always runs once ever (occurrence stays done across restarts) | behavioural (battery): Always fires once ever (#190) | #190 | |
| — | dependencies · Dependency matrix | section | section | differs: DC: force needs the Modbus client (this bridge); reserve never runs (#129); no trusted-rating gate | behavioural (battery): force needs the Modbus client (this bridge): :9000 has no battery force (transport limit, HYBRID-CAPABILITIES); reserve write never runs (#129): 1405 is cloud-only (PROTOCOL.md) | #129 | |
| — | examples · 1. Evening top-up | section | section | differs: weekly fire-at+duration (#160); power in % or kW (W API only); target SoC field | behavioural (battery): hidden duration ends the force (#160) | #160 | |
| — | examples · 2. Evening peak discharge until the minimum SoC | section | section | differs: daily 17:00 + 240 min because of #160 | behavioural (battery): workaround for #160 changes the window | #160 | |
| — | examples · 3. Charge from the grid when the NEM spot price is low | section | section | same: stale NEM price kept forever | #207 | ||
| — | examples · 4. Storm forecast: fill the battery | section | section | differs: weather.code not in the picker; condition text unverified | needs owner: needs owner: is weather.condition text "thunder" right, or should the example use weather.code? |
||
| — | examples · 5. Peak-demand window | section | section | differs: window flag None when undefined; overlapping force schedules release each other | behavioural (battery): overlapping force schedules release each other (#189) | #189 | |
| — | examples · 6. Weekend export, unless Home Assistant says you are away | section | section | same: since 0.5.4 an unavailable entity has no value, as in the Modbus Bridge | #167 (fixed in 0.5.4) | ||
| — | examples · 7. Full by 07:00, starting as late as possible | section | no | missing here: no time.* sensors; one cron schedule per rung instead | Depends on: time.* sensors (SEN-01), SENSOR-PARITY §A |
#162 | |
| — | examples · More examples (Direct Connect only) | no | section | Direct Connect only: template-based recipes moved from the old troubleshooting page |
Existing issues this page touches¶
| Issue | Where |
|---|---|
| #157 Turning a schedule on/off wiped its settings | Fixed in 0.5.2: a PUT merges what it sends into the stored schedule (index). |
| #160 A force in a Recurring window stops at the hidden duration | triggers, actions, exit |
| #161 Timeline, next fire and Test use the container clock | restarts-and-clock |
| #162 Scheduler parity with the Modbus Bridge | most missing here rows |
| #167 An unavailable HA entity read 0 | Fixed in 0.5.4: it now has no value (conditions). |
#168 PUT without enabled re-enables |
index |
#169 %ha:…% placeholders are not substituted |
actions |
| #129 reserve_soc is always skipped | actions |
| #172 No failure notification | outcomes |
| #182 The default gateway is the first registered and moves | targets |
| #165, #171, #173, #174, #175, #183 | release button, notification switch, dispatch notifications, Release read-back, worker restart guard, scheduler heartbeat |
Issues filed from this review¶
Each was found while writing the Scheduler pages, from a code read; the ones marked
reproduced were confirmed by driving scheduler.tick with a temporary store and a
monkeypatched battery_control.execute (no hardware, no emulator, so not evidence of what an
aGate does). The Test against live point (it reads the default gateway's values) was added
to #161.
| Issue | Title | Evidence | Rows |
|---|---|---|---|
| #188 | Scheduler on/off picker stores "false" as text, which runs as on: smart circuit turns ON, Go off-grid / reconnect goes OFF-GRID (fixed in 0.5.5) | reproduced in the engine; the form path is a code read | ACT-34 |
| #189 | A force schedule's window end sends Release even if it never fired, or after another schedule or the Battery Control widget took the battery; exit HA actions run too; flapping exit conditions repeat both | reproduced | HAA-06, EXT-01, EXT-05, EXT-24 |
| #190 | An Always schedule fires only once, ever (its single stored run stays finished), yet keeps sending Release on every falling edge | reproduced | TRG-28, TRG-29 |
| #191 | A force refused by the Modbus client (this bridge), and a mode or off-grid write the aGate rejects, are logged "fired" and never retried | reproduced | ACT-13, ACT-24, OUT-34 |
| #192 | Stop, Pause, the shutdown release and the boot reconcile use the first gateway's host, not the host the force was recorded on | code read | TGT-20, EXT-20, OUT-24, RST-01, RST-08 |
| #193 | Run now from the UI acts on the top-bar gateway, not the schedule's own gateway | code read | TGT-09, OUT-28 |
| #194 | battery_control supervises one force per process: a second gateway's force drops the first one's time limit and target SoC | code read | ACT-39 |
| #195 | Deleting a running schedule does not release its force | reproduced | EXT-04, EXT-21 |
| #196 | Priority only counts on the same tick: a force that becomes ready later overrides a running one whatever their priorities (default If busy = override) | reproduced | PRI-03 |
| #200 | Pause does not hold a run: the tick re-attempts paused runs, and a run that already succeeded is not found | reproduced | IDX-12, OUT-36 |
| #197 | Force retries sleep inside the scheduler tick and stall every gateway (cf. #183) | code read | ACT-40 |
| #201 | The scheduler can never record an UNKNOWN outcome, and its resilience audit hook never writes (signature mismatch) | reproduced | ACT-41, OUT-32, OUT-35 |
| #198 | Weekly with no days, Monthly with no day of month, and One-off with no date fire every day; a Recurring window with start = end is open all day | reproduced | TRG-09, TRG-23, TRG-51 |
| #202 | Validate actions, HA actions, cron, day of month and months when a schedule is saved; import should flag unknown sensors and operators | code read | CND-02, CND-35, ACT-02, HAA-01 |
| #203 | On-entry HA actions repeat on every retry, and a retry waits the whole hold again | code read | CND-27, HAA-07 |
| #204 | If busy = defer re-defers and logs every tick for interval, cron and second-window schedules | code read | PRI-19 |
| #205 | History rows should name the gateway (gateway scope "all" rows cannot be told apart) | code read | TGT-06 |
| #206 | grid.connected reads 0 whenever grid power is exactly 0 W | code read | SEN-04 |
| #207 | A stale AEMO NEM price is kept forever when the fetch fails | code read | SEN-10, SEN-19 |
| #208 | Every N minutes of 24 h or more: Next shows anchor + N, the engine fires at the anchor | reproduced | TRG-19 |
| #199 | battery_control.release_stale() is never called; start-up relies on the reconcile policy alone | code read | RST-04 |
| #209 | An empty power sent through the API is a 0 W force; Always and zero-duration schedules get a 1-second retry deadline | code read | ACT-04, ACT-42 |