Skip to content

[orchestrator-v2] fix(orchestrator): Resume persisted Claude sessions after provider session recycle#3750

Open
mwolson wants to merge 1 commit into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/claude-session-resume
Open

[orchestrator-v2] fix(orchestrator): Resume persisted Claude sessions after provider session recycle#3750
mwolson wants to merge 1 commit into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/claude-session-resume

Conversation

@mwolson

@mwolson mwolson commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Claude threads that sit idle for more than 30 minutes fail instantly on the
next message with transport_error "Claude Agent SDK query failed." (the CLI
reports Session ID ... is already in use). This PR makes the adapter resume
the persisted native session instead of trying to recreate it.

One commit on fix/claude-session-resume: ClaudeAdapterV2.ts (the fix) and
ClaudeAdapterV2.test.ts (two new tests). Everything else comes from the base
branch.

Problem and Fix

Problem and Why it Happened Fix
After ProviderSessionManager idle-releases a provider session (30 min default), the adapter's in-memory openedNativeThreads set is lost. The next turn's openQuery therefore opens the native thread with {sessionId} (create semantics, --session-id) instead of {resume}, and the Claude CLI fails fast because the session id already exists on disk. In openQuery, treat a persisted provider turn as proof the native session exists: providerTurnOrdinal > 1 (computed by ProviderTurnStartService as max persisted turn ordinal for the provider thread plus 1) forces {resume} alongside the existing in-memory and rollback signals.

Edge cases checked: run attempt retries (session created on first attempt),
steering (steerTurn never calls openQuery), thread_start rollback (new
provider thread id resets the ordinal to 1, so create is used for the fresh
native session), mid-thread rollback (resumeSessionAt already forces
resume), forks in the same session instance (covered by openedWithResume),
and first-run failures before CLI spawn (no turn persisted, ordinal stays 1).

Validation

  • vp check: pass
  • vp run typecheck: pass
  • vp test apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts:
    14/14 pass, including two new tests (ClaudeAdapterV2 native session identity) asserting ordinal 1 opens with sessionId and ordinal 2 opens
    with resume
  • The new resume test fails without the adapter change (verified by
    stashing the fix and rerunning)
  • OrchestratorReplayFixtures.integration.test.ts (claude fixtures): pass

Known limitations

  • If the very first turn persists a provider turn but the CLI never created
    the native session (or the reverse: session created, persistence failed),
    the identity choice can still be wrong on retry. Both traps pre-date this
    change (the in-memory set had the same blind spots within a session
    instance); this PR keeps the fix minimal and does not add auto-retry
    identity flipping.
  • A native fork creates the CLI session before any provider turn is
    persisted for the forked thread. If the process restarts between the fork
    and the forked thread's first turn, the ordinal is still 1 and openQuery
    sends {sessionId} for an existing native session. The ordinal signal
    does not engage there, so behavior is identical to before this change
    (pre-existing hole, found by review; a forkedFrom-based signal was
    rejected because thread_start rollback preserves forkedFrom while
    minting a fresh, uncreated native session id).

Note

Resume persisted Claude sessions on subsequent provider turns in ClaudeAdapterV2

When a provider session is recycled (idle release), the adapter previously opened a new native Claude session on the next turn instead of resuming the existing one. openSession now checks providerTurnOrdinal > 1 as an additional condition to set shouldResume, ensuring the query opens in resume mode for any turn after the first. Tests are added to assert new-session behavior on the first provider turn and resume behavior on subsequent turns.

Macroscope summarized fb7f966.


Note

Medium Risk
Changes when the Claude Agent SDK query is opened in create vs resume mode for orchestrator v2 threads; wrong ordinal could mis-handle first-turn or post-recycle sessions, but scope is limited to Claude adapter session identity.

Overview
Fixes idle-released Claude provider sessions failing on the next message with Session ID ... is already in use by treating persisted history as proof the native CLI session already exists.

In ClaudeAdapterV2.openQuery, shouldResume now also becomes true when providerTurnOrdinal > 1, so a fresh adapter instance resumes with resume instead of opening with a fixed sessionId. Existing signals (resumeSessionAt, in-memory openedNativeThreads) are unchanged.

Tests add providerTurnOrdinal to the turn fixture and assert ordinal 1 creates (sessionId, no resume) while ordinal 2 resumes (resume, no sessionId).

Reviewed by Cursor Bugbot for commit fb7f966. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ca61244d-b1bf-46f0-8709-9319170cdd2e

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@mwolson mwolson force-pushed the fix/claude-session-resume branch from 3c8b95b to fb7f966 Compare July 7, 2026 02:44
@mwolson mwolson marked this pull request as ready for review July 7, 2026 12:21
@macroscopeapp

macroscopeapp Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved

Straightforward bug fix that adds a condition to properly resume Claude sessions after provider session idle-release. The change is minimal (one new condition in existing logic), well-commented, and thoroughly tested.

You can customize Macroscope's approvability policy. Learn more.

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

Labels

size:XS 0-9 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.

1 participant