Skip to content

fix: rate_min_base/rate_max_base computed from raw sparse fetch, not the gap-filled curve - #4553

Open
chalfontchubby wants to merge 1 commit into
mainfrom
fix/rate-min-base-pre-replicate-gap
Open

fix: rate_min_base/rate_max_base computed from raw sparse fetch, not the gap-filled curve#4553
chalfontchubby wants to merge 1 commit into
mainfrom
fix/rate-min-base-pre-replicate-gap

Conversation

@chalfontchubby

Copy link
Copy Markdown
Collaborator

Summary

Fixes #4544 - Predbat charging the car at the "high" import rate instead of the tariff's real off-peak price.

  • rate_min_base/rate_max_base were scanned from the raw import rate dict before rate_replicate() ran. For a tariff whose raw fetch only exposes the currently-active segment forward of "now" (confirmed via the reporter's debug.yaml: a fixed day/night Kraken/E.ON Next Drive Smart product, rates_min genuinely 8.0p but rate_min_base locked at 31.18p, equal to rate_max_base), the scan simply never saw the cheaper segment that hadn't started yet.
  • rate_add_io_slots()'s octopus_slot_low_rate=True path stamps IOG/SmartFlex dispatch slots with rate_min_base as the "low" price - so those slots got priced at the tariff's peak rate instead, making the optimiser see no benefit to charging the battery during them.
  • New rate_base_min_max() helper (fetch.py) replicates the raw rates first and scans the result, mirroring how rate_export_base is already built downstream of rate_replicate() on the export side (the export side never had this bug).

Test plan

  • New rate_base_min_max sub-test added to test_rate_replicate_missing_slots.py, reproducing the reported tariff's raw-vs-gap-filled scan directly - fails on main (well, would, if rate_base_min_max existed there) and passes with the fix.
  • ./run_all --quick - full suite green, including the random scenario regression (matches committed baseline across all 320 compared fields).
  • ./run_pre_commit clean.

🤖 Generated with Claude Code

…ve, not the raw sparse fetch (#4544)

rate_min_base/rate_max_base were captured from a scan of the raw import rate
dict before rate_replicate() ran. For a tariff whose forward-fetch window is
short (e.g. Kraken/E.ON Next Drive Smart, a fixed day/night product where the
raw fetch only exposes the currently-active segment), the scan only ever saw
the known segment and locked in the wrong "true" min/max for the day -
rate_add_io_slots() then stamped IOG/SmartFlex dispatch slots with that stale
value instead of the tariff's real off-peak price, showing as "Predbat charges
the car at the high import rate".

New rate_base_min_max() helper replicates first (mirroring how rate_export_base
is already built downstream of rate_replicate() on the export side) and scans
the result, so a segment that hasn't started yet but is recoverable from
history is reflected correctly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.

Predbat Planning High Import When Car Charging

1 participant