a73x

a50f92c1

test: tp2b resizes UP so a stale replica width has somewhere to show

a73x   2026-08-10 09:41

Commit message
test: tp2b resizes UP so a stale replica width has somewhere to show

Graded against row 7's mutation (the snapshot prefix resize commented
out): the previous shape survived it. A delta paints straight to the tty,
so a stale replica only shows in the full repaint that answers a snapshot,
which clips at min(replica, tty) — the damage must still be on screen then
and outside the stale geometry. Resizing UP with a filled screen and a
95-wide row puts it there.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

test/e2e.sh
Old New
@@ -1602,12 +1602,26 @@ ok "ptyclient controls: pty echo roundtrips, impossible expect fails loudly, std
1602 1602
1603 # ---- M12 tp2: resize under a real tty (campaign row 7's branch) -------- 1603 # ---- M12 tp2: resize under a real tty (campaign row 7's branch) --------
1604 # Two clients, two convergence points, because convergence is a scenario's 1604 # Two clients, two convergence points, because convergence is a scenario's
1605 # LAST act after detach: tp2a exercises the snapshot resize prefix (a 1605 # LAST act after detach.
1606 # 100x30 tty attaching to an 80x24 grid resizes the replica DOWN, then the 1606 #
1607 # claim's answering snapshot resizes it back UP); tp2b exercises the winch 1607 # tp2a is the suite's first attach at a size that is not the non-tty 80x24
1608 # path mid-session and is the leg that catches row 7 — its 95-wide row is 1608 # default: it pins the size a real tty reports reaching the daemon, and
1609 # two rows at 90 cols and one row at 100, so a replica whose width is 1609 # convergence measured against that size rather than the default. It does
1610 # stale settles into a different SHAPE than the grid it is replicating. 1610 # NOT exercise the snapshot resize prefix — an attach applies the
1611 # attacher's size to the grid BEFORE the answering resync, so the prefix
1612 # always equals the size the replica already has and the client's
1613 # resize-on-prefix guard never fires. Verified by probe, not by reading.
1614 #
1615 # tp2b is the leg that catches row 7 (the prefix ignored), and it only
1616 # catches it because of WHERE the damage can show. A delta paints its
1617 # rows straight to the tty, absolutely addressed and clipped to the tty,
1618 # so a stale replica is invisible on that path and a wrong row is healed
1619 # by the next delta that re-addresses it. The one moment the client paints
1620 # FROM the replica is the full repaint that answers a snapshot, clipped to
1621 # min(replica, tty) — so the damage has to be still ON SCREEN then, and in
1622 # a region the stale geometry cannot reach. Hence: fill the screen, put a
1623 # 95-wide row on it, then winch UP to 100x30. With the prefix ignored the
1624 # replica stays 90x28 and that repaint reproduces the OLD geometry.
1611 "$MUXD" run --sock "$SOCK12" --shell /bin/sh > "$OUT.tp2.d" 2>&1 & 1625 "$MUXD" run --sock "$SOCK12" --shell /bin/sh > "$OUT.tp2.d" 2>&1 &
1612 D12PID=$! 1626 D12PID=$!
1613 i=0 1627 i=0
@@ -1653,17 +1667,30 @@ set -e
1653 echo "e2e FAIL: tp2a ptyclient exited $RC:"; cat "$OUT.tp2a.log"; exit 1; } 1667 echo "e2e FAIL: tp2a ptyclient exited $RC:"; cat "$OUT.tp2a.log"; exit 1; }
1654 assert_converged "$OUT.tp2a" "$SOCK12" "pty attach at 100x30" 100 30 1668 assert_converged "$OUT.tp2a" "$SOCK12" "pty attach at 100x30" 100 30
1655 1669
1670 # Resize UP, not down: a replica LARGER than the grid is invisible (the
1671 # paint clips at min(replica, tty) either way), so only a replica left
1672 # too SMALL has anywhere to show. `seq 1 60` fills the screen so growing
1673 # to 30 rows has to pull history down rather than append blanks, and the
1674 # 95-wide row is wider than the stale 90 and narrower than the new 100.
1675 #
1676 # PS1 is still tp2rdy@ from tp2a: same daemon, same shell, and the
1677 # assignment outlived the client that typed it. Note where the prompt
1678 # expects sit — the sentinel is re-emitted whenever the prompt ROW is
1679 # repainted, including by the echo of a command typed at it, so each
1680 # trailing prompt is consumed BEFORE the resize. That leaves the expect
1681 # after `resize` satisfiable only by the answering snapshot's repaint.
1656 set +e 1682 set +e
1657 timeout 40 "$PTYCLIENT" --cols 100 --rows 30 --out "$OUT.tp2b" --err "$OUT.tp2b.err" -- \ 1683 timeout 40 "$PTYCLIENT" --cols 90 --rows 28 --out "$OUT.tp2b" --err "$OUT.tp2b.err" -- \
1658 "$MUX" --sock "$SOCK12" > "$OUT.tp2b.log" 2>&1 <<'EOF' 1684 "$MUX" --sock "$SOCK12" > "$OUT.tp2b.log" 2>&1 <<'EOF'
1659 expect \x1b[?1049h 10000 1685 expect \x1b[?1049h 10000
1660 send printf 'tp2-%s\\n' live\n 1686 send seq 1 60; printf 'fill-%s\\n' done\n
1661 expect tp2-live 10000 1687 expect fill-done 10000
1662 resize 90 28 1688 expect tp2rdy@ 10000
1663 expect tp2-live 10000
1664 send printf '%095d\\n' 7\n 1689 send printf '%095d\\n' 7\n
1665 expect 00007 10000 1690 expect 00007 10000
1666 expect tp2rdy@ 10000 1691 expect tp2rdy@ 10000
1692 resize 100 30
1693 expect tp2rdy@ 10000
1667 send \x1c 1694 send \x1c
1668 waitexit 10000 1695 waitexit 10000
1669 EOF 1696 EOF
@@ -1671,21 +1698,16 @@ RC=$?
1671 set -e 1698 set -e
1672 [ "$RC" -eq 0 ] || { 1699 [ "$RC" -eq 0 ] || {
1673 echo "e2e FAIL: tp2b ptyclient exited $RC:"; cat "$OUT.tp2b.log"; exit 1; } 1700 echo "e2e FAIL: tp2b ptyclient exited $RC:"; cat "$OUT.tp2b.log"; exit 1; }
1674 # The second `expect tp2-live` is the resize's answering snapshot, and it 1701 # Graded against the mutation (row 7: the prefix resize commented out),
1675 # is the leg's real assertion: `tp2-live` reaches the stream exactly once 1702 # and this is what the mutated build actually did — two divergences in one
1676 # per full paint (the typed line says `tp2-%s`), the cursor consumed that 1703 # diff, neither of them an expect timeout, since every needle still
1677 # one, and nothing in the session wrote anything since — so only a REPAINT 1704 # arrives on a stale replica:
1678 # can satisfy it, and the resize is the only thing that could have asked 1705 # the 30-row grid came back with its top rows missing, because a 28-row
1679 # for one. 1706 # replica has 28 rows to repaint from;
1680 # 1707 # the 95-wide row came back still WRAPPED at 90 into "...0" + "00007",
1681 # `00007` is a synchronization point and NOT a discriminator, which is 1708 # because the replica that reflowed it is still 90 wide, while the
1682 # worth saying plainly: the 95-wide row wraps into 90 zeros and "00007" at 1709 # daemon had already rejoined it into one 95-char row at 100.
1683 # 90 cols, but an unwrapped 95-char row ends in those same five bytes, so 1710 assert_converged "$OUT.tp2b" "$SOCK12" "pty resize mid-session" 100 30
1684 # the needle arrives either way. What the stale width would change is the
1685 # SHAPE of the grid — one row or two — and only the convergence check
1686 # below can see that. PS1 is still tp2rdy@ from tp2a: same daemon, same
1687 # shell, and the assignment outlived the client that typed it.
1688 assert_converged "$OUT.tp2b" "$SOCK12" "pty resize mid-session" 90 28
1689 rm -f "$OUT.tp2a" "$OUT.tp2a.err" "$OUT.tp2a.log" \ 1711 rm -f "$OUT.tp2a" "$OUT.tp2a.err" "$OUT.tp2a.log" \
1690 "$OUT.tp2b" "$OUT.tp2b.err" "$OUT.tp2b.log" "$OUT.tp2.d" 1712 "$OUT.tp2b" "$OUT.tp2b.err" "$OUT.tp2b.log" "$OUT.tp2.d"
1691 ok "a pty client resizes: snapshot prefix applied, winch follows the tty" 1713 ok "a pty client resizes: snapshot prefix applied, winch follows the tty"