#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" && pwd) SEND_MESSAGE="$SCRIPT_DIR/send-message.sh" AGENT_SEND="$SCRIPT_DIR/agent-send.sh" SOCKET="mosaic-test-$RANDOM-$$" TARGET="target-$RANDOM" DEFAULT_TARGET="default-target-$RANDOM" TMPDIR=$(mktemp -d) ART_OUT=$(mktemp) AMB_OUT=$(mktemp) AMB_ERR=$(mktemp) A2_OUT=$(mktemp) A2_ERR=$(mktemp) UNIQ_OUT=$(mktemp) UNIQ_ERR=$(mktemp) TWIN="twin-$RANDOM-$$" trap 'tmux -L "$SOCKET" kill-server >/dev/null 2>&1 || true; tmux kill-session -t "$DEFAULT_TARGET" >/dev/null 2>&1 || true; tmux kill-session -t "$TWIN" >/dev/null 2>&1 || true; rm -rf "$TMPDIR" $ART_OUT $AMB_OUT $AMB_ERR $A2_OUT $A2_ERR $UNIQ_OUT $UNIQ_ERR' EXIT fail() { echo "FAIL: $*" >&2 exit 1 } require_tmux() { command -v tmux >/dev/null 2>&1 || fail "tmux is required" } capture_named() { tmux -L "$SOCKET" capture-pane -t "=$TARGET:0.0" -p } capture_default() { tmux capture-pane -t "=$DEFAULT_TARGET:0.0" -p } require_tmux tmux -L "$SOCKET" new-session -d -s "$TARGET" -c "$TMPDIR" 'PS1="❯ " exec bash --noprofile --norc -i' tmux new-session -d -s "$DEFAULT_TARGET" -c "$TMPDIR" 'PS1="❯ " exec bash --noprofile --norc -i' "$SEND_MESSAGE" -L "$SOCKET" -t "=$TARGET" -m "named socket hello" >/tmp/send-message-named.out sleep 0.2 named_pane="$(capture_named)" || fail "could not capture named socket pane" grep -qF "named socket hello" <<<"$named_pane" || fail "send-message.sh did not deliver to named socket" default_pane="$(capture_default)" || fail "could not capture default socket pane" if grep -qF "named socket hello" <<<"$default_pane"; then fail "send-message.sh leaked named-socket message to default tmux server" fi "$AGENT_SEND" -L "$SOCKET" -S "tester:source" -s "=$TARGET" -m "agent socket hello" >/tmp/agent-send-named.out sleep 0.2 named_pane="$(capture_named)" || fail "could not capture named socket pane" grep -qF "[tester:source ->" <<<"$named_pane" || fail "agent-send.sh did not include preamble" grep -qF "agent socket hello" <<<"$named_pane" || fail "agent-send.sh did not deliver to named socket" default_pane="$(capture_default)" || fail "could not capture default socket pane" if grep -qF "agent socket hello" <<<"$default_pane"; then fail "agent-send.sh leaked named-socket message to default tmux server" fi # Concurrency: parallel senders on one server must not cross-deliver or drop. # Locks the unique-per-invocation paste buffer (a fixed buffer name raced: # load overwrote load, -d deleted underneath — messages swapped between panes). CONC_N=5 for i in $(seq 1 "$CONC_N"); do tmux -L "$SOCKET" new-session -d -s "conc-$i" -c "$TMPDIR" 'PS1="❯ " exec bash --noprofile --norc -i' done pids=() for i in $(seq 1 "$CONC_N"); do "$SEND_MESSAGE" -L "$SOCKET" -t "=conc-$i" -m "CONCPAYLOAD-${i}-END" >/dev/null & pids+=($!) done for pid in "${pids[@]}"; do wait "$pid" || fail "concurrent send-message.sh invocation exited non-zero" done sleep 0.2 for i in $(seq 1 "$CONC_N"); do pane=$(tmux -L "$SOCKET" capture-pane -t "=conc-$i:0.0" -p) grep -qF "CONCPAYLOAD-${i}-END" <<<"$pane" \ || fail "concurrent send dropped payload for pane conc-$i" for j in $(seq 1 "$CONC_N"); do [ "$j" = "$i" ] && continue if grep -qF "CONCPAYLOAD-${j}-END" <<<"$pane"; then fail "concurrent send cross-delivered payload $j to pane conc-$i" fi done done # B1 (2026-08-29): socket default resolution in agent-send.sh. Measured # defect: tasking sends without -L landed in a stale default-socket twin of # the target seat; rc 0 reported honest delivery to the wrong pane. # Arm A: session on MULTIPLE sockets, no -L -> refuse with rc 4 naming both. tmux -L "$SOCKET" new-session -d -s "$TWIN" -c "$TMPDIR" 'PS1="❯ " exec bash --noprofile --norc -i' tmux new-session -d -s "$TWIN" -c "$TMPDIR" 'PS1="❯ " exec bash --noprofile --norc -i' amb_rc=0 env -u MOSAIC_TMUX_SOCKET "$AGENT_SEND" -s "$TWIN" -m "must refuse" >$AMB_OUT 2>$AMB_ERR || amb_rc=$? [ "$amb_rc" -eq 4 ] || fail "ambiguity refusal: rc=$amb_rc want 4 (stderr: $(cat $AMB_ERR))" grep -q "multiple sockets" $AMB_ERR || fail "ambiguity refusal message missing socket list" grep -qF "$SOCKET" $AMB_ERR || fail "ambiguity refusal message does not name the test socket" tmux kill-session -t "$TWIN" >/dev/null 2>&1 || true tmux -L "$SOCKET" kill-session -t "$TWIN" >/dev/null 2>&1 || true # Arm A2: with MOSAIC_TMUX_SOCKET exported, a twin session is NOT ambiguous: # the env var disambiguates by precedence (codex PR #1466 blocker). tmux -L "$SOCKET" new-session -d -s "$TWIN" -c "$TMPDIR" 'PS1="❯ " exec bash --noprofile --norc -i' tmux new-session -d -s "$TWIN" -c "$TMPDIR" 'PS1="❯ " exec bash --noprofile --norc -i' a2_rc=0 MOSAIC_TMUX_SOCKET="$SOCKET" "$AGENT_SEND" -s "$TWIN" -m "env disambiguated" >$A2_OUT 2>$A2_ERR || a2_rc=$? [ "$a2_rc" -eq 0 ] || fail "env disambiguation: rc=$a2_rc (stderr: $(cat $A2_ERR))" sleep 0.2 a2_pane="$(tmux -L "$SOCKET" capture-pane -t "=$TWIN:0.0" -p)" || fail "cannot capture twin (arm A2)" grep -qF "env disambiguated" <<<"$a2_pane" || fail "env disambiguation did not deliver on the named socket" a2_default="$(tmux capture-pane -t "=$TWIN:0.0" -p)" || true if grep -qF "env disambiguated" <<<"$a2_default"; then fail "env disambiguation cross-delivered to the default-socket twin" fi tmux kill-session -t "$TWIN" >/dev/null 2>&1 || true tmux -L "$SOCKET" kill-session -t "$TWIN" >/dev/null 2>&1 || true # Arm B: session unique to ONE socket, no -L -> auto-resolve to that socket # and deliver there. # Arm A3: prefix matching must not produce false socket hits (codex PR # #1466): a session named TWIN-old must not count as a hit for target # TWIN (tmux target syntax prefix-matches without '='). PSEUDO="${TWIN}-old" tmux new-session -d -s "$PSEUDO" -c "$TMPDIR" 'PS1="❯ " exec bash --noprofile --norc -i' A3_ERR=$(mktemp) a3_rc=0 env -u MOSAIC_TMUX_SOCKET "$AGENT_SEND" -s "$TWIN" -m "prefix trap" >/dev/null 2>"$A3_ERR" || a3_rc=$? # TWIN exists nowhere (both twins killed after arm A2); with '=' the # PSEUDO session is not a hit, so the sender must fail target-not-found # (rc 1) instead of delivering into the prefix-named session. [ "$a3_rc" -eq 1 ] || fail "prefix false-hit: rc=$a3_rc want 1 (stderr: $(cat "$A3_ERR"))" if tmux capture-pane -t "=$PSEUDO:0.0" -p 2>/dev/null | grep -qF "prefix trap"; then fail "delivery landed in the prefix-named session (false socket hit)" fi tmux kill-session -t "$PSEUDO" >/dev/null 2>&1 || true rm -f "$A3_ERR" # Arm A4: compound targets pin the SESSION component exact (codex PR # #1466): 'TWIN:0.0' must not resolve into the prefix-named session. PSEUDO2="${TWIN}-old" tmux new-session -d -s "$PSEUDO2" -c "$TMPDIR" 'PS1="❯ " exec bash --noprofile --norc -i' A4_ERR=$(mktemp) a4_rc=0 env -u MOSAIC_TMUX_SOCKET "$AGENT_SEND" -s "$TWIN:0.0" -m "compound trap" >/dev/null 2>"$A4_ERR" || a4_rc=$? [ "$a4_rc" -eq 1 ] || fail "compound prefix false-hit: rc=$a4_rc want 1 (stderr: $(cat "$A4_ERR"))" if tmux capture-pane -t "=$PSEUDO2:0.0" -p 2>/dev/null | grep -qF "compound trap"; then fail "compound delivery landed in the prefix-named session" fi tmux kill-session -t "$PSEUDO2" >/dev/null 2>&1 || true rm -f "$A4_ERR" uniq_rc=0 env -u MOSAIC_TMUX_SOCKET "$AGENT_SEND" -s "$TARGET" -m "autoresolved hello" >$UNIQ_OUT 2>$UNIQ_ERR || uniq_rc=$? [ "$uniq_rc" -eq 0 ] || fail "unique auto-resolution: rc=$uniq_rc (stderr: $(cat $UNIQ_ERR))" sleep 0.2 auto_pane="$(capture_named)" || fail "could not capture named socket pane (arm B)" grep -qF "autoresolved hello" <<<"$auto_pane" || fail "auto-resolution did not deliver to the named-socket pane" default_pane2="$(capture_default)" || fail "could not capture default socket pane (arm B)" if grep -qF "autoresolved hello" <<<"$default_pane2"; then fail "auto-resolution cross-delivered to the default socket pane" fi echo "ok - named tmux socket send tools"