fix(server): fail Claude turns waiting for unsupported mod input#24320
Problem
Claude Code 2.1.303 with the blast-radius mod holds Bash calls behind a terminal pane that T3 cannot display. Running rm -r build in a disposable repository leaves the turn Running without any way to answer the mod.
Change
Fail the active turn with an error naming the mod and explaining how to continue when Claude requests pane focus. Close the query without answering the mod, and prevent follow-ups from reusing that stopping query. Panes without a focus request keep their existing behavior.
Scope and approval
Fixes https://github.com/pingdotgg/t3code/issues/17531
GitCafe: #17531
Triaged bug via the automated issue flow.
Verification
- Red test on main: the captured focus frame followed by an ordered notice barrier produced no terminal event (
expected failed; received undefined). vp test run apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts: 211 passed, including focused/passive frames and a follow-up submitted while close is held. Both final reviewers independently passed the full file.- Targeted lint, server scoped typecheck (
vp run --filter t3 typecheck), and diff whitespace checks passed. Both Python fixture scripts parse; the isolated reproduction seed ran successfully. - Real web run: focus → query.close in 5 ms, persisted failure 85 ms after focus, full error visible. The disposable fixture hash stayed unchanged. A same-selection follow-up opened a fresh query, resumed the session and completed; a repeated focus terminated the previously observed Claude PID.
Evidence
Linux, Chromium 154, light theme, 1280×800 CSS viewport; after DPR 2 and visual scale 1. Claude 2.1.303, blast-radius 0.1.0 from pinned playground commit, isolated Claude configuration inherited by the actual child. The reproduction scripts are not committed; they are uploaded as seed.py (isolated Bash/mod reproduction) and seed-native.py (offline native presentation fixture).
| Web · light · 1280×800 | Before | After | Diff0 | DiffT |
|---|---|---|---|---|
| Focused mod | Before: Bash remains Running 3b95e7831b | After: named mod error and recovery guidance 1a464140dc | Zero-tolerance difference Same pair; zero tolerance, 8× amplification | Threshold difference Same pair; max channel delta >16/255 |
Before recording begins after submission and remains Running for 40.9 seconds. The before transcript records the mod timing out about 16 minutes later.
After focus and recovery recording: submit at ~00:07; focus and close at ~00:16.66; full error by ~00:28; fresh resumed query at ~00:32.89; successful tool result at ~00:42.44; UI Done by ~00:53.28.
Repeated-focus recording: submit near the start, focus at ~00:05.77, then failure. The separately recorded process snapshot finds the previously observed PID absent afterward.
Evidence index and complete timestamp guide, sanitized after transcript, and artifact hashes.
What else changed in the captures: identifiers, timestamps, sidebar threads, timeline grouping/collapse, and the error panel replacing Running. Historical main/UI differs between before and after; clocks were not frozen and before DPR was not measured. Pixel differences are descriptive. The adapter behavior and existing failure renderers are unchanged between the captured revision and the PR head. Later commits clarify comments and merge main through f416175804. Reproduction-only fixture scripts were added and then removed from the branch; the uploaded copies above are byte-identical.
Verification limits
The runtime follow-up opened about 16 seconds after close. Immediate retry is proven by the deterministic held-close test, not a real-time recording.
Real passive-frame behavior is unverified: two loaded fixture-mod runs completed, but emitted no
ui_panes. The ordered protocol test covers a passive pane.Desktop/Electron was not run separately; its failure renderer is shared with web. Reconnect and remote client lifecycle were not exercised separately. No platform-specific runtime code changed.
The historical before source is not the final merge base. The proof auditor recomputed the supplied diffs exactly but did not rebuild a capture from the uploaded seed.
Native presentation unverified: the EAS iOS simulator build failed with
Unable to resolve module dependency: GhosttyKitinT3TerminalNative(Pods). No installable artifact or simulator session was produced. The static fixture exported successfully and its scoped mobile typecheck passed; those checks do not prove native rendering. No mobile runtime source changed. The uploaded native fixture script preserves the exact failure message for a later native capture. Sanitized build failure, fixture provenance.
Models: Claude Opus 5.5 and GPT-6.1-Sol, through Claude Code and Codex in T3 Code.
Checks
Added 8 commits
- fix(server): replace Claude queries stopped by unsupported mod input13dbd8e
- Merge main into fix/issue-175311a46414
- Merge remote-tracking branch 'origin/main' into fix/issue-175312a0c059
- test(mobile): make the mod error presentation fixture reproducible4290a61
- fix(server): stop Claude turns that wait for unsupported mod panes45b81ec
- test(server): seed the Claude mod hold reproduction81ca238
- test(server): a mod pane requesting focus must fail the Claude turn (#17531)ce34ac8
- docs: clarify unsupported pane interaction and fixture usagee703b2d
Approvability
Verdict: Approved at 69b6a99
Macroscope's review found this PR approvable — This is a narrowly scoped server bug fix that converts an unsupported Claude mod interaction from an indefinite running state into an explicit failure, then ensures follow-ups use a fresh process. Passive panes and normal Claude turns remain unchanged, with regression coverage for the affected lifecycle paths.
Notes:
- No code objects were reviewed. Approvability was decided on eligibility alone.
You can add or adjust custom eligibility rules. Learn more.
Thread transfer impact
✅ Thread transfer remains within every enforced ceiling.
| Provider | Metric | Main baseline | This PR | Impact | PR ceiling | |
|---|---|---|---|---|---|---|
| Codex | Total thread wire | 5.0 KiB | 5.0 KiB | 0 B (0.0%) | 6.8 KiB | ✅ |
| Codex | Thread snapshot wire | 3.8 KiB | 3.8 KiB | 0 B (0.0%) | 4.9 KiB | ✅ |
| Codex | Live turn WebSocket wire | 1.2 KiB | 1.2 KiB | 0 B (0.0%) | 2.0 KiB | ✅ |
| Codex | Live turn WebSocket decoded | 20.9 KiB | 20.9 KiB | 0 B (0.0%) | 29.3 KiB | ✅ |
| Codex | Live turn messages | 2 | 2 | 0 (0.0%) | 8 | ✅ |
| Claude | Total thread wire | 5.0 KiB | 5.0 KiB | −7 B (−0.1%) | 6.8 KiB | ✅ |
| Claude | Thread snapshot wire | 3.8 KiB | 3.8 KiB | 0 B (0.0%) | 4.9 KiB | ✅ |
| Claude | Live turn WebSocket wire | 1.2 KiB | 1.2 KiB | −7 B (−0.6%) | 2.0 KiB | ✅ |
| Claude | Live turn WebSocket decoded | 21.2 KiB | 21.2 KiB | 0 B (0.0%) | 29.3 KiB | ✅ |
| Claude | Live turn messages | 2 | 2 | 0 (0.0%) | 8 | ✅ |
Baseline: 3f3a1bf · PR result: 69b6a99 · 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.
No actionable comments were generated in the recent review.
External image Recent review info
External image Run configuration
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: fix/issue-17531
- File: .coderabbit.config.ts
- Commit: 2a0c059
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Team
- Run ID:
b200a33d-5b65-4166-a749-8a0bd41f93b9
External image Commits
Reviewing files that changed from the base of the PR and between 3f3a1bf419f07b4dcbb3be9f9fbb4ed54055ee4f and 2a0c059f1ed230c0ef8a577c93179bfd73722ce1.
External image Files selected for processing: 4
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.tsapps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.tsscripts/fixtures/issue-17531/seed-native.pyscripts/fixtures/issue-17531/seed.py
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.
Walkthrough
The Claude adapter now fails turns that request focus on a mod UI pane and avoids reusing queries that are stopping. Regression tests cover pane-focus handling and follow-up turns. Two scripts set up issue-specific Claude Code and native UI fixtures.
Changes: Claude provider handling
Layer / File(s) Summary Handle focus requests and stopping queries
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts,apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.tsThe adapter identifies focus-requested panes, fails the active turn with claude_mod_ui_unsupported, and closes the query without an interrupt. Continuation and unchanged-selection paths no longer reuse a stopping query. Tests cover focused and passive panes, plus a follow-up turn while the prior query closes.Issue 17531 fixture tooling
Layer / File(s) Summary Prepare the mod environment and native evidence fixture
scripts/fixtures/issue-17531/seed.py,scripts/fixtures/issue-17531/seed-native.pyseed.pycreates a disposable project and installs a pinned playground plugin using an isolated Claude configuration.seed-native.pyvalidates a pinned checkout, writes a static provider-failure screen and EAS profile, and updates.gitignorewhen needed.Priority: External image Normal
Estimated code review effort: 3 (Moderate) | ~20 minutes
Change: Bug fix · Severity of issue fixed: Medium
Sequence Diagram(s)
mermaid1 sequenceDiagram 2 participant ClaudeCodeQuery 3 participant ClaudeAdapterV2 4 participant ActiveTurn 5 ClaudeCodeQuery->>ClaudeAdapterV2: Send ui_panes frame with focus_requested_id 6 ClaudeAdapterV2->>ActiveTurn: Fail with claude_mod_ui_unsupported 7 ClaudeAdapterV2->>ClaudeCodeQuery: Close query without interrupt Suggested reviewers:
t3dotgg
Merge Risk: External image Minimal · up to 2a0c0
The change is mergeable after normal checks; the investigated handling and fixture setup concerns do not establish a blocking failure.
Pre-merge checks: Passed 4
Check name Status Explanation Title check Passed The title clearly and concisely describes the primary server fix: failing Claude turns that wait for unsupported mod input. Linked Issues check Passed Issue #17531targets the Claude turn hang caused by unsupported mod pane input. The adapter now detects a pane-focus request, emits theclaude_mod_ui_unsupportedprovider failure with the mod name a…Out of Scope Changes check Passed The changes remain related to #17531. Adapter tests verify the failure and query-lifecycle behavior. The two fixture scripts reproduce the issue and document the native presentation evidence without c…Description check Passed The pull request description covers the problem, implementation, scope, linked issue, verification results, evidence, and known limitations. It is sufficiently complete for review, although it does no… Full details: Linked Issues check
Explanation
Issue
#17531targets the Claude turn hang caused by unsupported mod pane input. The adapter now detects a pane-focus request, emits theclaude_mod_ui_unsupportedprovider failure with the mod name and recovery guidance, closes the query without answering the mod, and prevents reuse of a stopping query. The added tests cover focused panes, passive panes, and follow-up submission during query close. The issue's generic settings proposal and longer-term proposals are alternatives, not acceptance criteria for this fix.
Full details: Out of Scope Changes check
Explanation
The changes remain related to
#17531. Adapter tests verify the failure and query-lifecycle behavior. The two fixture scripts reproduce the issue and document the native presentation evidence without changing unrelated runtime behavior. No unrelated product feature or provider behavior is established by the reviewed changes.
Full details: Description check
Explanation
The pull request description covers the problem, implementation, scope, linked issue, verification results, evidence, and known limitations. It is sufficiently complete for review, although it does not include a direct maintainer approval comment beyond the stated automated triage.
Finishing Touches
📝 Generate docstrings
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
- Commit to this branch
- Create a new PR
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Comment @coderabbitai help to get the list of available commands.
Added 1 commit
- chore: drop issue-17531 reproduction-only fixture scripts69b6a99