Skip to content

Migrate burn plans rolling-window usage to archive query #91

@willwashburn

Description

@willwashburn

Context

burn plans (and computePlanUsage in @relayburn/analyze) computes monthly/rolling usage by calling queryAll() and reducing in memory (packages/cli/src/commands/plans.ts:6,60, packages/analyze/src/plans.ts). For users with several plans, the same ledger gets walked once per plan and once per burn plans invocation. The archive's turns table is already indexed on ts and carries every cost-relevant token column (input_tokens, output_tokens, reasoning_tokens, cache_read_tokens, cache_create_5m_tokens, cache_create_1h_tokens).

PR #78 explicitly defers this rewire:

Rewiring burn summary / compare / plans / @relayburn/mcp to read from the archive (each command is a self-contained migration that keeps the in-memory fallback intact).

Issue #40 calls this out as well:

burn limits / burn plans (#5, #39) want repeated spend lookups over rolling windows.

Proposal

  1. Add a planUsageFromArchive(plan, now) helper that issues a single SELECT SUM(input_tokens), SUM(output_tokens), ..., SUM(...) FROM turns WHERE ts >= ? AND ts <= ? AND <provider filter> for the plan's reset window.
  2. Translate the per-provider matchers (anthropic vs cursor vs custom) into SQL WHERE clauses on model / source.
  3. Compute projectedEndOfCycleUsd, limitedData, etc. from the SQL aggregates plus the existing pricing snapshot; these are arithmetic over already-grouped numbers.
  4. Keep the queryAll() path behind a fallback flag.

Tests:

  • Parity test against the existing implementation for built-in presets (Claude pro / max, custom budget) and for the limited data early-window path.
  • Mid-cycle reset-day boundary correctness.
  • Multi-plan list output: text and --json.

Acceptance criteria

  • burn plans (list view) queries the archive with one SQL aggregate per plan, not a full ledger scan per plan.
  • Output is byte-identical to the pre-migration implementation for the parity fixture (text and --json).
  • All built-in presets and custom plans continue to render correctly, including limitedData flagging.
  • Fallback flag preserves the old behavior.
  • Performance: on a ledger with >=100k turns and 3 configured plans, burn plans returns in <100ms after the archive is current.

Out of scope

Refs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions