Repository navigation
fix(loadpoint): plan a one-phase car above the charger's minimum, not at it - #1806
Merged
Merged
Conversation
… at it Once a car was marked one-phase, the planner got its one-phase levels (1,380-3,680 W) with the charger's own minimum, 4,140 W on a charger set up for three phases. The planner drops every level below its minimum, so it had only 0 and the car stopped charging: device-simulator rig s14 on 2e84710, 0 W for the last 15 min with the goal not reached. The order for a one-phase car is three times the plan, so the plan's minimum is a third of the charger's: 6 A on one phase. Its maximum is the top one-phase level. loadpoint.PlanningLimits holds this, and main.go and the field matrix both use it. The field matrix planned with PlanningSteps alone: it never took the one-phase branch in main.go and ignored the minimum the planner drops levels below. It now uses PlanningLimits and drops levels outside the minimum and maximum as mpc does; without the fix 24 sweep rows (one-phase car, planned, a charger with a 4,140 W minimum) fail on energy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
…three-phase steps Review of #1806: a third of the charger's minimum gave the planner a 1,380 W level on the field table, whose minimum (1,600 W) is a one-phase one. Three times it, 4,140 W, is not on the table, so a plan slot at that level with the plan's peak went out as 0 W; on coarse tables the car drew up to 30 % less than the plan counted. A marked one-phase car's levels are now the charger's three-phase planning steps divided by three, up to its one-phase maximum, so each is a third of an order the table and minimum allow. Without a table nothing changes: 4,140 W gives 1,380 W, 4,800 W gives 1,610 W. PlanningLimits also needs a charger that can run three phases (threePhaseCapable, which includes a three-phase site). TestOnePhaseCarLevelsAreOrders ticks the controller at every level the planner keeps, for five chargers and two fuses. Two field-matrix rows ask a small goal of the one-phase car on the help report's table; both were idle with room on the previous head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release blocker from #1801. Found by the device-simulator rig on 2e84710, scenario s14-one-phase-car-25A.
Problem
In s14, a one-phase car charges from a three-phase charger set up as the settings page does it: minimum 4,140 W, maximum 11,040 W. About a minute in, #1801 marks the car as one-phase. On the next replan the plan has no charging for the car:
commanded_w0,plan_next_whnull, and the goal is missed. The rig saw this both on a reactive-load replan and on aloadpoint_soc_changedreplan. Before #1801 the car drew 3.1 kW for the whole run.The cause is in the planner's input. Once the car is marked,
main.gogives the planner the car's one-phase levels, 1,380–3,680 W, together withLimitPower's minimum. That minimum is the charger's own, 4,140 W.mpc'snormalizedStepsdrops every level below the minimum, so only 0 was left.Change
loadpoint.PlanningLimitsnow holds the planner's range and steps for a session.main.go(planningLimitsForLoadpoint) and the field matrix both call it.A one-phase car takes a third of each three-phase order. Its levels are the charger's three-phase planning steps divided by three, up to its one-phase maximum, so each level is a third of an order that the charger's table and minimum allow. The minimum is the lowest level and the maximum the highest.
This applies only when the charger can run three phases (
threePhaseCapable, which also requires a three-phase site).Core's side was already right. It multiplies the plan by three before snapping to the charger's steps, so every level goes out as the step it came from.
Why the field matrix missed it
The matrix replans every 15 minutes, but its
fieldPlanningStepscalledPlanningStepsdirectly:CarPhasesbranch inmain.go, so a marked car was planned at three-phase levels, which Core then multiplied by three.It now calls
PlanningLimitsand drops levels outside its minimum and maximum, asmpcdoes. Without the fix this fails 24 existing sweep rows onenergy: one-phase car, planned, a charger with a 4,140 W minimum. For example,sweep/25A/auto/none/easee40s/car1p/balanced/planneddelivered 0.9 of 8.8 kWh.Two new rows,
help1022/20A/auto/own/{fast2s,easee40s}/car1p/2A/planned+need1000W, ask a small goal on the help report's table, so the plan picks the lowest level. Both were idle with room on the previous head, 5fda29b.Evidence
main.godoesTestOnePhaseCarLevelsAreOrders(loadpoint) ticks the controller at every level the planner keeps, with the plan's peak, for five chargers and two fuses. Every level must go out as an order within the charger and the fuse, and the car must draw within 1 % of the plan.TestOnePhaseCarPlanningLimits(loadpoint) checks the range and the number of kept levels for five chargers. It used to lock in the third-of-minimum rule for the field table; it now expects the table's thirds.TestOnePhaseCarPlanChargesAtALevelCoreCanOrder(cmd/ftw) runsmpc.Optimizeon the inputmain.gogives the planner. At least one slot must charge at one of the car's levels, and three times that level must be within the charger's range. With master's limits it fails: "no slot charges the car at a level Core can order (limits 4140-11000 W, ...)".go/test/sitemerged in locally. The car was marked about 76 s in.plan_next_wh4,524, order 11,040 W.failonly because test(site): run Core against device-simulator, short set on PRs, full set nightly #1797's known list still names both criteria; those two lines can go.go vetis clean, andgo test ./internal/... ./cmd/ftw/...passes in 60 packages.Behaviour that changes beyond the fix
Limits
mpc/deadline_directive.go) still sizes the order from the charger's own steps. For a marked car the controller multiplies that by three, within the charger's maximum, so with no plan the car draws its full current instead of the level the goal needs.CarMaxWis below the charger's minimum, on a charger without a table, gets 0 W. Example: a plug-in hybrid with max 3,680 W against a 4,140 W minimum.deadline_directive.go:42callsSnapChargeWwith a maximum below the minimum, andDeadlineNeedhas no "keep one step" fallback without a table. This is left for a follow-up.ev_planning_limits.go, so it needs a rebase.Review findings
PlanningLimitsshould need a three-phase site; the planner test did not assert what it meantthreePhaseCapable; test renamed and asserts an orderable slot🤖 Generated with Claude Code