Skip to content

fix: MODEL DISTRIBUTION shows retired models (4.5) from stats-cache historical data #140

@pitimon

Description

@pitimon

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions