WhatIf: grid connection export limit, independent of battery - #4672
Conversation
Adds export_limit_kw as a top-level WhatIf config field (default 10kW), combined via min() with whatever apply_hardware() already derives for export capability. Previously this only existed as battery.export_limit_kw, so a PV-only (no-battery) run had no way to model a grid export cap at all - only battery-equipped runs could. A legacy battery.export_limit_kw is still read as a fallback so existing YAML configs and stored runs keep working.
There was a problem hiding this comment.
🟡 Changes recommended
The new validation rejects export_limit_kw: 0, which is a backward-incompatible behavior change (legacy configs could previously accept 0) and removes the ability to model “no export allowed.”
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR updates the annual “WhatIf” (offline/annual prediction) configuration to support a top-level export_limit_kw representing the grid connection export cap, so PV-only runs can model an export limit even when no battery is configured. It also updates the web UI to present this as independent of the battery, maintains a legacy fallback for older configs, and updates unit tests and docs accordingly.
Changes:
- Add/validate top-level
export_limit_kwin annual config (with legacy fallback frombattery.export_limit_kw) and apply it as amin()cap inapply_hardware(). - Update the annual web form to move “Export limit” into a new “Grid connection” fieldset and prefill it from the live instance’s export limit setting.
- Update docs and tests to reflect the new config shape and behavior.
File summaries
| File | Description |
|---|---|
| docs/annual-prediction.md | Documents new top-level export_limit_kw and legacy compatibility. |
| apps/predbat/web_annual.py | Moves export limit to top-level grid field, updates prefill/post handling and run details rendering. |
| apps/predbat/annual.py | Introduces DEFAULT_EXPORT_LIMIT_KW, validates export_limit_kw, and applies it as a grid cap in apply_hardware(). |
| apps/predbat/tests/test_web_annual.py | Updates form POST expectations and verifies export limit default/prefill behavior. |
| apps/predbat/tests/test_annual_config.py | Adds coverage for new top-level key, legacy fallback, precedence, and PV-only behavior. |
| apps/predbat/tests/test_annual_bootstrap.py | Updates apply_hardware() calls and adds scenarios validating export cap clipping behavior. |
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The move to a top-level field accidentally added exclusive_minimum=True, rejecting 0 - a regression from the original battery.export_limit_kw, which allowed 0 to model a zero-export grid connection. Flagged by Copilot review on PR #4672.
Summary
export_limit_kwas a top-level WhatIf (annual prediction) config field, defaulting to 10kW - the property's grid-connection export cap, combined viamin()with whateverapply_hardware()already derives for export capability (the battery's inverter, or summed solar kWp for a PV-only run).battery.export_limit_kw, so a battery-less run had no way to model a grid export cap at all. It's still read as a legacy fallback so existing hand-written YAML configs and previously stored runs keep behaving the same.export_limitsetting into this field.annual_cli.pyjust feeds YAML intovalidate_config(), so the new key works from the command line automatically.docs/annual-prediction.md.Test plan
./run_all --test annual_config --test annual_bootstrap --test web_annualpasses./run_all --quickpasses (full suite, includingannual_scenarios,annual_job,annual_cli_machine_end_to_end)./run_pre_commitpasses (ruff, black, cspell, markdownlint)🤖 Generated with Claude Code