[BUG] Desktop sidebar: `lastActivityAt` is persisted for a turn that never happened, so an idle session outranks live ones forever and a restart does not fix it

Status Open
Reported on v2.1.241
Maintainer reply None cached
Activity 0 comments · opened Aug 26, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

A session whose last turn finished at 08:45 got lastActivityAt stamped at 12:59:41
4 h 14 min later — for a turn that produced nothing: no user message, no assistant
message, nothing appended to its transcript. The sidebar sorts by that field, so the dead
session sits above sessions that are actively streaming, and it stays there.

This is the part that survives an app restart. The session record on disk has no
running/status field, so the pulsing dot clears when the app restarts — but the bogus
timestamp is persisted, and nothing ever recomputes it. The row is promoted once and never
falls back.

This is deliberately not another report of the pulsing dot (#74646, #74875, #86768). The
dot is the in-memory half and is already well documented. This is the persisted half: a
write to lastActivityAt with no turn behind it.

Evidence

Session local_40b78d37-…, cliSessionId d4600c35-…, macOS Tahoe 26.5, claude-code
2.1.241.

The turn ended cleanly — this is not a wedged session. The last transcript entry is an
assistant message with stop_reason: "end_turn" at 2026-08-26T12:45:49Z. No dangling
tool_use without its tool_result.

The transcript was never touched again, and it does not contain the text of the message
that was submitted at 12:59.

lastActivityAt = 12:59:41 local, 4 h 14 min after that last write.

lastFocusedAt is a separate field and only moved when the session was later opened, so
merely opening a session is not what stamps activity.

The CLI process is alive and healthy — PID with --resume=d4600c35-…, started the
previous evening, 19 h elapsed, state S, ~0.4 % CPU. So this is not "the backing process
died and the submit had nowhere to go". It is up and idle and would have answered.

The API disagrees with the sidebar: the sessions API reports isRunning: false and the
transcript reader labels the session (idle) while the row keeps animating and keeps its
promoted position.

How rare it is. Across 297 sessions where the session record could be matched to its
transcript, exactly one has a meaningful mismatch: this one, at 253.9 minutes. The
next two are 7.7 and 10.8 min (ordinary end-of-turn lag). Every other session is within
0.0 minutes. So the timestamp is normally correct — this is a rare path that writes it
without a turn.

It does not keep re-promoting itself. Watching the record for 10 minutes, lastActivityAt
never moved again; only lastFocusedAt changed, when the session was opened. It was stamped
once and froze. That is why it looks like the session "moves itself up": it never comes back
down.

A third visible symptom of the same event: the text typed at 12:59 is still sitting unsent in
the composer, never consumed.

Expected

  • Do not persist an activity timestamp for a turn that was never recorded — stamp it when a

turn is written to the transcript, or roll it back when the submit produces nothing.

  • If a submit does not result in a turn, surface an error. Here the CLI was alive and

reachable, so the failure was silent and recoverable-looking.

  • Reconcile sidebar ordering against real session state (the transcript's own last write) on

app start, so an already-corrupted timestamp self-heals instead of outranking live sessions
forever.

What I could not determine

What exactly the app did at 12:59:41. A lost submit and a draft-save that bumps activity leave
the same trace on disk. Either way no turn exists and the timestamp was written.

Environment

  • Claude Code 2.1.241, Claude Desktop (macOS)
  • macOS Tahoe 26.5, Apple Silicon

View original on GitHub ↗