Skip to content

Resumed session shows empty transcript: live sessions orphaned across selfdev reload (picker preview still works) #753

Description

@yumhum

Summary

Resuming a session from the session picker shows an empty transcript, even though the picker's own preview renders the conversation correctly. The on-disk transcript is fully intact — this is an attach/render bug, not data loss.

The session is status: Active with a live PID, but the running server group reports zero sessions, so the session sits in orphan_sessions instead. Resume finds the file but cannot attach to the live session, and the orphan path does not replay the stored messages into the UI.

Version

v0.66.0 (b45bb9b52), Linux x86_64. Session was started under v0.65.0 (d847d62e4) and survived a selfdev reload into 0.66.0.

Reproduction

  1. Start a session and build up some history.
  2. Trigger selfdev reload (or have another session trigger one) so the binary swaps underneath the running session.
  3. Open the session picker. The preview shows the conversation.
  4. Resume that session. The transcript pane is empty.

Evidence

Picker cache (~/.jcode/cache/session-picker-list-v1.json), generated while the session was live:

server_groups: observatory (is_running=true, v0.66.0) → sessions = 0
orphan_sessions: 128
  session_wolf_1785705679673_… status=Active msgs=345 needs_catchup=false

The session process is alive and is in fact the parent of the tools running inside it:

last_pid: 41330 → PID ALIVE
(a shell spawned by that very session reports ppid=41330)

Transcript on disk is complete and still being appended to:

session_wolf_….json  604K, messages=333 (179 user / 154 assistant)
… later in the same run: messages=392, snapshot_bytes=616606, result=ok

So persistence is healthy — SESSION_PERSISTENCE … phase=save_done result=ok status=Active keeps firing normally. Only the registry/UI association is lost.

The reload snapshot only captures the triggering session

~/.jcode/reload-traces/reload_1785759155118_….jsonl:

phase=signal_received  pid=41330  hash=d847d62e4  triggering_session=session_cat_…
phase=candidate_snapshot   members recorded at reload: 1
    session_cat_1785759152503_…  ready
phase=intent_skipped
phase=graceful_shutdown_complete
phase=background_tasks_finalized
phase=exec_start

Only 1 member was snapshotted (the session that triggered the reload). Other live sessions, including session_wolf_…, were not in the candidate set, so nothing re-adopts them after exec_start. An earlier trace from the previous reload shows the same shape with a different triggering session.

This looks like the direct cause: the reload hands over only the triggering session's membership, and every other live session is orphaned on the far side of the exec.

Scale of the symptom

On this machine: 128 orphans, 24 with needs_catchup: true, 25 of them native session_* (rest are imported claude:/codex: entries with 0 messages).

Several orphans carry crash statuses that look like the same handover gap rather than genuine crashes:

Crashed: "Process 3293084 exited unexpectedly (no shutdown signal captured)"   ×5 (same PID)
Crashed: "Terminal or window closed (SIGHUP)"

Five sessions attributing their death to one shared PID suggests they were all children of a server process that went away during a reload, and none of them were re-adopted.

Nothing in ~/.jcode/logs/jcode-2026-08-03.log mentions orphan, adopt, or reattach — grep returns zero hits — so the reclassification is currently silent.

Expected behaviour

  1. On server start after a reload, any session whose last_pid is still alive should be re-adopted into the server group rather than reclassified as an orphan.
  2. Reload's candidate_snapshot should capture all live session members, not only the triggering session.
  3. Failing both, resuming an orphan that has an intact transcript should replay its stored messages into the UI. The picker already proves the data is readable — resume should use the same path.
  4. Orphaning/adoption decisions should be logged, so this is diagnosable without hand-parsing the picker cache.

Impact

The work is recoverable (the JSON is intact, and session_search can still find it), but the user loses all visible scrollback and any sense that the session is continuous. Because selfdev reload is routine during self-dev work, this hits often — hence 128 orphans on a single machine.

Workarounds

  • Avoid selfdev reload while sessions you care about are live.
  • Use session_search to recover content from an orphaned session.
  • The agent process itself retains in-context history, so a resumed session can still be asked to recap even when the pane looks empty.

Metadata

Metadata

Assignees

No one assigned

    Labels

    autonomous: noNeeds your brain: a product/design decision is required before anyone acts.bugSomething isn't workingpriority: highP1 - important bug or impactful feature, fix soonregressionWorked in a previous version; broke later. Often bisectable.triage: needs-decisionNeeds maintainer decision/design thought

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions