fix(usage): Grok and Cursor usage limits show pace and the even-spend line#21897

merged8
main
GitHub fork: fix/grok-usage-window-duration
opened22d agobyWwookiist
View on GitHubTwo-way sync enabledPR last imported 4h ago

Problem

Fixes #21896. The Grok and Cursor rows on Usage → Limits never show the pace icon or the even-spend marker. Their windows have no windowDurationMins, so the client cannot tell how much of the period has elapsed.

  • Grok: the billing response already reports currentPeriod.start, but grokUsageResponseToLimits does not decode it.
  • Cursor: the usage response already reports billingCycleStart, but cursorUsageResponseToLimits only reads billingCycleEnd.

Change

packages/provider-grok/src/server/usageLimits.ts now decodes currentPeriod.start and sets windowDurationMins to the rounded minutes between start and end. Because it uses the reported bounds, monthly periods get their real length instead of a fixed constant. If start is missing, not a string, unparsable, or not before end, the window stays as it is today, without a duration.

start is decoded as Schema.optional(Schema.Unknown) so an unexpected value cannot fail the whole billing read. This matches the shape #17061 adds to the same struct, so whichever PR lands second has a trivial rebase. #21802 also touches this file, and I will rebase if either lands first.

packages/provider-cursor/src/server/usageLimits.ts does the same for Cursor. It decodes billingCycleStart (a millisecond timestamp, string or number, like billingCycleEnd) and sets windowDurationMins on each monthly window to the rounded minutes between the two. If the start is missing, not positive, or not before the end, the window is reported without a duration, as before.

Scope and approval

This is a small, focused fix for an obvious bug, filed as #21896. Claude, Codex, and OpenCode Go windows already send windowDurationMins, and the Usage page uses it the same way for every provider. Grok and Cursor already return the period start, but their adapters discard it. The fix changes one function per adapter. It does not change contracts, clients, or settings. Cursor was added after a report on #21896.

Verification

  • Confirmed against the live billing endpoint that the Grok response includes the period start. Weekly account, period fields only: {"type":"USAGE_PERIOD_TYPE_WEEKLY","start":"2026-10-14T20:51:37.352+00:00","end":"2026-10-21T20:51:37.352+00:00"}.
  • Confirmed against the live Cursor endpoint (GetCurrentPeriodUsage) that the response includes billingCycleStart next to billingCycleEnd. For the current cycle the two differ by exactly 30 days, which is 43200 minutes.
  • Grok, before merging current main: vp test run apps/server/src/provider/GrokProvider.test.ts passed 36 tests. New cases cover a real-shaped weekly period (10080 minutes), a February monthly period (40320 minutes), unusable starts (missing, null, number, invalid string, equal to end, after end), and an HTTP decoding test that would fail if start were dropped from the schema. With the source change reverted, the two duration tests fail and the rest pass.
  • Cursor: vp test run src/server/usageLimits.test.ts in packages/provider-cursor passes 8 tests. New cases cover a 30-day and a 31-day cycle (43200 and 44640 minutes) and unusable starts (missing, empty, 0, non-numeric, equal to the end). With the source change reverted, the duration test fails and the rest pass.
  • vp fmt --check and vp lint on packages/provider-cursor/src/server: clean.
  • Manual check for Grok: ran vp run dev with an isolated --home-dir, added the Grok provider, and opened Usage → Limits with the same account.
    • Before (change reverted): the row shows only 96% left. The tooltip reads Grok: 96% left, resets in 2d 0h.
    • After: the row shows the "Under pace" icon and the even-spend marker. The tooltip reads Grok: 96% left, resets in 2d 1h, 29% of the window left.

Before:

After:

Not checked:

  • The Cursor row on the Usage page. The Cursor change is covered by the unit tests and the live response check above only.
  • A monthly Grok period on a real account (I only have a weekly one; the unit test covers it) and the mobile client.
  • After merging current main I could not install dependencies locally (pnpm install --frozen-lockfile stops on minimumReleaseAge for 29 lockfile entries), so the Grok tests, the typecheck, and the knip pre-commit step did not run locally for the final commit. CI needs to cover those.

