OPT-34 fix (rig F-1): a replaced evening forecast does not come back #225

Merged
admin merged 1 commits from OPT-34-fix into release/1.0 2026-11-01 14:21:45 +01:00
Owner

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.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC

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
admin added 1 commit 2026-11-01 12:46:11 +01:00
OPT-34 fix (rig F-1): a replaced evening forecast does not come back
checks / unit (pull_request) Successful in 21m5s
infra-pin / fresh (pull_request) Successful in 2s
6263a57b6b
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>
Author
Owner

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.
**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.0 2026-11-01 14:21:45 +01:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/goodwe-addon#225