openai / openai/codex

TUI can permanently lose transcript scrollback when resize lands during replay/stream (cells become incomplete; later resizes can't restore)

Open
#37,987 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug CLI session TUI
Dominant language
Rust
Stars
125k
Forks
19.5k
PR merge metrics
PR metrics pending

Description

Summary

The codex TUI can permanently lose transcript scrollback when a terminal resize lands while a resumed session is still replaying (or while an agent response is streaming). Resize reflow clears terminal scrollback and re-emits from transcript_cells; when the cells are incomplete at that moment (replay still in progress, stream cells not yet consolidated), the re-emitted scrollback is shorter than the transcript — and unlike #30745, the missing rows are never restored by later resizes, because the rebuild source itself (transcript_cells) is missing them.

Environment

  • codex 0.147.0 TUI (main screen; runs inside a headless terminal host that owns the PTY)
  • Terminal host: herdr 0.8.0 (ghostty-vt based), which resizes the shared PTY whenever the attached client's viewport changes
  • Client: mobile terminal app, 56 columns; toggling the on-screen keyboard changes the viewport between 17 and 45 rows, so resizes arrive repeatedly during a session

Reproduction

  1. codex resume <session-id> for a long session (observed: 4605-line session JSONL).
  2. Confirm the working directory prompt with Enter; the replay starts.
  3. Immediately trigger a resize while the replay/stream is still settling (in my setup: split/close the pane, equivalent to the client viewport changing mid-session).
  4. After the prompt returns, scrollback contains only part of the transcript:
    • observed scroll + viewport total of 76 rows → 51 rows after one resize round-trip, stable at 51 afterwards.
    • The 25 missing rows never come back; repeated resizes re-emit the same 51 rows.
  5. pane read --source recent on the surviving scrollback shows the welcome header, an interrupted-conversation notice and the prompt — no conversation history at all.

Additional observation: resuming the same session ID from two TUI instances at once makes the replay entirely empty — the resumed view shows only the welcome header and prompt, with zero history, until all instances are closed and a single instance resumes the session again.

Expected

  • A resize that lands mid-replay or mid-stream should not permanently shrink scrollback: either the clear+re-emit should wait until transcript_cells is complete, or it should be skipped entirely when cells are known to be incomplete.
  • (Secondary) Resuming a session ID that is already open in another instance should not silently produce an empty replay.

Actual

In tui/src/app/resize_reflow.rs, reflow_transcript_now() returns early when transcript_cells.is_empty() (after clearing pending history lines); when cells are merely partial, the re-emit is exactly the partial set, and every later resize re-emits the same partial set. The initial replay path (begin_initial_history_replay_buffer / finish_initial_history_replay_buffer) buffers display lines separately from cells, so a resize that lands between replay inserts and the flush can commit only a prefix.

Notes

Related issues:

  • #30745 — rows disappear after inline viewport height changes; restored by a terminal resize. In our case the cells themselves are lost, so a terminal resize cannot restore them (same family, worse stage).
  • #24235 — scrollback corruption in Termius mobile SSH (mobile-client-specific rendering).
  • #21635 — resume main view shows partial transcript due to terminal_resize_reflow_max_rows cap.
  • #37635 — repeated repaints during paginated history refill on resume.

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 in tui/src/app/resize_reflow.rs, reading reflow_transcript_now() alongside begin_initial_history_replay_buffer and finish_initial_history_replay_buffer. Reproduce a resize during resumed replay or streaming, then trace how transcript_cells and buffered display lines are committed. Done means mid-replay or mid-stream resizes no longer permanently lose transcript rows.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.