feat(usage-budget): tier-aware Usage Budget card for Enterprise + Pro [GET-20]#54
Conversation
…ants [GET-20] The usage endpoint returns a different payload per account tier; rendering half-populated bars on Enterprise accounts has been the visible bug since April. UsageLimitsData and UsageBudgetResult are now discriminated unions on kind, lib/usage-limits-parser.ts is the single classifier from raw JSON, and the budget agent branches on kind to produce a tier-appropriate render contract (session windows, monthly credit, or unsupported). Conversation store re-tags pre-GET-20 records as session on read so the upgrade is forward-compatible without a write migration.
Replace the inline session-shape validation in fetchAndStoreUsageLimits with parseUsageResponse so all three tier variants flow through the same dispatch path. STORE_USAGE_LIMITS becomes a discriminated message; the background handler rebuilds the matching UsageLimitsData variant without re-parsing. Delta tracking now uses getTrackedUtilization, which returns sessionPct on session and utilizationPct on credit so the math is the same on both tiers in tier-appropriate units. Overlay state narrows to renderable variants only — the unsupported budget has no UI to draw and is gated out at the call site.
… [GET-20] UsageBudgetCard branches on budget.kind: session keeps the existing session+weekly layout, credit renders a single monthly spend bar with the agent's "$X of $Y spent" label and an Enterprise pill, and unsupported shows "Saar can't read usage on this account type yet". A new isClaudeTab prop disambiguates the empty state — off-tab users get a prompt to open claude.ai instead. The in-page overlay's weekly bar is now scoped to session budgets (credit has no weekly window) and the "this reply" delta label switches to "% of monthly" when the budget is credit-tier, since lastDeltaUtilization is tracked in tier-appropriate units.
…abel [GET-20]
New coverage:
- usage-limits-parser.test.ts: all four parser outcomes (session, credit,
unsupported, null) plus dispatch priority and malformed-input edges,
anchored on the verbatim Enterprise fixture from 2026-04-23.
- usage-budget.test.ts: credit variant zone boundaries, currency-aware
"$X of $Y spent" label, Dec→Jan reset rollover, unknown-currency
fallback, and getTrackedUtilization.
- usage-budget-card.test.tsx: render tests for the three GET-20 ACs —
Enterprise spend bar, Pro/Personal session+weekly layout, Teams /
unrecognized empty state, plus the off-tab "Open claude.ai" branch.
- overlay-delta-label.test.ts: locks in Option B from the plan — "% of
session" on session budgets, "% of monthly" on credit budgets.
Existing fixtures retagged with kind: 'session' across audit, integration,
and unit suites. 1,548 tests green.
|
@DevanshuNEU is attempting to deploy a commit to the Dev's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 16 minutes and 36 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (20)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Summary
Anthropic's
/api/organizations/{orgId}/usageendpoint returns a different shape per account tier. The Usage Budget card silently rendered the "Open claude.ai" placeholder on Enterprise accounts because the response hadfive_hour: null/seven_day: nulland the real data sat underextra_usage. This PR adds tier dispatch end-to-end so Enterprise users see their monthly spend and Pro/Personal users keep the existing layout with no regression.Type of Change
feat— New featureWhat Was Changed
Foundation (tier types + parser):
lib/message-types.ts—UsageLimitsData,UsageBudgetResult, andStoreUsageLimitsMessageare now discriminated unions onkind:session(Pro/Personal/Max/Team),credit(Enterprise),unsupported(recognized 200 with neither shape).lib/usage-limits-parser.ts(new) — single classifier from raw endpoint JSON to typedUsageLimitsData. Returnsnullonly when the body is not even an inspectable object (caller treats as transient failure and keeps the previous render).lib/usage-budget.ts—computeUsageBudgetbranches onkind. Credit path renders"$304.91 of $500.00 spent"viaIntl.NumberFormat(currency formatter cached by code),"Resets May 1"viaIntl.DateTimeFormatwith Dec→Jan rollover, and zone classification onutilizationPctalone. NewgetTrackedUtilization(budget)returns the tier-appropriate value for delta tracking.lib/conversation-store.ts—getUsageLimitsre-tags pre-GET-20 untagged records assessionon read so the upgrade is forward-compatible without a write migration.Wiring:
entrypoints/claude-ai.content.ts—fetchAndStoreUsageLimitsusesparseUsageResponse; delta tracking usesgetTrackedUtilization; both call sites gate onkind !== 'unsupported'before applying budget to overlay state.entrypoints/background.ts—STORE_USAGE_LIMITSrebuilds the matchingUsageLimitsDatavariant from the discriminated message.lib/overlay-state.ts—applyUsageBudgetnarrowed toRenderableBudget(session | credit); the type system now rejects unsupported budgets at the boundary.Render:
entrypoints/sidepanel/components/UsageBudgetCard.tsx— branches onbudget.kind. Session keeps the existing two-bar layout; credit renders a single Monthly bar with the$X of $Y spentstatus,Resets {date}, and an Enterprise pill; unsupported (and on-tab!budget) shows"Saar can't read usage on this account type yet". NewisClaudeTabprop disambiguates the off-tab "Open claude.ai" case.entrypoints/sidepanel/App.tsx— passesisClaudeTab.ui/overlay.ts— weekly bar gated tokind === 'session'(Enterprise has no weekly window). The "this reply" delta label switches to"% of monthly"on credit budgets so the wording matches the unit.Tests (1,548 passing, 1,492 → 1,548 net +56):
tests/unit/usage-limits-parser.test.ts(new) — all four parser outcomes + dispatch priority + malformed input edges, anchored on the verbatim Enterprise fixture from 2026-04-23.tests/unit/usage-budget-card.test.tsx(new) — render tests for AC#1/fix(background): cast storage reads to typed interfaces to resolve TS2322 #2/fix(inject): eliminate race condition in SSE token counting #3 (Enterprise spend bar, Pro/Personal session+weekly layout, Teams unsupported empty state, off-tab prompt).tests/unit/overlay-delta-label.test.ts(new) — locks in"% of session"vs"% of monthly"based on budget kind.tests/unit/usage-budget.test.ts— credit variant zone boundaries, currency formatting, Dec→Jan rollover, unknown-currency fallback, andgetTrackedUtilization.kind: 'session'across audit, integration, and unit suites.How to Test
bun run compile && bun run test && bun run build— all three green.bun run devand load the unpacked build from.output/chrome-mv3/.claude.ai, send a message, verify the side panel Usage Budget card still shows Session and Weekly bars with correct percentages. The overlay weekly bar still renders. The "this reply" line says"X% of session".claude.aion the Northeastern Enterprise account, send a message, verify the card shows a single Monthly bar with"$X.XX of $Y.YY spent","Resets May 1", and an "Enterprise" pill in the header. The overlay weekly bar is hidden. The "this reply" line says"X% of monthly"./usageresponse lacks both shapes, verify the card shows"Saar can't read usage on this account type yet"."Open claude.ai to load usage data".chrome.storage.local, verify the card still renders the session layout (the read shim re-tags untagged records).Checklist
bun run test) — 55 files, 1,548 tests.bun run compile).bun run build).feat, 1×test).Related Issues
Closes GET-20.
Notes for Reviewer
"% of session". On Enterprise,lastDeltaUtilizationis monthly utilization, so the wording was misleading. Approach picked in plan: switch the label bystate.usageBudget.kindrather than dropping the % entirely or adding overlay-state plumbing for tier separately.sessionon read. Storage is left untouched; the next write overwrites with the fully-tagged shape. This matches the issue's out-of-scope clause and avoids a migration write that has to defend against partial failures.nullso we don't retry the constructor.