Problem
MODEL DISTRIBUTION donut shows Haiku 4.5 (57%), Opus 4.5 (34%) — but these models have zero active sessions. Only Opus 4.6 and Sonnet 4.6 are currently in use.
Root Cause
Donut data comes from stats-cache.json (modelUsage) which is cumulative all-time totals from Anthropic SDK — includes every model ever used.
stats-cache (historical): JSONL sessions (actual):
haiku-4.5: 122M cache tokens (no sessions)
opus-4.5: 1.1B cache tokens (no sessions)
sonnet-4.5: 68M cache tokens (no sessions)
opus-4.6: 2.5B cache tokens 199 sessions ← active
sonnet-4.6: 748M cache tokens 1,833 sessions ← active
The donut includes cache tokens from retired models, making them appear dominant (Haiku 4.5 at 57%) when they haven't been used in months.
Dual Source Problem
This is the same dual-source issue documented in ADR-002:
- stats-cache.json → authoritative for all-time totals (includes retired models)
- JSONL sessions → authoritative for current/windowed data (only active models)
The donut should use JSONL-derived model data (or filter stats-cache by active models).
Fix Options
Option A — Filter by active sessions (recommended)
Only show models that have at least 1 session in the selected date range:
// Cross-reference with sessions to find active models
const activeModels = new Set(sessions.map(s => s.model).filter(Boolean));
const data = Object.entries(modelUsage)
.filter(([model]) => activeModels.has(model))
.map(...)
Option B — Use JSONL session tokens for donut
Aggregate tokens from sessions directly instead of stats-cache:
const modelTokens = new Map();
for (const s of sessions) {
if (!s.model) continue;
const current = modelTokens.get(s.model) || 0;
modelTokens.set(s.model, current + (s.input_tokens || 0) + (s.output_tokens || 0));
}
This respects the date range filter (from/to) and only shows models actually used in that window.
Option C — Show both with visual distinction
Keep all models but visually distinguish active vs retired:
● Opus 4.6 (33%) ← solid color (active)
● Sonnet 4.6 (15%) ← solid color (active)
○ Haiku 4.5 (25%) ← dimmed/striped (retired)
○ Opus 4.5 (20%) ← dimmed/striped (retired)
Data Evidence
Model usage from JSONL sessions (current):
claude-sonnet-4-6: 1,833 sessions (Mar-Apr 2026)
claude-opus-4-6: 199 sessions (Feb-Apr 2026)
<synthetic>: 14 sessions (Mar 2026)
Model usage from stats-cache (all-time, includes retired):
haiku-4.5: 122M cache tokens — NO active sessions
opus-4.5: 1.1B cache tokens — NO active sessions
sonnet-4.5: 68M cache tokens — NO active sessions
Context
Problem
MODEL DISTRIBUTION donut shows Haiku 4.5 (57%), Opus 4.5 (34%) — but these models have zero active sessions. Only Opus 4.6 and Sonnet 4.6 are currently in use.
Root Cause
Donut data comes from
stats-cache.json(modelUsage) which is cumulative all-time totals from Anthropic SDK — includes every model ever used.The donut includes cache tokens from retired models, making them appear dominant (Haiku 4.5 at 57%) when they haven't been used in months.
Dual Source Problem
This is the same dual-source issue documented in ADR-002:
The donut should use JSONL-derived model data (or filter stats-cache by active models).
Fix Options
Option A — Filter by active sessions (recommended)
Only show models that have at least 1 session in the selected date range:
Option B — Use JSONL session tokens for donut
Aggregate tokens from sessions directly instead of stats-cache:
This respects the date range filter (from/to) and only shows models actually used in that window.
Option C — Show both with visual distinction
Keep all models but visually distinguish active vs retired:
Data Evidence
Context