Plan and dispatch physical battery and EV fleets with the compiled worker - #1118
Conversation
0750442 to
260848e
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. |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_e7d2748d-bbe9-402b-8e9a-2cc48b6ad63c) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c78eb7abf9
ℹ️ 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".
| } | ||
| if totalCapacityWh <= 0 { | ||
| if totalCapacityWh < 0 { | ||
| return ReasonNoBatteryCapacity |
There was a problem hiding this comment.
Keep batteryless sites unavailable when Core DP is selected
When a batteryless site explicitly selects planner.engine: core—or uses the stable/development default—this condition now reports the planner as available and buildMPC constructs it, but OptimizeContext immediately rejects the same parameters through coreDPModelError because CapacityWh == 0. Every replan therefore fails validation and any EV on the site receives no schedule; admission should depend on selecting a planner that supports the zero-storage topology, or Core should remain unavailable for it.
AGENTS.md reference: AGENTS.md:L19-L25
Useful? React with 👍 / 👎.
| if len(slots)*assets >= 193*6 || p.PVCurtailment.MinW > 0 || p.PVUncertaintyW > 0 || p.PVRelativeUncertainty > 0 { | ||
| return 5 * time.Second |
There was a problem hiding this comment.
Preserve risk inputs until the time budget is chosen
For Energyplan requests whose only reason for the larger budget is configured PV uncertainty, this risk branch is unreachable: EnergyplanOptimizer.Optimize clears PVUncertaintyW and PVRelativeUncertainty before ExternalOptimizer.buildRequest invokes energyplanTimeBudget. Such requests consequently receive 500 ms rather than the documented 5 s unless they independently cross the fleet threshold or have PV-control proof, increasing budget errors or prematurely accepted feasible plans on the risk-adjusted horizon.
Useful? React with 👍 / 👎.
Sites without a home battery, or with several batteries or EVs, could receive an unsupported-topology error from the compiled planner. This change lets Core use the bundled Energyplan 0.3.0 worker for those sites and preserves each device's identity, physical limits and energy target from the request through validation and dispatch.
Core checks the raw response before translating it, including complete device maps, slot times, EV deadlines and PV command bounds. Multi-battery dispatch tracks each battery's measured delivery while retaining the existing site limit, state-of-charge, slew and safety checks. If Core DP cannot represent the site after a worker failure, Core keeps the old plan for diagnosis and withholds its execution directive instead of dropping devices.
PV control credit requires verified generation-control semantics. This first adapter supports one site PV control domain with the reviewed Ferroamp Lua bytes and an effective positive release setting. Export-only limits, other unverified drivers and multiple independent PV control domains get no such credit; their measured/forecast PV remains in the model. The proof comes from the loaded bytes and effective init and changes with driver generation. Restored diagnostics with physical device maps or PV dependence remain archives until a new plan has current physical inputs and runtime permission. This prevents restore from turning per-battery budgets into aggregate dispatch. Loss of proof or usable telemetry stops battery, EV and legacy plan execution and marks the archived plan outdated. Manual and protective PV limits retain precedence.
Planning stays outside the control tick. Small requests use at most 500 ms. Larger requests use at most 5 s when
slots * (3 * physical batteries + 2 * active EVs) >= 193 * 6, or when PV control/risk requires it. A real aggregate battery counts as one; a batteryless site counts as zero. The outer worker timeout is 7 s, and replacement/cancellation still stops the process.Validation:
make verifypassed with the final worker pin on the master fix from test(ftwdb): match the live sidecar I/O budget #1119, including native processes, Go suites, compose/container/release checks, vet and build.make native-solver-testpassed with the pinned package, including the real process budget and Core plan replay.Private paired worker PR: https://github.com/srcfl/energyplan/pull/6. Only compiled workers, licenses/notices and public bundle metadata are included here. The bundle pins source
3b9c59baecb71a91a8bc01208b4b8d5b9a5bfa60; Linux ARM64 SHA256fde573c1330e7b9adcaddc42893296fdd375e0efcc8298ea947a155780780545(1,155,360 bytes).PR #971 retains its stack order and ownership of its Python, true-zero-PV and broader shared-physics changes. PR #1036 keeps its evaluator, benchmark and report semantics, including its existing review findings. This PR only takes the physical-device boundary, raw-response validation and verifiable PV control; it does not supersede either PR.
PR #888 retains right of way on its export-guard work (related #885). The small dispatch hooks here preserve the existing guard, residual allocation, minimum command and release paths, as coordinated; that draft's implementation is not pulled into this change. Includes a minor changeset for the new supported site configurations.
Note
High Risk
Changes real-time battery/EV dispatch, MPC plan execution gates, and verified PV curtailment—paths that directly affect grid and device control if validation or proof logic is wrong.
Overview
Extends Energyplan 0.3.0 so MPC can plan sites with no home battery, multiple batteries, and multiple EVs, each with its own limits and energy targets.
buildMPCno longer requires aggregate battery capacity; worker requests/responses are validated for complete device maps, slot timing, EV deadlines, and PV cap bounds before plans are accepted.Dispatch carries per-battery slot energy (
StorageEnergyWh) through slot directives and usesdistributePlannedStoragesso multi-battery sites honor individual budgets (blocked batteries do not have their share reassigned) while still respecting site clamps and existing safety paths.PV generation curtailment from plans is gated on a runtime proof tied to loaded, reviewed Ferroamp Lua bytes, effective init, driver generation, and fresh telemetry—not config flags alone. Revoked or stale proof stops slot directives, EV/battery plan execution, and planned PV caps; manual/protective ceilings still win. Restored diagnostics with physical maps or PV control stay archives until a new solve validates current inputs.
When the primary worker fails and Core DP cannot model the topology, Core keeps the previous plan for diagnosis but withholds execution instead of falling back to a reduced aggregate model. Solve budgets scale (500 ms vs 5 s) for large fleets and PV/risk cases; transport timeout rises to 7 s.
Reviewed by Cursor Bugbot for commit c78eb7a. Bugbot is set up for automated code reviews on this repo. Configure here.