Skip to content

fix(dashboard): always show time-range rows at 0 and disabled Extra Usage as no data - #1555

Merged
robinebers merged 1 commit into
mainfrom
sco-67-always-show-ranges
Nov 3, 2026
Merged

robinebers merged 1 commit into
mainfrom
sco-67-always-show-ranges

Conversation

@robinebers

@robinebers robinebers commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

TL;DR

Time-range rows (Today, Yesterday, This Week, This Month, Last/Prior 30 Days) now always show. When the provider reports nothing for a range, the row reads 0 in its usual unit and its popup says " didn't report any data for this range." When Claude, Cursor, or Copilot reports Extra Usage as off, that row now shows too: Claude and Cursor read $0 spent with no bar, and Copilot reads 0. The account page's switch is now the only way to hide one of these rows.

What was happening

  • ChatGPT, Cursor, and Ollama built a range row only from the days the provider returned, so a day with no use, or a failed read, removed Today (or any other range) from the card.
  • OpenRouter seeded Today, This Week, and This Month at $0 in its own mapper (noSpend), so those rows always showed. Its Yesterday and Prior 30 Days still dropped when the activity read was empty or failed. That is why the two providers behaved differently.
  • Claude dropped Extra Usage when extra_usage.is_enabled was false. Cursor dropped it when on-demand was off or $0, and Copilot dropped it when overage wasn't permitted.

What this changes

  • WidgetDescriptor.unreportedValues: one shared fallback. When a snapshot has no line for a descriptor that has this fallback, WidgetDataStore.data(for:) shows it as a values row (0 in the row's units, with no bar). Every .window history descriptor gets it from its own measures, so no provider needs its own patch.
  • OpenRouter's noSpend seeding is removed. Its listedKeysSpend starts from nothing and relies on the shared fallback.
  • Every window row now gets its UsageBreakdown, even with nothing read. UsageBreakdown.isEmpty is true when nothing was reported, so the popup shows the shared empty state from fix(openrouter): drop BYOK from saved rows, share one popup empty state, name every account #1552.
  • Claude extra, Cursor onDemand, and Copilot extra use .showingWhenUnreported(...), so a disabled Extra Usage reads 0.
  • Row order, defaults, and the account-page switches are unchanged. The page already listed every descriptor, so empty ranges were listed and on by default before this PR, and they still are. Switching one off hides it, and an empty range can be pinned (covered by a test).
  • README, docs/dashboard.md, docs/providers.md, and CHANGELOG are updated.

Heads-up

  • No new rows and no new positions. Every row this PR now shows already existed in widgetDescriptors and keeps its place. Two cases now show where they used to hide:

    • An OpenRouter standard key's Yesterday and Prior 30 Days read $0. OpenRouter lets only a Management key read activity, so these rows can never show anything else.
    • An Ollama legacy plan, which reports only requests, shows its three ranges at $0 · 0 tokens.

    Robin may want those two hidden by default instead. That is a defaults question for Robin.

  • Not changed: open balances still follow their existing rules. These are ChatGPT Extra Usage credits (hidden at a $0 balance by an explicit rule from feat(dashboard): rebuild the panel around Priority and All Usage #1535), Devin and Ollama Extra Usage balances, and Grok's pay-as-you-go badge, which already reads "Disabled". A balance at $0 also lists under Used Up in Priority, so making those show at $0 is a separate call.

  • The CLI's limits export still sends only what the provider reported. The zero fallback applies to the dashboard only.

Tests

All run on the Mac mini (macOS 15.7.7) with nice -n 10 script/test_quiet.sh --filter ….

  • Red without the fix (test changes only, on main 313213a): 15 tests failed across UnreportedRowsTests (5), CodexUsageHistoryTests (2), CursorUsageHistoryTests (2), CursorMetricsTests (2), OllamaUsageHistoryTests (2), OpenRouterProviderTests (1: empty and failed activity leave Yesterday and Prior 30 Days at "No data" with no popup), and OpenRouterUsageHistoryTests (1).
  • Green with the fix: 170 tests, 0 failures, across those suites plus UsageHistory, UsageBreakdownDetail, PriorityBoard, DashboardFamily, AccountMetricSettings, WidgetDataStore, WidgetDataStorePlan, LimitsEnvelope, SignInAgain, DashboardLiveLayout, CodexUsageClientAndMapper, CursorTeamPool, CopilotOrgBilling, ClaudePlan, AccountChange, and OpenRouterUsageMapper.
  • New UnreportedRowsTests covers five cases:
    • Every range of every provider reads 0 in its unit.
    • Claude with extra usage off reads $0 spent with no bar and stays on the card.
    • Cursor and Copilot Extra Usage read 0 when not reported.
    • An empty range is listed on the account page, on by default, pinnable (it shows in Pinned), and hidden only by its switch.
    • A range with nothing read gets empty-state details.
  • Tests whose assertions encoded the old hiding are updated to the new behavior. No test was deleted.

Screenshots

I made these offscreen on the Mac mini with an uncommitted render test, from the same fixtures before and after. Before this change, an unreported range had no row, so it had no popup either.

ChatGPT, no use today. Before: Today is missing. After: 0 tokens.
before/chatgpt-card-light.png after/chatgpt-card-light.png
before/chatgpt-card-dark.png after/chatgpt-card-dark.png
Today popup after:
after/chatgpt-today-popup-light.png after/chatgpt-today-popup-dark.png

OpenRouter, empty activity read. Before: Yesterday and Prior 30 Days are missing. After: every range is $0.
before/openrouter-card-light.png after/openrouter-card-light.png
before/openrouter-card-dark.png after/openrouter-card-dark.png
Yesterday popup after:
after/openrouter-yesterday-popup-light.png after/openrouter-yesterday-popup-dark.png

Claude, Extra Usage disabled. Before: the row is hidden. After: $0 spent with no bar.
before/claude-card-light.png after/claude-card-light.png
before/claude-card-dark.png after/claude-card-dark.png

Account page (ChatGPT, no data read). It lists Today, Yesterday, and Last 30 Days, each on by default. This page was the same before. The switches look grey only because the render window was never key.
after/account-page-light.png after/account-page-dark.png

Open in Capy


Note

Medium Risk
Changes central display logic in WidgetDataStore and history aggregation across many providers, which can affect what users see after failed refreshes though behavior is intentional and well-tested.

Overview
Dashboard metrics that used to disappear when a provider had nothing to say now stay visible at 0, with account-page switches as the only way to hide them.

Shared fallback: WidgetDescriptor.unreportedValues plus WidgetDataStore.data(for:) synthesize a values row when the snapshot has no line. History window descriptors get zero fallbacks from their usual measures (e.g. $0 · 0 tokens for Cursor). Claude, Cursor, and Copilot Extra Usage use .showingWhenUnreported(...) so disabled or off plans show $0 spent or 0 instead of omitting the row.

History / breakdowns: HistoryRow.append still builds usage breakdowns even when no line is appended, and UsageBreakdown no longer requires totals—empty ranges drive the existing “didn’t report any data” popup. OpenRouter drops the old noSpend pre-seed and relies on the same fallback (notably standard keys now show Yesterday and Prior 30 Days at $0).

Docs and CHANGELOG describe the behavior; tests add UnreportedRowsTests and update history/metrics expectations for zero rows on failed or quiet reads.

Reviewed by Cursor Bugbot for commit f031ea1. Bugbot is set up for automated code reviews on this repo. Configure here.

…sage as no data

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@cursor

cursor Bot commented Nov 3, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 72fadeae-d275-45ae-88e1-1a243b8797be)

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed the full diff and traced the zero-value fallbacks through history aggregation, dashboard visibility, Priority classification, and CLI export.

  • Display fallbacks: Unreported time ranges and Claude, Cursor, and Copilot Extra Usage now display zero in their declared units without overriding reported values or changing balance behavior.
  • History details: Empty windows receive breakdowns for the existing no-data popup, and OpenRouter uses the shared fallback instead of seeded totals.
  • Coverage and documentation: Regression tests cover units, visibility, pinning, disabled Extra Usage, and failed history reads; documentation describes the changed behavior. GitHub's Build and Test check passed. I did not run the macOS suite locally because this runner is Linux.

Pullfrog  | View workflow run | Using gpt-6-astra | 𝕏

@robinebers
robinebers merged commit 16d35bc into main Nov 3, 2026
7 checks passed
@robinebers
robinebers deleted the sco-67-always-show-ranges branch November 3, 2026 07:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant