Skip to content

fix(mpc): aim an EV deadline past the horizon at its last slot - #1498

Merged
frahlg merged 3 commits into
masterfrom
1497-ev-deadline-horizon
Oct 2, 2026
Merged

frahlg merged 3 commits into
masterfrom
1497-ev-deadline-horizon

Conversation

@frahlg

@frahlg frahlg commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Problem

When a departure passes while the car is still plugged in, the next departure lies past the published prices. Core sent that slot index to Energyplan without bounding it to the horizon, and the worker rejected the whole request:

07:06:35 level=ERROR msg="mpc: primary optimizer failed; using Core DP fallback" err="optimizer invalid_request: invalid EV identity, energy, target or steps: easee"

The home box planned with Core DP from 07:06 until the car was unplugged at 07:13 on 2 Oct. With prices for the next day published at about 13:00, a car left plugged in all morning would keep Energyplan out for hours.

Change

Core DP already clamped a deadline past the horizon to its last slot ("so the DP still sees it"), and the fleet contract check already read the deadline that way. Only the request to Energyplan sent it unbounded.

  • LoadpointSpec.deadlineSlot(n) holds the rule: -1 without a target or deadline, otherwise the deadline, but at most the horizon's last slot. Core DP and the Energyplan request both use it; the DP's behaviour is unchanged.
  • A car that leaves inside the horizon goes first: when one does, a departure past the horizon gets no deadline in the Energyplan request. Otherwise the two compete for surplus as equals (Codex reproduced today's single-phase car left 3 kWh short while tomorrow's three-phase car took the hour of surplus).
  • ValidatePlan still reports a shortfall only for a departure inside the horizon. A later departure is planned when its prices arrive, so the reserve plan's "short at departure" alert does not appear for it.
  • The main.go comment now says both planners clamp.

Energyplan treats a deadline as a requirement reduced to what is reachable. With grid charging deferred (the departure is past the published prices), a single car now gets the reachable surplus, as with Core DP.

Tests

  • TestNativeEVDeadlinePastHorizonPlans runs the bundled Rust worker: before the change it failed with the box's exact error; now it plans, charges from both surplus slots and reports no shortfall.
  • TestNativeEVDeadlineInsideHorizonGoesFirst: 64 quarter-hours, one hour of 5 kW surplus, a single-phase car needing 3 kWh by the last slot and a three-phase car needing 18 kWh tomorrow (6–16 A steps). Without the priority rule today's car is 3 kWh short; with it, it gets its 3 kWh.
  • TestEVDeadlinePastHorizonRequestUsesLastSlot, TestEVDeadlineInsideHorizonGoesFirst and TestEVDeadlineSlot check the request and the rule without the worker.
  • Each rule fails a test when reverted. The native tests run in CI's native-solver job. make verify clean.

Review

A local Codex review found the two-car priority problem and the misleading reserve alert; both are fixed here.

Fixes #1497.

🤖 Generated with Claude Code

When a departure passed while the car was still plugged in, the next
one lay past the published prices. Core sent that slot index to
Energyplan unbounded, and the worker rejected the request ("invalid EV
identity, energy, target or steps"), so the box fell back to Core DP
until prices arrived or the car was unplugged. The home box did so on
2 Oct, 07:06–07:13.

Core DP already clamps such a deadline to the horizon's last slot, and
the fleet contract check already reads it that way. Move the rule into
LoadpointSpec.deadlineSlot and use it for the DP, the Energyplan
request and the plan check, so both planners aim at the same slot.

Fixes #1497

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-02T09:02:17.968893Z 51fb9a9 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

frahlg and others added 2 commits October 2, 2026 11:19
Two findings from a local Codex review:

- With two cars, a departure past the horizon clamped to the last slot
  competed equally with a car leaving in that slot. With real charger
  steps, the worker gave one hour of surplus to tomorrow's three-phase
  car and left today's single-phase car 3 kWh short. A departure past
  the horizon now gets no deadline when another car leaves inside it.
- The plan check reported a shortfall at the horizon's end for a later
  departure. The reserve plan's alert would then say the car is short
  at departure, although the plan does not yet cover the departure
  night. Only a departure inside the horizon is checked, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
A third local Codex review: a plugged-in car stays active after it
reaches its target, so a satisfied departure inside the horizon still
removed tomorrow's deadline, and the surplus went to the grid instead
of tomorrow's car. Only a car whose target is above its current SoC now
takes priority. The SoC bounds sent to the optimizer move into
LoadpointSpec.requestSoC so the rule and the request read the same
values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@frahlg
frahlg merged commit 317e93c into master Oct 2, 2026
15 checks passed
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.

Optimizer rejects an EV whose next deadline is past the published prices

1 participant