Claude Opus 5.5 and Claude Sonnet 5.5 in T3 Code (Claude Code harness).

🤖 Generated with Claude Code

Fixes pingdotgg/t3code#21896

Checks

22 successful · 16 skipped
All checks passed
4d0eb0e

Added 1 commit

  • fix(provider-grok): Grok usage limits show pace and the even-spend line88b7794
Synced from GitHub

Explain Change →

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

External image Run configuration

External image Commits

Reviewing files that changed from the base of the PR and between 4160402f28b10504194f5c8811f7e632e8cd10e0 and 4d0eb0e15e143945f1e33ce9f6ab882059288a4f.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review

No actionable comments were generated in the recent review.

Walkthrough

Grok and Cursor usage limit converters now derive windowDurationMins from reported period boundaries. Tests cover valid durations and cases where the duration is omitted because the start bound is invalid or unavailable.

Changes: Usage window duration

Layer / File(s)Summary
Derive and validate the Grok window duration
packages/provider-grok/src/server/usageLimits.ts, apps/server/src/provider/GrokProvider.test.ts
The converter calculates duration from the reported period bounds and retains its zero-usage inference conditions. Tests cover weekly and monthly periods, invalid starts, and duration calculation through readGrokAccount.
Derive and validate the Cursor window duration
packages/provider-cursor/src/server/usageLimits.ts, packages/provider-cursor/src/server/usageLimits.test.ts
The response type accepts a billing-cycle start as a string or number. The converter includes a positive duration when the bounds allow calculation. Tests cover 30- and 31-day cycles and invalid starts.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: jieyuexing, juliusmarminge

Merge Risk: External image Minimal · previous review 41604

No actionable issue is established for the Grok or Cursor duration changes; they are mergeable after normal checks.

Pre-merge checks: Passed 4

Check nameStatusExplanation
Title checkPassedThe title clearly identifies the Grok and Cursor usage-limit fix and its visible effects. It is concise, specific, and related to the main changes.
Description checkPassedThe description includes all required sections: problem, change, scope and approval, and verification. It explains the implementation, linked issue, tests, manual checks, limitations, and remaining ve…
Linked Issues checkPassedIssue #21896 requires Grok usage windows to provide the period duration so the Usage page can show the pace icon, even-spend marker, and window-percentage tooltip. grokUsageResponseToLimits now pars…
Out of Scope Changes checkPassedThe Grok source and tests directly implement #21896. The Cursor source and tests address the same reported symptom by using the already available billingCycleStart and are explicitly included in the…
Full details: Description check

Explanation

The description includes all required sections: problem, change, scope and approval, and verification. It explains the implementation, linked issue, tests, manual checks, limitations, and remaining verification gaps.

Full details: Linked Issues check

Explanation

Issue #21896 requires Grok usage windows to provide the period duration so the Usage page can show the pace icon, even-spend marker, and window-percentage tooltip. grokUsageResponseToLimits now parses currentPeriod.start and currentPeriod.end, computes rounded minutes, and adds windowDurationMins only for a valid positive duration. The Grok tests cover weekly periods, variable monthly periods, unusable starts, and HTTP decoding. Existing client behavior can use this field for the requested indicators.

Full details: Out of Scope Changes check

Explanation

The Grok source and tests directly implement #21896. The Cursor source and tests address the same reported symptom by using the already available billingCycleStart and are explicitly included in the current PR intent. The Cursor changes preserve the existing fallback when the start is missing, invalid, or not before the end. No unrelated contract, client, settings, or repository changes appear in the reviewed diff.

Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
External image Recent review info

External image Run configuration

External image Commits

Reviewing files that changed from the base of the PR and between b98a5c6392121bf18fff49f04edeb4fdba2d9a8a and 4160402f28b10504194f5c8811f7e632e8cd10e0.

External image Files selected for processing: 3

  • packages/provider-cursor/src/server/usageLimits.test.ts
  • packages/provider-cursor/src/server/usageLimits.ts
  • packages/provider-grok/src/server/usageLimits.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Added 2 commits

  • Merge remote-tracking branch 'github/main' into takeover-21897f55a6d4
  • fix(provider-grok): reuse validated billing period boundscdc2312

