a73x

1477514f

test: the Linux-to-Mac leg pins the port the Mac's daemon actually announced

a73x   2026-09-04 10:16

Commit message
test: the Linux-to-Mac leg pins the port the Mac's daemon actually announced

The entry dial starts the Mac's daemon bare, and what happens next is the
product's: `mux d endpoint` creates the default key file on a box that has
none, and the daemon then binds a QUIC listener lazily on an EPHEMERAL
port. Measured 64152 on this fixture. The leg asked lsof about 4433, found
nothing, and called a working handoff a failure.

It now reads the port out of the announce and asks the Mac whether
anything is bound there, so the OS still answers the question the daemon
was only asked to raise. The `endpoint none` branch stays for a daemon
that offers no arm at all, and the leg reports which of the two carried
the session rather than assuming either.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SakwJEwD9dXBoRP5kWbemW

test/xos.sh
Old New
@@ -50,10 +50,12 @@ LAN_IP=${LAN#*@}
50 REPO="${MUX_MAC_REPO:-code/rad/mux}" 50 REPO="${MUX_MAC_REPO:-code/rad/mux}"
51 BRANCH=mac-journey 51 BRANCH=mac-journey
52 QUIC_PORT=4433 52 QUIC_PORT=4433
53 # 4433 as /proc/net/udp writes a wildcard bind, which is the spelling 53 # The port as /proc/net/udp writes a wildcard bind, which is the spelling
54 # os_oracle.sh's udp_local_bound takes on BOTH arms — the Darwin arm 54 # os_oracle.sh's udp_local_bound takes on BOTH arms — the Darwin arm converts
55 # converts it, so a leg never learns which OS it is asking. 55 # it, so a leg never learns which OS it is asking. Derived rather than written
56 QUIC_HEX=00000000:1151 56 # out, because a hand-typed hex goes stale the moment somebody edits the port
57 # above it; leg 7 spells the same derivation for the port a Mac announces.
58 QUIC_HEX=$(printf '00000000:%04X' "$QUIC_PORT")
57 59
58 # BatchMode so a broken auth fails in seconds rather than prompting a 60 # BatchMode so a broken auth fails in seconds rather than prompting a
59 # harness nobody sits in front of; accept-new so the first run records a 61 # harness nobody sits in front of; accept-new so the first run records a
@@ -61,9 +63,10 @@ QUIC_HEX=00000000:1151
61 # spawns plain `ssh $HOST` and reads that same file. 63 # spawns plain `ssh $HOST` and reads that same file.
62 SSH_OPTS="-o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new" 64 SSH_OPTS="-o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new"
63 65
64 # now_ms and the pid_*/file_* names the remote legs source for themselves. 66 # now_ms for the leg clock, and sha256_of for the two installed-image hashes.
65 # The harness spells time and paths through the oracle so this script would 67 # The pid_*, file_* and udp_* names are sourced by the REMOTE legs from the
66 # still answer if it were ever run FROM a Mac. 68 # copy beside the binary on each box, which is what keeps a leg from having to
69 # know which OS is answering it.
67 . "$(dirname "$0")/os_oracle.sh" 70 . "$(dirname "$0")/os_oracle.sh"
68 71
69 OK_COUNT=0 72 OK_COUNT=0
@@ -343,12 +346,15 @@ LINFO=$(lssh 60 <<'L'
343 . ~/xos/os_oracle.sh 346 . ~/xos/os_oracle.sh
344 echo "ver=$(~/.local/bin/mux --version)" 347 echo "ver=$(~/.local/bin/mux --version)"
345 echo "sha=$(sha256_of ~/.local/bin/mux)" 348 echo "sha=$(sha256_of ~/.local/bin/mux)"
349 echo "exe=$(real_path ~/.local/bin/mux)"
346 echo "rtd=${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" 350 echo "rtd=${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
347 L 351 L
348 ) 352 )
349 LAN_VER=$(printf '%s\n' "$LINFO" | sed -n 's/^ver=//p') 353 LAN_VER=$(printf '%s\n' "$LINFO" | sed -n 's/^ver=//p')
350 LAN_GOT_SHA=$(printf '%s\n' "$LINFO" | sed -n 's/^sha=//p') 354 LAN_GOT_SHA=$(printf '%s\n' "$LINFO" | sed -n 's/^sha=//p')
355 LAN_EXE=$(printf '%s\n' "$LINFO" | sed -n 's/^exe=//p')
351 LAN_RTD=$(printf '%s\n' "$LINFO" | sed -n 's/^rtd=//p') 356 LAN_RTD=$(printf '%s\n' "$LINFO" | sed -n 's/^rtd=//p')
357 [ -n "$LAN_EXE" ] || fail reset "$LAN would not resolve the path of its installed mux"
352 [ "$LAN_VER" = "$WANT_VER" ] || 358 [ "$LAN_VER" = "$WANT_VER" ] ||
353 fail reset "$LAN answers '$LAN_VER', this tree built '$WANT_VER'" 359 fail reset "$LAN answers '$LAN_VER', this tree built '$WANT_VER'"
354 [ "$LAN_GOT_SHA" = "$LAN_BIN_SHA" ] || 360 [ "$LAN_GOT_SHA" = "$LAN_BIN_SHA" ] ||
@@ -434,7 +440,14 @@ L
434 # does not hold is invisible from the client — the handshake simply never 440 # does not hold is invisible from the client — the handshake simply never
435 # answers — and leg 5 would then be grading the ssh fallback while reporting 441 # answers — and leg 5 would then be grading the ssh fallback while reporting
436 # QUIC. 442 # QUIC.
443 #
444 # XDG_CONFIG_HOME is UNSET for this one read. The announce that matters is the
445 # one at the far end of the MAC's entry dial, which is a fresh ssh carrying
446 # this box's own environment and so resolves ~/.config/mux/key; asking under
447 # the prelude's isolated config dir would check a sibling file that happens to
448 # hold the same bytes and guard nothing.
437 ANN=$(lssh 30 <<'L' 449 ANN=$(lssh 30 <<'L'
450 unset XDG_CONFIG_HOME
438 ~/.local/bin/mux d endpoint </dev/null 451 ~/.local/bin/mux d endpoint </dev/null
439 L 452 L
440 ) 453 )
@@ -447,6 +460,17 @@ pgrep -x mux | head -1
447 L 460 L
448 ) 461 )
449 [ -n "$LPID" ] || fail mac-to-linux "no mux process on $LAN after mux d start -d" 462 [ -n "$LPID" ] || fail mac-to-linux "no mux process on $LAN after mux d start -d"
463 # The image this daemon is running, recorded before anything is pushed at it.
464 # Leg 9 reads it again after the refused push: on Linux an upgrade keeps the
465 # pid across the exec, so the pid alone cannot tell an untouched daemon from
466 # one that swallowed a new image, and the exe is what can.
467 LIS=$(lssh 30 <<L
468 . ~/xos/os_oracle.sh
469 pid_exe $LPID
470 L
471 )
472 [ "$LIS" = "$LAN_EXE" ] ||
473 fail mac-to-linux "daemon $LPID on $LAN execs '$LIS', not the installed '$LAN_EXE'"
450 # Bound BEFORE the dial, asked of /proc and not of the daemon: a leg that 474 # Bound BEFORE the dial, asked of /proc and not of the daemon: a leg that
451 # read "no answer" from the Mac could otherwise be blaming the network for a 475 # read "no answer" from the Mac could otherwise be blaming the network for a
452 # listener that was never up. 476 # listener that was never up.
@@ -598,19 +622,27 @@ mssh 60 >/dev/null <<M || fail linux-to-mac "shell $L2M_PID is not a child of da
598 . \$HOME/xos/os_oracle.sh 622 . \$HOME/xos/os_oracle.sh
599 pid_children $MPID | grep -qx $L2M_PID 623 pid_children $MPID | grep -qx $L2M_PID
600 M 624 M
601 # WHICH transport carried it, read off the announce rather than assumed. The 625 # WHICH transport carried it, read off the announce rather than assumed.
602 # entry dial started this daemon bare — no --quic, no key — so what it says 626 # The entry dial starts this daemon BARE — no --quic and no --key on any
603 # is `endpoint none`, the handoff's explicit "no coordinates", and the 627 # command line — and what the Mac does with that is the product's own
604 # session stays on the ssh pipe. There is no positive line for that case 628 # behaviour, not this gate's to arrange: `mux d endpoint` creates the
605 # (the client only speaks up when QUIC was tried and lost), so the pin is 629 # default key file when the box has none and the daemon then binds a QUIC
606 # three facts: the daemon offers no arm, it binds no UDP port, and the 630 # listener lazily, on an EPHEMERAL port rather than 4433, so the announce
607 # client printed no fallback sentence. If a future daemon does announce an 631 # names a port nothing here could have predicted. Whichever of the two
608 # arm here, this leg says so instead of quietly grading the other transport. 632 # answers comes back, the leg asserts the matching OS fact and reports what
633 # carried the session; what it will not do is grade one transport while
634 # reporting the other.
635 #
609 # An `if` and not `grep ... && fail`: an AND-OR list whose first command 636 # An `if` and not `grep ... && fail`: an AND-OR list whose first command
610 # fails is the ordinary case here, and reading it as the leg's verdict is 637 # fails is the ORDINARY case here, and reading that as the leg's verdict is
611 # the wrong way round. 638 # the wrong way round.
612 case "$MANN" in 639 case "$MANN" in
613 "endpoint none") 640 "endpoint none")
641 # No arm to move onto, so the pipe that carried the announce is the
642 # session. The daemon's own word is what says so — there is no
643 # positive line on the client side, which only speaks up when QUIC
644 # was tried and lost — and the OS fact beside it is that nothing is
645 # bound at the port this gate would otherwise expect.
614 printf '%s\n' "$MSTATE" | grep -qx 'udp=none' || 646 printf '%s\n' "$MSTATE" | grep -qx 'udp=none' ||
615 fail linux-to-mac "$MAC announces no endpoint yet binds UDP $QUIC_PORT: $MSTATE" 647 fail linux-to-mac "$MAC announces no endpoint yet binds UDP $QUIC_PORT: $MSTATE"
616 if grep -q 'attaching over ssh' "$SCRATCH/l2m.err"; then 648 if grep -q 'attaching over ssh' "$SCRATCH/l2m.err"; then
@@ -618,12 +650,23 @@ case "$MANN" in
618 fi 650 fi
619 L2M_WIRE="ssh handoff (the daemon announced 'endpoint none')" ;; 651 L2M_WIRE="ssh handoff (the daemon announced 'endpoint none')" ;;
620 'endpoint '*) 652 'endpoint '*)
621 printf '%s\n' "$MSTATE" | grep -qx 'udp=bound' || 653 MPORT=${MANN#endpoint }
622 fail linux-to-mac "$MAC announces '$MANN' but binds no UDP $QUIC_PORT: $MSTATE" 654 MPORT=${MPORT%% *}
655 case "$MPORT" in
656 ''|*[!0-9]*) fail linux-to-mac "$MAC announces no readable port: '$MANN'" ;;
657 esac
658 # The announced port, as /proc/net/udp writes a wildcard bind — the
659 # spelling both arms of the oracle take. Asked of lsof on the Mac,
660 # so the claim "the daemon is listening there" is the OS's and not
661 # the daemon's own.
662 mssh 60 >/dev/null <<M || fail linux-to-mac "$MAC announces '$MANN' but binds no UDP $MPORT"
663 . \$HOME/xos/os_oracle.sh
664 udp_local_bound $(printf '00000000:%04X' "$MPORT")
665 M
623 if grep -q 'attaching over ssh' "$SCRATCH/l2m.err"; then 666 if grep -q 'attaching over ssh' "$SCRATCH/l2m.err"; then
624 fail linux-to-mac "$MAC offered QUIC ('$MANN') and the dial fell back to ssh" 667 fail linux-to-mac "$MAC offered QUIC on $MPORT and the dial fell back to ssh"
625 fi 668 fi
626 L2M_WIRE="QUIC (the daemon announced '$MANN')" ;; 669 L2M_WIRE="QUIC on the lazily-bound port $MPORT" ;;
627 *) 670 *)
628 fail linux-to-mac "$MAC's daemon answers no announce this leg can read: '$MANN'" ;; 671 fail linux-to-mac "$MAC's daemon answers no announce this leg can read: '$MANN'" ;;
629 esac 672 esac
@@ -775,6 +818,8 @@ printf '%s\n' "$POST" | grep -qx "lanpid=$LPID" ||
775 fail upgrade-refused "$LAN's daemon is no longer $LPID: $POST" 818 fail upgrade-refused "$LAN's daemon is no longer $LPID: $POST"
776 printf '%s\n' "$POST" | grep -qx "macexe=$MAC_EXE" || 819 printf '%s\n' "$POST" | grep -qx "macexe=$MAC_EXE" ||
777 fail upgrade-refused "$MAC's daemon execs something else now: $POST" 820 fail upgrade-refused "$MAC's daemon execs something else now: $POST"
821 printf '%s\n' "$POST" | grep -qx "lanexe=$LAN_EXE" ||
822 fail upgrade-refused "$LAN's daemon execs something else now: $POST"
778 ok upgrade-refused "both pushes refused on uname alone; both images and both daemons untouched" 823 ok upgrade-refused "both pushes refused on uname alone; both images and both daemons untouched"
779 824
780 # ---- leg 10: stop — and each box's socket goes with its daemon --------- 825 # ---- leg 10: stop — and each box's socket goes with its daemon ---------