Split update_pred into plan_once()/execute_once() entry points#4186
Draft
mgazza wants to merge 6 commits into
Draft
Split update_pred into plan_once()/execute_once() entry points#4186mgazza wants to merge 6 commits into
mgazza wants to merge 6 commits into
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 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.
What
Refactors
update_pred()into three separately callable pieces, withupdate_pred()itself becoming a pure composition of them so existing behaviour is unchanged:plan_once(scheduled=True)— pre-flight fetches +calculate_plan+ persist + rate publish; returns a plan artifact summary (recomputed,plan_valid,plan_version,plan_last_updated) orNoneon the existing pre-condition failures.execute_once(refetch_inverter=True)— optional inverter re-read +execute_plan()._post_run_bookkeeping(...)— the existing post-run tail, moved verbatim.Also adds a monotonic
plan_versionto the plan artifact persisted bysave_plan()/load_plan().Note on
plan_version: it is an in-memory monotonic counter persisted alongside the plan bysave_plan()and restored byload_plan(); if the stored artifact expires (8h) or storage is unavailable it restarts from 0 on the next process start. Within a running process it strictly increases, which is the property downstream consumers rely on.Why
For predbat.com we want to schedule planning and execution independently (event-driven replans on tariff drops / settings changes, rather than only the 5-minute boundary) and run many instances in one pooled process. That needs separately callable, re-entrant plan/execute entry points and a versioned plan artifact so a stale slow plan can never overwrite a newer one. Same pattern as the recent storage/cache provider split: the entry points live upstream, all pooling/scheduling stays in our SaaS layer, and self-hosted behaviour is untouched.
Parity
tests/test_plan_execute_split.pystarts with six characterisation scenarios written against the ORIGINAL fusedupdate_pred(fresh-plan reuse, recompute, aged-plan double-execute, inverter-fetch failure, zero rates, template) — they were committed passing before the refactor and pass unchanged after it.Question
The aged-plan path recomputes via
calculate_plan(recompute=True)but does not callsave_plan(), unlike the main recompute path — so a plan recomputed on age isn't restored after a restart. This PR deliberately preserves that behaviour (and the characterisation test pins it). Was that intentional, or worth fixing in a follow-up?🤖 Generated with Claude Code