Files
stack/v1/packages/mosaic/framework/tools/tmux/test-send-message-verdict.sh
T

211 lines
11 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# test-send-message-verdict.sh — locks the fail-loud verdict logic of the patched
# send-message.sh against three real tmux-pane fixtures on a throwaway socket:
#
# 1. DELIVERED — a REPL that renders a ` ` input box and submits on Enter
# (text scrolls to history, box clears) => exit 0 "✓ delivered".
# 2. DELIVERED — a pane with NO prompt glyph that DOES submit => exit 0. A pi
# seat is this fixture (U+2500 rule, no glyph). Reshaped for
# #1257; see the note at the fixture for why the old exit-2
# assertion was wrong.
# 2b. UNCONFIRMED— a glyphless pane that never submits (raw/no-echo hung TUI)
# => must fail loud. This carries the historical
# false-positive guard that fixture 2 used to be credited with.
# 3. DRAFT — a ` `-prompt pane that never submits (message stays on the
# input line) => exit 2, stderr "unsubmitted draft".
# 4. DELIVERED — a pane whose input box is two `─` rules with NO prompt glyph
# (box shape) anywhere (pi's shape) and which submits => exit 0. Pre-#1362
# the glyph probe could not see this box at all, so EVERY send
# to such a pane reported "may be UNDELIVERED" while landing.
# 5. DRAFT — the same glyphless box, holding our tail across every flush
# (box shape) Enter => exit 2, stderr "unsubmitted draft". Pre-#1362 this
# also reported unconfirmed, so the true state was invisible.
# 6. DELIVERED — a SHAPELESS REPL (no glyph, no box) that submits => exit 0.
# The 2026-09-04 scratch probe regression: shape probing alone reports "may
# be UNDELIVERED" on this pane while the message is consumed; the cursor-row
# draft transition is the authoritative runtime-agnostic verdict.
# 6b. UNCONFIRMED— a shapeless pane in raw/no-echo mode that never reads stdin
# (shapeless) => exit 2 "could not confirm submission" (never delivered).
set -uo pipefail
HERE=$(cd -- "$(dirname -- "$0")" && pwd)
SEND="${SEND:-$HERE/send-message.sh}"
SOCKET="verdict-test-$RANDOM-$$"
TMP=$(mktemp -d)
trap 'tmux -L "$SOCKET" kill-server >/dev/null 2>&1 || true; rm -rf "$TMP"' EXIT
PASS=0; FAIL=0
ok() { PASS=$((PASS+1)); printf ' ok %s\n' "$1"; }
no() { FAIL=$((FAIL+1)); printf ' FAIL %s\n %s\n' "$1" "$2"; }
command -v tmux >/dev/null 2>&1 || { echo "tmux required" >&2; exit 1; }
# --- Fixture 1: a submitting REPL with a prompt box (interactive bash, glyph PS1).
# readline strips bracketed-paste markers just like a real agent REPL; Enter
# executes (text -> scrollback), leaving a fresh empty ` ` box.
tmux -L "$SOCKET" new-session -d -s repl -c "$TMP" \
'PS1=" " exec bash --noprofile --norc -i'
sleep 0.3
out=$("$SEND" -L "$SOCKET" -t "=repl" -m "verdict fixture one delivered ok" 2>"$TMP/e1"); rc=$?
if [ "$rc" -eq 0 ] && grep -qF "✓ delivered" <<<"$out"; then
ok "delivered: -prompt REPL that submits => exit 0 ✓ delivered"
else
no "delivered: -prompt REPL that submits => exit 0 ✓ delivered" "rc=$rc out=[$out] err=[$(cat "$TMP/e1")]"
fi
# --- Fixture 2: NO prompt glyph, and the pane DOES submit (interactive bash).
# RESHAPED 2026-08-16 (#1257), deliberately. This fixture previously asserted
# exit 2 here and was labelled "false-positive FIXED". That assertion was wrong,
# and locking it in is what kept E7 alive: the pane submits, so "delivered" is
# the truth, and a pi seat — whose input box is a bare U+2500 rule with no glyph
# — IS this fixture. Reporting exit 2 for it told operators a delivered message
# may be undelivered, and the retry that advice invites is the duplicate.
#
# The guard this fixture was reaching for is real and is NOT dropped: "never
# infer delivered from absence" is now enforced positively by fixture 2b below
# (glyphless AND not submitting => must fail) and by fixture 3 (locatable box
# still carrying our tail => draft). Absence alone decides nothing either way.
tmux -L "$SOCKET" new-session -d -s noglyph -c "$TMP" \
'PS1="sh-noglyph$ " exec bash --noprofile --norc -i'
sleep 0.3
out=$("$SEND" -L "$SOCKET" -t "=noglyph" -m "verdict fixture two must fail loud" 2>"$TMP/e2"); rc=$?
if [ "$rc" -eq 0 ] && grep -qF "✓ delivered" <<<"$out"; then
ok "delivered: glyphless pane that submits => exit 0 (runtime-agnostic, E7 FIXED)"
else
no "delivered: glyphless pane that submits => exit 0" "rc=$rc out=[$out] err=[$(cat "$TMP/e2")]"
fi
# --- Fixture 2b: NO prompt glyph AND never submits — a hung managed TUI holding the
# terminal in raw/no-echo, which is what a stuck agent seat actually is (measured
# on live pi: stty -echo -icanon). Nothing is echoed, nothing is consumed, so
# there is no positive evidence of submission and the tool MUST fail loud. This
# is the historical false-positive guard, kept as a positive test.
tmux -L "$SOCKET" new-session -d -s rawstuck -c "$TMP" \
'bash --noprofile --norc -c "stty -echo -icanon min 1 time 0 2>/dev/null; exec sleep infinity"'
sleep 0.3
if out=$("$SEND" -L "$SOCKET" -t "=rawstuck" -r 1 -m "verdict fixture two-b never submitted" 2>"$TMP/e2b"); then
no "unconfirmed: glyphless hung TUI must NOT report success" "expected non-zero, got 0 (out=[$out])"
else
rc=$?
if [ "$rc" -ne 0 ] && grep -qF "could not confirm submission" "$TMP/e2b"; then
ok "unconfirmed: glyphless hung TUI (raw/no-echo) => non-zero + 'could not confirm submission'"
else
no "unconfirmed: glyphless hung TUI => non-zero + stderr" "rc=$rc err=[$(cat "$TMP/e2b")]"
fi
fi
# --- Fixture 3: a box that never submits (sleep ignores stdin; TTY echo keeps the
# pasted tail sitting on the line) => draft => exit 2.
tmux -L "$SOCKET" new-session -d -s draft -c "$TMP" \
'printf " "; exec sleep infinity'
sleep 0.3
if out=$("$SEND" -L "$SOCKET" -t "=draft" -r 1 -m "verdict fixture three stuck unsubmitted draft" 2>"$TMP/e3"); then
no "draft: unsubmitted message must NOT report success" "expected exit 2, got 0 (out=[$out])"
else
rc=$?
if [ "$rc" -eq 2 ] && grep -qF "unsubmitted draft" "$TMP/e3"; then
ok "draft: stuck -line message => exit 2 + 'unsubmitted draft'"
else
no "draft: stuck -line message => exit 2 + stderr" "rc=$rc err=[$(cat "$TMP/e3")]"
fi
fi
# --- Fixtures 4 and 5: a pi-shaped pane. The input box is two `─` rules with the
# text between them and NO prompt glyph anywhere, so the glyph probe alone can
# never locate it and every send reports "may be UNDELIVERED" (#1362). The
# renderer below is the shape, not the runtime: MODE=clear submits (box empties),
# MODE=keep leaves the text sitting in the box.
cat > "$TMP/pibox.sh" <<'PIBOX'
#!/usr/bin/env bash
MODE=${1:-clear}
RULE=$(printf '─%.0s' $(seq 1 60))
buf=""
draw() {
printf '\033[H\033[2J'
printf 'fixture output line\n\n'
printf '%s\n' "$RULE"
printf '%s\n' "$buf"
printf '%s\n' "$RULE"
printf '~/fixture (main)\n'
printf 'tok 0 model fixture\n'
}
draw
while IFS= read -r line; do
# keep: hold the tail across every flush Enter, which is what a stuck draft does.
if [ "$MODE" = keep ]; then [ -n "$line" ] && buf=$line; else buf=""; fi
draw
done
PIBOX
chmod +x "$TMP/pibox.sh"
tmux -L "$SOCKET" new-session -d -s pibox -c "$TMP" "exec bash '$TMP/pibox.sh' clear"
sleep 0.3
out=$("$SEND" -L "$SOCKET" -t "=pibox" -m "pi fixture four delivered ok" 2>"$TMP/e4"); rc=$?
if [ "$rc" -eq 0 ] && grep -qF "✓ delivered" <<<"$out"; then
ok "delivered: glyphless box-drawn REPL that submits => exit 0 ✓ delivered"
else
no "delivered: glyphless box-drawn REPL that submits => exit 0 ✓ delivered" "rc=$rc out=[$out] err=[$(cat "$TMP/e4")]"
fi
tmux -L "$SOCKET" new-session -d -s piboxdraft -c "$TMP" "exec bash '$TMP/pibox.sh' keep"
sleep 0.3
if out=$("$SEND" -L "$SOCKET" -t "=piboxdraft" -r 1 -m "pi fixture five stuck in the box" 2>"$TMP/e5"); then
no "draft: glyphless box-drawn pane holding our tail must NOT report success" "expected exit 2, got 0 (out=[$out])"
else
rc=$?
if [ "$rc" -eq 2 ] && grep -qF "unsubmitted draft" "$TMP/e5"; then
ok "draft: message left in a glyphless box => exit 2 + 'unsubmitted draft'"
else
no "draft: message left in a glyphless box => exit 2 + stderr" "rc=$rc err=[$(cat "$TMP/e5")]"
fi
fi
# --- Fixtures 6 and 6b: a SHAPELESS REPL. The pane renders nothing at all: no
# prompt glyph and no rule box, so locate_input_box() alone can never see it
# and shape-probing alone reports "may be UNDELIVERED" on a delivered message
# (measured live 2026-09-04, scratch probe: a shapeless consumer CONSUMED the
# message while the shipped shape probe exited 2 with retry advice - the exact
# #1257 regression). The cursor-row draft transition is the authoritative,
# runtime-agnostic delivered verdict: fixture 6's consumer submits => exit 0.
# Fixture 6b is the guard arm: a shapeless pane whose foreground never reads
# stdin keeps the echoed paste on the cursor line across every flush Enter =>
# DRAFT => exit 2, never delivered.
cat > "$TMP/shapeless.py" <<'SHAPELESS'
import sys
for line in sys.stdin:
pass # consume and render nothing
SHAPELESS
tmux -L "$SOCKET" new-session -d -s shapeless -c "$TMP" "exec python3 -u '$TMP/shapeless.py'"
sleep 0.3
out=$("$SEND" -L "$SOCKET" -t "=shapeless" -m "fixture six shapeless consumed ok" 2>"$TMP/e6"); rc=$?
if [ "$rc" -eq 0 ] && grep -qF "✓ delivered" <<<"$out"; then
ok "delivered: shapeless REPL that submits => exit 0 ✓ delivered (probe regression)"
else
no "delivered: shapeless REPL that submits => exit 0 ✓ delivered" "rc=$rc out=[$out] err=[$(cat "$TMP/e6")]"
fi
# MEASURED LIMIT (2026-09-04, this suite's development): a shapeless pane in
# COOKED mode whose foreground never reads stdin (e.g. 'sleep infinity') scrolls
# its kernel echo off the cursor row on the flush Enter, so no runtime-agnostic
# signal available to the sender distinguishes it from a delivering pane. The
# non-reading guard therefore requires either a locatable box still carrying the
# tail (fixture 3) or raw/no-echo mode (fixture 2b). Real REPL seats read stdin,
# which is why this limit is not reachable against agent seats; recorded here so
# nobody rediscovers it as a silent gap.
tmux -L "$SOCKET" new-session -d -s shapelessraw -c "$TMP" 'stty raw -echo; exec sleep infinity'
sleep 0.3
if out=$("$SEND" -L "$SOCKET" -t "=shapelessraw" -r 1 -m "fixture six b shapeless raw never consumed" 2>"$TMP/e6b"); then
no "unconfirmed: shapeless raw non-reading pane must NOT report success" "expected exit 2, got 0 (out=[$out])"
else
rc=$?
if [ "$rc" -eq 2 ] && grep -qF "could not confirm submission" "$TMP/e6b"; then
ok "unconfirmed: shapeless raw non-reading pane => exit 2 + 'could not confirm submission'"
else
no "unconfirmed: shapeless raw non-reading pane => exit 2 + stderr" "rc=$rc err=[$(cat "$TMP/e6b")]"
fi
fi
echo "---"
echo "PASS=$PASS FAIL=$FAIL"
[ "$FAIL" -eq 0 ]