Cause.solarfc.read_sum() (app/solarfc.py:538 on release/1.0) asked Hold.stand_in(..., as_today=True) (:342) for the evening's tomorrow figure whenever the today sensors were stale, until 06:00. It did not ask whether a newer today reading had been seen. Rig: silent from 17:05, one fresh brighter reading at 02:00 (A's level drops, A stops at 69.5 %). At 05:00 that reading is 3 h old, the 17:05 figure came back ("kept for tonight", level 95 %), the latch took it and A charged to 94.4 %.
Fix.Hold.replaced(): once every today sensor has given a fresh reading for the day (after midnight, so newer than any evening figure), the evening figure is no stand-in for that day. A stale newer reading follows the OPT-27 rules (at night: no forecast), and the latch keeps the level it set. The hold is saved, so a restart keeps the rule. Window, age limits, latch rules and screen text are unchanged.
Tests.test_opt34.py: solarfc unit checks (brighter and darker 02:00 reading, restart at 03:00, two today sensors) and three whole-night Controller runs (brighter, brighter + restart at 03:00, darker). Red on release/1.0 (10 FAIL), green here. Mutants: no replaced() check (10 FAIL), any instead of all (1 FAIL).
CHANGELOG OPT-34 line extended; one paragraph in the OPT-34 DECISIONS note.
OPT-34 rig fix (TEST-23 report, finding F-1).
**Cause.** `solarfc.read_sum()` (`app/solarfc.py:538` on release/1.0) asked `Hold.stand_in(..., as_today=True)` (`:342`) for the evening's tomorrow figure whenever the today sensors were stale, until 06:00. It did not ask whether a newer today reading had been seen. Rig: silent from 17:05, one fresh brighter reading at 02:00 (A's level drops, A stops at 69.5 %). At 05:00 that reading is 3 h old, the 17:05 figure came back ("kept for tonight", level 95 %), the latch took it and A charged to 94.4 %.
**Fix.** `Hold.replaced()`: once every today sensor has given a fresh reading for the day (after midnight, so newer than any evening figure), the evening figure is no stand-in for that day. A stale newer reading follows the OPT-27 rules (at night: no forecast), and the latch keeps the level it set. The hold is saved, so a restart keeps the rule. Window, age limits, latch rules and screen text are unchanged.
**Tests.** `test_opt34.py`: solarfc unit checks (brighter and darker 02:00 reading, restart at 03:00, two today sensors) and three whole-night Controller runs (brighter, brighter + restart at 03:00, darker). Red on release/1.0 (10 FAIL), green here. Mutants: no `replaced()` check (10 FAIL), any instead of all (1 FAIL).
CHANGELOG OPT-34 line extended; one paragraph in the OPT-34 DECISIONS note.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
After a fresh today reading in the night (02:00 on the rig) went stale
(05:00), Hold.stand_in(as_today=True) served the 17:05 "tomorrow" figure
again until 06:00: the plan went back to 95 %, the latch took it, and
Leftover solar charged back up. read_sum() now skips that stand-in once
every today sensor has given a fresh reading for the day
(Hold.replaced()); the stale newer reading follows the OPT-27 rules.
Co-Authored-By: Claude <noreply@anthropic.com>
The fix is right.Hold.replaced() (app/solarfc.py:355) is computed from the stored today records, so it needs no new store field. A store from d4c01da works as it is, and a restart keeps the rule (unit + f1_bright_rs). It is keyed by day, so the next night's evening figure still works (probe). After 06:00 nothing changes (_bell_start). main.py is untouched.
"All today sensors": this does not bring F-1 back. With one sensor fresh at 02:00 and the other dead all night, the evening sum stands in from 00:00 to 05:59 and never changes, so no level moves and nothing comes back.
Tests: new checks are red on base (10 FAIL) and green on head. Mutant "drop replaced()" gives 10 FAIL. Mutant "any for all" gives 1 FAIL. test_opt27 stays green under both. The whole-night checks go through the real Controller (_read_forecast + cycle). Screen lines at each 15 min are true: f1_dark says "The charge under way goes on to its planned level" while A charges after 05:00.
Digests, base = head = the dev's numbers: modes_off c1b230c2… (32974), arb_epex e5230acc…, own_silent_state_epex 558439f3…, p4_ls_silent_epex 8d39070d….
Full suite locally: 93 files, 0 failed, 1211 s; test_freeze part 3 ran on the hwsim. CI run 1491 job 2642 is green on 6263a57.
Docs: the CHANGELOG line and the DECISIONS paragraph are true, and the rig numbers match the test report.
Findings (none blocking):
Low, app/solarfc.py:360: replaced() asks whether every sensor has read fresh, not whether a fresh sum was formed. Two today sensors: t1 fresh only at 00:30, t2 fresh only at 04:00. The two readings are never fresh together, so no fresh sum ever replaced the evening one. At 04:01 the forecast still goes from the 17:05 figure to "no forecast" (base keeps 17:05 to 06:00). This is not F-1: nothing older comes back, and a charge under way keeps its latched level. A charge that has not started yet loses the evening figure two hours early. This is a rare shape, and a card only if the owner wants it.
Info, app/solarfc.py:549: a today sensor that is renamed or added during the night, after a 02:00 reading, has no record. The 17:05 figure then comes back until 06:00 (probe). This needs an options change in the middle of the night, so no action.
Info, .gitea/ci/run-tests.sh:50: test_opt34 takes 304 s in CI and is the 5th-longest file. Advice: put it in HEAVY after test_modes_p3.py, in a later CI housekeeping change (HEAVY is a sort order). test_tariff24_weather.py (222 s) is not listed either.
**OPT-34 fix review (Opus), head 6263a57: approve, merging.**
Checks, all on 6263a57 (base d4c01da):
- **The fix is right.** `Hold.replaced()` (`app/solarfc.py:355`) is computed from the stored today records, so it needs no new store field. A store from d4c01da works as it is, and a restart keeps the rule (unit + `f1_bright_rs`). It is keyed by day, so the next night's evening figure still works (probe). After 06:00 nothing changes (`_bell_start`). `main.py` is untouched.
- **"All today sensors":** this does not bring F-1 back. With one sensor fresh at 02:00 and the other dead all night, the evening sum stands in from 00:00 to 05:59 and never changes, so no level moves and nothing comes back.
- **Tests:** new checks are red on base (10 FAIL) and green on head. Mutant "drop replaced()" gives 10 FAIL. Mutant "any for all" gives 1 FAIL. test_opt27 stays green under both. The whole-night checks go through the real `Controller` (`_read_forecast` + `cycle`). Screen lines at each 15 min are true: f1_dark says "The charge under way goes on to its planned level" while A charges after 05:00.
- **Digests**, base = head = the dev's numbers: modes_off `c1b230c2…` (32974), arb_epex `e5230acc…`, own_silent_state_epex `558439f3…`, p4_ls_silent_epex `8d39070d…`.
- **Full suite** locally: 93 files, 0 failed, 1211 s; test_freeze part 3 ran on the hwsim. **CI** run 1491 job 2642 is green on 6263a57.
- **Docs:** the CHANGELOG line and the DECISIONS paragraph are true, and the rig numbers match the test report.
Findings (none blocking):
- **Low**, `app/solarfc.py:360`: `replaced()` asks whether every sensor has read fresh, not whether a fresh sum was formed. Two today sensors: t1 fresh only at 00:30, t2 fresh only at 04:00. The two readings are never fresh together, so no fresh sum ever replaced the evening one. At 04:01 the forecast still goes from the 17:05 figure to "no forecast" (base keeps 17:05 to 06:00). This is not F-1: nothing older comes back, and a charge under way keeps its latched level. A charge that has not started yet loses the evening figure two hours early. This is a rare shape, and a card only if the owner wants it.
- **Info**, `app/solarfc.py:549`: a today sensor that is renamed or added during the night, after a 02:00 reading, has no record. The 17:05 figure then comes back until 06:00 (probe). This needs an options change in the middle of the night, so no action.
- **Info**, `.gitea/ci/run-tests.sh:50`: test_opt34 takes 304 s in CI and is the 5th-longest file. Advice: put it in HEAVY after `test_modes_p3.py`, in a later CI housekeeping change (HEAVY is a sort order). test_tariff24_weather.py (222 s) is not listed either.
admin
merged commit cdafa2c189 into release/1.02026-11-01 14:21:45 +01:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
OPT-34 rig fix (TEST-23 report, finding F-1).
Cause.
solarfc.read_sum()(app/solarfc.py:538on release/1.0) askedHold.stand_in(..., as_today=True)(:342) for the evening's tomorrow figure whenever the today sensors were stale, until 06:00. It did not ask whether a newer today reading had been seen. Rig: silent from 17:05, one fresh brighter reading at 02:00 (A's level drops, A stops at 69.5 %). At 05:00 that reading is 3 h old, the 17:05 figure came back ("kept for tonight", level 95 %), the latch took it and A charged to 94.4 %.Fix.
Hold.replaced(): once every today sensor has given a fresh reading for the day (after midnight, so newer than any evening figure), the evening figure is no stand-in for that day. A stale newer reading follows the OPT-27 rules (at night: no forecast), and the latch keeps the level it set. The hold is saved, so a restart keeps the rule. Window, age limits, latch rules and screen text are unchanged.Tests.
test_opt34.py: solarfc unit checks (brighter and darker 02:00 reading, restart at 03:00, two today sensors) and three whole-night Controller runs (brighter, brighter + restart at 03:00, darker). Red on release/1.0 (10 FAIL), green here. Mutants: noreplaced()check (10 FAIL), any instead of all (1 FAIL).CHANGELOG OPT-34 line extended; one paragraph in the OPT-34 DECISIONS note.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
OPT-34 fix review (Opus), head
6263a57: approve, merging.Checks, all on
6263a57(based4c01da):Hold.replaced()(app/solarfc.py:355) is computed from the stored today records, so it needs no new store field. A store fromd4c01daworks as it is, and a restart keeps the rule (unit +f1_bright_rs). It is keyed by day, so the next night's evening figure still works (probe). After 06:00 nothing changes (_bell_start).main.pyis untouched.Controller(_read_forecast+cycle). Screen lines at each 15 min are true: f1_dark says "The charge under way goes on to its planned level" while A charges after 05:00.c1b230c2…(32974), arb_epexe5230acc…, own_silent_state_epex558439f3…, p4_ls_silent_epex8d39070d….6263a57.Findings (none blocking):
app/solarfc.py:360:replaced()asks whether every sensor has read fresh, not whether a fresh sum was formed. Two today sensors: t1 fresh only at 00:30, t2 fresh only at 04:00. The two readings are never fresh together, so no fresh sum ever replaced the evening one. At 04:01 the forecast still goes from the 17:05 figure to "no forecast" (base keeps 17:05 to 06:00). This is not F-1: nothing older comes back, and a charge under way keeps its latched level. A charge that has not started yet loses the evening figure two hours early. This is a rare shape, and a card only if the owner wants it.app/solarfc.py:549: a today sensor that is renamed or added during the night, after a 02:00 reading, has no record. The 17:05 figure then comes back until 06:00 (probe). This needs an options change in the middle of the night, so no action..gitea/ci/run-tests.sh:50: test_opt34 takes 304 s in CI and is the 5th-longest file. Advice: put it in HEAVY aftertest_modes_p3.py, in a later CI housekeeping change (HEAVY is a sort order). test_tariff24_weather.py (222 s) is not listed either.