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
- 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.
- Translate the per-provider matchers (anthropic vs cursor vs custom) into SQL
WHERE clauses on model / source.
- Compute
projectedEndOfCycleUsd, limitedData, etc. from the SQL aggregates plus the existing pricing snapshot; these are arithmetic over already-grouped numbers.
- 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
Out of scope
Refs
Context
burn plans(andcomputePlanUsagein@relayburn/analyze) computes monthly/rolling usage by callingqueryAll()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 perburn plansinvocation. The archive'sturnstable is already indexed ontsand 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:
Issue #40 calls this out as well:
Proposal
planUsageFromArchive(plan, now)helper that issues a singleSELECT SUM(input_tokens), SUM(output_tokens), ..., SUM(...) FROM turns WHERE ts >= ? AND ts <= ? AND <provider filter>for the plan's reset window.WHEREclauses onmodel/source.projectedEndOfCycleUsd,limitedData, etc. from the SQL aggregates plus the existing pricing snapshot; these are arithmetic over already-grouped numbers.queryAll()path behind a fallback flag.Tests:
limited dataearly-window path.--json.Acceptance criteria
burn plans(list view) queries the archive with one SQL aggregate per plan, not a full ledger scan per plan.--json).limitedDataflagging.burn plansreturns in <100ms after the archive is current.Out of scope
burn plans add/remove/set-reset-day— these touch the plans config file, not the ledger.summary,compare, or MCP tools.Refs
burn archive(#40) #78 (Derived analytics archive: materialize the ledger into a local queryable store #40 follow-up)