diff --git a/packages/mosaic/framework/guides/FLEET-COMMS.md b/packages/mosaic/framework/guides/FLEET-COMMS.md index 4a6a602b..99ec4f1a 100644 --- a/packages/mosaic/framework/guides/FLEET-COMMS.md +++ b/packages/mosaic/framework/guides/FLEET-COMMS.md @@ -53,21 +53,23 @@ sends, it does not auto-reply. ### Exit codes -| rc | Meaning | -| --- | ---------------------------------------------- | -| 0 | delivered or queued | -| 1 | target session not found | -| 2 | text reached the pane but is **still a draft** | -| 3 | usage error (bad class, missing `-s`) | +| rc | Meaning | +| --- | -------------------------------------------------------------------------------------------- | +| 0 | delivered or queued | +| 1 | target session not found | +| 2 | submission unconfirmed: draft still on the input line, or no positive evidence of submission | +| 3 | usage error (bad class, missing `-s`) | -**Never retry on rc=2.** The message is in the target pane; retrying double-sends it. Confirm -instead: +**Never retry on rc=2.** The message may be in the target pane, and a retry can double-send it. +Confirm instead: ```bash tmux capture-pane -p -t :0.0 | tail -20 ``` -rc=2 is the normal result when the target is an idle pi seat. +rc=0 is the normal result for both idle and busy pi seats (submission confirmed by draft +transition, not by prompt glyph). rc=2 on a healthy seat is exceptional — treat it as a real +report and investigate the pane. ## Durable comms diff --git a/packages/mosaic/framework/tools/quality/test-enumeration-exclusions.txt b/packages/mosaic/framework/tools/quality/test-enumeration-exclusions.txt index 5eae9427..3963b9ae 100644 --- a/packages/mosaic/framework/tools/quality/test-enumeration-exclusions.txt +++ b/packages/mosaic/framework/tools/quality/test-enumeration-exclusions.txt @@ -28,6 +28,7 @@ packages/mosaic/framework/tools/git/test-lane-brief-pr-linkage.sh | unmeasured i # --- tools/tmux: require a live tmux server --- packages/mosaic/framework/tools/tmux/test-send-message-socket.sh | requires a real tmux server on a throwaway socket; CI image ships no tmux; #1017 burndown (needs tmux in image or a signed permanent exclusion) packages/mosaic/framework/tools/tmux/test-send-message-verdict.sh | requires real tmux-pane fixtures on a throwaway socket; CI image ships no tmux; #1017 burndown (same condition as its sibling) +packages/mosaic/framework/tools/tmux/test-send-message-glyph-agnostic.sh | requires real tmux-pane fixtures on a throwaway socket; CI image ships no tmux; #1017 burndown (same condition as its siblings) — signed at adoption of #1262 (rev-code-02 F5), red-first verified on sb-it-1-dt # --- single-suite directories: unmeasured in CI --- diff --git a/packages/mosaic/framework/tools/tmux/send-message.sh b/packages/mosaic/framework/tools/tmux/send-message.sh index 56144d54..0fb1e135 100755 --- a/packages/mosaic/framework/tools/tmux/send-message.sh +++ b/packages/mosaic/framework/tools/tmux/send-message.sh @@ -33,8 +33,10 @@ # 1 tmux target not found # 2 submission NOT confirmed — either still an unsubmitted draft, or the REPL # input box could not be located to confirm the message actually landed. -# Locating the box is runtime-specific; see locate_input_box() below, and -# add a shape there before pointing this tool at a new runtime. +# Delivered verdicts are runtime-agnostic (cursor-row draft transition, or +# the queued banner); locate_input_box() below adds positive DRAFT evidence +# for panes that render a recognizable box, and never gates delivery on a +# runtime's rendering shape. # Delivery is NEVER inferred from absence of evidence: if we cannot positively # see the input box clear of the message (or the queued banner), we fail loud # so the sender learns immediately instead of a silent worker->lead stall. @@ -99,11 +101,33 @@ printf '%s' "$MSG" | "${tmux_cmd[@]}" load-buffer -b "$BUF" - # would otherwise accumulate forever. sleep 0.5 +# 2) Submit, then POSITIVELY confirm submission by DRAFT TRANSITION, not by prompt +# glyph. The historical bug was treating ABSENCE of a draft as delivery; the +# 2026-08 fix over-corrected to glyph inference (grep '❯|^>|│ >'), which locates +# only Claude Code's box and false-NEGATIVES every glyphless REPL (pi renders a +# U+2500 rule, no glyph) — a delivered message reported "UNDELIVERED", driving a +# retry that duplicates it. Runtime-agnostic evidence: our message tail sits on +# the INPUT line (located by the cursor row, not a glyph) BEFORE Enter, and has +# LEFT it AFTER — that transition is positive proof of submission and needs no +# glyph. Absence alone still never means delivered: if we never saw our draft on +# the input line we stay UNCONFIRMED (wrong/dead pane), and a draft that never +# leaves the input line stays a DRAFT (exit 2), preserving both historical guards. +_cursor_line() { # echo the pane's current input (cursor) line, glyph-free + local cy line + cy=$("${tmux_cmd[@]}" display-message -p -t "$EFFECTIVE_TARGET" -F '#{cursor_y}' 2>/dev/null) || return 1 + [ -n "$cy" ] || return 1 + "${tmux_cmd[@]}" capture-pane -t "$EFFECTIVE_TARGET" -p 2>/dev/null | sed -n "$((cy + 1))p" +} +_draft_on_input() { # true iff our message tail is sitting on the input line now + [ -n "$snippet" ] || return 1 + grep -qF "$snippet" <<<"$(_cursor_line)" +} + # Locate the REPL input box in a captured pane. Prints the box's contents on -# stdout and returns 0 when the box was FOUND; returns 1 when it could not be -# located at all. Found-but-empty is a real, distinct answer (an empty input box -# is what a submitted message leaves behind), so the caller must branch on the -# return code, never on whether the output is empty. +# stdout and returns 0 when the box was FOUND; returns 1 when it could not +# be located at all. Found-but-empty is a real, distinct answer (an empty input +# box is what a submitted message leaves behind), so the caller must branch on +# the return code, never on whether the output is empty. # # Two REPL shapes are recognised: # * a prompt-glyph line — `❯`, a leading `>`, or `│ >`. Claude Code and most @@ -113,10 +137,15 @@ sleep 0.5 # what makes it safe: agent output can contain its own rules, but nothing is # drawn below the input box except the status line. # -# Adding a runtime means adding its shape HERE. A shape that is missing does not -# degrade gracefully: it turns every send to that runtime into a false -# "may be UNDELIVERED", which is what #1362 measured on pi and #1257 on another -# arm of the same probe. +# Compose authority rule (#1332 O1): this function is POSITIVE DRAFT EVIDENCE +# ONLY. A located box still carrying our tail is affirmative proof the message +# was not consumed (the cursor-row check's blind spot: a redrawn TUI can park +# the cursor off the input line, which the draft-transition anchor cannot see). +# Its failure to find a box proves NOTHING and must never produce an +# UNDELIVERED verdict: a shapeless-but-submitting pane delivers via the +# cursor-row transition regardless (measured, scratch probe 2026-09-04; +# shapeless REPL consumed the message while shape probing alone reported +# "may be UNDELIVERED" — the exact #1257 regression this split prevents). locate_input_box() { local pane=$1 glyph_line rule_lines top bottom glyph_line=$(printf '%s\n' "$pane" | grep -E '❯|^>|│ >' | tail -1) @@ -139,13 +168,12 @@ locate_input_box() { return 0 } -# 2) Submit, then POSITIVELY confirm submission; flush with another Enter if it is -# still a draft. Success requires positive evidence — the queued banner, OR the -# REPL input box located AND clear of our message tail. The historical bug was -# treating ABSENCE of a draft as delivery: if the input box was never located -# (wrong pane / prompt-glyph drift), an unsubmitted message read as "delivered" -# and worker->lead relays stalled silently. We now default to UNCONFIRMED and only -# upgrade to delivered on positive evidence; anything we cannot confirm fails loud. +# Baseline: after the paste, our draft must be on the input line. This is positive +# proof we are on the right pane and the paste landed — the anchor the transition +# check measures against. +saw_draft=0 +_draft_on_input && saw_draft=1 + status="unconfirmed" for attempt in $(seq 1 $((RETRIES + 1))); do "${tmux_cmd[@]}" send-keys -t "$EFFECTIVE_TARGET" Enter @@ -155,19 +183,30 @@ for attempt in $(seq 1 $((RETRIES + 1))); do if grep -qF "$QUEUED_RE" <<<"$pane"; then status="queued"; break fi - # If we cannot see the input box, we have NO evidence of submission state — - # stay UNCONFIRMED and retry; never infer delivery. - if ! inputbox=$(locate_input_box "$pane"); then - status="unconfirmed"; continue + # POSITIVE draft evidence from a located input box, when one exists. This is + # the cursor-row check's blind spot: a redrawn TUI (pi's box) can park the + # cursor off the input line, which the draft-transition anchor cannot see, + # while a pane in COOKED mode (a plain shell whose foreground process never + # reads stdin) echoes our paste via the kernel line discipline and moves the + # cursor off it on Enter, indistinguishable from a real submit by cursor row + # alone. If a locatable box still carries our tail, that is affirmative proof + # the message was not consumed. Absence of a recognizable shape is never used + # for anything — that inference is the original E7 bug, and the delivered + # verdict stays with the runtime-agnostic cursor-row transition. + if inputbox=$(locate_input_box "$pane"); then + if [ -n "$snippet" ] && grep -qF "$snippet" <<<"$inputbox"; then + status="draft"; continue + fi fi - # Input box located AND still carrying our tail => unsubmitted draft. Flush + retry. - # (Submitted messages scroll up into history; a draft stays in the box.) - if [ -n "$snippet" ] && grep -qF "$snippet" <<<"$inputbox"; then - status="draft"; continue + if [ "$saw_draft" = 1 ]; then + if _draft_on_input; then + status="draft"; continue # still on the input line => not submitted; flush + retry + fi + status="delivered"; break # left the input line => positively submitted fi - # Input box located AND clear of our tail => positively submitted. This is the - # only path to success besides the queued banner. - status="delivered"; break + # No confirmed baseline yet: try to (re)acquire it; never infer delivery from absence. + if _draft_on_input; then saw_draft=1; status="draft"; continue; fi + status="unconfirmed"; continue done [ "$VERBOSE" = 1 ] && { echo "--- pane tail ($TARGET) ---"; printf '%s\n' "$pane" | tail -4; echo "---"; } @@ -176,6 +215,6 @@ case "$status" in delivered) echo "✓ delivered to $TARGET"; exit 0 ;; queued) echo "✓ queued to $TARGET (agent busy — will process when it returns to prompt)"; exit 0 ;; draft) echo "✗ still an unsubmitted draft on $TARGET after $RETRIES flush attempts" >&2; exit 2 ;; - unconfirmed) echo "✗ could not confirm submission on $TARGET: REPL input box not locatable after $((RETRIES + 1)) attempts — message may be UNDELIVERED (check target/pane, retry, or escalate)" >&2; exit 2 ;; + unconfirmed) echo "✗ could not confirm submission on $TARGET: REPL input prompt not locatable after $((RETRIES + 1)) attempts — message may be UNDELIVERED (check target/pane, retry, or escalate)" >&2; exit 2 ;; *) echo "✗ could not confirm submission on $TARGET (unexpected state '$status')" >&2; exit 2 ;; esac diff --git a/packages/mosaic/framework/tools/tmux/test-send-message-glyph-agnostic.sh b/packages/mosaic/framework/tools/tmux/test-send-message-glyph-agnostic.sh new file mode 100755 index 00000000..55d0ac13 --- /dev/null +++ b/packages/mosaic/framework/tools/tmux/test-send-message-glyph-agnostic.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +# Red-first regression test for E7 (#1017 task 2): the confirm-check must bind +# "delivered" to WHETHER THE MESSAGE WAS SUBMITTED, not to which runtime's prompt +# glyph is present. A pi seat renders a U+2500 rule input box with no ❯/^>/│ > +# glyph; send-message.sh:118 locates the box only by glyph, so a genuinely +# delivered message on a glyphless REPL falsely reports exit 2 "may be UNDELIVERED", +# and the operator's rc=2-driven retry duplicates it. +# +# Parameterized on $SEND: RED against the shipping blob (B and D fail), GREEN +# against a candidate patch. No pi; no fake HOME; hermetic throwaway socket. +# +# Submission counting is EXACT and terminal-echo-independent: the fixture message +# is `echo >>SINK`; each real submission appends one line. wc -l SINK == +# number of times the REPL actually executed the send. This does not depend on how +# many times the marker string is painted on screen. +set -u +SEND="${SEND:?set SEND=/path/to/send-message.sh}" +SOCKET="glyphagnostic-$$" +TMP="$(mktemp -d)" +tmux() { command tmux -L "$SOCKET" "$@"; } +cleanup() { command tmux -L "$SOCKET" kill-server 2>/dev/null; rm -rf "$TMP"; } +trap cleanup EXIT +pass=0; fail=0 +ok() { printf 'ok %s\n' "$1"; pass=$((pass+1)); } +no() { printf 'FAIL %s -- %s\n' "$1" "$2"; fail=$((fail+1)); } + +mk() { tmux new-session -d -s "$1" -x 120 -y 40 -c "$TMP" "PS1='$2' exec bash --noprofile --norc -i"; sleep 0.5; } +subs() { [ -f "$1" ] && wc -l <"$1" | tr -d ' ' || echo 0; } # exact submission count + +echo "SEND=$SEND tmux $(command tmux -V | awk '{print $2}')" + +# --- A (control): glyph box (❯) that submits => exit 0, exactly one submission. +mk ctl '❯ ' +SINK="$TMP/sink.ctl" +out=$("$SEND" -L "$SOCKET" -t ctl -m "echo x >>'$SINK'" 2>"$TMP/e.ctl"); rc=$?; sleep 0.4 +if [ "$rc" = 0 ] && [ "$(subs "$SINK")" = 1 ]; then + ok "control: ❯-box submits => exit 0, exactly one submission" +else no "control: ❯-box submits => exit 0, one submission" "rc=$rc subs=$(subs "$SINK") err=[$(cat "$TMP/e.ctl")]"; fi + +# --- B (THE false-rc regression): glyphless U+2500 box that SUBMITS. Message lands +# (subs==1) yet shipping reports exit 2. Must be exit 0. +mk sub $'──────── \n' +SINK="$TMP/sink.sub" +out=$("$SEND" -L "$SOCKET" -t sub -m "echo x >>'$SINK'" 2>"$TMP/e.sub"); rc=$?; sleep 0.4 +if [ "$rc" = 0 ] && [ "$(subs "$SINK")" = 1 ]; then + ok "glyphless: U+2500 box that submits => exit 0 (delivered, not 'UNDELIVERED')" +else no "glyphless: U+2500 box that submits => exit 0" \ + "rc=$rc subs=$(subs "$SINK")(delivered=$([ "$(subs "$SINK")" -ge 1 ] && echo yes||echo no)) err=[$(cat "$TMP/e.sub")]"; fi + +# --- D (duplicate arm): operator follows the rc=2 stderr and retries once. On the +# glyphless box, shipping => two submissions (the reported duplicate). The +# property: one logical send => exactly one submission. Same fix closes it. +mk dup $'──────── \n' +SINK="$TMP/sink.dup" +tries=0 +for attempt in 1 2; do + tries=$((tries+1)) + out=$("$SEND" -L "$SOCKET" -t dup -m "echo x >>'$SINK'" 2>/dev/null); rc=$? + sleep 0.4 + [ "$rc" = 0 ] && break # operator stops retrying only when told delivered +done +if [ "$(subs "$SINK")" = 1 ]; then + ok "duplicate: one logical send (rc-driven retry) => exactly one submission (tries=$tries)" +else no "duplicate: one logical send => exactly one submission" "submissions=$(subs "$SINK") tries=$tries"; fi + +# --- E (faithful hung managed TUI, NOT a cooked shell): raw/no-echo, paints nothing. +# A cooked `sleep infinity` echoes the paste via the kernel line discipline and +# false-passes a cursor-row fix that is correct on real seats (measured). So: raw. +mk_rawstuck() { tmux new-session -d -s "$1" -x 120 -y 40 -c "$TMP" \ + "bash --noprofile --norc -c 'stty -echo -icanon min 1 time 0 2>/dev/null; exec sleep infinity'"; sleep 0.5; } +mk_rawstuck estuck +SINK="$TMP/sink.estuck" +out=$("$SEND" -L "$SOCKET" -t estuck -r 1 -m "this stuck draft was never submitted" 2>/dev/null); rc=$? +sleep 0.3 +if [ "$rc" != 0 ] && [ "$(subs "$SINK")" = 0 ]; then + ok "raw/no-echo stuck TUI (not submitted) => non-zero (no false delivered)" +else no "raw stuck TUI must NOT report delivered" "rc=$rc subs=$(subs "$SINK")"; fi + +# --- F (busy/queued branch, your BUSY-not-runtime finding): glyphless pane rendering the +# queued banner, never consuming. QUEUED_RE :113 fires before the glyph grep => rc=0. +mk_busy() { tmux new-session -d -s "$1" -x 120 -y 40 -c "$TMP" \ + "bash --noprofile --norc -c 'printf \"Press up to edit queued messages\n\"; exec sleep infinity'"; sleep 0.5; } +mk_busy ebusy +SINK="$TMP/sink.ebusy" +out=$("$SEND" -L "$SOCKET" -t ebusy -m "echo x >>'$SINK'" 2>/dev/null); rc=$?; sleep 0.3 +if [ "$rc" = 0 ]; then + ok "busy/queued-banner glyphless => exit 0 (queued is delivery; runtime owns custody)" +else no "busy/queued-banner must report delivered" "rc=$rc"; fi + +# --- C (historical-bug guard): unresolvable target. No pane ever carried our draft +# => must fail, never infer delivered from absence of a glyph/snippet. +if out=$("$SEND" -L "$SOCKET" -t "nonexistent-$$" -m "echo x >>'$TMP/sink.wrong'" 2>/dev/null); then + no "wrong-pane: unresolvable target must NOT report success" "expected non-zero, got 0" +else ok "wrong-pane: unresolvable target => non-zero (no false delivered)"; fi + +echo "---"; echo "pass=$pass fail=$fail" +[ "$fail" = 0 ] diff --git a/packages/mosaic/framework/tools/tmux/test-send-message-verdict.sh b/packages/mosaic/framework/tools/tmux/test-send-message-verdict.sh index 1186c657..1559920f 100755 --- a/packages/mosaic/framework/tools/tmux/test-send-message-verdict.sh +++ b/packages/mosaic/framework/tools/tmux/test-send-message-verdict.sh @@ -4,10 +4,13 @@ # # 1. DELIVERED — a REPL that renders a `❯ ` input box and submits on Enter # (text scrolls to history, box clears) => exit 0 "✓ delivered". -# 2. UNCONFIRMED — a pane with NO locatable prompt glyph. This is the exact -# historical FALSE POSITIVE: pre-patch it printed "✓ delivered" -# exit 0; post-patch it MUST fail loud (exit 2, stderr -# "could not confirm submission"). +# 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 @@ -17,10 +20,16 @@ # 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="$HERE/send-message.sh" +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 @@ -44,19 +53,44 @@ else no "delivered: ❯-prompt REPL that submits => exit 0 ✓ delivered" "rc=$rc out=[$out] err=[$(cat "$TMP/e1")]" fi -# --- Fixture 2: NO prompt glyph (default bash PS1). THE regression: pre-patch this -# was a silent false-positive "delivered"; post-patch it must be unconfirmed→exit 2. +# --- 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 -if out=$("$SEND" -L "$SOCKET" -t "=noglyph" -m "verdict fixture two must fail loud" 2>"$TMP/e2"); then - no "unconfirmed: glyphless pane must NOT report success" "expected exit 2, got 0 (out=[$out])" +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" -eq 2 ] && grep -qF "could not confirm submission" "$TMP/e2"; then - ok "unconfirmed: glyphless pane => exit 2 + 'could not confirm submission' (false-positive FIXED)" + 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 pane => exit 2 + stderr" "rc=$rc err=[$(cat "$TMP/e2")]" + no "unconfirmed: glyphless hung TUI => non-zero + stderr" "rc=$rc err=[$(cat "$TMP/e2b")]" fi fi @@ -126,6 +160,51 @@ else 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 ]