Repository navigation
Keep saved EV goals charging through plan failures - #1657
Merged
Merged
Conversation
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
frahlg
force-pushed
the
fix/ev-deadline-continuity
branch
from
October 16, 2026 04:56
04d15c1 to
cb02293
Compare
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. |
frahlg
added a commit
that referenced
this pull request
Oct 16, 2026
…as a deadline before the replan #1657's reserve took its power from the charger and its target from the goal alone: a Volvo whose own charger takes 7.4 kW reserved 11 kW on an Easee. LimitPower moves into loadpoint, and DeadlineNeed and the plan both hold to the lower of the charger and the car, keeping the charger's lowest step, and to the car's charge limit while its level is exact. The car's binding carries that limit; its phases bound nothing beyond its own rating, so the unread CarPhases goes. A goal the car brings cleared the loadpoint's rolled deadline until the next control tick, and the replan right after a tap planned without the car. The runtime rolls the schedules before every replan and after its first sync, and replans when a sync hands a loadpoint a goal or a surplus choice. A visitor's goal ends its surplus-only charging: someone who asks for a goal wants it met, and the plan and the reserve plan from empty while the level stays unknown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
frahlg
added a commit
that referenced
this pull request
Oct 16, 2026
* feat(cars): the car apart from the charger, in Core The box keeps its owners' cars in one state.db row and decides which car each charging session is: the charger's identity, the car's own report within a minute, the only or usual car, one tap after car.which, or a visitor. The session's car gives the loadpoint its capacity, goal, surplus choice and level, and the planner reads them. A car reading stays exact until 1 kWh has reached it. The search-based pairing and its refusals on ambiguity are gone. The loadpoint routes and ops act on the session's car for one release. Migration makes Car 1 from the loadpoint and a car from each vehicles[] profile; nothing the owner set is lost. docs/cars.md is the contract; two reviews shaped it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cars): agents read and ask by car, and the plan push names the car #1646 landed first, so this does the wiring left to whichever came second. An agent names a car in car.goal.set and car.soc.set by the id cars.get gave it (agent_args kind car), and the box checks the car and the goal as the request arrives. cars.get answers with the car class under the agent key: levels and goals, nothing that names a car. The redactor takes the cars' names, VINs, identifiers and sources out of logs and config. loadpoints.get and FTW Cloud's lp carry each charger's car by an opaque id, and an agent's plan.get and command outcomes name chargers and cars by its own ids. The plan's chargers carry the session's car. A change of car replans before it tells listeners, so a phone sees the new car on its charger at once, with the plan pending. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cars): the reserve holds to the session's car, and a car's goal has a deadline before the replan #1657's reserve took its power from the charger and its target from the goal alone: a Volvo whose own charger takes 7.4 kW reserved 11 kW on an Easee. LimitPower moves into loadpoint, and DeadlineNeed and the plan both hold to the lower of the charger and the car, keeping the charger's lowest step, and to the car's charge limit while its level is exact. The car's binding carries that limit; its phases bound nothing beyond its own rating, so the unread CarPhases goes. A goal the car brings cleared the loadpoint's rolled deadline until the next control tick, and the replan right after a tap planned without the car. The runtime rolls the schedules before every replan and after its first sync, and replans when a sync hands a loadpoint a goal or a surplus choice. A visitor's goal ends its surplus-only charging: someone who asks for a goal wants it met, and the plan and the reserve plan from empty while the level stays unknown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cars): the plan is pending before a charger shows a new car The tap test failed in CI with the Volvo's first plan not pending. The order was right: the feed hears of a change only from the planner, after RequestReplan marks the plan pending. But the feed folds changes within its 100 ms settle, and the test's replan failed at once without prices, so it had ended before the folded push was written. The test now holds the tap's replan in its read of the loadpoints, as a real solve takes seconds, and still asks that the first plan naming the Volvo be pending. A real gap remained: the loadpoint showed the new car a moment before the replan request marked the plan pending, and a push written then showed the car beside the old plan as current. The runtime now asks for a replan before it hands the loadpoints a change and again after the schedules roll; the second supersedes the first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Saved EV goals currently stop charging when a replan fails, prices are missing, or no home battery qualifies. Two chargers can also each receive the whole site's EV fuse cap. This change keeps an unmet saved goal as current EV intent and divides one live fuse budget across all charger commands.
The reserve uses the existing Service directive and charger path. It never publishes a successful optimizer plan or grants battery energy. A valid accepted zero budget still waits for its planned cheap window. Missing prices no longer turn a saved goal into an automatic solar-only goal; explicit solar-only and Stop remain effective.
Final charger offers reserve capacity before optional battery charging, including manual offers and sites without a battery. Required charging precedes opportunistic offers; deadlines order required cars. The allocation uses legal steps and never spends a sibling's commanded reduction before measuring it. Raw EV samples must bracket the selected site sample before earning replacement credit. The existing 64-point EV history retains observed stops within the same second. Fresh raw overload and phase limits can trim or stop charging. Existing freshness gates and the five-minute fuse cooldown remain.
Validation:
make verifyon master4bd7bd43(including Recover saved load learning after clock-jump labels #1656), with driver pin76ddd584and the pinned native worker.-racesuites for control, loadpoint, MPC and telemetry withFTW_NATIVE_SOLVERset to the bundled worker.Related work: #1650 owns the car model and adds other main wiring. This PR adds only the saved-goal snapshot and final EV-offer wiring there. #888 touches the same dispatch file for PV curtailment; these changes concern EV fuse allocation. Runtime hardware validation follows publication.