Skip to content

Dispatch starvation when Daikin quota tight (post-Phase A) #309

@albinati

Description

@albinati

Symptom

On 2026-05-10 morning (~09:00 BST), action_schedule had 0 Daikin actions queued for the day despite the LP planning a tank lift to 65°C at 13:30 UTC + evening reheats. Plan ran fine; dispatch's budget guard pruned everything.

Root cause

src/scheduler/lp_dispatch.py:710-715:

reserve = int(getattr(config, "DAIKIN_RESERVE_FOR_HEARTBEAT", 30))
headroom = max(0, quota_remaining("daikin") - reserve)

Phase A (#308) removed Daikin calls from the heartbeat. The 24h rolling quota window still contained yesterday's pre-Phase-A burn (145/180 used). At plan-fire time, quota_remaining=31, headroom=31-30=1 → most LP-planned action pairs got pruned by _apply_write_budget.

The window will clear naturally by ~22:42 UTC (24h after Phase A deploy), so dispatch will recover today / tomorrow without intervention.

Why this is a real concern

Once steady-state, expected Daikin usage:

  • Brief reads (08:00, 22:00 BST): ~4-10/day
  • LP plan dispatches (multiple MPC fires): ~30-60/day
  • Slot reconciles (cache-hit mostly): ~5-10/day
  • Token refresh (lazy): ~3/day
  • Total: ~50-80/day out of 180 budget

The 30-call reserve is sized for old heartbeat-era. With heartbeat now using 0/day, it's still meaningful safety buffer for slot-boundary reconciles + briefs + token refresh, but worth re-tuning once we observe ~14 days of steady-state usage.

Proposed actions

Not urgent — wait for self-recovery first.

  • Observe Daikin call patterns for 7 days post-Phase-A. Capture per-kind histogram from api_call_log.
  • Right-size DAIKIN_RESERVE_FOR_HEARTBEAT based on observed steady-state non-dispatch usage. Likely 10-15 instead of 30.
  • Consider renaming the var (it's no longer about heartbeat). Maybe DAIKIN_RESERVE_FOR_OPS.
  • Add a panic-mode dispatch fallback: when headroom < threshold, write only NEGATIVE / PEAK pairs (skip CHEAP / SOLAR_PREHEAT) so critical safety actions always make it through.
  • Brief warning line when today's plan was pruned ("Daikin dispatch dropped N/M pairs due to quota — \ cost upside lost").

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions