fix(server): fail Claude turns waiting for unsupported mod input#24320

merged9
main
fix/issue-17531
opened6d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 3h ago

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×800BeforeAfterDiff0DiffT
Focused modBefore: 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: GhosttyKit in T3TerminalNative (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

22 successful · 16 skipped
All checks passed
69b6a99

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
Synced from GitHub

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.

Synced from GitHub

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
CodexLive turn WebSocket wire1.2 KiB1.2 KiB0 B (0.0%)2.0 KiB✅
CodexLive turn WebSocket decoded20.9 KiB20.9 KiB0 B (0.0%)29.3 KiB✅
CodexLive turn messages220 (0.0%)8✅
ClaudeTotal thread wire5.0 KiB5.0 KiB−7 B (−0.1%)6.8 KiB✅
ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
ClaudeLive turn WebSocket wire1.2 KiB1.2 KiB−7 B (−0.6%)2.0 KiB✅
ClaudeLive turn WebSocket decoded21.2 KiB21.2 KiB0 B (0.0%)29.3 KiB✅
ClaudeLive turn messages220 (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.

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review.

External image Recent review info
External image Run configuration
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.ts
  • apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
  • scripts/fixtures/issue-17531/seed-native.py
  • scripts/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.ts
The 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.py
seed.py creates a disposable project and installs a pinned playground plugin using an isolated Claude configuration. seed-native.py validates a pinned checkout, writes a static provider-failure screen and EAS profile, and updates .gitignore when needed.

Priority: External image Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

mermaid
1sequenceDiagram
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 nameStatusExplanation
Title checkPassedThe title clearly and concisely describes the primary server fix: failing Claude turns that wait for unsupported mod input.
Linked Issues checkPassedIssue #17531 targets the Claude turn hang caused by unsupported mod pane input. The adapter now detects a pane-focus request, emits the claude_mod_ui_unsupported provider failure with the mod name a…
Out of Scope Changes checkPassedThe 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 checkPassedThe 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 #17531 targets the Claude turn hang caused by unsupported mod pane input. The adapter now detects a pane-focus request, emits the claude_mod_ui_unsupported provider 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