fix(cursor-origin): personal namespace on a later page is found #35918
OriginCli.personalNamespace made one GET /v1/origin/namespaces request and searched only that page; its schema did not read nextPageToken. Origin pages namespaces 30 at a time ordered by slug, so a personal namespace sorting after 30 others was reported missing ('This Cursor account has no Origin namespace'). The fix adds nextPageToken to OriginNamespaceListSchema, and personalNamespace (now an Effect.fn with span 'OriginCli.personalNamespace') loops: fetch the page (passing pageToken via URLSearchParams after the first), return the first 'user' namespace slug, otherwise follow nextPageToken. It stops when there is no token, or when Origin repeats a token it already sent, which guards against a looping server. Only then does it fail with the same not-found OriginCliError as before. I did not reuse OriginPullRequestProvider.readPages: it lives inside another service, collects every page, forces pageSize=100 and caps at 10 pages, while this lookup can stop on the first match. No new regex or parser: the only new parsing is an optional nullable string field in an existing Effect Schema.
Fixes pingdotgg/t3code#35905
Reproduction on main#
On origin/main 6f108e8556 I added packages/source-control-cursor-origin/src/server/OriginCli.test.ts. It runs the unmodified OriginCli.layer, replaces only the Node HTTP transport (vi.mock of @effect/platform-node/NodeHttpClient) with in-memory responses and the host's origin auth token call with a synthetic token. Page one returns 30 team namespaces and nextPageToken 'page-2'; the request carrying pageToken=page-2 returns the personal namespace 'zz-personal' (type 'user'). Running vp test run src/server/OriginCli.test.ts fails with OriginCliError 'Cursor Origin failed in personalNamespace: This Cursor account has no Origin namespace. Claim one at cursor.com/codebase.' The test expects 'zz-personal' and a second request with pageToken=page-2; no second page is ever requested. I did not run the full app UI or use a real Origin account.
Evidence#
Being captured: before and after in the real app. This section is filled in before the pull request can merge.
Tests#
vp test run src/server/OriginCli.test.ts on the base (fix stashed): fails with OriginCliError 'no Origin namespace'. vp test run src/server/ in packages/source-control-cursor-origin with the fix: 2 files, 4 tests pass. vp run check:changed: format, lint, knip, typecheck of 11 packages and tests of 2 files all pass.
Not in this change#
- OriginPullRequestProvider.readPages could move into OriginCli as a shared pagination helper; not needed for this fix.
Who did the work#
- Written by Claude Opus 5.5, in Claude Code
- Reviewed by GPT-6.1 Sol, in Codex, and by Claude Opus 5.5, each on its own
- Proof captured by GPT-6.1 Sol and checked by Claude Opus 5.5
Run by the t3code factory in T3 Code.
- 1
github-actions[bot](GitHub profile, opens in a new tab) added labelsvouch:trusted
tanstack-source added labelsbug
github-actions[bot](GitHub profile, opens in a new tab) added labelssize:M
Approvability#
Verdict: Approved at
efa7ff3Macroscope's review found this PR approvable — Namespace lookup now searches later API pages instead of reporting a missing personal namespace prematurely. It preserves existing selection and authorization behavior, with repeated-token protection and existing request safeguards.
You can add or adjust custom eligibility rules. [Learn more](https://docs.macroscope.com/approvability#example-custom-eligibility-rules).Thread transfer impact#
✅ Thread transfer remains within every enforced ceiling.
Provider Metric Main baseline This PR Impact PR ceiling Codex Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅ Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅ Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅ Codex Live turn WebSocket decoded 21.5 KiB 21.5 KiB 0 B (0.0%) 24.4 KiB ✅ Codex Live turn messages 1 1 0 (0.0%) 8 ✅ Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅ Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅ Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅ Claude Live turn WebSocket decoded 21.9 KiB 21.9 KiB 0 B (0.0%) 24.4 KiB ✅ Claude Live turn messages 1 1 0 (0.0%) 8 ✅ Other scenarios#
All 64 scenario measurements match
main.All 64 scenario measurements
Provider Scenario Metric Main baseline This PR Impact PR ceiling Codex short turn resumeWebSocket decoded10.5 KiB 10.5 KiB 0 B (0.0%) 12.7 KiB ✅ Codex short turn resumeWebSocket messages2 2 0 (0.0%) 2 ✅ Codex long turn running, cold openHTTP decoded281.7 KiB 281.7 KiB 0 B (0.0%) 302.7 KiB ✅ Codex long turn running, cold openrows75 75 0 (0.0%) 75 ✅ Codex long turn running, history pageHTTP decoded92.4 KiB 92.4 KiB 0 B (0.0%) 107.4 KiB ✅ Codex long turn running, history pagerows75 75 0 (0.0%) 75 ✅ Codex long turn finished, cold openHTTP decoded381.5 KiB 381.5 KiB 0 B (0.0%) 410.2 KiB ✅ Codex long turn finished, cold openrows151 151 0 (0.0%) 151 ✅ Codex long turn finished, socket cold openWebSocket decoded381.6 KiB 381.6 KiB 0 B (0.0%) 410.2 KiB ✅ Codex long turn finished, socket cold openWebSocket messages2 2 0 (0.0%) 2 ✅ Codex long turn finished, socket cold openrows151 151 0 (0.0%) 151 ✅ Codex long turn finished, work pageHTTP decoded186.2 KiB 186.2 KiB 0 B (0.0%) 200.2 KiB ✅ Codex long turn finished, work pagerows150 150 0 (0.0%) 150 ✅ Codex idle thread resumeWebSocket decoded65 B 65 B 0 B (0.0%) 200 B ✅ Codex idle thread resumeWebSocket messages1 1 0 (0.0%) 1 ✅ Codex fleet shell snapshotHTTP decoded42.4 KiB 42.4 KiB 0 B (0.0%) 53.7 KiB ✅ Codex fleet shell snapshotrows27 27 0 (0.0%) 27 ✅ Codex fleet shell subscribeWebSocket decoded65 B 65 B 0 B (0.0%) 200 B ✅ Codex fleet shell subscribeWebSocket messages1 1 0 (0.0%) 1 ✅ Codex fleet shell resume checkHTTP decoded18 B 18 B 0 B (0.0%) 100 B ✅ Codex fleet shell resume checkrows0 0 0 0 ✅ Codex stale shell reloadHTTP decoded42.4 KiB 42.4 KiB 0 B (0.0%) 53.7 KiB ✅ Codex stale shell reloadrows27 27 0 (0.0%) 27 ✅ Codex stale shell resumeWebSocket decoded140 B 140 B 0 B (0.0%) 400 B ✅ Codex stale shell resumeWebSocket messages2 2 0 (0.0%) 2 ✅ Codex stale todo list cold openHTTP decoded72.4 KiB 72.4 KiB 0 B (0.0%) 83.0 KiB ✅ Codex stale todo list cold openrows75 75 0 (0.0%) 75 ✅ Codex stale todo list cold opennodes2 2 0 (0.0%) 4 ✅ Codex stale todo list cold opensubagents2 2 0 (0.0%) 4 ✅ Codex stale todo list cold openplans1 1 0 (0.0%) 2 ✅ Codex stale todo list cold openproviderTurns1 1 0 (0.0%) 2 ✅ Codex stale todo list cold opencheckpoints1 1 0 (0.0%) 2 ✅ Claude short turn resumeWebSocket decoded10.6 KiB 10.6 KiB 0 B (0.0%) 12.7 KiB ✅ Claude short turn resumeWebSocket messages2 2 0 (0.0%) 2 ✅ Claude long turn running, cold openHTTP decoded283.3 KiB 283.3 KiB 0 B (0.0%) 302.7 KiB ✅ Claude long turn running, cold openrows75 75 0 (0.0%) 75 ✅ Claude long turn running, history pageHTTP decoded93.4 KiB 93.4 KiB 0 B (0.0%) 107.4 KiB ✅ Claude long turn running, history pagerows75 75 0 (0.0%) 75 ✅ Claude long turn finished, cold openHTTP decoded384.2 KiB 384.2 KiB 0 B (0.0%) 410.2 KiB ✅ Claude long turn finished, cold openrows151 151 0 (0.0%) 151 ✅ Claude long turn finished, socket cold openWebSocket decoded384.3 KiB 384.3 KiB 0 B (0.0%) 410.2 KiB ✅ Claude long turn finished, socket cold openWebSocket messages2 2 0 (0.0%) 2 ✅ Claude long turn finished, socket cold openrows151 151 0 (0.0%) 151 ✅ Claude long turn finished, work pageHTTP decoded188.1 KiB 188.1 KiB 0 B (0.0%) 200.2 KiB ✅ Claude long turn finished, work pagerows150 150 0 (0.0%) 150 ✅ Claude idle thread resumeWebSocket decoded66 B 66 B 0 B (0.0%) 200 B ✅ Claude idle thread resumeWebSocket messages1 1 0 (0.0%) 1 ✅ Claude fleet shell snapshotHTTP decoded43.0 KiB 43.0 KiB 0 B (0.0%) 53.7 KiB ✅ Claude fleet shell snapshotrows27 27 0 (0.0%) 27 ✅ Claude fleet shell subscribeWebSocket decoded66 B 66 B 0 B (0.0%) 200 B ✅ Claude fleet shell subscribeWebSocket messages1 1 0 (0.0%) 1 ✅ Claude fleet shell resume checkHTTP decoded18 B 18 B 0 B (0.0%) 100 B ✅ Claude fleet shell resume checkrows0 0 0 0 ✅ Claude stale shell reloadHTTP decoded43.0 KiB 43.0 KiB 0 B (0.0%) 53.7 KiB ✅ Claude stale shell reloadrows27 27 0 (0.0%) 27 ✅ Claude stale shell resumeWebSocket decoded140 B 140 B 0 B (0.0%) 400 B ✅ Claude stale shell resumeWebSocket messages2 2 0 (0.0%) 2 ✅ Claude stale todo list cold openHTTP decoded73.4 KiB 73.4 KiB 0 B (0.0%) 83.0 KiB ✅ Claude stale todo list cold openrows75 75 0 (0.0%) 75 ✅ Claude stale todo list cold opennodes2 2 0 (0.0%) 4 ✅ Claude stale todo list cold opensubagents2 2 0 (0.0%) 4 ✅ Claude stale todo list cold openplans1 1 0 (0.0%) 2 ✅ Claude stale todo list cold openproviderTurns1 1 0 (0.0%) 2 ✅ Claude stale todo list cold opencheckpoints1 1 0 (0.0%) 2 ✅ Baseline:
afff0d3· PR result:efa7ff3· Source CI: successScenario and decoded snapshot size
10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
- Codex decoded thread snapshot: 108.5 KiB
- Claude decoded thread snapshot: 108.8 KiB
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.
No actionable comments were generated in the recent review.
Walkthrough
-
personalNamespacenow follows namespace pagination tokens to find a user namespace on a later page. The response schema preservesnextPageToken, and a test checks the returned namespace and page-token request order.Changes: Personal namespace lookup
Layer / File(s) Summary Paginated personal namespace lookup
packages/source-control-cursor-origin/src/server/OriginCli.ts,packages/source-control-cursor-origin/src/server/OriginCli.test.tsThe response schema accepts an optional nullable nextPageToken. The lookup requests further pages until it finds a user namespace, reaches the end, or encounters a repeated token. The test checks a user namespace on the second page and verifies the request tokens.Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix · Severity of issue fixed: Medium
Possibly related PRs
- pingdotgg/t3code#33093: Added the Cursor Origin provider and the
personalNamespacelookup that this change updates.
Suggested labels:
bugfixSuggested reviewers:
maria-rcks,macroscopeapp - pingdotgg/t3code#33093: Added the Cursor Origin provider and the
Merge Risk:
Minimal · up toefa7f-
Personal namespace lookup now follows pagination, so users whose personal namespace is on a later page no longer hit a false not-found error. No actionable merge risk remains.
Pre-merge checks:
4-
Check name Status Explanation Title check The title names the actual change: personalNamespace now finds the personal namespace when it sits on a later page of results. It uses the conventional commit form and matches the code summary, the li… Description check The description covers the problem, the change, the scope, and verification. It explains the cause (one page read, sorted by slug, 30 per page), the pagination loop with repeated-token protection, and… Linked Issues check [ #35905] has three coding requirements. (1) Follow namespace pagination tokens until the personal namespace is found or pages run out. The diff replaces the single request in OriginCli.personalNamespa…Out of Scope Changes check All source changes map to #35905. The schema field and the personalNamespace loop are the requested fix. The Effect.fn wrapper with span 'OriginCli.personalNamespace' changes the tracing shape only fo…Full details: Title check
-
Explanation
The title names the actual change: personalNamespace now finds the personal namespace when it sits on a later page of results. It uses the conventional commit form and matches the code summary, the linked issue, and the objectives. It is 63 characters and 9 words, which is concise.
Full details: Description check
-
Explanation
The description covers the problem, the change, the scope, and verification. It explains the cause (one page read, sorted by slug, 30 per page), the pagination loop with repeated-token protection, and why readPages was not reused. It links issue
#35905and gives reproduction steps and test results. The Evidence section is still a placeholder, and the template asks for before and after proof only for UI changes, so this is a minor gap. The description also lacks a clear fix-only scope statement tied to the bug, but the issue link satisfies the Scope requirement. The Verification section lists focused tests with observed results, which the template asks for, and it states what was not checked. Model attribution is included at the end, as the template asks.Resolution
Optional: replace the placeholder Evidence section with the captured before and after output, or state that no UI change is involved and remove the placeholder before merge.
Full details: Linked Issues check
-
Explanation
[
#35905] has three coding requirements. (1) Follow namespace pagination tokens until the personal namespace is found or pages run out. The diff replaces the single request in OriginCli.personalNamespace with a do/while loop. It sends pageToken through URLSearchParams after the first page and sets pageToken from list.nextPageToken. It returns the first namespace with type 'user' when one appears. (2) Preserve nextPageToken in the response schema. OriginNamespaceListSchema gains nextPageToken: Schema.optional(Schema.NullOr(Schema.String)). (3) Preserve not-found when pages are exhausted. The loop ends when no token is returned or when a token repeats. It then fails with OriginCliError reason 'not-found' and the same detail text as before. The repeated-token guard prevents an endless loop against a server that repeats a token. The author reports a reproduction test on the base that fails and passes with the fix. I did not inspect the test file. The source diff alone establishes the behavior.
Full details: Out of Scope Changes check
-
Explanation
All source changes map to
#35905. The schema field and the personalNamespace loop are the requested fix. The Effect.fn wrapper with span 'OriginCli.personalNamespace' changes the tracing shape only for this function and does not change its public signature. The new test file OriginCli.test.ts supports the fix by reproducing the later-page failure. The PR does not change readPages or other services. The author states that OriginPullRequestProvider.readPages was not reused, so no unrelated code moved. No unrelated change was found in the reviewed diff.
-
Finishing Touches
-
Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Usage-based review receipt#
- Mode: Continue automatically
- Reviewed files: 2
- Charged: $0.50
- View usage details
Note
This review was completed with usage-based billing: files reviewed beyond your plan's included limits are billed at $0.25/file. View usage-based billing.
Recent review info-
Run configuration-
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: factory/issue-35905
- File: .coderabbit.config.ts
- Commit: efa7ff3
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Team
- Run ID:
fb5acd6c-ca39-422a-9cbc-7a681e30de0f
Commits-
Reviewing files that changed from the base of the PR and between afff0d3efe6f9ad22df9aebb3acb07bb144b49cd and efa7ff3fa25276e72165e1b12b671b05a409116c.
Files selected for processing: 2-
packages/source-control-cursor-origin/src/server/OriginCli.test.tspackages/source-control-cursor-origin/src/server/OriginCli.ts
Limit details: You’ve used all 10 included reviews currently available. Your 18 included PR review attempts over the past 7 days set your current allowance at 10 reviews per hour.
-
-
The automated pipeline stopped on this pull request and will not merge it:
the fix is written and reviewed, but proving it needs something no worker has:
- Permanent blocker: requires a signed-in Cursor Origin account with at least 30 earlier-sorting team namespaces and its personal namespace on a later page. The VM has no Origin CLI on PATH, and no suitable Origin session was available for this reproduction. The injected Cursor agent key does not provide the CLI session-token path used by this integration.
- Namespace discovery and repository creation without an explicit owner remain unverified on both commits. No capture upload was attempted because no valid capture was produced.
It stays open for a person to finish or close.
Sign in to join this conversation.
macroscopeapp[bot](GitHub profile, opens in a new tab) approved these changes