Summary
Follow-up from #276 (see design doc docs/superpowers/specs/2026-07-12-dp-continuous-action-reformulation-design.md) and #282 (Approach 1, merged/pending as PR #284). Approach 1 (hardware-aware breakpoint enumeration in Step 2) closed the Step-2-vs-V mismatch, but directly tested against #275's own "Worse" reproduction scenario, it made zero measurable difference — the SOE held past midnight was bit-identical to Option B alone. Root cause: Step 1's value function V (computed once by backward induction, on a fixed SOE_STEP_KWH grid, then linearly interpolated) itself carries approximation error that no amount of exact Step 2 search against that same V can recover from.
This issue is Approach 2: rework _run_dynamic_programming's backward induction to track V as an exact piecewise-linear function of SoE — a small number of genuine (soe, value, slope) breakpoints derived recursively from the next period's breakpoints plus that period's own reward breakpoints — instead of a sampled grid. If V itself has no approximation error, there's no gap left for Step 2 to inherit, regardless of search method.
Why this is needed (not just Approach 1 again)
#282's postmortem: even with an exact Step 2 search, using the same (grid-approximated) V, the DP still holds the same amount of charge on #275's defining reproduction. This confirms the bottleneck is V itself, not Step 2's fidelity to it — exactly what the original design doc predicted Approach 1 alone might not fully close.
Scope
Out of scope for the initial investigation
References
Summary
Follow-up from #276 (see design doc
docs/superpowers/specs/2026-07-12-dp-continuous-action-reformulation-design.md) and #282 (Approach 1, merged/pending as PR #284). Approach 1 (hardware-aware breakpoint enumeration in Step 2) closed the Step-2-vs-V mismatch, but directly tested against #275's own "Worse" reproduction scenario, it made zero measurable difference — the SOE held past midnight was bit-identical to Option B alone. Root cause: Step 1's value functionV(computed once by backward induction, on a fixedSOE_STEP_KWHgrid, then linearly interpolated) itself carries approximation error that no amount of exact Step 2 search against that sameVcan recover from.This issue is Approach 2: rework
_run_dynamic_programming's backward induction to trackVas an exact piecewise-linear function of SoE — a small number of genuine(soe, value, slope)breakpoints derived recursively from the next period's breakpoints plus that period's own reward breakpoints — instead of a sampled grid. IfVitself has no approximation error, there's no gap left for Step 2 to inherit, regardless of search method.Why this is needed (not just Approach 1 again)
#282's postmortem: even with an exact Step 2 search, using the same (grid-approximated)
V, the DP still holds the same amount of charge on #275's defining reproduction. This confirms the bottleneck isVitself, not Step 2's fidelity to it — exactly what the original design doc predicted Approach 1 alone might not fully close.Scope
V[t, :]as a list of breakpoints instead of aSOE_STEP_KWH-spaced array.V[t, :]'s breakpoints fromV[t+1, :]'s breakpoints plus the period's own reward breakpoints (physical charge/discharge bounds, theBATTERY_EXPORT_THRESHOLD_KWHself-throttle crossing) — reusing Replace DP per-period grid search with closed-form breakpoint enumeration (Approach 1 of #276) #282's hardware-percent-grid action space so any implementation stays R==P-safe by construction, not just accurate.Out of scope for the initial investigation
References
docs/superpowers/specs/2026-07-12-dp-continuous-action-reformulation-design.md— original options analysis