send-message.sh: false '✓ delivered' for long messages — draft detection misses wrapped input #695

Open
opened 2026-07-08 21:21:30 +00:00 by jason.woltje · 0 comments
Owner

Summary

tools/tmux/send-message.sh (framework source: packages/mosaic/framework/tools/tmux/send-message.sh) reports ✓ delivered and exits 0 when a long message is still sitting as an unsubmitted draft in the target pane's input box. The sender believes delivery succeeded; the recipient agent never sees the message.

Root cause

The draft heuristic (lines ~96–101) checks whether the message tail (last 32 printable chars) appears on the last prompt-glyph line:

snippet=$(printf '%s' "$MSG" | ... | tail -c 32)
...
promptline=$(printf '%s' "$pane" | grep -E '❯|^>|│ >' | tail -1)
if [ -n "$snippet" ] && printf '%s' "$promptline" | grep -qF "$snippet"; then
  status="draft"; continue
fi
status="delivered"; break

When a message is longer than the pane width, the input box wraps it: only the first wrapped line carries the glyph (and holds the message start); the message tail sits on glyph-less continuation lines. The snippet-on-promptline check therefore misses, the loop falls through to status="delivered", and the swallowed-Enter draft goes undetected — the exact failure the double-Enter/verify design exists to catch.

Reproduction (observed in the field, 2026-07-08)

  1. Target: remote Claude Code pane, mid-turn (busy), via agent-send.sh -H user@host -s <session>.
  2. Send a ~570-char single-line message (wraps to ~7 lines in the input box).
  3. Enter is swallowed; message remains a draft.
  4. Script prints ✓ delivered to <session>, exit 0.
  5. Manual tmux capture-pane confirms the full message still on the input line(s); a manual send-keys Enter was required to submit it (it then landed as a queued message).

Short messages are unaffected (start == tail on the line), which is why this passes casual testing.

Suggested fix directions

  • Search for the snippet in the pane region from the last prompt glyph to the bottom status bar (i.e., prompt line + wrapped continuation lines), not just the single glyph line; or
  • Detect a draft positionally: any non-empty input-box content below the last after the Enter flush; or
  • Verify submission positively instead (message text appears above the input separator / in scrollback) before claiming delivered.

Also worth a test case in test-send-message-socket.sh: message > pane width with a swallowed first Enter.

Impact

Silent inter-agent message loss in fleet orchestration — sender proceeds on a false delivery confirmation. Exit code 2 (still draft) exists for exactly this case but is unreachable for wrapped messages.

## Summary `tools/tmux/send-message.sh` (framework source: `packages/mosaic/framework/tools/tmux/send-message.sh`) reports `✓ delivered` and exits 0 when a **long message is still sitting as an unsubmitted draft** in the target pane's input box. The sender believes delivery succeeded; the recipient agent never sees the message. ## Root cause The draft heuristic (lines ~96–101) checks whether the **message tail** (last 32 printable chars) appears on the **last prompt-glyph line**: ```bash snippet=$(printf '%s' "$MSG" | ... | tail -c 32) ... promptline=$(printf '%s' "$pane" | grep -E '❯|^>|│ >' | tail -1) if [ -n "$snippet" ] && printf '%s' "$promptline" | grep -qF "$snippet"; then status="draft"; continue fi status="delivered"; break ``` When a message is longer than the pane width, the input box **wraps** it: only the *first* wrapped line carries the `❯` glyph (and holds the message *start*); the message *tail* sits on glyph-less continuation lines. The snippet-on-promptline check therefore misses, the loop falls through to `status="delivered"`, and the swallowed-Enter draft goes undetected — the exact failure the double-Enter/verify design exists to catch. ## Reproduction (observed in the field, 2026-07-08) 1. Target: remote Claude Code pane, mid-turn (busy), via `agent-send.sh -H user@host -s <session>`. 2. Send a ~570-char single-line message (wraps to ~7 lines in the input box). 3. Enter is swallowed; message remains a draft. 4. Script prints `✓ delivered to <session>`, exit 0. 5. Manual `tmux capture-pane` confirms the full message still on the input line(s); a manual `send-keys Enter` was required to submit it (it then landed as a queued message). Short messages are unaffected (start == tail on the `❯` line), which is why this passes casual testing. ## Suggested fix directions - Search for the snippet in the pane region **from the last prompt glyph to the bottom status bar** (i.e., prompt line + wrapped continuation lines), not just the single glyph line; or - Detect a draft positionally: any non-empty input-box content below the last `❯` after the Enter flush; or - Verify submission positively instead (message text appears **above** the input separator / in scrollback) before claiming `delivered`. Also worth a test case in `test-send-message-socket.sh`: message > pane width with a swallowed first Enter. ## Impact Silent inter-agent message loss in fleet orchestration — sender proceeds on a false delivery confirmation. Exit code 2 (`still draft`) exists for exactly this case but is unreachable for wrapped messages.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#695