Skip to content

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

Merged
springfall2008 merged 1 commit into
mainfrom
fix/rate-min-base-pre-replicate-gap
Aug 17, 2026
Merged

fix: rate_min_base/rate_max_base computed from raw sparse fetch, not the gap-filled curve#4553
springfall2008 merged 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>

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 an import-tariff edge case in Predbat’s rate processing where rate_min_base / rate_max_base were previously derived from the raw (potentially sparse) fetched rates rather than the gap-filled replicated curve, which could misprice IO/SmartFlex dispatch slots and lead the optimiser to avoid charging during genuinely off-peak periods (Issue #4544).

Changes:

  • Introduces rate_base_min_max() in fetch.py to build the “base” replicated import curve first, then scan min/max from that gap-filled curve.
  • Updates fetch_sensor_data() to compute rate_import_base, rate_min_base, and rate_max_base via the new helper.
  • Adds a targeted regression sub-test reproducing the sparse-forward-fetch day/night tariff scenario and asserting rate_min_base comes from the replicated curve.

Reviewed changes

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

File Description
apps/predbat/fetch.py Computes rate_min_base/rate_max_base from the replicated “base” import curve via new rate_base_min_max() helper.
apps/predbat/tests/test_rate_replicate_missing_slots.py Adds a regression sub-test ensuring base min/max reflect the gap-filled curve for sparse forward fetches (#4544).

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

@springfall2008
springfall2008 merged commit 40f5dfe into main Aug 17, 2026
3 checks passed
@chalfontchubby
chalfontchubby deleted the fix/rate-min-base-pre-replicate-gap branch August 21, 2026 09:43
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

3 participants