mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-22 00:02:23 +00:00
A pane's screen comes back on re-attach out of the replay ring, and the ring is a window: eight megabytes wide, dropped from the front as it fills. That is the right shape for text, which is only worth what is still on screen, and the wrong one for modes. A full-screen program announces itself exactly once — `btop` sends `?1049h` and its mouse-reporting modes when it starts and then does nothing but refresh — so a long enough run of refreshes pushes the only copy of that announcement out of the front of the ring. What the client replays is then a screenful of alternate-buffer frames with nothing left to say they belong on the alternate buffer: it paints them onto its primary screen with reporting off, and `wheel_route`, which reads exactly those modes, sends the wheel to the scrollback of a screen that has none. That is the "a screen that should not scroll starts scrolling" in the report. `replay_state` already refuses to rely on the ring for anything that matters — cwd, prompt state, the remote context, the agent, the exit — because all of those are facts about the pane rather than bytes on it. The modes are the same kind of fact and were the exception, so the daemon now folds the bytes it hands the ring into a small tracker (`core::term_modes`) and `replay_state` re-sends what is still on. Tracked are the modes that decide input routing or which buffer is on screen: the alternate screen in its three spellings, the mouse reporting level and its encodings, alternate scroll, DECCKM, focus reporting and bracketed paste. They are replayed in the order the application set them, because the emulator treats the reporting modes as a level and not as independent bits, so the last one set has to be last here too. The frame goes *ahead* of the ring rather than after it. That way the replayed frames are painted into the buffer they were drawn for, and re-entering an alternate screen the ring turns out to still carry is a no-op in the emulator, so a prefix and a ring that both carry the mode cannot fight. Where the ring does still carry a toggle it wins on its own terms, since the fold runs over every byte the pane ever wrote and therefore agrees with the ring's last word on any mode the ring still mentions. Cursor visibility (`?25`) and autowrap (`?7`) are deliberately not tracked. Any frame of a running TUI repaints them within milliseconds, whereas restoring a stale `?25l` would leave a shell with an invisible cursor — a worse failure than the one being fixed, and one the existing `restore_preamble` already goes out of its way to avoid. A daemon handoff starts the fold empty rather than carrying it, so a pane adopted across a daemon restart is no worse off than it is today; the ring it carries is all it ever had. Claude-Session: https://claude.ai/code/session_01UUyWQXzcBAoBzaSX8pc7nU