Impact: negligible — read this before prioritising
No user will ever see this in their savings. Measured at +0.0016 SEK on a 96-period day whose optimized result is −47.82 SEK: about 0.003% relative error, order 0.6 SEK/year if it recurred every day. The dashboard overstates predicted savings by a fraction of an öre.
It is filed because it is a plan/execution divergence, not because of its size. The corpus gate that caught it is zero-tolerance for a reason: this same class was 3.57 SEK across 33 fixtures before #497 fixed it, and the gate exists so the mechanism cannot hide behind a small number. Treat this as a canary and a correctness record, not as lost savings.
Not measured: the worst case. This is one observed day. The drift accumulates across IDLE periods with sub-grid-step surpluses and only converts to cost when the battery reaches a bound, so a day with many such surpluses and repeated bound-hits could be larger — but there is no evidence it ever becomes material, and that should be bounded properly (bess-analyst) rather than extrapolated from a single fixture before anyone spends time on a fix.
Found while implementing #624 (PR #629). Not caused by that change — see the control experiment below. Filed separately because it is a distinct defect with its own cause and its own fix.
Symptom
The DP plans a cost its own execution does not deliver, breaching the corpus-wide zero-tolerance R == P gate in test_realized_matches_planned_across_all_fixtures.
Root cause
Passive solar charging below one SOE grid step is invisible to the DP's snapped trajectory but real to the hardware.
At period 32 of regression_2026_08_17_624:
- solar 0.0990 kWh, consumption 0.0956 kWh → surplus 0.0034 kWh
SOE_STEP_KWH is 0.025 — the surplus is an order of magnitude smaller, so the DP's snapped SOE trajectory cannot represent absorbing it and plans it as export
- the command the DP derives for IDLE is
ControlCommand(battery_mode='load_first', discharge_rate_pct=0, grid_charge=False, charge_rate_pct=100) — which makes the inverter absorb the surplus into the battery anyway
period 32 intent=IDLE
battery_charged P= 0.00000 R= 0.00341 <<<
grid_exported P= 0.00341 R= 0.00000 <<<
solar_to_battery P= 0.00000 R= 0.00341 <<<
The battery then runs 0.0033 kWh fuller than planned. That is costless for 32 periods, until period 64, where the battery reaches max_soe:
period 64 intent=SOLAR_STORAGE
battery_charged P= 0.80774 R= 0.80433 <<<
grid_exported P= 0.53748 R= 0.54089 <<<
Being fuller leaves that much less room for solar, which is exported instead — and the two periods' cost deltas (+0.006321 at 32, −0.004766 at 64) sum to exactly the observed +0.001555.
Not caused by #624's window bisection
Measured, not assumed. With detect_tie_windows patched to return no windows — no PWL solve, no splice, no bisection — the gap is bit-identical:
windows ON : R=-47.814616 P=-47.816171 gap=+0.001555
windows OFF: R=-47.800070 P=-47.801625 gap=+0.001555
Two reviewers independently attributed the gap to the bisection seam during PR #629's review. The seam's own measured contribution is 0.000000 SEK.
Current state
Recorded in KNOWN_PLAN_EXECUTION_GAP_SEK (core/bess/tests/integration/test_plan_faithfulness.py) with this evidence, so the corpus gate stays meaningful for everything else.
That entry is self-invalidating rather than a silencer: both the corpus test and test_the_bisected_schedule_is_executable_as_planned assert the gap equals +0.0016, so fixing this issue reddens the suite and forces the entry's deletion. It cannot rot unnoticed.
Note that adding it re-opened a table the header comment describes as collapsed by #497 ("any future gap is a real finding, and there is no band for one to hide in"). That was a deliberate, documented concession made in PR #629 — flagged here so the next reader sees it rather than discovering it.
Suggested direction
Either credit passive charging below one SOE step in the DP's IDLE flow model, or stop snapping the reported trajectory where the physical transition is representable. Deciding between those is an optimizer-architecture call (P4 — the flow record must not be re-derived), not something to pick during a fix.
Impact: negligible — read this before prioritising
No user will ever see this in their savings. Measured at +0.0016 SEK on a 96-period day whose optimized result is −47.82 SEK: about 0.003% relative error, order 0.6 SEK/year if it recurred every day. The dashboard overstates predicted savings by a fraction of an öre.
It is filed because it is a plan/execution divergence, not because of its size. The corpus gate that caught it is zero-tolerance for a reason: this same class was 3.57 SEK across 33 fixtures before #497 fixed it, and the gate exists so the mechanism cannot hide behind a small number. Treat this as a canary and a correctness record, not as lost savings.
Not measured: the worst case. This is one observed day. The drift accumulates across IDLE periods with sub-grid-step surpluses and only converts to cost when the battery reaches a bound, so a day with many such surpluses and repeated bound-hits could be larger — but there is no evidence it ever becomes material, and that should be bounded properly (
bess-analyst) rather than extrapolated from a single fixture before anyone spends time on a fix.Found while implementing #624 (PR #629). Not caused by that change — see the control experiment below. Filed separately because it is a distinct defect with its own cause and its own fix.
Symptom
The DP plans a cost its own execution does not deliver, breaching the corpus-wide zero-tolerance
R == Pgate intest_realized_matches_planned_across_all_fixtures.Root cause
Passive solar charging below one SOE grid step is invisible to the DP's snapped trajectory but real to the hardware.
At period 32 of
regression_2026_08_17_624:SOE_STEP_KWHis 0.025 — the surplus is an order of magnitude smaller, so the DP's snapped SOE trajectory cannot represent absorbing it and plans it as exportControlCommand(battery_mode='load_first', discharge_rate_pct=0, grid_charge=False, charge_rate_pct=100)— which makes the inverter absorb the surplus into the battery anywayThe battery then runs 0.0033 kWh fuller than planned. That is costless for 32 periods, until period 64, where the battery reaches
max_soe:Being fuller leaves that much less room for solar, which is exported instead — and the two periods' cost deltas (+0.006321 at 32, −0.004766 at 64) sum to exactly the observed +0.001555.
Not caused by #624's window bisection
Measured, not assumed. With
detect_tie_windowspatched to return no windows — no PWL solve, no splice, no bisection — the gap is bit-identical:Two reviewers independently attributed the gap to the bisection seam during PR #629's review. The seam's own measured contribution is 0.000000 SEK.
Current state
Recorded in
KNOWN_PLAN_EXECUTION_GAP_SEK(core/bess/tests/integration/test_plan_faithfulness.py) with this evidence, so the corpus gate stays meaningful for everything else.That entry is self-invalidating rather than a silencer: both the corpus test and
test_the_bisected_schedule_is_executable_as_plannedassert the gap equals +0.0016, so fixing this issue reddens the suite and forces the entry's deletion. It cannot rot unnoticed.Note that adding it re-opened a table the header comment describes as collapsed by #497 ("any future gap is a real finding, and there is no band for one to hide in"). That was a deliberate, documented concession made in PR #629 — flagged here so the next reader sees it rather than discovering it.
Suggested direction
Either credit passive charging below one SOE step in the DP's IDLE flow model, or stop snapping the reported trajectory where the physical transition is representable. Deciding between those is an optimizer-architecture call (P4 — the flow record must not be re-derived), not something to pick during a fix.