Commit 5282391
refactor(enphase): replace per-family write patches with a single reconcile pass
The previous commit on this branch (create-path retry, a pending-status
debounce, and a bugfix for the debounce interacting badly with activation)
kept revealing new problems in different places - and review surfaced a
fourth, structural gap: a family being disabled can leave a stale, still-live
window that a *different* family's write then collides with, which none of
the per-family retry/prune machinery could see across families. That's the
signal to stop patching and reconsider the architecture rather than add a
fifth fix (systematic-debugging Phase 4.5).
Replaces apply_battery_schedule with a single reconcile function, called
both periodically (a new 5-minute tier in run(), so a missed/dropped write-
switch trigger can't leave the cloud diverged from the plan indefinitely)
and from the write switch as before:
apply_battery_schedule: up to 3 read-clean-write attempts, short backoff
between, then defer to the next periodic call or trigger.
_reconcile_once: fresh read, then two phases - delete anything that must
not survive (a family being disabled, or an enabled-but-moving family
whenever more than one family is changing this pass) *before* any family
writes anything, then write/activate what's still needed.
The delete-vs-update-in-place split (see the design doc's "Update strategy")
is what actually closes the cross-family gap: a new window for one family
can otherwise collide with a different family's old, not-yet-updated window
even when neither family's *new* windows overlap each other. Counting how
many families are changing this pass is enough to decide - no interval-
overlap math needed, and DTG/RBD are mutually exclusive by construction so
it only has to reason about two families at a time, not three.
Removed as no longer needed: _put_schedule_with_conflict_retry /
_create_schedule_with_conflict_retry (two near-duplicate per-write retry
helpers -> one outer retry), _write_and_activate, the pending-status
debounce and its schedule_pending_since tracking, and the on-failure cache
invalidation (every attempt re-reads from the cloud, so there is nothing
local left to invalidate).
Also adds a scripted live test harness (enphase.py --reconcile-sequence),
driving a sequence of real schedule changes - including the cross-family
case - against a real account using only midnight-05:00 windows and RBD
(freeze-export) rather than a real DTG target, so nothing it does can
actually charge from or export to the grid.
Design: docs/superpowers/specs/2026-08-08-enphase-schedule-reconcile-design.md
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>1 parent 9985d8f commit 5282391
3 files changed
Lines changed: 775 additions & 286 deletions
File tree
- apps/predbat
- tests
- docs/superpowers/specs
0 commit comments