Skip to content
Source
Sign inSign up

fix(cursor-origin): personal namespace on a later page is found #35918

Openjuliusmarmingewants to merge 2 commits intomain fromrefs/pull/35918/headopened View on GitHub

juliusmarmingecommented

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

    2. tanstack-source added labelsbug

    3. Approvability

      Verdict: Approved at efa7ff3

      Macroscope'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).
    4. Thread transfer impact

      ✅ Thread transfer remains within every enforced ceiling.

      ProviderMetricMain baselineThis PRImpactPR ceiling
      CodexTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
      CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
      CodexLive turn WebSocket wire1.2 KiB1.2 KiB0 B (0.0%)2.0 KiB✅
      CodexLive turn WebSocket decoded21.5 KiB21.5 KiB0 B (0.0%)24.4 KiB✅
      CodexLive turn messages110 (0.0%)8✅
      ClaudeTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
      ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
      ClaudeLive turn WebSocket wire1.2 KiB1.2 KiB0 B (0.0%)2.0 KiB✅
      ClaudeLive turn WebSocket decoded21.9 KiB21.9 KiB0 B (0.0%)24.4 KiB✅
      ClaudeLive turn messages110 (0.0%)8✅

      Other scenarios

      All 64 scenario measurements match main.

      All 64 scenario measurements
      ProviderScenarioMetricMain baselineThis PRImpactPR ceiling
      Codexshort turn resumeWebSocket decoded10.5 KiB10.5 KiB0 B (0.0%)12.7 KiB✅
      Codexshort turn resumeWebSocket messages220 (0.0%)2✅
      Codexlong turn running, cold openHTTP decoded281.7 KiB281.7 KiB0 B (0.0%)302.7 KiB✅
      Codexlong turn running, cold openrows75750 (0.0%)75✅
      Codexlong turn running, history pageHTTP decoded92.4 KiB92.4 KiB0 B (0.0%)107.4 KiB✅
      Codexlong turn running, history pagerows75750 (0.0%)75✅
      Codexlong turn finished, cold openHTTP decoded381.5 KiB381.5 KiB0 B (0.0%)410.2 KiB✅
      Codexlong turn finished, cold openrows1511510 (0.0%)151✅
      Codexlong turn finished, socket cold openWebSocket decoded381.6 KiB381.6 KiB0 B (0.0%)410.2 KiB✅
      Codexlong turn finished, socket cold openWebSocket messages220 (0.0%)2✅
      Codexlong turn finished, socket cold openrows1511510 (0.0%)151✅
      Codexlong turn finished, work pageHTTP decoded186.2 KiB186.2 KiB0 B (0.0%)200.2 KiB✅
      Codexlong turn finished, work pagerows1501500 (0.0%)150✅
      Codexidle thread resumeWebSocket decoded65 B65 B0 B (0.0%)200 B✅
      Codexidle thread resumeWebSocket messages110 (0.0%)1✅
      Codexfleet shell snapshotHTTP decoded42.4 KiB42.4 KiB0 B (0.0%)53.7 KiB✅
      Codexfleet shell snapshotrows27270 (0.0%)27✅
      Codexfleet shell subscribeWebSocket decoded65 B65 B0 B (0.0%)200 B✅
      Codexfleet shell subscribeWebSocket messages110 (0.0%)1✅
      Codexfleet shell resume checkHTTP decoded18 B18 B0 B (0.0%)100 B✅
      Codexfleet shell resume checkrows0000✅
      Codexstale shell reloadHTTP decoded42.4 KiB42.4 KiB0 B (0.0%)53.7 KiB✅
      Codexstale shell reloadrows27270 (0.0%)27✅
      Codexstale shell resumeWebSocket decoded140 B140 B0 B (0.0%)400 B✅
      Codexstale shell resumeWebSocket messages220 (0.0%)2✅
      Codexstale todo list cold openHTTP decoded72.4 KiB72.4 KiB0 B (0.0%)83.0 KiB✅
      Codexstale todo list cold openrows75750 (0.0%)75✅
      Codexstale todo list cold opennodes220 (0.0%)4✅
      Codexstale todo list cold opensubagents220 (0.0%)4✅
      Codexstale todo list cold openplans110 (0.0%)2✅
      Codexstale todo list cold openproviderTurns110 (0.0%)2✅
      Codexstale todo list cold opencheckpoints110 (0.0%)2✅
      Claudeshort turn resumeWebSocket decoded10.6 KiB10.6 KiB0 B (0.0%)12.7 KiB✅
      Claudeshort turn resumeWebSocket messages220 (0.0%)2✅
      Claudelong turn running, cold openHTTP decoded283.3 KiB283.3 KiB0 B (0.0%)302.7 KiB✅
      Claudelong turn running, cold openrows75750 (0.0%)75✅
      Claudelong turn running, history pageHTTP decoded93.4 KiB93.4 KiB0 B (0.0%)107.4 KiB✅
      Claudelong turn running, history pagerows75750 (0.0%)75✅
      Claudelong turn finished, cold openHTTP decoded384.2 KiB384.2 KiB0 B (0.0%)410.2 KiB✅
      Claudelong turn finished, cold openrows1511510 (0.0%)151✅
      Claudelong turn finished, socket cold openWebSocket decoded384.3 KiB384.3 KiB0 B (0.0%)410.2 KiB✅
      Claudelong turn finished, socket cold openWebSocket messages220 (0.0%)2✅
      Claudelong turn finished, socket cold openrows1511510 (0.0%)151✅
      Claudelong turn finished, work pageHTTP decoded188.1 KiB188.1 KiB0 B (0.0%)200.2 KiB✅
      Claudelong turn finished, work pagerows1501500 (0.0%)150✅
      Claudeidle thread resumeWebSocket decoded66 B66 B0 B (0.0%)200 B✅
      Claudeidle thread resumeWebSocket messages110 (0.0%)1✅
      Claudefleet shell snapshotHTTP decoded43.0 KiB43.0 KiB0 B (0.0%)53.7 KiB✅
      Claudefleet shell snapshotrows27270 (0.0%)27✅
      Claudefleet shell subscribeWebSocket decoded66 B66 B0 B (0.0%)200 B✅
      Claudefleet shell subscribeWebSocket messages110 (0.0%)1✅
      Claudefleet shell resume checkHTTP decoded18 B18 B0 B (0.0%)100 B✅
      Claudefleet shell resume checkrows0000✅
      Claudestale shell reloadHTTP decoded43.0 KiB43.0 KiB0 B (0.0%)53.7 KiB✅
      Claudestale shell reloadrows27270 (0.0%)27✅
      Claudestale shell resumeWebSocket decoded140 B140 B0 B (0.0%)400 B✅
      Claudestale shell resumeWebSocket messages220 (0.0%)2✅
      Claudestale todo list cold openHTTP decoded73.4 KiB73.4 KiB0 B (0.0%)83.0 KiB✅
      Claudestale todo list cold openrows75750 (0.0%)75✅
      Claudestale todo list cold opennodes220 (0.0%)4✅
      Claudestale todo list cold opensubagents220 (0.0%)4✅
      Claudestale todo list cold openplans110 (0.0%)2✅
      Claudestale todo list cold openproviderTurns110 (0.0%)2✅
      Claudestale todo list cold opencheckpoints110 (0.0%)2✅

      Baseline: afff0d3 · PR result: efa7ff3 · Source CI: success

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

    5. Explain Change →

      No actionable comments were generated in the recent review.

      Walkthrough

      personalNamespace now follows namespace pagination tokens to find a user namespace on a later page. The response schema preserves nextPageToken, 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.ts
      The 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 personalNamespace lookup that this change updates.

      Suggested labels: bugfix

      Suggested reviewers: maria-rcks, macroscopeapp

      Merge Risk: Minimal · up to efa7f

      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: Passed 4

      Check nameStatusExplanation
      Title checkPassedThe 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 checkPassedThe 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 checkPassed[#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 checkPassedAll 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 #35905 and 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

      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

      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.ts
      • packages/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.

    6. juliusmarmingecommented

      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.