Skip to content

fix: blank dashboard — model filter fallback + empty-string model normalisation#109

Open
HaydenHaines wants to merge 8 commits into
phuryn:mainfrom
HaydenHaines:main
Open

fix: blank dashboard — model filter fallback + empty-string model normalisation#109
HaydenHaines wants to merge 8 commits into
phuryn:mainfrom
HaydenHaines:main

Conversation

@HaydenHaines
Copy link
Copy Markdown
Contributor

Summary

This PR fixes two root causes of the blank dashboard that users have been reporting in issues #76, #88, #90, #93, #99, #106.

Root cause 1 — readURLModels returns empty set (JS)

When a user's model names in the DB don't contain 'opus', 'sonnet', or 'haiku', readURLModels filtered to zero billable models and returned an empty selectedModels set. Every row was then filtered out, producing a blank dashboard across all date ranges — including "All".

Fix: if no billable models are found, fall back to selecting ALL models.

// before
if (!param) return new Set(allModels.filter(m => isBillable(m)));

// after
if (!param) {
  const billable = allModels.filter(m => isBillable(m));
  return new Set(billable.length > 0 ? billable : allModels);
}

Root cause 2 — empty-string model not normalised to 'unknown' (SQL)

Turns can have model = '' (empty string, not NULL). COALESCE(model, 'unknown') only catches NULL — empty strings pass through as '', creating an invisible bucket that the model filter never selects. Fixed with COALESCE(NULLIF(model, ''), 'unknown') in all three query sites.

This PR also includes 7 previously accumulated fixes that were committed locally but not yet pushed upstream (session names display, concurrent HTTP server, pricing refactor, Cowork audit tracking, bookmarkable URL fix, range filter bounds fix, peak-hour highlighting removal).

Test plan

  • python3 -m pytest --tb=short -q — all 130 tests pass
  • New TestEmptyStringModel regression tests cover the COALESCE(NULLIF(...)) fix
  • New test_read_url_models_falls_back_to_all_when_no_billable covers the JS fallback

Fixes #76, #106 (and partially resolves #88, #90, #93, #99)

🤖 Generated with Claude Code

HaydenHaines and others added 8 commits April 29, 2026 00:05
Parse customTitle / agentName from JSONL records (emitted by Claude Code's
/rename command) and store per-session as session_name. The dashboard now
shows "name (id...)" when a name is set, falling back to the truncated ID
otherwise. CSV export now includes both columns.

customTitle is preferred over agentName; the last non-empty value per
session wins, with empty strings ignored so a later blank record can't
clobber an earlier rename. Incremental scans preserve the stored name
when the appended slice contains no rename records (COALESCE NULLIF).

Schema: new sessions.session_name column, migrated via ALTER TABLE on
init_db for existing DBs. Dashboard query falls back to NULL if the
migration hasn't run yet.

Tests: 17 new cases covering resolver precedence, parsing, incremental
scan preservation/update, migration, and dashboard API/HTML output.
self.path includes the query string, so /?range=all and /api/data?cachebust=1
were falling through to the 404 branch. Parse with urllib.parse.urlparse and
match on the path component only. Add three HTTP regression tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Anthropic removed the peak-hours throttle for Pro/Max accounts (May 2026),
making the red bars, ⚡ labels, and "Peak — Anthropic US hours" tooltip
misleading. Drops PEAK_HOURS_UTC, isPeakHour, displayHourToUTC, the
peak-legend CSS, and all related chart rendering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dashboard showed 0 across all ranges when a user's model names didn't
contain 'opus'/'sonnet'/'haiku'. Root cause: readURLModels filtered to
billable models only, producing an empty set that silently filtered out
all data.

Fix 1 (JS): readURLModels now falls back to selecting ALL models when
no billable models are found, so non-standard or unrecognised model
names no longer result in a blank dashboard.

Fix 2 (SQL): COALESCE(NULLIF(model, ''), 'unknown') replaces
COALESCE(model, 'unknown') in all three query sites so that empty-
string model values (not just NULL) are normalised to 'unknown'.

Tests added for both regression paths.

Fixes phuryn#76, phuryn#106

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: cutoff is not defined in applyFilter() causes blank charts Dashboard shows 0 data despite valid stats in terminal

1 participant