Skip to content

fix(chat): look a Codex chain up again once a rollout in it is archived - #19

Merged
devswha merged 1 commit into
devswha:mainfrom
Yoonwoo-Ha:fix/chain-archived-parent
Sep 24, 2026
Merged

devswha merged 1 commit into
devswha:mainfrom
Yoonwoo-Ha:fix/chain-archived-parent

Conversation

@Yoonwoo-Ha

Copy link
Copy Markdown
Contributor

Follow-up to #18, as requested in its merge review.

Problem

historyChain keeps a complete chain cached until 64 others push it out. If the parent rollout was archived during that time, every read that reached the parent failed with transcript_missing, and the route answered scrollback. Right after a backtrack the live file is small, so even the newest page reached the parent: the whole chat fell back to terminal output until the entry was evicted or the server restarted.

Fix

When a remembered chain names a file that no longer exists (checked where the stream already stats its files), the chain is forgotten and looked up again. It comes back shorter, because archived_sessions/ isn't searched, under another stream id. A cursor into the old chain then answers 409 once and the chat reloads.

Tests

  • conversation.test.ts: a complete chain is remembered, then the parent moves to archived_sessions/. The newest page still reads (the live file's turns only), and a before cursor into the old chain answers HistoryChanged. Without the fix the test fails with transcript_missing.
  • bun test: 270 pass. Typecheck clean.

🤖 Generated with Claude Code

Follow-up to devswha#18's review. A complete chain stays cached until 64 others
push it out. If its parent rollout was archived meanwhile, every read that
reached the parent failed with transcript_missing and the chat fell back to
terminal output. Right after a backtrack the live file is small, so even the
newest page reached the parent.

When a remembered chain names a file that no longer exists, the chain is
forgotten and looked up again. It comes back shorter (archived_sessions/ is
not searched) under another stream id, so a cursor into the old chain
answers 409 once and the chat reloads.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@devswha
devswha merged commit 56be84f into devswha:main Sep 24, 2026
@devswha

devswha commented Sep 24, 2026

Copy link
Copy Markdown
Owner

Merged. Thanks. The shorter chain is cached like any incomplete one, so sessions/ is walked at most once every 30s, and there's no 409 loop.

One small follow-up: codexHistoryTail (server/codex.ts, called from codexTranscriptPath) still reads the old cached chain. Right after a backtrack the live file is under 1MB, so its tail reaches the archived parent, readRange throws, and the candidate is dropped. For an app-server Codex TUI with no open rollout fd, codexTranscriptPath then finds nothing, and the pane shows terminal output until the entry is evicted or the server restarts. The new missing-file check in transcriptStream is never reached on that path. Please add the same check (forget and look up again) in codexHistoryTail.

@Yoonwoo-Ha

Copy link
Copy Markdown
Contributor Author

Thanks. It's in #20: codexHistoryTail and codexHistorySegments now share one check (forget the chain and look it up again when a file in it is gone). There is a test that fails without it.

devswha pushed a commit that referenced this pull request Sep 24, 2026
From the merge reviews:

- #19: codexHistoryTail read the remembered chain as it was. After a
  backtrack the live file's tail reached an archived parent, the read
  threw, and an app-server TUI without an open rollout lost its screen
  match until the entry was evicted. Both codexHistoryTail and
  codexHistorySegments now use the chain only while every file in it
  exists, and look it up again otherwise. transcriptStream's own check is
  folded into that.
- #16: the 32 candidates for a screen match are interactive threads only,
  so a burst of `codex exec` runs no longer pushes a pane's own thread
  out.
- #16: another pane now claims a newer thread only when its screen shows
  that thread's first message as well as its answer. An answer of this
  pane quoted or pasted there claims nothing. Its screen is matched
  against this pane's own thread and its own binding too, so a match is
  unique across all of them.
- #16: the conversation route hands its session snapshot down, so an
  unsure poll takes no extra snapshot, and closed panes' bindings are
  dropped with it.

Not changed: narrowing `source='vscode'`. On this machine, TUIs attached
to a Codex Desktop app-server record originator "Codex Desktop" too, so
the store cannot tell a Desktop or plugin thread from a TUI's. A thread
no pane shows keeps reading as unsure, never as another conversation.

Tests: the archived-parent tail and the exec burst each fail without
their change. A pane showing only the other thread's answer leaves this
pane unsure; the pane that typed it claims it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
devswha added a commit that referenced this pull request Sep 24, 2026
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.

2 participants