Note

Written by gpt-6.1-sol on behalf of Maria

thanks @wookiist. the reported period bounds are the right source for pace and the even-spend marker, including variable-length months. i kept your commits and merged current main into this branch.

i simplified the duration calculation to reuse main's strict period-boundary parser. the same parsed bounds now serve zero-usage inference and duration, so impossible dates cannot produce a misleading pace. no client, contract, or settings changes. i kept your weekly/monthly, invalid-start, and billing-decoding tests, added an impossible start, and updated the existing zero-usage expectations.

verification passed through blacksmith-testbox: the two duration tests fail against main for the missing field; all 26 grok tests pass with the fix; vp run check:changed passes format, lint, knip, graphql generation, affected typechecks (5 packages), and focused tests. the worker needed its shallow snapshot attached to the pinned main commit for the changed-file comparison.

browser evidence uses the real usage page in system chrome with the same fixed weekly billing fixture and clock. each snapshot uses the actual converter from main or this branch. the after capture shows both the pace icon and even-spend marker. this proves rendering, not live account integration. live grok billing credentials and native mobile/desktop clients are unverified on this vm. the existing mocked HTTP decoding test covers the provider read path. both independent reviews approve cdc2312da3a21573b4b7f6a776dba1810b4a3cf3, with no findings. github CI and four preview workflows are action_required with no jobs: a maintainer must approve these fork workflows. the green status contexts do not include those blocked workflows. coderabbit skipped a fresh review due to its review quota. this pr is waiting on human workflow approval, not merge-ready yet.

Synced from GitHub

Thanks @maria-rcks for picking this up! Reusing the shared period-boundary parser makes sense, and the extra impossible-start test is a nice addition. Happy to help with anything else if needed.

Added 2 commits

  • Merge upstream/main into fix/grok-usage-window-durationa1982c9
  • fix(provider-cursor): report the billing-cycle length for usage windowsb98a5c6
Synced from GitHub

@maria-rcks @juliusmarminge I pushed a follow-up that adds the same fix for Cursor, as discussed in #21896, and merged current main into the branch (no conflicts). Could you take another look?

Both providers are covered by unit tests that need no account: the Grok cases in GrokProvider.test.ts and the Cursor cases in usageLimits.test.ts. The live Cursor response does include billingCycleStart, a 30-day cycle for my account. For the manual check, the Grok screenshots are in the PR description. I did not check the Cursor row on the Usage page itself.

Locally I could only run the Cursor tests after the merge, because pnpm install --frozen-lockfile stops on minimumReleaseAge. So the Grok tests and the typecheck need CI.

Also, the PR has had pr:gate-failed since Oct 27. If a specific gate failed, or CI is waiting for a run approval, please let me know what I should change.

Written by Claude Sonnet 5.5 on behalf of @wookiist.

Added 3 commits

  • Merge remote-tracking branch 'origin/main' into fix/grok-usage-window-duration94a0d51
  • test(usage): drop redundant Grok decode test and restating comments4160402
  • Merge remote-tracking branch 'origin/main' into fix/grok-usage-window-duration4d0eb0e

Evidence

Real web app; fresh databases; same browser, 1280×800 viewport and light theme. Synthetic upstream responses exercise each commit's unchanged adapters: Grok seven-day period and Cursor thirty-day billing cycle, both halfway elapsed.

Steps on both commits: enable the fixture accounts before startup → pair → Usage → Limits → hover Grok Weekly → hover Cursor Models.

Base omits pace icons, even-spend lines and window percentages. Head shows the icons and halfway lines on all three rows, with 'Even pace — 50% left by now' in both inspected hover panels.

Reproduction files: launcher and interaction steps, settings seed, synthetic upstream responses, Grok CLI fixture.

AI-assisted; verified with the tests and tools listed above.

Not shown:

  • Live Grok/Cursor account sign-in and billing services were not exercised; synthetic credentials and upstream responses made the comparison repeatable.
  • Malformed, missing or reversed billing boundaries were not visually exercised.