Skip to content

fix(planner): count a departure miss only above half a minimum run - #1533

Merged
frahlg merged 1 commit into
masterfrom
62-ev-need-rounding
Oct 7, 2026
Merged

frahlg merged 1 commit into
masterfrom
62-ev-need-rounding

Conversation

@frahlg

@frahlg frahlg commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

One of a pair with srcfl/energyplan#66 (private), which rounds an EV need below one minimum charging run to the nearest whole run. Merge them together. Part of srcfl/energyplan#62.

Problem

Energyplan now treats an EV need of at most half a minimum charging run as met and starts no charger for it. ValidatePlan counted every departure miss above 1 Wh, so the plan view would show such a need as a missed departure.

Rule

One run R stores the smallest allowed step for Charging.MinChargeSeconds at the charge efficiency Core sends (0.9 when unset). Core counts a departure miss only above max(1 Wh, R/2). A car that is charging at plan start (Charging.InitialCharging) keeps 1 Wh, since the worker keeps its exact target then. Without a minimum run the threshold stays 1 Wh.

For the home box (4140 W smallest step, 300 s, 0.9) R = 310.5 Wh and the threshold is 155.25 Wh.

Change

  • go/internal/mpc/charging_periods.go: departureMissWh holds the threshold, with a doc comment naming the Energyplan rule.
  • go/internal/mpc/external_optimizer.go: ValidatePlan uses it instead of the fixed 1 Wh.
  • docs/energyplan-contract.md: one new paragraph after the charging_periods paragraph states the rule. It is byte-identical with the Energyplan copy in the paired PR.
  • Patch changeset.

Core's own DP planner does not change. The threshold applies to every plan ValidatePlan replays, so a Core DP fallback or shadow plan that misses by half a run or less no longer shows a miss either.

Tests

  • TestDepartureMissFollowsEnergyplanNeedRounding: 155.25 Wh for the home box, also with an unset efficiency and steps from MinChargeW; 1 Wh without a minimum run, for a car charging at plan start, without a charging step, and for a run below 2 Wh.
  • TestValidatePlanCountsADepartureMissOnlyAboveHalfARun: a car that cannot charge misses 149, 150 and 151 Wh against a 150 Wh threshold; only 151 Wh counts. A 2 Wh miss counts for a car charging at plan start and without a minimum run; 1 Wh does not.

make verify: passes on f26154f (tests, compose migration, container boundary, release workflow, native solver tests, vet, build).

Notes

  • Until FTW pins an Energyplan build with the paired change, the 0.5.0 worker still charges such needs. This PR alone only stops showing a miss of at most half a run.
  • Core does not send charging to a worker that lacks the charging_periods feature. That worker keeps the 1 Wh rule while Core uses half a run. The pinned worker has the feature.
  • Core sends max_energy_wh equal to the target, so Core's cars never round up; the 253 Wh need from srcfl/energyplan#62 keeps its exact target. The Energyplan PR lists the options.
  • No open FTW PR touches external_optimizer.go, charging_periods.go or the contract. This branch is rebased on docs: let gap_satisfied cover the fleet search too #1532, which edited the contract's status table.

🤖 Generated with Claude Code

Energyplan now rounds an EV need below one minimum charging run to the
nearest whole run (srcfl/energyplan#62). A need of at most half a run
counts as met, so the plan starts no charger for it. ValidatePlan
counted every miss above 1 Wh, so the plan view would show that need as
a missed departure.

departureMissWh computes the same threshold from what Core sends: half
the energy of the smallest allowed step for MinChargeSeconds at the
charge efficiency (0.9 when unset), and at least 1 Wh. For a 4140 W step
and 300 s this is 155.25 Wh. A car that is charging at plan start keeps
1 Wh, since the worker then keeps its exact target. The threshold
applies to every plan ValidatePlan replays, Core DP fallback included.

docs/energyplan-contract.md states the rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frahlg
frahlg marked this pull request as ready for review October 7, 2026 13:13
@frahlg
frahlg merged commit e0a57fc into master Oct 7, 2026
15 checks passed
@frahlg
frahlg deleted the 62-ev-need-rounding branch October 7, 2026 13:13
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 7, 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-07T13:15:50.256660Z f26154f Draft marked ready
ℹ️ 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f26154f376

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// is planned when its prices arrive.
if lp.TargetSoC > 0 && i == lp.TargetSlotIdx {
if missing := max(0, lp.TargetSoC-evSoC[lp.ID]) * lp.CapacityWh; missing > 1 {
if missing := max(0, lp.TargetSoC-evSoC[lp.ID]) * lp.CapacityWh; missing > lp.departureMissWh() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Apply the half-run tolerance only to initially small needs

When an EV starts with a normal multi-run need but the plan finishes slightly short—for example, a 10 kWh need with 100 Wh still missing—Energyplan never rounds that original need to zero, yet this comparison applies the half-run threshold to the final residual and removes the real departure shortfall. Determine whether the initial target - initial energy qualified for rounding; otherwise retain the 1 Wh threshold so an unmet requested target remains visible.

AGENTS.md reference: AGENTS.md:L22-L23

Useful? React with 👍 / 👎.

@frahlg frahlg mentioned this pull request Oct 7, 2026
6 tasks done
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.

1 participant