Running at rev 8803834036205cf2cac5cfca98bb3875812c897a.
src/boxlite/src/rest/litebox.rs:708 calls String::from_utf8_lossy on each PTY payload, and ExecStdout::Item is String, so there is no carry for a partial codepoint across payload boundaries.
A multi-byte character that straddles two WebSocket frames is replaced with U+FFFD before any consumer sees it, and the original bytes are unrecoverable downstream. Box-drawing characters, braille spinners and emoji are the common casualties, which is most of a full-screen TUI redraw under load.
This matters for any consumer proxying a guest PTY to a real terminal: the corruption is silent and cannot be repaired above this layer. Buffering an incomplete trailing sequence until the next payload, or making the item type Bytes and letting the consumer decode, would both fix it.
Running at rev
8803834036205cf2cac5cfca98bb3875812c897a.src/boxlite/src/rest/litebox.rs:708callsString::from_utf8_lossyon each PTY payload, andExecStdout::ItemisString, so there is no carry for a partial codepoint across payload boundaries.A multi-byte character that straddles two WebSocket frames is replaced with U+FFFD before any consumer sees it, and the original bytes are unrecoverable downstream. Box-drawing characters, braille spinners and emoji are the common casualties, which is most of a full-screen TUI redraw under load.
This matters for any consumer proxying a guest PTY to a real terminal: the corruption is silent and cannot be repaired above this layer. Buffering an incomplete trailing sequence until the next payload, or making the item type
Bytesand letting the consumer decode, would both fix it.