Skip to content

fix(output): stop load_energy_predicted's whole-day total drifting through the day - #4519

Merged
springfall2008 merged 1 commit into
mainfrom
fix/load-predicted-day-total
Aug 15, 2026
Merged

fix(output): stop load_energy_predicted's whole-day total drifting through the day#4519
springfall2008 merged 1 commit into
mainfrom
fix/load-predicted-day-total

Conversation

@chalfontchubby

Copy link
Copy Markdown
Collaborator

Summary

Fixes the remaining part of #4496: load_energy_predicted's whole-day today total (and its state/chart) drifted through the day whenever load_scaling/load_scaling_dynamic != 1.0, even with nothing about the underlying forecast changing.

  • Root cause: fix(output): apply load_scaling to the predicted load curve's future portion #4506/fix(output): apply load_scaling_dynamic and manual_load_adjust to today_remaining #4511 (both merged) made load_today_comparison() apply load_scaling/load_scaling_dynamic/manual_load_adjust to future minutes only, which correctly fixed today_remaining (it now matches the plan's own step_data_history() convention). But the same accumulator (load_total_pred) that those future-scaled buckets feed into is also the source the whole-day today total is read from - and it sums every minute, unscaled-past alongside scaled-future. As minutes_now advances, buckets keep flipping from the scaled group to the unscaled one, so the published today total mechanically shrinks (load_scaling > 1) or grows (load_scaling < 1) as the day goes on.
  • Fix: a separate accumulator (load_total_pred_day) applies the same scaling consistently to every minute regardless of past/future, and is now the sole source for load_energy_predicted's state/today/today_so_far/today_remaining/results. load_total_pred itself, and the actual-vs-predicted divergence ratio it feeds (which deliberately wants raw/unscaled past minutes to compare against real consumption), are untouched.
  • Added a regression test that calls load_today_comparison() twice on the same day (00:00 and 15:00) with load_scaling=1.05 and asserts the today total and state are identical - confirmed it fails on main (30.24 → 29.34) and passes with this fix.

On the "should it be perfectly flat?" question

@nbullus, to be precise about what this fix does and doesn't claim: load_energy_predicted's today total was never architecturally "frozen at midnight" - load_today_comparison() recomputes the whole day from scratch every 5-minute cycle, there's no snapshot. We don't expect it to be a perfectly flat line forever - if the underlying days_previous/load-ML model's own forecast genuinely updates (e.g. as new historical data ages in), or if load_scaling_dynamic/manual_load_adjust config itself changes mid-day (a saving session gets added, a manual override starts), the total should move, and that's legitimate evolution, not a bug. What this fixes is the total moving for no reason other than the clock ticking forward - the minutes_now boundary shouldn't itself be a source of drift when nothing else has changed.

@gcoan - separately, your today/today_so_far confusion on load_energy_predicted is a real docs gap, not (as far as I can tell) a code bug: those two attributes aren't documented in docs/output-data.md at all, only today_remaining is, and even that section's description ("to end of plan") doesn't match what the code actually computes (strictly midnight-to-midnight). I haven't fixed the docs as part of this PR - flagging it separately rather than scope-creeping this fix.

After this

This is the third pass at #4496 in a fairly short window (#4506, #4511, now this). Given that history, we're going to step back from this specific area for a bit rather than keep iterating reactively - if either of you spot more drift after this lands, please do keep reporting it with a debug.yaml, but we'd rather let this one bed in and be looked at with fresh eyes next time than risk another narrow fix that misses a fourth edge case.

Test plan

  • New regression test (_test_predicted_today_stable_across_the_day in test_load_today_comparison.py) fails on main, passes with this fix
  • Full existing load_today_comparison suite still passes
  • ./run_all --quick passes
  • pre-commit clean

…rough the day

load_today_comparison() applied load_scaling/load_scaling_dynamic/manual_load_adjust
to future minutes only (#4506, #4511), which correctly fixed today_remaining but
also fed load_total_pred - the accumulator the whole-day "today" total is read
from - a mix of unscaled past buckets and scaled future ones. As minutes_now
advanced, buckets kept flipping from the scaled group to the unscaled one, so
the published "today" total (and its chart) drifted by whatever load_scaling
wasn't 1.0, even though nothing about the underlying forecast changed.

Adds a separate, consistently-scaled accumulator (load_total_pred_day) used only
for load_energy_predicted's state/today/today_so_far/today_remaining/results,
leaving load_total_pred itself (and the actual-vs-predicted divergence ratio it
feeds) untouched.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a drift bug in load_energy_predicted where the published whole-day “today” total (and state/chart) changed over the course of the day purely because minutes_now advanced when load_scaling/load_scaling_dynamic/manual_load_adjust were non-1.0. It does this by introducing a separate, consistently-scaled full-day accumulator used exclusively for the predicted sensor’s totals, and adds a regression test to lock the behavior.

Changes:

  • Introduce a new full-day accumulator (load_total_pred_day) and corresponding timestamp series so load_energy_predicted totals are computed with consistent scaling across all minutes (past and future).
  • Keep the existing raw/unscaled accumulators (load_total_pred, load_total_pred_now) intact for the actual-vs-predicted divergence logic.
  • Add a regression test that recomputes the same day at 00:00 and 15:00 with load_scaling=1.05 and asserts today/state remain stable.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
apps/predbat/output.py Adds a consistently-scaled full-day predicted accumulator and uses it as the sole source for load_energy_predicted state/today/today_so_far/today_remaining/results to prevent clock-driven drift.
apps/predbat/tests/test_load_today_comparison.py Adds a regression test ensuring load_energy_predicted whole-day totals do not drift as minutes_now advances when scaling is constant.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@springfall2008
springfall2008 merged commit 4e564b1 into main Aug 15, 2026
3 checks passed
@springfall2008
springfall2008 deleted the fix/load-predicted-day-total branch August 15, 2026 12:18
@nbullus

nbullus commented Aug 15, 2026 via email

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants