Skip to content

fix(session): close turns left open by a process that died - #113

Merged
filipeforattini merged 1 commit into
mainfrom
fix/orphan-turns
Sep 4, 2026
Merged

fix(session): close turns left open by a process that died#113
filipeforattini merged 1 commit into
mainfrom
fix/orphan-turns

Conversation

@filipeforattini

@filipeforattini filipeforattini commented Sep 4, 2026

Copy link
Copy Markdown

The complaint this answers

"fica aquele build infinito fazendo nada… tudo o que eu escrevo fica queued"

Two different failures were being treated as one. The live turn that stalls is covered by the
watchdog and the other guards in 0.14.0. This is the other one, and nothing addressed it.

time.completed on an assistant message is written by the process running the turn. When that
process is killed — an OOM (which this user hit repeatedly), a machine going to sleep, a crash —
nobody writes it. The message stays open forever.

The TUI computes its QUEUED badge purely from that:

pending = last assistant message with no time.completed
queued  = every message after it

So a session that survived one OOM stamps QUEUED on everything typed from then on, across
restarts, with no agent running
. The server processes those messages perfectly well — nothing
gates on it — but the interface says the opposite, and there is no way for the user to tell it
apart from a real queue. There was no recovery of dangling messages anywhere: not on boot, not on
load, not on the next turn.

The fix, in two halves

  • Server: a fresh run closes anything left open first. Only one run exists per session at a
    time, and a turn interrupted while its process lives finalizes itself on the way out — so an open
    message found at the start of a new run belongs to a run that is gone. It is marked aborted with
    "The process ended before this turn finished." and recorded through the guard log from feat(session): record every guard intervention #112, so a
    week of these says the OOM came back.
  • TUI: the QUEUED badge now requires the session to actually be busy. An open message alone is
    not a queue.

Verification

  • Integration test seen failing first (the abandoned message stayed open, no trip recorded) and
    passing after: the message is closed with MessageAbortedError, the turn still runs normally, and
    the trip is counted under orphan.
  • Unit tests for the detection, including several crashes in a row and messages that are already
    finished.
  • packages/redcode session suite 456 pass, packages/tui 228 pass.

https://claude.ai/code/session_014XwJPDhq1ahcm3rd454WzQ


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Only one run exists per session at a time, so an assistant message still open
when a fresh run starts was left by a run that no longer exists. Until now
nothing closed it, and the TUI reads open as "a turn is in progress": every
message typed afterwards was stamped QUEUED, across restarts, with nothing
running behind it. A session that survived one OOM looked jammed forever.

Close them on the way in, count them as an intervention so a week of these
says the OOM came back, and stop the badge from calling an open message a
queue when the session is idle.

Claude-Session: https://claude.ai/code/session_014XwJPDhq1ahcm3rd454WzQ
@filipeforattini
filipeforattini merged commit f94e2cb into main Sep 4, 2026
7 checks passed
@filipeforattini
filipeforattini deleted the fix/orphan-turns branch September 4, 2026 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant