Skip to content

tech-debt: restore can replay a torn alt-screen snapshot for ssh and stripe panes #176

Description

@artyomsv

Tracked in techdebt/3-3-restore-replays-a-torn-alt-screen-snapshot-for-ssh.md (Medium / Medium). Found during code review of #173; not a regression from it.

Issue

#173 stops the daemon replaying a ring buffer into a pane whose child is on the alternate screen, because such a stream carries frame deltas rather than history. The decision reads pane.MouseModes.altScreen, which the daemon learns by scanning the pane's own output.

MouseModes is deliberately not persisted — it starts at the zero value after a daemon restart and only becomes true once this incarnation's child re-emits its enable sequence. On the first attach after a restore, therefore, the daemon cannot know the pane is on the alternate screen, and the ghostsnap replay proceeds using the snapshot loaded from disk.

For claude-code that is harmless: restoresOwnHistory (strategy preassign_id) already skips the restore replay for a separate reason. But ssh and stripe are ghost_buffer = true with strategy rerun and no such skip. A pane running vim, less or htop over ssh when the daemon restarts has its torn alt-screen snapshot replayed on the first attach — the symptom #172 fixes on the live-reconnect path.

Why it wasn't fixed in #173

Pre-existing behaviour: before #173 that replay happened too, and #173 does not make it worse. Closing it needs a design decision, and the options are not obviously ranked:

  • Persist the alt-screen bit with the snapshot. Cheapest to reason about, but MouseModes is documented as broadcast-not-persisted, and adding a field to the workspace format for it invites the question of what else belongs there.
  • Track "never scanned this incarnation" and treat an unscanned pane conservatively. But conservative in which direction? Skipping the replay for every freshly restored pane would break the common, correct case — a terminal pane replaying its history after a restart, which is the feature working as intended.
  • Sniff the snapshot itself for an unbalanced ?1049h when loading it from disk. Self-contained, no format change, but it is a second parser over the same bytes and inherits the ring-wrap problem: a snapshot that begins after the enable looks main-screen.

What would settle it

The same method #173 used on its own premise: capture a real ssh-hosted full-screen pane, restart the daemon, and replay the loaded snapshot through the client emulator (PaneModel.AppendOutput + vtRow) to see what the grid actually contains.

Worth checking first whether it needs code at all — rerun re-executes the command on restore, so the respawned child may repaint over the replay anyway. If it does, this is a comment rather than a fix.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    tech-debtKnown compromise, tracked in techdebt/

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions