Commit Graph
100 Commits
Author SHA1 Message Date
adminandClaude Opus 5.5 848140c29f SAFETY-107 review: test a writer that turns round on a dead pack; say when rule 3 applies
checks / unit (pull_request) Successful in 35m22s
infra-pin / fresh (pull_request) Successful in 2s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 03:52:39 +02:00
admin bf3ac7998c MAINT-14: maintenance with no SoC reading: charge still times out, drain holds at 0 W (#182)
infra-pin / fresh (push) Successful in 2s
2026-10-08 22:50:52 +02:00
adminandClaude Opus 5.5 61a61941bb MAINT-14 review: tests for a HOLD episode after a no-SoC charge, a MAINT-13 state file, and a true twin site at N=2
checks / unit (pull_request) Successful in 34m56s
infra-pin / fresh (pull_request) Successful in 1s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 22:14:26 +02:00
admin 8a17711f60 MAINT-13: a full pack that stops at 98-99 % is not a failed charge (#181)
infra-pin / fresh (push) Successful in 2s
2026-10-08 13:45:10 +02:00
adminandClaude Opus 5.5 ea31289ec0 MAINT-13 review: tests for a stale charge record and a clock step back; DOCS names the 7 day end
infra-pin / fresh (pull_request) Successful in 2s
checks / unit (pull_request) Successful in 34m49s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:08:40 +02:00
admin b527e99f13 SAFETY-103: no swing on old battery readings after a drain ends (#180)
infra-pin / fresh (push) Successful in 2s
2026-10-08 04:48:26 +02:00
adminandClaude Opus 5.5 c6f23a69d4 SAFETY-103 review: correct the swing after a refusal or lost link in DECISIONS
checks / unit (pull_request) Successful in 34m52s
infra-pin / fresh (pull_request) Successful in 2s
The test table gives 1.5 kW at N=2 and 3.9 kW summed at N=3 under a
surplus, and about 1 kW after a lost link without one; not 1.9 kW.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 04:13:08 +02:00
adminandClaude Opus 5.5 98dd110a4f SAFETY-103: test a dropped battery is not counted; guard a read
checks / unit (pull_request) Successful in 34m26s
infra-pin / fresh (pull_request) Successful in 1s
Mutation M13 (a battery out of the split counted in the house point)
survived; a direct check now kills it. win[0] is read through a guard
(test_named_absence).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 03:12:03 +02:00
adminandClaude Opus 5.5 138e45b53f SAFETY-103: no swing on old battery readings after a drain ends
checks / unit (pull_request) Failing after 35m9s
infra-pin / fresh (pull_request) Successful in 2s
While a battery settles from its ended drain (SAFETY-95), the house point
was grid + every battery's reading. A register can be 10 s older than the
meter, so B swung 860 -> 1650 -> 870 W on A's old reading (rig check 5).

Now the house point is held and moved only as far as the meter proves:
each battery is between its last changed reading and its commands since
(a reading that changed this cycle, or a refused side, as it reads).
N=1 and 1 s registers are byte-identical to release/1.0.

DECISIONS/SAFETY-103-old-readings-after-a-drain.md, test_safety103.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:25:55 +02:00
admin 451729c9b5 Release 0.16.0 (#178)
infra-pin / fresh (push) Successful in 1s
checks / unit (pull_request) Successful in 32m56s
infra-pin / fresh (pull_request) Successful in 2s
2026-10-08 01:02:20 +02:00
admin 340c7eef42 Merge pull request 'SAFETY-95: a maintenance drain that ends hands back smoothly' (#177) from safety-95-drain-end-reseed into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-10-07 17:48:53 +02:00
admin b2f55732b6 Merge pull request 'SAFETY-96: a battery the loop cannot move does not freeze it' (#176) from safety-96-stale-unit-site-total into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-10-06 06:19:12 +02:00
admin 1bf6b7f9a7 Merge pull request 'MAINT-10: maintenance start hour in local time, default 19:00' (#159) from maint-10-local-start-hour into release/1.0
infra-pin / fresh (push) Successful in 2s
2026-10-05 23:56:19 +02:00
admin 7ef73474dc Merge pull request 'SAFETY-90: the peak guard goes on after a P1 meter gap' (#175) from safety-90-peak-guard-gap into release/1.0
infra-pin / fresh (push) Successful in 2s
SAFETY-90: the peak guard goes on after a P1 meter gap (#175)
2026-10-05 13:23:32 +02:00
admin 3ed3302d2f Merge pull request 'Release 0.15.0' (#173) from release-0.15.0 into release/1.0
infra-pin / fresh (push) Successful in 1s
checks / unit (pull_request) Successful in 29m8s
infra-pin / fresh (pull_request) Successful in 1s
Release 0.15.0 (#173)
2026-10-05 01:52:40 +02:00
adminandClaude Opus 5.5 f01152b113 Release 0.15.0: bump version and close the CHANGELOG section
checks / unit (pull_request) Successful in 29m1s
infra-pin / fresh (pull_request) Successful in 1s
config.yaml version 0.14.0 -> 0.15.0 (minor: behaviour change from
SAFETY-94/97, no option change). New `## 0.15.0` section with the contents
since 0.14.0 (cf705a9 #171, 3129dae #172) and the known issues.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 00:48:04 +02:00
admin 3129daed62 Merge pull request 'CI-14: infra-pin to admin/goodwe 3b4ff84 (WITNESS-09)' (#172) from ci-14-infra-pin-3b4ff84 into release/1.0
infra-pin / fresh (push) Successful in 2s
2026-10-05 00:45:15 +02:00
admin cf705a9058 SAFETY-94 + SAFETY-97: no false stale or refusal on a lagging battery; refusals graded against each battery's idle reading (#171)
infra-pin / fresh (push) Failing after 2s
2026-10-04 17:27:20 +02:00
adminandClaude Opus 5.5 7d06aa674d SAFETY-97: centre the band on the idle reading clamped to 75 W
checks / unit (pull_request) Successful in 29m26s
infra-pin / fresh (pull_request) Failing after 2s
Owner decision 2026-10-04 (review R1). A wrong idle reading more than
about 100 W off hid every refusal on that battery. Clamped under the band,
the band keeps 0 W +-25 W, so a battery reading about 0 W while refusing is
caught whatever was learned or restored. Samples are still taken to 250 W.
Beyond about +-170 W of idle a battery behaves as in 0.14.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 16:57:16 +02:00
adminandClaude Opus 5.5 88ebf3a5a6 SAFETY-97 review: tests for four surviving mutants
checks / unit (pull_request) Successful in 28m57s
infra-pin / fresh (pull_request) Failing after 2s
The N=1 stale-path refusal and SAFETY-42's parked test are centred on the
idle reading; learning stops while control is stopped or the sign watchdog
has latched. Each had no check (review mutants X7, X8, X13, X14).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 14:29:27 +02:00
adminandClaude Opus 5.5 3db2b6392f SAFETY-97: test the centred stale-path refusal (mutant S10 survived)
checks / unit (pull_request) Successful in 29m7s
infra-pin / fresh (pull_request) Failing after 1s
At a 5 s meter a register frozen at rest on B trips the stale gate before
the 12-cycle evidence; its refusal must be centred on B's idle reading,
or the site stops and re-trips instead of refusing B.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019DBUfvndgHwaV339Fvd2gr
2026-10-04 13:07:06 +02:00
adminandClaude Opus 5.5 80bfc5721e SAFETY-97: point test_safety97 at MUTATION.md; record the DC-entity option
checks / unit (pull_request) Successful in 29m9s
infra-pin / fresh (pull_request) Failing after 1s
test_bytecode requires every suite to name MUTATION.md (CI run 1158).
DECISIONS: why the integration's DC battery power entity is not the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019DBUfvndgHwaV339Fvd2gr
2026-10-04 12:51:52 +02:00
adminandClaude Opus 5.5 6918e154c8 SAFETY-97: "gives nothing" is graded against each battery's idle reading
checks / unit (pull_request) Failing after 29m7s
infra-pin / fresh (pull_request) Failing after 2s
B's power reading shows -95 to -118 W at idle (standby draw), so the
|reading| < 100 W refusal band never held a refusing B: never at N=2,
and since SAFETY-94's shared rule not at N=1 either (review F1).

Each unit now learns its idle reading (app/idle.py): only while control
runs, the unit is not refused/stale/tripped and its command has stayed
within 50 W for 120 s; first value a 120 s mean, then a 30 min follow;
samples beyond 250 W dropped, value clamped to 250 W; saved per unit and
restored. The shared refusal evidence, compute()'s N=1 engage and end,
the unit refusal ends, the stale-path refusal and SAFETY-42's "parked"
test are centred on it. Until learned it is 0 W, the rule as it was.

Refusing B caught at N=1 28/28/65 s and N=2 24/24/60 s (1/2/5 s
meters), before never; refusing A unchanged. Healthy B with its offset,
SAFETY-94's scenarios, 96 runs: 0 stale, 0 refused. Live replay: 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019DBUfvndgHwaV339Fvd2gr
2026-10-04 12:21:24 +02:00
adminandClaude Opus 5.5 6759d21ea5 SAFETY-94: a healthy battery that lags or reverses is not flagged as frozen or refusing
checks / unit (pull_request) Successful in 28m10s
infra-pin / fresh (pull_request) Failing after 2s
The stale-reading gate counted its 35 s from the register's last change, so
after a rest the first read after a new command tripped it (SAFETY-58; live
2026-10-03, four trips 1 s after the command). It now counts only the time
the command asked the register to move.

At N=1 the refusal engaged after 12 frozen cycles if the reading was under
100 W at that moment, which a battery reversing through its lag passes at a
1 s meter. The refusal now needs the N>1 evidence at every roster size: under
100 W, one way, for 12 cycles spanning 22 s, restarting when the reading
moves 50 W towards the ask.

DECISIONS/SAFETY-94-lagging-battery.md; test_safety94.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 00:15:42 +02:00
admin 02ed1200dc Merge pull request 'Release 0.14.0' (#169) from release-0.14.0 into release/1.0
infra-pin / fresh (push) Successful in 1s
checks / unit (pull_request) Successful in 27m3s
infra-pin / fresh (pull_request) Successful in 2s
2026-10-03 11:29:13 +02:00
admin e51e3e02b2 Merge pull request 'CI-13: infra-pin to admin/goodwe 0c04488 (FW-05, WITNESS-08)' (#168) from ci-13-infra-pin-0c04488 into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-10-03 10:27:02 +02:00
admin 858f77cfb5 Merge pull request 'SAFETY-93: the maintenance charge end hands back smoothly, with no grid charging at a high house' (#167) from safety-93-no-grid-charge-at-charge-end into release/1.0
infra-pin / fresh (push) Failing after 2s
2026-10-03 00:58:37 +02:00
adminandClaude Opus 5.5 214051d1a8 SAFETY-93 review: a charge that ends by a stale link or a refusal hands back smoothly too
checks / unit (pull_request) Successful in 27m5s
infra-pin / fresh (pull_request) Failing after 1s
A battery still in CHARGE but dropped by the allocator (stale link, or a
SAFETY-73 refusal contradicting its charge) left its -2000 W in the loop's
start point, and B went 0 -> -1600 W in one cycle. The end is now noted
after the unit claims are filed: in CHARGE, live and not contradicted.
Tests: part 6 (stale link, refusal) and a spy on the guard suspension.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 00:10:21 +02:00
adminandClaude Opus 5.5 05eb93f139 SAFETY-93: the maintenance charge end hands back smoothly, with no grid charging at a high house
checks / unit (pull_request) Successful in 26m55s
infra-pin / fresh (pull_request) Failing after 1s
At N>=2, when a battery's maintenance charge ended, its watts stayed in the
loop's start point and landed on the other battery (B 0 -> -1600 W in one
cycle, charging from the grid at a 6000 W house). On the cycle a charge
ends, the loop now starts from what the others stood at plus that
battery's new command. N=1 and all identity digests unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 22:38:42 +02:00
admin f3e409cf76 Merge pull request 'SAFETY-91: a held battery is drawn only after the others are full' (#165) from safety-91-held-battery-last into release/1.0
infra-pin / fresh (push) Successful in 2s
2026-10-02 15:53:33 +02:00
adminandClaude Opus 5.5 4cd604afcb SAFETY-91 review: a held-back battery is released 1 point above its reserve
checks / unit (pull_request) Successful in 26m26s
infra-pin / fresh (pull_request) Successful in 1s
A SoC reading flipping across the reserve swapped ~1000 W between the
batteries on each flip (grid +-500 W with unequal lags). Also grades
next_quarter()'s staleness boundary (29.5 / 30.5 s).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 14:54:20 +02:00
adminandClaude Opus 5.5 6872353e2e SAFETY-91: a held battery is drawn only after the others are full
checks / unit (pull_request) Successful in 26m19s
infra-pin / fresh (pull_request) Successful in 1s
At N>=2 a battery at or under its own peak reserve now weighs 0 whenever
the site gives (not only for the peak), a draining battery's pin becomes
a floor at its drain rate so it rises before the held one gives, and a
quarter's edge is graded on the next quarter when its first telegram is
late. SAFETY-25 option A stays: the held battery is still drawn once the
others are full. N=1 unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 14:03:54 +02:00
admin 8c438ab2e6 Release 0.13.0 (#164)
infra-pin / fresh (push) Successful in 2s
checks / unit (pull_request) Successful in 25m53s
infra-pin / fresh (pull_request) Successful in 1s
2026-10-02 10:04:13 +02:00
adminandClaude Opus 5.5 b37b7f95dc REL-0.13.0 review: plainer, truer 0.13.0 changelog
checks / unit (pull_request) Successful in 25m52s
infra-pin / fresh (pull_request) Successful in 1s
Crash, not stop, for SAFETY-61; Watchdog off by default; its own
warning for the 50 W peak margin (also under a higher month peak);
"refuses power" for SAFETY-52/73; no one-house options claim.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:37:34 +02:00
adminandClaude Opus 5.5 28cab03947 REL-0.13.0: cut 0.13.0
checks / unit (pull_request) Successful in 25m55s
infra-pin / fresh (pull_request) Successful in 2s
Bump config.yaml version 0.12.0 -> 0.13.0 and close a ## 0.13.0
CHANGELOG section covering every merge since 0.12.0 (a45ed06), with the
known issues SAFETY-90/91/92/93/94. Option surface 77 -> 83, none removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:04:47 +02:00
admin 61072ca460 Merge pull request 'SAFETY-85: no false 'not keeping up' while maintenance or the peak guard sets the battery' (#163) from safety-85-no-false-not-keeping-up into release/1.0
infra-pin / fresh (push) Successful in 1s
SAFETY-85: no false 'not keeping up' while maintenance or the peak guard sets the battery (#163)
2026-10-01 20:52:17 +02:00
adminandClaude Opus 5.5 7b723a6cd5 SAFETY-85 review: grade discharge only, over the plant's settle time
checks / unit (pull_request) Successful in 25m47s
infra-pin / fresh (pull_request) Successful in 2s
Rule 2 graded each battery against last cycle's command and graded charges
too. On plantsim's battery (10 s lag) at the 2 s meter it warned at every
drain or charge start and 15 times an hour under the peak guard at N=2; a
charge tapering near full warned 11 times in 50 min (SAFETY-42 section 7).
Now a discharge is graded against the least it stood at over SHORT_CYCLES /
SHORT_SPAN_S. DOCS lists `mode-bound` under Loop reason. test_safety85 part 7:
peak guard with a dead battery, lagging plant, taper; part 3: the bound ends
with maintenance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:25:41 +02:00
admin 935878193b Merge pull request 'SAFETY-87: peak guard uses every battery that can still give' (#162) from safety-87-guard-uses-able-batteries into release/1.0
infra-pin / fresh (push) Successful in 2s
SAFETY-87: peak guard uses every battery that can still give (#162)
2026-10-01 12:06:41 +02:00
admin b8ddfd787f Merge pull request 'SAFETY-86: peak guard outranks the maintenance hold' (#161) from safety-86-peak-over-hold into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-10-01 02:27:36 +02:00
admin 4ad8298ead Merge pull request 'SAFETY-84: maintenance charge at N=2 no longer stalls' (#160) from safety-84-n2-maint-charge into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-30 21:00:56 +02:00
adminandClaude Opus 5.5 5c9f64d87a SAFETY-84 review: check the charging pack gives under the guard, and no-P1 at N=2
checks / unit (pull_request) Successful in 23m51s
infra-pin / fresh (pull_request) Successful in 1s
A 6500 W house needs more than B alone: A must give (the N>=2 suspension),
with a non-vacuous run without it (banks over the cap, 'Load too high').
Without P1 the charge is not sized, as at N=1: A charges at 2000 W.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 20:36:46 +02:00
admin 9d5b7d129a Merge pull request 'SAFETY-83: peak guard outranks the maintenance drain at N=1' (#158) from safety-83-peak-over-drain into release/1.0
infra-pin / fresh (push) Successful in 2s
2026-09-30 14:58:41 +02:00
admin 1145a931ac Merge pull request 'OPT-11 P4: solar forecast and day plan' (#156) from opt11-p4-solar-forecast into release/1.0
infra-pin / fresh (push) Successful in 2s
2026-09-29 23:01:48 +02:00
adminandClaude Opus 5.5 56cafefa79 SAFETY-83: a refiled peak floor stays under a safety SET, graded directly
checks / unit (pull_request) Successful in 23m32s
infra-pin / fresh (pull_request) Successful in 1s
Kills M5 (refiled at P_SAFETY) on its own sentence, not only through the
per-cycle claim check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:52:52 +02:00
adminandClaude Opus 5.5 3f69c174af SAFETY-83: grade the refile at its boundary, and N=2 on its own
checks / unit (pull_request) Successful in 23m37s
infra-pin / fresh (pull_request) Successful in 1s
A floor exactly at the drain rate stays at P_PEAK (kills `lo >= rate`), and
part 4's N=2 check no longer shares its failure list with N=1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:50:46 +02:00
adminandClaude Opus 5.5 d77f1b1fdf SAFETY-83: peak guard outranks the maintenance drain at N=1
checks / unit (pull_request) Successful in 16m54s
infra-pin / fresh (pull_request) Successful in 1s
At N=1 the drain is the site SET at P_MAINTENANCE (60), so the peak floor
(P_PEAK, 50) was not applied and the house imported what the drain left.
Where the floor asks for more than the drain rate, main.py now refiles the
peak claim at P_MAINTENANCE, so it wins; safety SETs still park everything.
Nothing else changes: safety78_identity --diff against 35cdffe changes only
cycles where the guard wanted more than the drain; N=2 is byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:40:14 +02:00
admin 35cdffe766 Merge pull request 'SAFETY-78: maintenance drain at N=2 no longer stalls' (#154) from safety-78-drain-at-two into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-29 22:20:29 +02:00
admin 4f25b24aa6 Merge pull request 'SAFETY-81: no false Load too high alarms' (#155) from safety-81-load-too-high into release/1.0
infra-pin / fresh (push) Successful in 2s
2026-09-29 21:45:19 +02:00
adminandClaude Opus 5.5 f967073cfe SAFETY-81 review: 10 s hold, ERROR line per episode, more scenarios
checks / unit (pull_request) Successful in 20m31s
infra-pin / fresh (pull_request) Successful in 2s
- The alarm must hold for peakguard.ALARM_HOLD_S (10 s) on the projection's
  clock. A load that tops cap + battery for ~5 s every 30 s alarmed at every
  quarter start while the quarter landed under the aim (sine4500_fast).
- A cycle with no battery reading leaves the hold alone.
- Notified once per quarter, but the ERROR line is written per episode.
- New sim scenarios (sine4500_fast, twice7000, step6500_gap) with 5a4cdc2
  digests; control still byte-identical. Unit checks for export and the
  hold across a missing reading. test_peakguard's saturated fixture moves
  the hold start back instead of waiting it out.
- DECISIONS and DOCS updated: costs of the hold, tolerance reasoning, the
  double count in control left to a follow-up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 20:58:37 +02:00
admin 5a4cdc273e Merge pull request 'OPT-11 P3: price runs per battery' (#153) from opt11-p3-price-runs into release/1.0
infra-pin / fresh (push) Successful in 2s
OPT-11 P3: price runs per battery (owner option A: selling off, Leftover solar solar-only until P4) (#153)
2026-09-29 11:37:46 +02:00
adminandClaude Opus 5.5 7a00f12c76 SAFETY-79: peak guard keeps a margin below the limit (#151)
infra-pin / fresh (push) Successful in 1s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 01:01:35 +02:00
admin 7337b791e5 OPT-11 P2: HA entities for battery modes (#152)
infra-pin / fresh (push) Successful in 2s
2026-09-29 00:13:49 +02:00
adminandClaude Opus 5.5 c664e38ef4 OPT-11 P2 review: refusals stay counted, removals survive a start with no broker
- A refusal past the log-once set or the 32 cap is counted in the log at
  1, 10, 100 and so on, so a repeated attack stays visible.
- The logged topic is printable only (no forged log lines).
- mode_announcement(): the start-up store logic, now tested with a real
  Store. A removed config topic stays stored, so a start with no broker
  cannot forget it (rename case tested).
- A test ties each HA mode option to the page's English name.
- packmode.enabled() is tested for "true", 1 and "false".
- Retained-command text, DOCS and DECISIONS updated to match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 23:58:34 +02:00
admin 7995e4df0f UX-13 P3: Simple view and Batteries screen (#150)
infra-pin / fresh (push) Successful in 2s
2026-09-28 23:44:26 +02:00
adminandClaude Opus 5.5 b310282729 OPT-11 P2: HA entities for battery modes
checks / unit (pull_request) Successful in 11m12s
infra-pin / fresh (pull_request) Successful in 2s
Each battery gets an MQTT-discovered Mode select and Use switch, only while
battery_modes_enabled is true. Commands go through handle_action(), the
/action path; refusals are logged once. Retained commands are never applied.
Turning modes off removes exactly the configs announced (kept in the store).
With modes off the announcement is byte-identical to ed739d4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 23:12:04 +02:00
adminandClaude Opus 5.5 ed739d4cdb OPT-11 P1: per-battery mode limits, on/off, solar order (#149)
infra-pin / fresh (push) Successful in 2s
Reviewed: a mode gives way to the peak floor only as far as it needs; SAFETY-03 kept at the rail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 19:53:22 +02:00
admin a5dddadf45 UX-13 P5: Dutch text, STYLE check, DOCS screenshots, period editor (#148)
infra-pin / fresh (push) Successful in 2s
2026-09-28 17:06:18 +02:00
adminandClaude Opus 5.5 8c34647d05 Merge pull request 'UX-15: setup-only mode, and wizard fixes F1, F2, meter entity, step 1' (#147) from UX-15-setup-only into release/1.0
infra-pin / fresh (push) Successful in 1s
Reviewed and live-tested on TEST-23: 0 service calls in setup-only mode; review comment 1896.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:27:27 +02:00
adminandClaude Opus 5.5 63e7e8a133 UX-15: mutations fail named checks, not crashes
checks / unit (pull_request) Successful in 10m38s
infra-pin / fresh (pull_request) Successful in 1s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 08:54:26 +02:00
adminandClaude Opus 5.5 159d7461d8 UX-15: setup-only mode, and the wizard fixes F1, F2, meter, step 1
A new install names no inverter. When that is the startup gate's only
refusal, the add-on now serves the setup wizard in setup-only mode instead
of exiting 78. It builds no controller, MQTT client or meter task, its
HomeAssistant is read-only (every service call refuses before sending),
Controller refuses a read-only HomeAssistant, and /action answers 409.
Any other refusal still exits 78. DECISIONS/UX-15-setup-only-mode.md.

Wizard fixes from the UX-13 P4 test:
- F1: /config/validate converts what it can, so a conversion error blocks
  its own step and the live checks still run; save 422 carries steps.
- F2: saves send the model the page opened (base); only keys this page
  changed are written onto the blob stored now.
- A meter entity missing from Home Assistant is red on the last step.
- Step 1 says the reading went down after a skip that followed a fall.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 08:48:21 +02:00
admin 4de96752ff Merge pull request 'UX-13 P4: the setup wizard' (#146) from UX-13-p4-setup into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-28 06:23:16 +02:00
adminandClaude Opus 5.5 be57b87c34 UX-13 P4: the setup wizard for installers
checks / unit (pull_request) Successful in 10m22s
infra-pin / fresh (pull_request) Successful in 1s
The Setup tab draws the Installer view's page model one step at a time,
from each field's `wizard` step in app/uilayout.py: meter (with the kettle
test), inverters and batteries, solar (optional), prices, peak limit
(battery modes: "comes in a later update", OPT-11), check and start.
It reuses P2's controls and saves through /config/validate and
/config/save. No route was added.

- First run: /config/model says `setup_needed` when the stored options name
  no power request entity, or on a new install (no `setup_done` and no
  `auto` in the Store, control not started). The page opens #setup only
  when opened with no route. The wizard's save writes `setup_done`.
- Kettle test: GET ha/entities?entity= reads one entity now, in W. The
  change decides: up keeps meter_invert off, down turns it on; a net or
  import/export meter that goes down blocks the step with what to check.
- Last step: validate.setup_checks() beside the refusals: the meter reads,
  each power request entity exists in HA (bad if not, SAFETY-77), battery
  levels and power with direction, solar sign, prices. Saves with
  shadow_mode on by default, then a confirmed restart naming the 0 W.
- P2 test finding (a): a stale save lists only the keys the other surface
  moved (the blob handed out on open, by fingerprint, against stored now).
- test_setup.py; tools/ux13_wizard_blobs.py makes the 88 blobs the wizard
  can save; all accepted by Supervisor 2026.08.0 AppOptions (offline).
- DECISIONS/UX-13-setup-wizard.md; DOCS "Setup, for a new install".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p
2026-09-28 05:31:18 +02:00
admin 515c11b380 Merge pull request 'UX-13 P2: the Installer settings view' (#145) from UX-13-p2-installer into release/1.0
infra-pin / fresh (push) Successful in 1s
Merge UX-13 P2: the installer settings view (#145)
2026-09-28 03:54:23 +02:00
admin 28a49ccf75 Merge pull request 'SAFETY-73: a battery that refuses, per inverter, with two or more' (#143) from SAFETY-73-per-unit-refusal into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-28 02:27:15 +02:00
admin a36dca60dd Merge pull request 'UX-13 P1: page shell and Home screen on a structured /status' (#144) from UX-13-p1-home into release/1.0
infra-pin / fresh (push) Successful in 1s
UX-13 P1: page shell and Home screen on a structured /status (#144)
2026-09-28 01:29:30 +02:00
adminandClaude Opus 5.5 fad73d4012 UX-13 P1 review: Home draws only what the cycle would do
checks / unit (pull_request) Successful in 9m36s
infra-pin / fresh (pull_request) Successful in 1s
- Trade blocks: none on a battery with no room, no sale at a negative price
  or while the emptiest battery is at arbitrage's floor, nothing when a
  level is unknown. A give after a charge may use what the charge put in.
- The refusal line names the real reason: prices not published vs gap.
- The plan's peak line uses the guard's ceiling (this month's peak once
  above the cap), as the peak card does.
- House below zero: 0 W inside the idle band, no figure beyond it.
- Price bars are "Low price" / "High price": the add-on trades in one hour.
- Control toggle: one request in flight at a time.
- test_home: the new cases; the house-sign mutation now goes red.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 01:18:33 +02:00
admin afd6af068d UX-13 P0: layout table, page<->options derivation, warning tier, entity list (#142)
infra-pin / fresh (push) Successful in 2s
2026-09-27 23:49:32 +02:00
adminandClaude Opus 5.5 badea3cb2d UX-13 P0 review: keep unread keys, back off a failed entity read
checks / unit (pull_request) Successful in 9m30s
infra-pin / fresh (pull_request) Successful in 1s
- uimodel: editing a listed inverter keeps the stored flat keys, and a
  region of "own" keeps a stored price_taxes_profile (both were dropped).
- haentities: a failed read also waits CACHE_S, so polls while Home
  Assistant is down do not queue one 10 s read each.
- ui_text: the Flanders preset names its DSO, and the help says
  Wallonia and Brussels have no figures yet. REGION_PRESETS cites the card.
- tests: decode of a reversed solar row, both kept keys, the backoff.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 23:39:43 +02:00
admin 652097abde Merge pull request 'SAFETY-52: a battery that refuses is asked for 0 W, with a 200 W probe every 15 min' (#141) from SAFETY-52-refused-hold into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-27 18:21:21 +02:00
adminandClaude Opus 5.5 3c0f2b9669 SAFETY-52 review: a refusal is under 100 W, and any delivery ends it
checks / unit (pull_request) Successful in 9m22s
infra-pin / fresh (pull_request) Successful in 1s
- Engage (and seed from a stale stop) below REFUSED_BELOW_W, the probe's
  own 100 W answer, not below saturation_w: a battery derated to 100-499 W
  was held at 0 W ~93 % of the time.
- A reading of 100 W or more in the held direction ends the refusal, probe
  or not: at a 1 s meter SETTLE_CYCLES is 12 s, shorter than a healthy
  reading's lag, and that held a healthy step at 0 W until the next probe.
- test_refusal part 5b and a seed test; DOCS states the N>1 limit; the
  DECISIONS record carries the traced cause of the replay's extra trips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 18:11:42 +02:00
admin d1f7e3336e Merge pull request 'UX-11: safety log lines give one plain sentence and the code, the figures go to DEBUG' (#140) from UX-11-short-safety-lines into release/1.0
infra-pin / fresh (push) Successful in 2s
Merge UX-11: short safety log lines, figures to DEBUG and events (#140)
2026-09-27 14:31:05 +02:00
adminandClaude Opus 5.5 3c298af3d8 UX-11 review: restored stops log their figures to events, the quiet-meter WARNING is rate-limited
checks / unit (pull_request) Successful in 9m7s
infra-pin / fresh (pull_request) Successful in 1s
- After a restart, each restored stop (direction per inverter and site,
  delivery, circulation) also writes its saved reason to the action log.
  log_level defaults to info and events starts empty, so the DEBUG
  evidence alone left the figures only in state.json.
- A flapping meter (ha_signed under a flat load, 42-97 s between changes)
  logs at most one WARNING/INFO pair per 10 minutes, with the episodes in
  between at DEBUG.
- LONG_LINE_OK refuses any key whose text is a safety reason.
- test_watchdog keeps the byte pin beside the meaning pin, since the text
  did not change.
- DOCS says the DEBUG line needs log_level debug.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 14:21:05 +02:00
admin c4032ebc21 Merge pull request 'CI: bump infra pin to d637d0b (admin/goodwe#61, UX-10)' (#139) from pin-bump-d637d0b into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-27 12:30:15 +02:00
admin 2b14b88cb4 Merge pull request 'UX-10: the last plain-language leftovers (log lines, two table rows, 'Why: Other', red at 0 s)' (#138) from UX-10-plain-leftovers into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-27 12:18:22 +02:00
adminandClaude Opus 5.5 e0b578756f UX-10 review: the line as logged gets the red-alarm shape, clamp lines at 30 words, plain HA 400
checks / unit (pull_request) Successful in 9m3s
infra-pin / fresh (pull_request) Successful in 2s
Part 6 checked the quoted reason alone, so title + reason + tails logged
as 4+ sentences. It now also checks the whole line (at most 3 sentences,
none over 30 words); 25 lines failed and are rewritten (one-sentence
wrappers, two-sentence circulation and peak reasons, STALE_READING's
fixed limits on a DEBUG line). The clamp lines for one inverter are
pinned at 30 words with OUTPUT_CLAMP and the numbers kept. Home
Assistant's bare '400: Bad Request' while it loads becomes one plain
line; still WARNING, throttled, a failed write.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 12:08:38 +02:00
admin 125b0702a2 Merge pull request 'CI: bump infra pin to ecd3864 (admin/goodwe#60, UX-08)' (#137) from pin-bump-ecd3864 into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-27 08:52:21 +02:00
admin 32b9e56357 Merge pull request 'UX-08 2d: plain log lines, the rest of the status page, and DOCS' (#136) from UX-08-2d-logs-docs into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-27 08:40:33 +02:00
adminandClaude Opus 5.5 6a95447248 UX-08 2d: plain log lines, the rest of the status page, and DOCS
infra-pin / fresh (pull_request) Successful in 1s
checks / unit (pull_request) Successful in 8m55s
Every WARNING and ERROR line is one plain line of at most 25 words, with
no card ids, capitals or semicolons; the reasoning of the ten longest is
on a DEBUG line. The ux08 allowlist is empty and its cap is 0 (43 -> 0).

The status page: the month-peak and peak-guard rows, the stale-reading
row, the top table (Why, Tariff, Arbitrage, Shadow mode, labels), the
Stopped banner and the line under the buttons, which now shows the plain
hint of each event instead of the raw action log. The Supervisor question
at start logs one line with a real reason.

Refusals are counted as shown (labels expanded, long cases driven), seven
were shortened, the card and parse errors lost their internals, a blank
value reads "empty", and the panel no longer files inverters.max_w under
the flat max_w. Option names lose "(JSON)", the NL texts are checked too.

DOCS gets a glossary (control board, isolator, Developer Tools) and card
ids move from headings to a "For installers" line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p
2026-09-27 08:01:16 +02:00
admin a02cd4b713 Merge pull request 'UX-08 2c: short refusals, error texts and option texts' (#135) from UX-08-2c-refusals into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-27 07:01:25 +02:00
admin e1d0970b23 Merge pull request 'UX-09: Details link for current HA, shadow wording, plain terms' (#134) from UX-09-2a-fixes into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-27 04:54:42 +02:00
adminandClaude Opus 5.5 63dee6db1e UX-09 review: short start-up timeout, latch rows pinned in shadow, plainer rows
checks / unit (pull_request) Successful in 8m50s
infra-pin / fresh (pull_request) Successful in 1s
The Supervisor questions for the Details link are asked together with a
3 s budget instead of one after the other at 10 s each, so a hung
Supervisor cannot hold control start for 20 s. In shadow mode the
circulating and site-direction latches are pinned to keep their own red
row that says how they clear. Plainer inverter and battery wording.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 04:45:06 +02:00
adminandClaude Opus 5.5 00e3ee9de8 UX-09: Details link for current HA, "would" in shadow mode, plain terms
infra-pin / fresh (pull_request) Successful in 2s
checks / unit (pull_request) Successful in 8m50s
- Details link: /config/app/<slug>/documentation on HA 2026.2+ (the old
  /hassio/addon path is a 404 from 2026.5), /hassio/addon on 2026.1 and
  older. Slug from GET /addons/self/info, version from GET /info, hostname
  as fallback.
- Shadow mode: the over-rating alarm and row say what would have been sent,
  the peak alarm no longer says the battery is giving all it can.
- "controller" -> "the add-on" / "control". Settings named by their labels;
  four labels changed to match (Peak reserve, Battery level entity, Solar
  production ..., Reversed-sign solar entities).
- Shadow banner and inverter link notes moved to messages.py and checked.
- DOCS Notifications and Status page rewritten for home owners, with a
  "For installers" part each. Allowlist 168 -> 167.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p
2026-09-27 04:10:39 +02:00
admin d57767fe38 Merge pull request 'UX-08 phase 2b: short, plain status rows and page banners' (#133) from UX-08-status-rows into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-27 03:19:54 +02:00
adminandClaude Opus 5.5 d017fc67bf UX-08 phase 2b: short, plain status rows and page banners
checks / unit (pull_request) Successful in 8m47s
infra-pin / fresh (pull_request) Failing after 1s
Every Commissioning row and every page banner is now worded in
app/messages.py (row_*, banner_*): one sentence of at most 15 words, a red
row up to three sentences so a latch still says how it clears, banners at
most 12 words. No row names a Home Assistant entity: sensors by their
setting, solar sources by their place in the list. Reason codes and limits
stay on the log line and event list; rows keep the numbers a reader acts on.

UX-07 item 1: ClampWatchdog counts over-rating and integrator-bound
engagements separately, and after an episode each count shows under its own
alarm's title instead of both under "output clamp".

No row colour, visibility or banner order changed. Rows carry an "id" so the
tests pin meaning rather than wording. The row and banner kinds leave the
allowlist (200 -> 168, cap equal). DOCS.md gains "Status page"; choices are in
DECISIONS/UX-08-short-notifications.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p
2026-09-27 02:12:10 +02:00
admin 5c151a3458 Merge pull request 'CI: bump infra pin to 7081df4 (admin/goodwe#59, UX-08)' (#132) from pin-bump-7081df4 into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-27 01:41:37 +02:00
admin 48ef06ac1f Merge pull request 'UX-08 phase 2a: short, plain notifications, and a ratchet for the rest' (#131) from UX-08-plain-notifications into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-27 01:29:46 +02:00
adminandClaude Opus 5.5 7b65a3e69a UX-08 review: tighter notification texts, and two meaning fixes
infra-pin / fresh (pull_request) Successful in 1s
checks / unit (pull_request) Successful in 8m48s
- not delivering: the body said control keeps running and then "start
  control"; clearing it takes stop then start, and it now says so.
- peak reserve: the "reserve not set" branch is really soc_floor None,
  i.e. an inverter's cut-out level missing; it now names that. The title
  is true on all three branches ("Battery stopped limiting the peak").
- no semicolon run-ons in bodies (STYLE.md + test); loop-bound, circulating,
  meter-frozen and multi-unit over-rating bodies rewritten to match.
- allowlist cap is now exact, so a shrink cannot leave room to regrow.
- DOCS names the settings behind "peak reserve" and "cut-out level";
  DECISIONS no longer states the HA anchor behaviour as fact.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 01:18:55 +02:00
admin 2503de124e Merge pull request 'SAFETY-40: the integrator bound is not a BUG SIGNAL; alarm numbers from the clamp tick' (#130) from SAFETY-40-clamp-alarm into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-26 23:19:11 +02:00
admin 59415ea83f Merge pull request 'CI: bump infra pin to 7689816 (admin/goodwe#58, SAFETY-34)' (#129) from pin-bump-7689816 into release/1.0
infra-pin / fresh (push) Successful in 2s
2026-09-26 16:15:23 +02:00
admin 397dd15dba SAFETY-34: re-assert latched alarms after a Core-only restart (#128)
infra-pin / fresh (push) Failing after 1s
2026-09-26 16:03:16 +02:00
admin fe132515fe Merge pull request 'CI: bump infra pin to a1d0618 (admin/goodwe#57, TOOL-9)' (#127) from pin-bump-a1d0618 into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-25 20:52:59 +02:00
admin 82f032e8cf Merge pull request 'TOOL-9: pin checks print FAIL under pipefail; job tokens via header' (#126) from TOOL-9 into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-25 20:39:47 +02:00
admin 6a8a5ffa27 Merge pull request 'CI-12: CI grades test_freeze.py against the real hwsim at a pinned admin/goodwe' (#125) from CI-12 into release/1.0
infra-pin / fresh (push) Successful in 1s
2026-09-25 18:19:43 +02:00
admin 16c796fa30 Merge pull request 'TEL-14: PV sign declared per entity (pv_invert_entities)' (#124) from TEL-14-pv-sign into release/1.0 2026-09-25 01:30:33 +02:00
admin 20260e86ec Merge pull request 'DOC-5: tell installers to turn on the Supervisor Watchdog' (#123) from DOC-5-watchdog into release/1.0 2026-09-25 01:17:35 +02:00
adminandClaude Opus 5.5 7fa045af85 TEL-14 N1: trim DECISIONS (drop probe transcript, §1 to the reason), move the mutation ledger there with M2/M5
checks / unit (pull_request) Successful in 8m44s
test_pv.py part 11 now prints a one-line pointer instead of the 12-row table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
2026-09-25 01:11:40 +02:00
adminandClaude Opus 5.5 93f349a6af TEL-14 B1: pin stray caution on the reported case and whitespace normalisation end to end
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
2026-09-25 01:10:13 +02:00
admin 43b274035f Merge pull request 'TEST-26: a missing value in a check is a named FAIL, not a traceback' (#122) from TEST-26 into release/1.0 2026-09-25 00:57:20 +02:00
admin 3e38bafcee Merge pull request 'SAFETY-62/SAFETY-60: operator tools refuse input they cannot read' (#120) from SAFETY-62-refuse-unread-input into release/1.0 2026-09-25 00:25:22 +02:00
admin 6e6527224a Merge pull request 'SAFETY-61: the control task's death ends the process, after the wind-down' (#121) from safety-61-control-task-death into release/1.0 2026-09-25 00:07:41 +02:00