Repository navigation
perf(server): Cursor item ordinals no longer copy a session-wide map per item - #13866
Conversation
…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>
| providerTurnId, | ||
| startedAt, | ||
| completed, | ||
| itemOrdinals: new Map(), |
There was a problem hiding this comment.
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
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 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.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
ApprovabilityVerdict: Approved at 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. |
2d359e3
into
t3code/codex-turn-mapping
…per item (pingdotgg#13866) (cherry picked from commit 2d359e3) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Cursor V2 adapter has the same item-ordinal problem as Claude (#13864). Every item ordinal of the session sat in one
Mapthat was copied on each new item (new Map(current)insideRef.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
resolveItemOrdinalcall passes the active turn. The keys are Cursor call ids, text and reasoning segment ids scoped torun.runId,plan:/todos:call ids, andterminal-failure:${providerTurnId}. A subagent keeps itsturnItemOrdinalon its own record (existing?.turnItemOrdinal ?? resolveItemOrdinal(...)), and that record also lives on the turn. Before the fix I instrumentedresolveItemOrdinalto 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):
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 runwithCursorAdapterV2.test.ts,OrchestratorReplayFixtures.integration.test.ts(which includes the 11 Cursor replay fixtures) andOrchestratorReplayRecovery.integration.test.ts: 3 files, 110 tests pass. The replay fixtures are unchanged.vp exec tsc --noEmit -p .inapps/server: no errors.vp linton the touched file: only the existinglayerunused-variable warning.Model: Claude Opus 5.5 (Claude Code)
🤖 Generated with Claude Code