Before submitting
Area
apps/server
Steps to reproduce
- Configure two enabled Claude provider instances, A and B, that use the
claudeAgent driver and resolve to the same Claude home / continuation key.
- Start a T3 thread on instance A and complete enough turns to persist a
non-empty Claude resume cursor.
- Leave the thread idle until its provider session is soft-stopped.
- In the existing thread, select instance B before sending the next message.
- Send a short reply that depends on the immediately preceding assistant
message, such as A in response to a list of proposed options.
The failure boundary is important: switching compatible instances while the
old provider session is active has a path that carries
activeSession.resumeCursor; switching after the session has stopped does
not.
Expected behavior
Because A and B advertise the same continuation identity, T3 should explicitly
carry the prior Claude resume cursor into B. If that is not safe for a given
pair of instances, T3 should reject the switch or require a transcript
handoff before sending the message.
A non-empty T3 thread should never silently start a blank provider-native
session.
Actual behavior
T3 keeps the full message history visible in the same UI thread but starts a
new Claude Agent SDK session without a resume cursor. Claude receives only the
new short message and replies as if the earlier conversation never happened.
In the observed incident:
- The old Claude JSONL remained present and readable.
- Neither the old nor new JSONL contained a
compact_boundary entry.
- The execution host, cwd, model, Claude home, driver, and continuation key
were unchanged.
- The replacement native session's persisted cursor became
turnCount: 1.
- T3's projected messages and checkpoints remained intact.
This rules out context-window exhaustion, compaction, missing native session
data, or a UI-history deletion.
The stopped-session path appears to lose the previous instance identity before
the turn starts:
- The model-selection update to B is projected before the turn-start event.
- With no active session,
ProviderCommandReactor.ensureSessionForThread
derives currentInstanceId from the already-updated
thread.modelSelection.instanceId.
- The reactor therefore sees B as both the current and desired instance and
starts it without explicitly carrying A's cursor.
ProviderService.startSession only falls back to the persisted cursor when
persistedBinding.providerInstanceId === resolvedInstanceId.
- The persisted binding belongs to A while the target is B, so the cursor is
rejected even though both instances have the same continuation key.
ClaudeAdapter consequently supplies a newly generated sessionId rather
than resume to the Agent SDK.
Related but distinct reports:
Impact
Major degradation or frequent failure
The reset is silent and the UI still displays the old conversation, so the
user cannot tell that approvals, architectural decisions, constraints, and
prior tool results are absent from the model's context.
Version or commit
Observed on v0.0.29 (1153afb4). The relevant logic is unchanged on main at
887dd6e455bb / v0.0.30-nightly.20260728.933.
Environment
T3 Code Desktop on macOS with a remote Linux execution host; Claude Code
2.1.218 via two configured claudeAgent instances; same model, host, cwd,
Claude home, and continuation key across the switch.
Logs or stack traces
# Last context-bearing turn completes on instance A.
# The provider session is later soft-stopped while idle.
# The user selects compatible instance B immediately before the next turn.
provider.instance_id=B
provider.resume_cursor.present=false
provider.resume_cursor.source=none
claude.resume.source=generated-session
claude.query.resume=""
# After the context-free response:
resumeCursor.turnCount=1
No credentials, prompt contents, project paths, or full local identifiers are
included above.
Suggested fix and regression test
Resolve the previous provider instance and resume cursor from the persisted
binding or stopped session before the newly projected model selection replaces
that identity. Then:
- If continuation identities match, explicitly pass the prior cursor to the
target instance.
- If they do not match, reject the switch or use a reviewed transcript handoff.
- Emit a warning/activity entry when a thread with completed turns starts a
provider session without a resume cursor.
Regression test:
- Start a Claude thread on instance A.
- Persist a non-empty cursor and soft-stop the session.
- Update the selection to compatible Claude instance B.
- Start the next turn.
- Assert that B receives A's prior cursor, or that the switch is explicitly
rejected before the user message is sent. It must not silently start blank.
Screenshots, recordings, or supporting files
No response.
Workaround
Use one provider instance per T3 thread. When changing route or provider
instance, start a new T3 thread with a reviewed handoff. If the original
Claude session still exists, resume it directly from the same Claude home and
working directory.
Before submitting
Area
apps/server
Steps to reproduce
claudeAgentdriver and resolve to the same Claude home / continuation key.non-empty Claude resume cursor.
message, such as
Ain response to a list of proposed options.The failure boundary is important: switching compatible instances while the
old provider session is active has a path that carries
activeSession.resumeCursor; switching after the session has stopped doesnot.
Expected behavior
Because A and B advertise the same continuation identity, T3 should explicitly
carry the prior Claude resume cursor into B. If that is not safe for a given
pair of instances, T3 should reject the switch or require a transcript
handoff before sending the message.
A non-empty T3 thread should never silently start a blank provider-native
session.
Actual behavior
T3 keeps the full message history visible in the same UI thread but starts a
new Claude Agent SDK session without a resume cursor. Claude receives only the
new short message and replies as if the earlier conversation never happened.
In the observed incident:
compact_boundaryentry.were unchanged.
turnCount: 1.This rules out context-window exhaustion, compaction, missing native session
data, or a UI-history deletion.
The stopped-session path appears to lose the previous instance identity before
the turn starts:
ProviderCommandReactor.ensureSessionForThreadderives
currentInstanceIdfrom the already-updatedthread.modelSelection.instanceId.starts it without explicitly carrying A's cursor.
ProviderService.startSessiononly falls back to the persisted cursor whenpersistedBinding.providerInstanceId === resolvedInstanceId.rejected even though both instances have the same continuation key.
ClaudeAdapterconsequently supplies a newly generatedsessionIdratherthan
resumeto the Agent SDK.Related but distinct reports:
is the remaining stopped-session + compatible-instance-switch boundary.
be safe to resume across.
Impact
Major degradation or frequent failure
The reset is silent and the UI still displays the old conversation, so the
user cannot tell that approvals, architectural decisions, constraints, and
prior tool results are absent from the model's context.
Version or commit
Observed on v0.0.29 (
1153afb4). The relevant logic is unchanged on main at887dd6e455bb/v0.0.30-nightly.20260728.933.Environment
T3 Code Desktop on macOS with a remote Linux execution host; Claude Code
2.1.218 via two configured
claudeAgentinstances; same model, host, cwd,Claude home, and continuation key across the switch.
Logs or stack traces
No credentials, prompt contents, project paths, or full local identifiers are
included above.
Suggested fix and regression test
Resolve the previous provider instance and resume cursor from the persisted
binding or stopped session before the newly projected model selection replaces
that identity. Then:
target instance.
provider session without a resume cursor.
Regression test:
rejected before the user message is sent. It must not silently start blank.
Screenshots, recordings, or supporting files
No response.
Workaround
Use one provider instance per T3 thread. When changing route or provider
instance, start a new T3 thread with a reviewed handoff. If the original
Claude session still exists, resume it directly from the same Claude home and
working directory.