Environment
- Rio for Windows using ConPTY
- WSL shell running inside Rio
- Codex CLI 0.145.0 as a real-world reproducer
The issue was not reproduced on macOS, where ConPTY is not involved.
Summary
Typing in TUIs using synchronized output can be displayed roughly 150–200 ms
late when Rio runs through ConPTY.
Keyboard input reaches the application immediately and the application emits
its updated frame quickly, but Rio buffers the frame until its 150 ms
synchronized-update timeout expires.
Plain applications such as cat are not affected.
Reproduction
Run these commands in a WSL shell inside Rio for Windows (Ctrl-C to stop):
# Control: immediate echo without synchronized output.
while IFS= read -rsn1 key; do
printf '\rWithout 2026: %s' "$key"
done
# Reproduction: one write containing BSU, content and ESU.
while IFS= read -rsn1 key; do
printf '\e[?2026h\rWith 2026: %s\e[?2026l' "$key"
done
Expected: both loops update immediately.
Actual: the second loop displays each isolated key roughly 150–200 ms late.
Codex is a concrete real-world reproducer. Its TUI depends on Ratatui and
Crossterm, and its draw path explicitly wraps frames in
sync_update.
Investigation
Instrumentation showed:
- input reached the application in about 1–2 ms;
- the application emitted its updated frame after about 20 ms;
- the visible update took about 206 ms;
cat remained immediate in the same Rio window.
ConPTY was observed returning the synchronized-update markers together, ahead
of the frame content:
chunk 1: ESC[?2026h ESC[?2026l
chunk 2: frame content
Rio arms a 150 ms timeout when parsing ESC[?2026h. When the matching
ESC[?2026l is parsed inline through the normal CSI dispatch path, the timeout
is not cleared. The following frame content is therefore treated as belonging
to a synchronized update and remains buffered until the timeout expires.
Proposed fix
Clear the synchronized-update timeout when dispatching ?2026l, mirroring the
existing ?2026h behavior.
When replaying a synchronized buffer that contains a new BSU after the current
ESU, explicitly re-arm the timeout for that remaining update.
Regression tests cover:
- an inline BSU+ESU pair followed by frame content;
- an ESU followed by a new BSU;
- the existing split-chunk ESU path.
AI assistance: the diagnosis and fix were developed with Claude Code using
Fable 5.
Environment
The issue was not reproduced on macOS, where ConPTY is not involved.
Summary
Typing in TUIs using synchronized output can be displayed roughly 150–200 ms
late when Rio runs through ConPTY.
Keyboard input reaches the application immediately and the application emits
its updated frame quickly, but Rio buffers the frame until its 150 ms
synchronized-update timeout expires.
Plain applications such as
catare not affected.Reproduction
Run these commands in a WSL shell inside Rio for Windows (
Ctrl-Cto stop):Expected: both loops update immediately.
Actual: the second loop displays each isolated key roughly 150–200 ms late.
Codex is a concrete real-world reproducer. Its TUI depends on Ratatui and
Crossterm, and its draw path explicitly wraps frames in
sync_update.Investigation
Instrumentation showed:
catremained immediate in the same Rio window.ConPTY was observed returning the synchronized-update markers together, ahead
of the frame content:
Rio arms a 150 ms timeout when parsing
ESC[?2026h. When the matchingESC[?2026lis parsed inline through the normal CSI dispatch path, the timeoutis not cleared. The following frame content is therefore treated as belonging
to a synchronized update and remains buffered until the timeout expires.
Proposed fix
Clear the synchronized-update timeout when dispatching
?2026l, mirroring theexisting
?2026hbehavior.When replaying a synchronized buffer that contains a new BSU after the current
ESU, explicitly re-arm the timeout for that remaining update.
Regression tests cover:
AI assistance: the diagnosis and fix were developed with Claude Code using
Fable 5.