Skip to content

fix(usage): Cursor account history loads about 4x faster - #14384

Open
im-kvijay wants to merge 2 commits into
pingdotgg:mainfrom
im-kvijay:fix/usage-cursor-parallel-pages
Open

im-kvijay wants to merge 2 commits into
pingdotgg:mainfrom
im-kvijay:fix/usage-cursor-parallel-pages

Conversation

@im-kvijay

Copy link
Copy Markdown
Contributor

What Changed

The Cursor account history reader now keeps up to six pages requested ahead of the one it is consuming, instead of requesting each page only after the previous one returned.

Pages are still consumed strictly in page order, so the count check, boundary-overlap reconciliation, the terminal-page rule and the "Sign in to Cursor again" result behave exactly as they did page by page. When the read ends for any reason, requests still in flight are cancelled.

The existing loop body became readPage with no changes inside it; the new code is the loop that drives it. 23 changed lines outside tests.

Why

Usage waits for every source before it shows anything, and on a busy Cursor account this reader is nearly all of that wait.

Cursor caps a page at 1,000 events (larger sizes return 400) and takes about a second to answer one regardless of size. A 30-day window with 36,479 events is 37 requests, which were made one after another.

A trace from a live server recorded a 60.9 s usage load with 60.6 s of it inside UsageService.collectDirs. On the same machine the warm Claude, Codex, Grok and OpenCode scan takes about 0.4 s. 60 s is also this reader's deadline, past which Cursor history is dropped for that load.

#10409 verified the reader against 118 Cursor records, which fit in one page.

I looked for a way to avoid paging. The dashboard CSV export is a single request but took 38 s and has no conversation ids, the aggregated endpoint does not reconcile with the event list, and the Admin API is Enterprise-only.

Validation

  • Same closed 30-day window on a real account, this branch against the reader on main: 45.9 s → 9.6 s, 37 requests each, identical records (same hash over timestamps, models, sessions, totals, cost and dedupe keys).
  • 90-day window on the same account: 44 pages in 12.7 s, every response 200. Those runs sent 118 requests in about 68 s without a rejection. Cursor's actual rate limit is unknown, and I had no larger account to test.
  • New test: at most six pages are in flight, and records stay in page order when later pages answer first. It fails on main.
  • New test: a failed page, and a 401 followed by a failed page, each end with the message a page-by-page read gives and leave no request open.
  • 45 tests pass across cursorUsageReader, usageTranscriptReader and UsageService; formatting, targeted lint and the server typecheck pass.

Usage still waits for Cursor before showing the local providers. This shortens that wait; it does not remove it.

Checklist

  • This PR is small and focused
  • I explained what changed and why

Implemented and verified with Claude Opus 5.5 through the Claude Code harness.

🤖 Generated with Claude Code

The reader requested one page of account events at a time. Cursor caps a
page at 1,000 events and takes about a second to answer one, so a busy
account spent most of a minute here before Usage could show anything.

Keep up to six pages requested ahead of the one being consumed. Pages are
still consumed in page order, so the read ends as it did before, and any
request still in flight is cancelled when it does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Sep 30, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at a8ae7ff

Macroscope's review found this PR approvable — This is a focused optimization of the existing Cursor history fetch path, adding bounded six-page concurrency while preserving page order, result handling, timeouts, and cancellation. The accompanying tests cover ordering, concurrency, failures, authentication responses, and cleanup, with no product-default or static-analysis changes.

Notes:

  • Diff unchanged. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Important

Review skipped

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

⚙️ Run configuration
  • Configuration used: Repository: pingdotgg/t3code/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6101ef1c-1333-43bb-8f1f-c8aa7bbf4065
📥 Commits

Reviewing files that changed from the base of the PR and between a8ae7ff and 2973f80.

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. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: pingdotgg/t3code/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 9e2e64ff-26ce-41b5-85bd-b339120c19ef

📥 Commits

Reviewing files that changed from the base of the PR and between c18e5ea and a8ae7ff.

📒 Files selected for processing (2)
  • apps/server/src/usage/cursorUsageReader.test.ts
  • apps/server/src/usage/cursorUsageReader.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.


📝 Walkthrough

Walkthrough

readCursorAccountUsage now fetches up to six usage pages concurrently and consumes their results in page order. It aborts outstanding requests when the read exits. Tests cover ordering, concurrency, and failure handling.

Changes

Cursor usage pagination

Layer / File(s) Summary
Concurrent page fetching, ordered results, and cancellation
apps/server/src/usage/cursorUsageReader.ts, apps/server/src/usage/cursorUsageReader.test.ts
The reader requests up to six pages ahead, validates page responses, and consumes events in page order. It aborts outstanding requests when the read exits. Tests check concurrency, ordering, and error handling.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Refactor

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant Reader as readCursorAccountUsage
  participant Page as readPage
  participant Cursor as Cursor API
  Caller->>Reader: Read account usage
  Reader->>Page: Request up to six pages ahead
  Page->>Cursor: Fetch usage page
  Cursor-->>Page: Return page response
  Page-->>Reader: Return validated events
  Reader-->>Caller: Return events in page order
Loading

Suggested reviewers: yash-singh1

Merge Risk: ⚪ Minimal · up to a8ae7

The change accelerates Cursor usage retrieval while preserving ordered results and cancelling outstanding requests. No actionable merge-blocking risk remains beyond normal checks.

Architecture Summary

Architecture risk: 🔵 Low · up to a8ae7

The change affects 1 system.

Changed systems: apps/server

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — apps/server (service) was modified; 2 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in apps/server/src/usage/cursorUsageReader.test.ts: Adds a pagination test that simulates 8,001 usage events, makes later pages respond sooner, and asserts that concurrency reaches six while timestamps remain in page order.
  • observed — Modified behavior in apps/server/src/usage/cursorUsageReader.test.ts: Adds failure-path tests where page 3’s request rejects while later requests are pending. For both a page-response failure and a 401 on page 2, the test checks the expected error, empty records, and no remaining open requests after abort.
  • observed — Modified behavior in apps/server/src/usage/cursorUsageReader.ts: Adds an abort controller for cancelling requests that remain in flight when the read exits.
  • observed — Modified behavior in apps/server/src/usage/cursorUsageReader.ts: Combines the shared cancellation signal with the 60-second deadline and moves page-fetching setup into readPage, which fetches and validates an individual page.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: faster Cursor account history loading through the usage reader optimization.
Description check ✅ Passed The description explains what changed, why it changed, validation results, test coverage, and checklist status. UI-specific sections are not required because this PR does not change the UI.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@juliusmarminge juliusmarminge added the macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews label Oct 1, 2026 — with ChatGPT Codex Connector

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants