You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Using a remote T3 Code server, clicking the Stop button gives no UI feedback and the thread stays stuck in Thinking / Working for Xm Ys indefinitely.
Screenshot attached: prompt list me all ~/dev/projects/* → Working for 6m 26s + Thinking, bottom composer shows red stop ■ still active, environment myrehat-dev.asia-southeast1-a.c.myrehat-... · Local checkout · main, model Muse Spark 1.2 Contrib..., Xhigh · Build, Full access.
Expected: Stop shows Stopping... immediately (disabled) and within seconds drops Thinking/Working, even on relay/tunnel. Actual: no visual change, subsequent Stop clicks also silent, thread never recovers until server restart or manual projection_thread_sessionsstopped + projection_turnsinterrupted repair.
Steps to reproduce (remote)
Start remote server (npx t3 --share / --tunnel / npx t3 behind Tailscale on myrehat-dev...).
Connect from app.t3.codes or mobile via pairingUrl: token (remote mode, not local).
Open thread with Local checkout, send a prompt that streams (list me all ~/dev/projects/* and it…, or any long agent run).
While Thinking/session.status === "running", click the red Stop button in the composer.
Actual
Button does not morph to Stopping..., not disabled, no toast, no spinner change (100–400ms relay RTT makes it obvious; local 10–20ms masks it).
Timeline keeps Working for ... ticking forever.
DB: projection_thread_sessions.status = 'running' with active_turn_id pinned to a turn already interrupted/completed (completed_at set), or NULL with pending turn forever (#4713 detection query hits):
SELECTs.thread_id, tu.state, tu.completed_atFROM projection_thread_sessions s
JOIN projection_turns tu ONtu.turn_id=s.active_turn_idWHEREs.status='running'ANDtu.stateIN ('interrupted','completed','error')
ANDtu.completed_atIS NOT NULL;
Every further Stop appends thread.turn-interrupt-requested in orchestration_events (accepted in orchestration_command_receipts) but produces no follow-up thread.session-set; the stop handler has nothing to act on.
Expected
Optimistic Stopping... within one frame on every surface (web composer, mobile ThreadRouteScreen), disabled until terminal session-setstopped/interrupted or error.
Even when buildThreadTurnInterruptInput omits turnId (stale activeTurnId), the client and projection still flip latestTurn.state → interrupted optimistically.
If provider interrupt succeeds yet CLI stays alive, server escalates after ~5s to stopSession → session-setstopped, so derivePhase → disconnected/ready and MessagesTimeline clears Working.
Relay blips surface as toast instead of silent no-op (reportFailure:false currently swallows EnvironmentRpcUnavailableError while phase === "available"|"offline").
Evidence & analysis
Investigated in worktree t3code-a1ef8329 (6a9d9f9):
UI:apps/web/src/components/ChatView.tsx:1246interruptThreadTurn = useAtomCommand(threadEnvironment.interruptTurn, {reportFailure:false}), 5487-5510onInterrupt has no isStoppingTurn state. Contrast handleStopBackgroundWork4677-4740 which correctly tracks isStoppingBackgroundWork, disables Button4543 and shows "Stopping..."4546.
Input guard:ChatView.logic.ts:141-150buildThreadTurnInterruptInput includes turnId only if session.status==="running" && activeTurnId!==null. Remote snapshots lag (THREAD_RESUME_MAX_GAP 1000, SHELL_COALESCE_WINDOW 50msws.ts:841), so Stop often persists thread.turn-interrupt-requested without turnId. Both threadReducer.ts:271-292 and ProjectionPipeline.ts:1441-1476 return unchanged/no-op for turnId===undefined.
Projection:session-logic.ts:1894-1905derivePhase = running iff session.status==="running"|"starting"; MessagesTimeline.tsx:210,1313WorkingTimelineRow only clears when isWorking===false. threadReducerlatestTurn.state==="interrupted" alone does not clear it.
Server reactor:ProviderCommandReactor.ts:1228-1321 only tears down on failure (recoverInterruptFailure → stopSession). On success it waits for provider session-set. When ClaudeAdapter.ts:query.interrupt() never settles / OpenCodeAdapter.ts:2932 10s abort times out / CodexAdapter ignores, session never leaves running. Serial interruptTurn (threadCommands.ts:177-182concurrency:{mode:"serial"} per (env,thread)) then queues further clicks.
Family:pingdotgg/t3code#4713 (40+ accepted interrupts no effect, SIGTERM workaround), #4589 (threads stop updating), #7820, #2644, #7349 (bounded Claude query.interrupt 10s + getContextUsage 1s — but only for failure path), #7589, #7987.
Impact
Major: remote is primary use (Tailscale/tunnel/mobile). User cannot cancel, cannot archive (useThreadActions.ts:214 refuses archive while running), mobile outbox gates on running (use-thread-outbox-drain.ts:317) so queued messages never deliver. Only way out is SIGTERM --resume <cursor> or manual DB session-set stopped + restart.
Environment
T3 Code v0.0.37-nightly.20260829.12186a9d9f9 (local) / remote myrehat-dev Linux aarch64, provider opencodeMuse Spark 1.2 Contrib...
Web + mobile optimistic isStoppingTurn (mirror isStoppingBackgroundWork) → Stopping... disabled.
Relax turnId===undefined guard to fallback to activeTurnId ?? latest unsettled turn.
Server 5s fallback stopSession when interrupt succeeds but session still running (success-still-running), with bounded getContextUsage.
interruptTurn timeout / singleFlight so promise doesn't hang; surface transport errors for Stop.
Tests + projector coverage.
Logs
state.sqliteorchestration_eventsthread.turn-interrupt-requestedaccepted without follow-up thread.session-set.
projection_thread_sessionsrunning + projection_turnsinterrupted/pending as above.
Managed via forkhub as fix-remote-stop-no-feedback-stuck-thinking-7h3k9p2m. See ImBIOS/.forkhubINTENT.md for full non-negotiables and implementation notes.
Before submitting
Area
apps/web • apps/mobile • packages/client-runtime • apps/server
Description
Using a remote T3 Code server, clicking the Stop button gives no UI feedback and the thread stays stuck in
Thinking/Working for Xm Ysindefinitely.Screenshot attached: prompt
list me all ~/dev/projects/*→Working for 6m 26s+Thinking, bottom composer shows red stop■still active, environmentmyrehat-dev.asia-southeast1-a.c.myrehat-...·Local checkout·main, modelMuse Spark 1.2 Contrib...,Xhigh · Build,Full access.Expected: Stop shows
Stopping...immediately (disabled) and within seconds dropsThinking/Working, even on relay/tunnel. Actual: no visual change, subsequent Stop clicks also silent, thread never recovers until server restart or manualprojection_thread_sessionsstopped+projection_turnsinterruptedrepair.Steps to reproduce (remote)
npx t3 --share/--tunnel/npx t3behind Tailscale onmyrehat-dev...).app.t3.codesor mobile viapairingUrl:token (remote mode, not local).list me all ~/dev/projects/* and it…, or any long agent run).Thinking/session.status === "running", click the red Stop button in the composer.Actual
Stopping..., not disabled, no toast, no spinner change (100–400ms relay RTT makes it obvious; local 10–20ms masks it).Working for ...ticking forever.projection_thread_sessions.status = 'running'withactive_turn_idpinned to a turn alreadyinterrupted/completed(completed_atset), orNULLwith pending turn forever (#4713detection query hits):active_turn_id IS NULL+pendingturn (report at2026-08-24T23:30:31Zin Thread session stuck inrunningafter turn interrupt — stop button becomes a no-op #4713).thread.turn-interrupt-requestedinorchestration_events(acceptedinorchestration_command_receipts) but produces no follow-upthread.session-set; the stop handler has nothing to act on.Expected
Stopping...within one frame on every surface (web composer, mobileThreadRouteScreen), disabled until terminalsession-setstopped/interruptedor error.buildThreadTurnInterruptInputomitsturnId(staleactiveTurnId), the client and projection still fliplatestTurn.state → interruptedoptimistically.stopSession→session-setstopped, soderivePhase→disconnected/readyandMessagesTimelineclearsWorking.reportFailure:falsecurrently swallowsEnvironmentRpcUnavailableErrorwhilephase === "available"|"offline").Evidence & analysis
Investigated in worktree
t3code-a1ef8329(6a9d9f9):apps/web/src/components/ChatView.tsx:1246interruptThreadTurn = useAtomCommand(threadEnvironment.interruptTurn, {reportFailure:false}),5487-5510onInterrupthas noisStoppingTurnstate. ContrasthandleStopBackgroundWork4677-4740which correctly tracksisStoppingBackgroundWork, disablesButton4543and shows"Stopping..."4546.ChatView.logic.ts:141-150buildThreadTurnInterruptInputincludesturnIdonly ifsession.status==="running" && activeTurnId!==null. Remote snapshots lag (THREAD_RESUME_MAX_GAP 1000,SHELL_COALESCE_WINDOW 50msws.ts:841), so Stop often persiststhread.turn-interrupt-requestedwithoutturnId. BoththreadReducer.ts:271-292andProjectionPipeline.ts:1441-1476returnunchanged/no-op forturnId===undefined.session-logic.ts:1894-1905derivePhase=runningiffsession.status==="running"|"starting";MessagesTimeline.tsx:210,1313WorkingTimelineRowonly clears whenisWorking===false.threadReducerlatestTurn.state==="interrupted"alone does not clear it.ProviderCommandReactor.ts:1228-1321only tears down on failure (recoverInterruptFailure→stopSession). On success it waits for providersession-set. WhenClaudeAdapter.ts:query.interrupt()never settles /OpenCodeAdapter.ts:293210s abort times out /CodexAdapterignores, session never leavesrunning. SerialinterruptTurn(threadCommands.ts:177-182concurrency:{mode:"serial"}per(env,thread)) then queues further clicks.pingdotgg/t3code#4713(40+ accepted interrupts no effect, SIGTERM workaround),#4589(threads stop updating),#7820,#2644,#7349(bounded Claudequery.interrupt10s +getContextUsage1s — but only for failure path),#7589,#7987.Impact
Major: remote is primary use (Tailscale/tunnel/mobile). User cannot cancel, cannot archive (
useThreadActions.ts:214refuses archive whilerunning), mobile outbox gates onrunning(use-thread-outbox-drain.ts:317) so queued messages never deliver. Only way out isSIGTERM --resume <cursor>or manual DBsession-set stopped+ restart.Environment
v0.0.37-nightly.20260829.12186a9d9f9(local) / remotemyrehat-devLinux aarch64, provideropencodeMuse Spark 1.2 Contrib...app.t3.codes/ desktop wrap, remote relay.claudeAgent, Codex, Cursor per Thread session stuck inrunningafter turn interrupt — stop button becomes a no-op #4713.Suggested fix (non-negotiables)
isStoppingTurn(mirrorisStoppingBackgroundWork) →Stopping...disabled.turnId===undefinedguard to fallback toactiveTurnId ?? latest unsettled turn.stopSessionwhen interrupt succeeds but session stillrunning(success-still-running), with boundedgetContextUsage.interruptTurntimeout /singleFlightso promise doesn't hang; surface transport errors for Stop.Logs
state.sqliteorchestration_eventsthread.turn-interrupt-requestedacceptedwithout follow-upthread.session-set.projection_thread_sessionsrunning+projection_turnsinterrupted/pendingas above.Managed via
forkhubasfix-remote-stop-no-feedback-stuck-thinking-7h3k9p2m. SeeImBIOS/.forkhubINTENT.mdfor full non-negotiables and implementation notes.