ci/woodpecker/pr/ci Pipeline failed
- F5 (rev-code-02 blocker): sign test-send-message-glyph-agnostic.sh into test-enumeration-exclusions.txt beside its tmux siblings; the CI image ships no tmux, so the suite stays manually run (#1017 burndown). - Adoption finding: the verdict suite hard-coded SEND to its sibling and ignored the SEND env var, so a red-first run against the shipping blob silently measured the patched copy instead (measured: shipping run printed PASS=4; with SEND honored it is PASS=3 FAIL=1, fixture 2 red, matching the recorded review numbers). SEND is now honored with the sibling as default, same contract as the glyph suite. - F6/D19: framework FLEET-COMMS.md claimed 'rc=2 is the normal result when the target is an idle pi seat'. Post-fix rc=0 is normal for idle and busy pi seats; rc=2 on a healthy seat is a real report. Never-retry advice kept, softened to 'may be in the pane' for the unconfirmed arm. Live verification on sb-it-1-dt (tmux 3.7b, pi glm-5.3 low, scratch session): idle pi - shipping rc=2 'may be UNDELIVERED' while the seat consumed the message and answered; patched rc=0 delivered, answered. Busy pi mid-turn - shipping rc=2 while the pane accepted both messages as steering input ('Steering: ...', 'Alt+Up to edit all queued messages'); patched rc=0 delivered, both consumed and acted on after the turn. Both D11 signatures: verdict now matches reality.
103 lines
5.3 KiB
Bash
Executable File
103 lines
5.3 KiB
Bash
Executable File
#!/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".
|
||
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 ] && printf '%s' "$out" | grep -qF "✓ delivered"; 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
|
||
|
||
echo "---"
|
||
echo "PASS=$PASS FAIL=$FAIL"
|
||
[ "$FAIL" -eq 0 ]
|