pingdotgg / pingdotgg/t3code

Thread session stuck in `running` after turn interrupt — stop button becomes a no-op

Open
#4,713 10 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
23k
Forks
5.9k
Avg merge
11h 14m
Merged PRs (30d)
357

Description

Version: 0.0.29-nightly.20260727.915 · macOS · provider claudeAgent

When a turn is interrupted, the turn projection is finalized correctly but no follow-up thread.session-set event is emitted. The session projection stays running with active_turn_id still pointing at the now-terminal turn.

From that point the thread is unrecoverable from the UI: every stop press emits a thread.turn-interrupt-requested event that is recorded as accepted in orchestration_command_receipts, but the orchestrator has no active turn left to act on, so nothing happens. There is no visible signal that the turn already ended.

Observed timeline

One thread, times UTC:

  • 21:00:35.001thread.session-setrunning, turn 06dd4ca9
  • 21:02:41 — turn interrupted: sub-agents emit task.completed / status: stopped, projection_turns.state = interrupted, completed_at set
  • 21:02:41 onwards — no further thread.session-set; session projection frozen at running
  • 21:0405:42 (next day) — 40+ thread.turn-interrupt-requested, all accepted, no effect

The provider child process stayed alive for 9 hours, in state R, RSS growing from 394 MB to 737 MB.

Detection query

This returns rows only in the broken state:

SELECT s.thread_id, tu.state, tu.completed_at
  FROM projection_thread_sessions s
  JOIN projection_turns tu ON tu.turn_id = s.active_turn_id
 WHERE s.status = 'running'
   AND tu.state IN ('interrupted','completed','error')
   AND tu.completed_at IS NOT NULL;
Workaround

SIGTERM the provider child process whose --resume matches the thread's resume cursor. The adapter then emits thread.session-setstopped with lastError: "Claude runtime stream failed.", and the turn is finalized as error. The thread is fully resumable afterwards, with history intact.

Suggested fix

Emit the session transition on the interrupt path itself, rather than relying solely on provider stream termination. A secondary guard — refusing to hold active_turn_id on a turn already in a terminal state — would make the desync self-correcting.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the turn interrupt path and the session/turn projection updates described in the issue; run the detection query to reproduce or verify the desynchronized state. Confirm that interruption emits a stopped session transition and that a terminal turn cannot remain active. Add coverage for the interrupted, completed, and error states if the relevant tests are located.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.