Problem
While Codex is streaming a response, scrolling upward can make terminal content overlap or appear out of order: newer content is hidden by stale rows and the browser-side view remains corrupted. A full browser refresh reconstructs a correct view from tmux.
This still reproduces after the scroll-intent fix in #259.
Confirmed timing gap
flushPendingWrites() captures preserveViewportY, calls terminal.write(writeChunk, callback), then restores the viewport outside the callback. Real xterm parsing is asynchronous, so the restore runs before the redraw changes the buffer.
The existing regression uses a synchronous terminal.write mock and passes. A delayed-callback smoke probe fails:
- Saved history position:
viewportY = 40 - Codex redraw parses later and moves it to live
baseY = 100 - Final position:
100; expected 40
Baseline: the three targeted terminal suites pass (39 tests), so this timing is not currently covered.
Expected behavior
Scrolling through history while Codex streams should keep the visible content coherent and anchored. Live redraws should continue at the bottom without repainting, overlapping, or reordering the history being viewed.
Acceptance criteria
- Restore the history anchor only after xterm has parsed the write.
- Preserve the anchor across consecutive and chunked Codex redraws.
- Add an asynchronous write-callback regression test.
- Add a browser smoke test using synchronized, cursor-addressed Codex-style redraws while scrolled up.
- Refresh is unnecessary to recover a coherent view.
Problem
While Codex is streaming a response, scrolling upward can make terminal content overlap or appear out of order: newer content is hidden by stale rows and the browser-side view remains corrupted. A full browser refresh reconstructs a correct view from tmux.
This still reproduces after the scroll-intent fix in #259.
Confirmed timing gap
flushPendingWrites()capturespreserveViewportY, callsterminal.write(writeChunk, callback), then restores the viewport outside the callback. Real xterm parsing is asynchronous, so the restore runs before the redraw changes the buffer.The existing regression uses a synchronous
terminal.writemock and passes. A delayed-callback smoke probe fails:viewportY = 40baseY = 100100; expected40Baseline: the three targeted terminal suites pass (39 tests), so this timing is not currently covered.
Expected behavior
Scrolling through history while Codex streams should keep the visible content coherent and anchored. Live redraws should continue at the bottom without repainting, overlapping, or reordering the history being viewed.
Acceptance criteria