cmux-tui: fix the replay row scroll and stale hook fence tests breaking the full gate
Summary
The dispatched cmux-tui full gate fails on every main-based branch. Causes on main:
1. VT replays scroll the mirror by one row (#14090). #14090 bumped ghostty to a formatter change that keeps trailing blank rows in VT replays. It emitted one row break too many (the one ending the final row), so every replay scrolled its target terminal by one row: the top row went into scrollback and later absolute-cursor output landed one row off. This broke:
session::remote::tests::ordered_resize_replay_recovers_from_stale_initial_replay(mirror read%\nlawrenceinstead oflawrence)pending_wrap_replay_preserves_cursor_with_origin_mode(valgrind startup baseline step)
manaflow-ai/ghostty#241 fixed the formatter on ghostty main (3429f20). This pins ghostty to fd8e62d, which is that commit plus the two hex escape commits from manaflow-ai/ghostty#239 that main already depended on (startup input bytes, #15081), and adds its GhosttyKit checksum.
2. Hook fence tests read the roster their calls bypass (#13299). #13299 moved list_agents onto the journal-folded agent roster. Seven hook fence tests call apply_agent_hook_record directly with hand-picked sequences, which never reaches the roster fold, so list_agents came back empty. They now assert on the projector's own live record:
stale_same_terminal_hook_sequence_cannot_overwrite_newer_state, hook_projection_does_not_relock_its_held_sequence_guard, delayed_old_hook_session_start_cannot_replace_active_session, late_sessionless_hook_event_cannot_attach_to_new_session, old_hook_session_end_cannot_fence_new_session, sessionless_hook_lifecycles_get_distinct_fence_identity, failed_hook_projection_does_not_consume_sequence_and_replay_succeeds.
3. Topology close failure test (#13299). #13299 narrowed the test-only forced patch failure trigger to journal rows with a resource revision, so a failed close now commits its failure outcome (operation.failed) instead of going indeterminate. topology_close_commit_failure_leaves_every_projection_live_and_fences_replay now expects that, and the same error on replay.
4. Report race test. concurrent_raw_socket_and_resource_hook_reports_serialize_to_hook_state assumed the socket report always commits first. When the hook wins, the socket report is retained without a new revision. It now checks one batch per committed revision with the hook's commit last.
5. Sidebar plugin CLI test (#13299). The generalized plugin manager reports validation errors on the plugin field; local_plugin_jsonl_never_connects_to_the_session_socket still expected sidebar_plugin.
6. Input to an exited keep-on-exit terminal. Receipted API input rejected writes to an exited hosted terminal with terminal_input_delivery_failed, while keep-on-exit terminals document typing on the final screen as a harmless no-op and the unreceipted path already drops those bytes. keep_on_exit_retains_tab_and_final_screen_until_close_and_degrades_on_restart has failed since. Receipted input to an exited terminal is now a successful no-op too.
7. rustfmt (#15163). cargo fmt --check failed on the OSC title suffix.
8. Plugin projection repair test. startup_repairs_a_plugin_projection_lost_after_journal_commit restarted the mux and expected a local PTY terminal to keep its agent, but local PTYs are detached on restart. It now repairs the lost projection on the live mux with reconcile_agent_roster_projections, checks that a second pass spends no revision, and checks that the roster entry survives the restart.
9. Live OSC 7 cwd tests (#12978). cloud_cwd_live_osc7_reaches_snapshot_and_event_feed and cloud_cwd_live_osc7_clear_reaches_snapshot used Mux::new_for_test, whose surfaces never run their command, so the shell never printed OSC 7 and both timed out since they were added. They now use Mux::new with a real local PTY.
The isolated core test runner stops at the first failure, which is why these surfaced one at a time.
Testing
- cmux-tui full gate on this commit.
- manaflow-ai/ghostty#241 adds a formatter test for the row count.
🤖 Generated with Claude Code
Summary by CodeRabbit
- Bug Fixes
- Input sent to an exited hosted terminal is now safely ignored instead of returning a connection error.
- Topology close failures now report an operation failure, with consistent error details when the request is replayed.
- Invalid sidebar plugin selections now identify the
pluginfield in validation errors. - Startup reconciliation restores missing agent projections without advancing the resource revision when no changes are needed.