Summary
When a high-priced export window enters the plan horizon — an Axle VPP event, and likely any alert-priced or saving-session slot — the export rate threshold is raised to that window's price. On a flat export tariff this excludes every ordinary export window from high_export_rates, so the optimiser has no export slot to consider for the rest of the horizon. The battery then sits full through peak PV and clips.
Reported as part of #4865 (PV clipping), but it is a separate mechanism with a much wider blast radius: it suppresses all rate-arbitrage exports, not just clipping-avoidance ones. Splitting it out so it doesn't get closed along with that issue.
Mechanism
set_rate_thresholds() picks a sensible threshold in automatic mode (fetch.py:2492-2496) — for a flat 20p export tariff with a 23.8p import minimum, that's rate_export_min + 0.5 = 20.5p.
fetch.py:1315-1319 then rescans and overwrites it with lowest, the lowest average among the windows that already cleared it:
self.high_export_rates, lowest, highest = self.rate_scan_window(self.rate_export, 5, self.rate_export_cost_threshold, True, alt_rates=self.rate_import)
if self.rate_high_threshold == 0 and lowest <= self.rate_export_max:
self.rate_export_cost_threshold = lowest
With a 100p VPP window in the scan, lowest becomes the VPP price rather than the base tariff's. The threshold ratchets up and every 20p window falls below it.
I assume this overwrite is deliberate for Agile-style tariffs, where adapting to what's actually on offer is right. It goes wrong when a rare high-price window sits alongside a flat base rate — the threshold stops describing "a good export rate" and starts describing "the VPP price". Worth a maintainer's ruling on the intent before picking a fix.
Evidence
Two independent instances from the same reporter, three months apart, both in #4865.
1. 14 June 2026 — logs attached to #4036. The threshold flips mid-day exactly when the event is fetched:
05:45 High export rate found rates in range 20.0p to 20.0p
...
18:40 AxleAPI: Successfully fetched event data - export event 2026-06-15 06:00-07:00
18:45 Setting Axle VPP session ... pence_per_kwh 100
...
20:45 High export rate found rates in range 99p to 120.0p
Same day, same system, unchanged PV data — ordinary export windows vanish the moment the event enters the horizon. The reporter's comment at the time: "with an Axle event tomorrow, Predbat doesn't want to force export at all", with ~13 kWh of predicted clipping.
2. 4 September 2026 — predbat_debug.yaml on #4865, v8.54.3. Replayed against current main:
rate_export_cost_threshold = 120.0, against a flat daytime export rate of 20.0p
high_export_rates contains only the two Axle windows, at +1695 and +1725 minutes
- PV peak is at +20 minutes, with no candidate export window anywhere near it
- clipping 2.10 kWh in the incoming plan, rising to 3.26 kWh after
calculate_plan()
Inserting an export window over the PV peak by hand makes no difference, because the only windows the optimiser can reach are 28 hours away.
The reporter guessed the cause both times — "this might be caused by the Axle event later in the day, but I don't know why that would affect it" — and was right.
Reproduction
Replay the 4 September file from #4865 against main and inspect rate_export_cost_threshold and high_export_rates. It makes a ready-made regression case.
Not yet explained
Clipping getting worse after recalculation on the September file (2.10 → 3.26 kWh) is a separate oddity I haven't accounted for. It may be a consequence of having no reachable export window, or it may be its own bug.
Scope
Anyone on a flat export tariff with occasional high-price windows: Axle VPP, Octopus saving sessions, alert-priced slots. The clipping in these reports is how it surfaced, but the same suppression would block ordinary rate-arbitrage exports too.
Filed by Claude on chalfontchubby's behalf, from analysis of the debug files and logs attached to #4865.
Summary
When a high-priced export window enters the plan horizon — an Axle VPP event, and likely any alert-priced or saving-session slot — the export rate threshold is raised to that window's price. On a flat export tariff this excludes every ordinary export window from
high_export_rates, so the optimiser has no export slot to consider for the rest of the horizon. The battery then sits full through peak PV and clips.Reported as part of #4865 (PV clipping), but it is a separate mechanism with a much wider blast radius: it suppresses all rate-arbitrage exports, not just clipping-avoidance ones. Splitting it out so it doesn't get closed along with that issue.
Mechanism
set_rate_thresholds()picks a sensible threshold in automatic mode (fetch.py:2492-2496) — for a flat 20p export tariff with a 23.8p import minimum, that'srate_export_min + 0.5= 20.5p.fetch.py:1315-1319then rescans and overwrites it withlowest, the lowest average among the windows that already cleared it:With a 100p VPP window in the scan,
lowestbecomes the VPP price rather than the base tariff's. The threshold ratchets up and every 20p window falls below it.I assume this overwrite is deliberate for Agile-style tariffs, where adapting to what's actually on offer is right. It goes wrong when a rare high-price window sits alongside a flat base rate — the threshold stops describing "a good export rate" and starts describing "the VPP price". Worth a maintainer's ruling on the intent before picking a fix.
Evidence
Two independent instances from the same reporter, three months apart, both in #4865.
1. 14 June 2026 — logs attached to #4036. The threshold flips mid-day exactly when the event is fetched:
Same day, same system, unchanged PV data — ordinary export windows vanish the moment the event enters the horizon. The reporter's comment at the time: "with an Axle event tomorrow, Predbat doesn't want to force export at all", with ~13 kWh of predicted clipping.
2. 4 September 2026 —
predbat_debug.yamlon #4865, v8.54.3. Replayed against current main:rate_export_cost_threshold= 120.0, against a flat daytime export rate of 20.0phigh_export_ratescontains only the two Axle windows, at +1695 and +1725 minutescalculate_plan()Inserting an export window over the PV peak by hand makes no difference, because the only windows the optimiser can reach are 28 hours away.
The reporter guessed the cause both times — "this might be caused by the Axle event later in the day, but I don't know why that would affect it" — and was right.
Reproduction
Replay the 4 September file from #4865 against main and inspect
rate_export_cost_thresholdandhigh_export_rates. It makes a ready-made regression case.Not yet explained
Clipping getting worse after recalculation on the September file (2.10 → 3.26 kWh) is a separate oddity I haven't accounted for. It may be a consequence of having no reachable export window, or it may be its own bug.
Scope
Anyone on a flat export tariff with occasional high-price windows: Axle VPP, Octopus saving sessions, alert-priced slots. The clipping in these reports is how it surfaced, but the same suppression would block ordinary rate-arbitrage exports too.
Filed by Claude on chalfontchubby's behalf, from analysis of the debug files and logs attached to #4865.