Upstream the 2026-07-09 live hot-fix from web1: send-message.sh used a fixed tmux buffer name (__mosaic_send) shared by all concurrent senders on one server — load-buffer overwrote load-buffer and paste-buffer -d deleted underneath peers, cross-delivering or dropping messages. Bit the fleet during the simultaneous restart (standing briefs swapped between sessions). Buffer name is now unique per invocation (PID + nanoseconds). Also brings auto-submit-drafts.sh (coordinator draft-flush watchdog, until now only a loose file in the deployed ~/.config/mosaic/tools/tmux/) under source control, and extends test-send-message-socket.sh with a concurrency lock: 5 parallel sends to distinct panes, asserting no drop and no cross-delivery. The lock fails 3/3 runs against the pre-fix script and passes post-fix. Without this, the next framework redeploy would regress the live fix.
79 lines
2.7 KiB
Bash
Executable File
79 lines
2.7 KiB
Bash
Executable File
#!/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)
|
|
trap 'tmux -L "$SOCKET" kill-server >/dev/null 2>&1 || true; tmux kill-session -t "$DEFAULT_TARGET" >/dev/null 2>&1 || true; rm -rf "$TMPDIR"' 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" 'bash --noprofile --norc -i'
|
|
tmux new-session -d -s "$DEFAULT_TARGET" -c "$TMPDIR" 'bash --noprofile --norc -i'
|
|
|
|
"$SEND_MESSAGE" -L "$SOCKET" -t "=$TARGET" -m "named socket hello" >/tmp/send-message-named.out
|
|
sleep 0.2
|
|
capture_named | grep -qF "named socket hello" || fail "send-message.sh did not deliver to named socket"
|
|
if capture_default | grep -qF "named socket hello"; 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
|
|
capture_named | grep -qF "[tester:source ->" || fail "agent-send.sh did not include preamble"
|
|
capture_named | grep -qF "agent socket hello" || fail "agent-send.sh did not deliver to named socket"
|
|
if capture_default | grep -qF "agent socket hello"; 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" '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)
|
|
printf '%s' "$pane" | grep -qF "CONCPAYLOAD-${i}-END" \
|
|
|| fail "concurrent send dropped payload for pane conc-$i"
|
|
for j in $(seq 1 "$CONC_N"); do
|
|
[ "$j" = "$i" ] && continue
|
|
if printf '%s' "$pane" | grep -qF "CONCPAYLOAD-${j}-END"; then
|
|
fail "concurrent send cross-delivered payload $j to pane conc-$i"
|
|
fi
|
|
done
|
|
done
|
|
|
|
echo "ok - named tmux socket send tools"
|