framework tools/tmux: B1 fixes from codex (precedence + TMUX_TMPDIR) + env-disambiguation arm
ci/woodpecker/pr/ci Pipeline was canceled

- MOSAIC_TMUX_SOCKET now disambiguates BEFORE the ambiguity refusal
  (the old order told users to set the env var while never consulting
  it on multi-hit; codex blocker).
- Socket discovery scans ${TMUX_TMPDIR:-/tmp}/tmux-UID, tmux's own
  socket dir — TMPDIR was wrong wherever they diverge (codex blocker).
- Arm A2: env var beats ambiguity (twin delivers on the named socket,
  no cross-delivery); arms A/B run hermetic (env unset).
- Same precedence + dir fix applied to brain agent-watch.
This commit is contained in:
2026-08-28 20:44:54 -05:00
parent 2adfaf1812
commit 1dc48063cf
2 changed files with 32 additions and 16 deletions
@@ -155,15 +155,19 @@ B64=$(printf '%s' "$FULL" | base64 -w0)
vflag=""; [ "$VERBOSE" = 1 ] && vflag="-v"
# Socket default resolution (B1, 2026-08-29): explicit -L wins; else the
# launcher-exported MOSAIC_TMUX_SOCKET; else the tmux default socket. When
# the target session exists on MULTIPLE socket servers and no explicit -L
# was given, refuse with a disambiguation error instead of silently picking
# one (measured 2026-08-28/29: tasking sends landed in a stale default-
# socket twin of the target seat; rc 0 reported honest delivery to the
# wrong pane). Local targets only; remote targets pass -L through as-is.
# Socket default resolution (B1, 2026-08-29). Precedence: explicit -L >
# launcher-exported MOSAIC_TMUX_SOCKET > unique socket hit > refusal on
# ambiguity > tmux default socket. The ambiguity refusal fires ONLY when
# no explicit or env choice exists and the session name lives on multiple
# servers (measured 2026-08-28/29: tasking sends landed in a stale
# default-socket twin; rc 0 reported honest delivery to the wrong pane).
# Socket discovery scans tmux's own socket dir, ${TMUX_TMPDIR:-/tmp}/tmux-UID
# (codex PR #1466: TMPDIR is not where tmux keeps -L sockets).
if [ -z "$SOCKET_NAME" ] && [ -n "${MOSAIC_TMUX_SOCKET:-}" ]; then
SOCKET_NAME="$MOSAIC_TMUX_SOCKET"
fi
if [ -z "$SOCKET_NAME" ] && [ -z "$SSH_TARGET" ]; then
socket_dir="${TMPDIR:-/tmp}/tmux-$(id -u)"
socket_dir="${TMUX_TMPDIR:-/tmp}/tmux-$(id -u)"
hits=""
for sf in "$socket_dir"/*; do
[ -S "$sf" ] || continue
@@ -173,17 +177,12 @@ if [ -z "$SOCKET_NAME" ] && [ -z "$SSH_TARGET" ]; then
hit_count=$(printf '%s' "$hits" | wc -w)
if [ "$hit_count" -gt 1 ]; then
echo "agent-send.sh: REFUSING - session '$DST_SESSION' exists on multiple sockets:$hits" >&2
echo " Pass -L <socket> explicitly (or set MOSAIC_TMUX_SOCKET)." >&2
echo " Pass -L <socket> explicitly (or export MOSAIC_TMUX_SOCKET to disambiguate)." >&2
exit 4
elif [ "$hit_count" -eq 1 ]; then
SOCKET_NAME="${hits# }"
elif [ -n "${MOSAIC_TMUX_SOCKET:-}" ]; then
SOCKET_NAME="$MOSAIC_TMUX_SOCKET"
fi
fi
if [ -z "$SOCKET_NAME" ] && [ -n "${MOSAIC_TMUX_SOCKET:-}" ] && [ -n "$SSH_TARGET" ]; then
SOCKET_NAME="$MOSAIC_TMUX_SOCKET"
fi
socket_args=()
if [ -n "$SOCKET_NAME" ]; then
@@ -88,17 +88,34 @@ done
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
"$AGENT_SEND" -s "$TWIN" -m "must refuse" >/tmp/amb.out 2>/tmp/amb.err || amb_rc=$?
env -u MOSAIC_TMUX_SOCKET "$AGENT_SEND" -s "$TWIN" -m "must refuse" >/tmp/amb.out 2>/tmp/amb.err || amb_rc=$?
[ "$amb_rc" -eq 4 ] || fail "ambiguity refusal: rc=$amb_rc want 4 (stderr: $(cat /tmp/amb.err))"
grep -q "multiple sockets" /tmp/amb.err || fail "ambiguity refusal message missing socket list"
grep -qF "$SOCKET" /tmp/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" >/tmp/a2.out 2>/tmp/a2.err || a2_rc=$?
[ "$a2_rc" -eq 0 ] || fail "env disambiguation: rc=$a2_rc (stderr: $(cat /tmp/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.
uniq_rc=0
"$AGENT_SEND" -s "$TARGET" -m "autoresolved hello" >/tmp/uniq.out 2>/tmp/uniq.err || uniq_rc=$?
env -u MOSAIC_TMUX_SOCKET "$AGENT_SEND" -s "$TARGET" -m "autoresolved hello" >/tmp/uniq.out 2>/tmp/uniq.err || uniq_rc=$?
[ "$uniq_rc" -eq 0 ] || fail "unique auto-resolution: rc=$uniq_rc (stderr: $(cat /tmp/uniq.err))"
sleep 0.2
auto_pane="$(capture_named)" || fail "could not capture named socket pane (arm B)"