vt: fix wire snapshots (S1/S5 follow-ups) #1

Open
opened 2026-10-02 00:16:04 +00:00 by jhgaylor · 0 comments
Owner

The spike is done; this issue is the "Fix now, in crates/vt" work it found (seven fixes, prototyped in the spike's src/patched.rs), plus the build-tag and upstream items.

From PLAN.md, section "S: spikes → S1/S5 follow-ups".


  • S1/S5 follow-ups: done 2026-10-01. See spikes/s1s5-followup.
    • New fixtures: Claude Code (it draws in the alt screen), origin mode,
      DECSLRM, the saved cursor in primary and alt screens (1049 and 47),
      Kitty graphics and sixel.

    • Checkpoints (GHOSTSNP) round-trip all of them exactly, except Kitty
      images, which GHOSTSNP v1 leaves out by design. libghostty doesn't parse
      sixel, so there's nothing to carry.

    • The wire path is wrong today on 13 of 18 fixtures, in Ghostty and in
      xterm.js. This is the formatter snapshot plus fix-ups that the browser
      gets on attach. The visible failures:

      • the screen shifts up a row whenever the cursor sits below the last
        text (after a program exits, after clear);
      • the saved cursor is lost;
      • origin-mode cursors are off;
      • blank cells take the previous text's colours (black boxes beside
        Claude Code's logo);
      • hyperlinks and protected cells are lost;
      • the primary screen's Kitty keyboard flags are lost while an alt screen
        shows.

      S1's fixtures all left the cursor on their last line of text, so they
      missed this.

    • Fix now, in crates/vt (not tied to a milestone). All seven fixes
      are prototyped in the spike's src/patched.rs, and with them all 17
      non-image fixtures are exact in both engines:

      1. pad dropped rows straight after the content, not after the cursor
        move;
      2. place the cursor relative to the scroll region under DECOM;
      3. carry each screen's saved cursor, by cloning through GHOSTSNP and
        restoring on the clone to read it;
      4. replay into a scratch terminal and repaint cells that differ
        (colours, hyperlinks, protection);
      5. emit the primary screen's Kitty keyboard flags;
      6. turn off Kitty image storage for xterm.js clients
        (set_kitty_image_storage_limit(0)): today the engine tells programs
        images work, and each pane holds up to 10 MB of images nobody sees;
      7. add the new fixtures, plus probes of cursor, saved cursor and cells,
        to the crate's tests.

      Snapshots then take 1–3.3 ms instead of 0.03–0.5 ms, mostly from the
      prototype's slow cell compare.

    • Cross-build: the pinned Ghostty (22d13172) and main (0081d453)
      can't read each other's GHOSTSNP. Both directions fail cleanly with
      INVALID_VALUE on every fixture (the 64-byte BLAKE3 removal). So M2's
      "discard and replay" is safe.

      • But the tag doesn't tell builds apart: build_info says 0.1.0-dev
        in both, and engine_tag() is identical.
      • Derive a real tag at build time, or hash a fixed canary terminal's
        GHOSTSNP.
    • Upstream issues to file:

      • GHOSTSNP: bump the version on wire changes, and carry Kitty images;
      • build_info: include the git hash;
      • the formatter: blank-cell colours, hyperlinks and protection not
        emitted, cursor move before the scroll region, only the active
        screen's Kitty keyboard flags.
    • Still open: a pending wrap on the live cursor (no fixture ends with
      one); a longer Claude Code session with tool output.

The spike is done; this issue is the "Fix now, in `crates/vt`" work it found (seven fixes, prototyped in the spike's `src/patched.rs`), plus the build-tag and upstream items. _From PLAN.md, section "S: spikes → S1/S5 follow-ups"._ --- - **S1/S5 follow-ups: done 2026-10-01.** See [spikes/s1s5-followup](https://git.inevitable.fyi/jhgaylor/illogical/src/branch/main/spikes/s1s5-followup/README.md). - **New fixtures:** Claude Code (it draws in the alt screen), origin mode, DECSLRM, the saved cursor in primary and alt screens (1049 and 47), Kitty graphics and sixel. - **Checkpoints (GHOSTSNP)** round-trip all of them exactly, except Kitty images, which GHOSTSNP v1 leaves out by design. libghostty doesn't parse sixel, so there's nothing to carry. - **The wire path is wrong today on 13 of 18 fixtures,** in Ghostty and in xterm.js. This is the formatter snapshot plus fix-ups that the browser gets on attach. The visible failures: - the screen shifts up a row whenever the cursor sits below the last text (after a program exits, after `clear`); - the saved cursor is lost; - origin-mode cursors are off; - blank cells take the previous text's colours (black boxes beside Claude Code's logo); - hyperlinks and protected cells are lost; - the primary screen's Kitty keyboard flags are lost while an alt screen shows. S1's fixtures all left the cursor on their last line of text, so they missed this. - **Fix now, in `crates/vt` (not tied to a milestone).** All seven fixes are prototyped in the spike's `src/patched.rs`, and with them all 17 non-image fixtures are exact in both engines: 1. pad dropped rows straight after the content, not after the cursor move; 2. place the cursor relative to the scroll region under DECOM; 3. carry each screen's saved cursor, by cloning through GHOSTSNP and restoring on the clone to read it; 4. replay into a scratch terminal and repaint cells that differ (colours, hyperlinks, protection); 5. emit the primary screen's Kitty keyboard flags; 6. turn off Kitty image storage for xterm.js clients (`set_kitty_image_storage_limit(0)`): today the engine tells programs images work, and each pane holds up to 10 MB of images nobody sees; 7. add the new fixtures, plus probes of cursor, saved cursor and cells, to the crate's tests. Snapshots then take 1–3.3 ms instead of 0.03–0.5 ms, mostly from the prototype's slow cell compare. - **Cross-build:** the pinned Ghostty (`22d13172`) and `main` (`0081d453`) can't read each other's GHOSTSNP. Both directions fail cleanly with `INVALID_VALUE` on every fixture (the 64-byte BLAKE3 removal). So M2's "discard and replay" is safe. - But the tag doesn't tell builds apart: `build_info` says `0.1.0-dev` in both, and `engine_tag()` is identical. - Derive a real tag at build time, or hash a fixed canary terminal's GHOSTSNP. - **Upstream issues to file:** - GHOSTSNP: bump the version on wire changes, and carry Kitty images; - `build_info`: include the git hash; - the formatter: blank-cell colours, hyperlinks and protection not emitted, cursor move before the scroll region, only the active screen's Kitty keyboard flags. - **Still open:** a pending wrap on the live cursor (no fixture ends with one); a longer Claude Code session with tool output.
Sign in to join this conversation.
No description provided.