Skip to content

perf(server): Cursor item ordinals no longer copy a session-wide map per item - #13866

Merged
juliusmarminge merged 1 commit into
t3code/codex-turn-mappingfrom
v2/cursor-item-ordinals
Sep 26, 2026
Merged

juliusmarminge merged 1 commit into
t3code/codex-turn-mappingfrom
v2/cursor-item-ordinals

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

The Cursor V2 adapter has the same item-ordinal problem as Claude (#13864). Every item ordinal of the session sat in one Map that was copied on each new item (new Map(current) inside Ref.update) and never pruned, as was the per-turn counter map beside it. A long session paid O(items) memory and O(items²) copying.

What changed

The ordinal map moves onto the turn (ActiveCursorTurn.itemOrdinals). It is mutated in place and goes away when the turn settles. The counter map is gone, because the map's size is the counter. OpenCode and Pi already allocate ordinals this way.

Why per-turn is safe

Every resolveItemOrdinal call passes the active turn. The keys are Cursor call ids, text and reasoning segment ids scoped to run.runId, plan:/todos: call ids, and terminal-failure:${providerTurnId}. A subagent keeps its turnItemOrdinal on its own record (existing?.turnItemOrdinal ?? resolveItemOrdinal(...)), and that record also lives on the turn. Before the fix I instrumented resolveItemOrdinal to flag any hit on an ordinal a different turn had allocated, then ran the full replay suites plus the Cursor adapter tests: 79 Cursor allocations, 0 cross-turn hits. The instrumentation was not committed.

Benchmark

A scratch, uncommitted script ran the resolver exactly as it was before and after, in 10 turns, resolving each item twice (first sight plus one later update):

N items before after
1,000 60 ms 1 ms
10,000 7.6 s 4 ms
50,000 253 s 37 ms

In #13864, the end-to-end benchmark through the real Claude adapter showed the same curve (50k items: 325.6 s before, 2.1 s after). A 50k-entry map retains about 1.8 MiB for the life of the session. After the fix, that memory is bounded by the largest single turn.

Verification

  • vp test run with CursorAdapterV2.test.ts, OrchestratorReplayFixtures.integration.test.ts (which includes the 11 Cursor replay fixtures) and OrchestratorReplayRecovery.integration.test.ts: 3 files, 110 tests pass. The replay fixtures are unchanged.
  • Before the fix, the cross-turn instrumentation run described above (14 files, 566 tests) found 0 Cursor hits.
  • vp exec tsc --noEmit -p . in apps/server: no errors.
  • vp lint on the touched file: only the existing layer unused-variable warning.
  • Not run: repo-wide checks, live Cursor.

Model: Claude Opus 5.5 (Claude Code)

🤖 Generated with Claude Code


Devin Review

…per item

The Cursor V2 adapter kept every item ordinal of the session in one Map
that it copied on each new item and never pruned, so a long session paid
O(items) memory and O(items^2) copying. Every lookup comes from the turn
that allocated the ordinal (a subagent keeps its ordinal on its own
record), so the map now lives on the turn, is mutated in place, and goes
away when the turn settles.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Sep 26, 2026
providerTurnId,
startedAt,
completed,
itemOrdinals: new Map(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes backend behavior: reusing a native item ID in a later turn now assigns a new turn-local ordinal. Could you add a focused adapter test covering repeated IDs across turns and stable ordinals within a turn? The existing two-turn test does not assert ordinals. This needs a test-file change, so no inline fix is applicable.

Posted via Macroscope — Effect Service Conventions

@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ No successful main baseline artifact is available yet. This run establishes the initial measurement.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire — 4.9 KiB — 6.8 KiB ✅
Codex Thread snapshot wire — 3.7 KiB — 4.9 KiB ✅
Codex Live turn WebSocket wire — 1.1 KiB — 2.0 KiB ✅
Codex Live turn WebSocket decoded — 20.4 KiB — 29.3 KiB ✅
Codex Live turn messages — 1 — 8 ✅
Claude Total thread wire — 4.9 KiB — 6.8 KiB ✅
Claude Thread snapshot wire — 3.7 KiB — 4.9 KiB ✅
Claude Live turn WebSocket wire — 1.2 KiB — 2.0 KiB ✅
Claude Live turn WebSocket decoded — 20.8 KiB — 29.3 KiB ✅
Claude Live turn messages — 2 — 8 ✅

Baseline: unavailable · PR result: 6eee08e · 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: 106.1 KiB
  • Claude decoded thread snapshot: 106.4 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeapp Bot commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 6eee08e

Macroscope's review found this PR approvable — This is a focused server-side optimization that bounds Cursor ordinal state to the active turn while preserving stable ordinals within each turn. It changes later-turn reuse of native IDs to use new turn-local ordinals, but introduces no schema, configuration, security, billing, or deployment impact.

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

@juliusmarminge
juliusmarminge merged commit 2d359e3 into t3code/codex-turn-mapping Sep 26, 2026
24 of 25 checks passed
@juliusmarminge
juliusmarminge deleted the v2/cursor-item-ordinals branch September 26, 2026 22:02
dillonc-dev added a commit to exarch-run/t3code that referenced this pull request Sep 27, 2026
…per item (pingdotgg#13866)

(cherry picked from commit 2d359e3)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant