a50f92c1
test: tp2b resizes UP so a stale replica width has somewhere to show
a73x 2026-08-10 09:41
Commit message
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" |