a73x

f9c185db

test(e2e): pin the title stack's count, and sweep the leg's residue

a73x   2026-08-15 20:02

Commit message
test(e2e): pin the title stack's count, and sweep the leg's residue

Three gaps in the leg as it shipped.

The trap did not know about $OUT.title{,.err,.log,.sh}, so its rm_swept —
which runs only on success — left them behind on exactly the runs where
somebody is debugging the leg.

Order was pinned but not COUNT. A second push leaves the run one deeper
than it found it, and the argument that it cannot happen (the reconnect
path re-enters with alt_screen already true) was prose with no test under
it. Exactly one of each, now.

The free case: the M7 dead-transport leg already runs a client with
non-tty stdin that dies before any frame, so it can say for nothing that a
client which entered nothing pushed nothing.

That last needle wanted -F and did not have it. Without it `[22;0t` is a
malformed bracket expression and grep exits 2, which `grep && { fail }`
reads as "not found" — an assertion that could never fire, in a check
added to catch assertions that never fire. Found by running the needle by
hand against a capture known to contain it, then confirmed live by pushing
at setup and watching it catch that.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

test/e2e.sh
Old New
@@ -787,6 +787,10 @@ cleanup() {
787 # the session runs. Spelled from $OUT rather than from a variable of its 787 # the session runs. Spelled from $OUT rather than from a variable of its
788 # own, for the reason the M12 controls above are. 788 # own, for the reason the M12 controls above are.
789 rm -f "$OUT.clip" "$OUT.clip.err" "$OUT.clip.log" "$OUT.clip.sh" 789 rm -f "$OUT.clip" "$OUT.clip.err" "$OUT.clip.log" "$OUT.clip.sh"
790 # The title leg's identical four. Its own rm_swept runs only on success,
791 # so without this line the residue survives exactly the runs where the
792 # leg failed and somebody is looking at it.
793 rm -f "$OUT.title" "$OUT.title.err" "$OUT.title.log" "$OUT.title.sh"
790 # ...and its other half: the paste capture and the file nvim wrote, which 794 # ...and its other half: the paste capture and the file nvim wrote, which
791 # IS that scenario's assertion rather than a log beside it. 795 # IS that scenario's assertion rather than a log beside it.
792 rm -f "$OUT.paste" "$OUT.paste.err" "$OUT.paste.log" "$OUT.pasted.txt" 796 rm -f "$OUT.paste" "$OUT.paste.err" "$OUT.paste.log" "$OUT.pasted.txt"
@@ -1036,6 +1040,18 @@ grep -q "transport command failed before a session started" "$OUT.dead" || {
1036 grep -q "is muxd installed on the host" "$OUT.dead" && { 1040 grep -q "is muxd installed on the host" "$OUT.dead" && {
1037 echo "e2e FAIL: old lostMsg wording still emitted alongside the new pin" 1041 echo "e2e FAIL: old lostMsg wording still emitted alongside the new pin"
1038 cat "$OUT.dead"; exit 1; } 1042 cat "$OUT.dead"; exit 1; }
1043 # Free ride on this capture, for a property with nothing to do with the exit
1044 # code: this client had NON-TTY stdin and died before any frame, so it is
1045 # the one place in the suite that proves mux does not push a title onto a
1046 # terminal it never took over. An unmatched push is a title stack that only
1047 # grows, and nothing later would pop it — the teardown never runs.
1048 # -F is load-bearing, not decoration: without it `[22;0t` is a malformed
1049 # bracket expression, grep EXITS 2 rather than 1, and `grep && { fail }`
1050 # reads an error as "not found" — an assertion that can never fire. Caught
1051 # by running this needle by hand against a capture known to contain it.
1052 grep -qaF "$(printf '\033[22;0t')" "$OUT.dead" && {
1053 echo "e2e FAIL: a client that entered nothing still pushed the title stack"
1054 cat -v "$OUT.dead"; exit 1; }
1039 1055
1040 # M13 spec amendment: a socket path past sun_path's 107 usable bytes is 1056 # M13 spec amendment: a socket path past sun_path's 107 usable bytes is
1041 # refused by name in both binaries, before either acts on it — the failure 1057 # refused by name in both binaries, before either acts on it — the failure
@@ -2788,6 +2804,9 @@ grep -qa 'TITLEDONE' "$OUT.title" || {
2788 # Terminator included, for the same reason as the clipboard needle: the 2804 # Terminator included, for the same reason as the clipboard needle: the
2789 # builder writes the escape whole or writes nothing, and a needle stopping 2805 # builder writes the escape whole or writes nothing, and a needle stopping
2790 # at the payload could not tell one from half of one. 2806 # at the payload could not tell one from half of one.
2807 # OSC **0**, deliberately, against a fixture that wrote OSC **2** — the
2808 # asymmetry is the instrument, and it is argued at the head of this leg.
2809 # Do not "fix" either side to match the other without reading that.
2791 TITLEESC=$(printf '\033]0;mux-e2e-title\007') 2810 TITLEESC=$(printf '\033]0;mux-e2e-title\007')
2792 grep -qaF "$TITLEESC" "$OUT.title" || { 2811 grep -qaF "$TITLEESC" "$OUT.title" || {
2793 echo "e2e FAIL: the window title never reached the host tty"; exit 1; } 2812 echo "e2e FAIL: the window title never reached the host tty"; exit 1; }
@@ -2796,18 +2815,33 @@ grep -qaF "$TITLEESC" "$OUT.title" || {
2796 # and popped once — and an unmatched pop does not restore a title, it pops 2815 # and popped once — and an unmatched pop does not restore a title, it pops
2797 # whatever the terminal had underneath, which is somebody else's. The 2816 # whatever the terminal had underneath, which is somebody else's. The
2798 # offsets say: pushed before mux set anything, popped after. 2817 # offsets say: pushed before mux set anything, popped after.
2799 title_off() { 2818 first_offset() {
2800 grep -aboF "$2" "$1" | head -1 | cut -d: -f1 2819 grep -aboF "$2" "$1" | head -1 | cut -d: -f1
2801 } 2820 }
2802 PUSH_AT=$(title_off "$OUT.title" "$(printf '\033[22;0t')") 2821 occurrences() {
2803 POP_AT=$(title_off "$OUT.title" "$(printf '\033[23;0t')") 2822 grep -aoF "$2" "$1" | wc -l
2804 SET_AT=$(title_off "$OUT.title" "$TITLEESC") 2823 }
2824 PUSH_ESC=$(printf '\033[22;0t')
2825 POP_ESC=$(printf '\033[23;0t')
2826 PUSH_AT=$(first_offset "$OUT.title" "$PUSH_ESC")
2827 POP_AT=$(first_offset "$OUT.title" "$POP_ESC")
2828 SET_AT=$(first_offset "$OUT.title" "$TITLEESC")
2805 [ -n "$PUSH_AT" ] || { echo "e2e FAIL: no title push on the host tty"; exit 1; } 2829 [ -n "$PUSH_AT" ] || { echo "e2e FAIL: no title push on the host tty"; exit 1; }
2806 [ -n "$POP_AT" ] || { echo "e2e FAIL: no title pop on the host tty (exit left it set)"; exit 1; } 2830 [ -n "$POP_AT" ] || { echo "e2e FAIL: no title pop on the host tty (exit left it set)"; exit 1; }
2807 [ "$PUSH_AT" -lt "$SET_AT" ] || { 2831 [ "$PUSH_AT" -lt "$SET_AT" ] || {
2808 echo "e2e FAIL: mux set the title at $SET_AT before pushing at $PUSH_AT"; exit 1; } 2832 echo "e2e FAIL: mux set the title at $SET_AT before pushing at $PUSH_AT"; exit 1; }
2809 [ "$SET_AT" -lt "$POP_AT" ] || { 2833 [ "$SET_AT" -lt "$POP_AT" ] || {
2810 echo "e2e FAIL: the title pop at $POP_AT came before the set at $SET_AT"; exit 1; } 2834 echo "e2e FAIL: the title pop at $POP_AT came before the set at $SET_AT"; exit 1; }
2835 # Exactly one of each, which order alone does not catch. A second push is a
2836 # stack this run leaves one deeper than it found it, and the argument that
2837 # it cannot happen — the reconnect path re-enters with alt_screen already
2838 # true (client.zig) — was prose with no test behind it until here.
2839 PUSH_N=$(occurrences "$OUT.title" "$PUSH_ESC")
2840 POP_N=$(occurrences "$OUT.title" "$POP_ESC")
2841 [ "$PUSH_N" -eq 1 ] || {
2842 echo "e2e FAIL: $PUSH_N title pushes on one run, want exactly 1"; exit 1; }
2843 [ "$POP_N" -eq 1 ] || {
2844 echo "e2e FAIL: $POP_N title pops on one run, want exactly 1"; exit 1; }
2811 rm_swept "$OUT.title" "$OUT.title.err" "$OUT.title.log" "$OUT.title.sh" 2845 rm_swept "$OUT.title" "$OUT.title.err" "$OUT.title.log" "$OUT.title.sh"
2812 ok "the window title reaches the host as OSC 0, pushed before and popped after" 2846 ok "the window title reaches the host as OSC 0, pushed before and popped after"
2813 2847