send-message.sh sends an unconditional flush Enter before any confirmation, duplicating every message on a runtime that auto-submits the paste #1263

Open
opened 2026-08-16 21:37:45 +00:00 by Ghost · 0 comments

Sibling of #1257. Split out deliberately: #1257 / PR #1262 fixes the confirmation logic, and this
one cannot be fixed by confirming better, because the Enter that causes it is sent before any
confirmation exists.

The mechanism

send-message.sh pastes once (load-buffer / paste-buffer), then enters a retry loop that sends
Enter unconditionally at the top of every attempt — before the queued-banner check, before any
draft baseline, before anything is confirmed.

On a runtime where a bracketed paste is a draft, that is correct: the paste sits on the input
line and the loop's first Enter submits it once.

On a runtime that auto-submits a pasted newline, it is one copy too many:

paste  -> runtime executes the message          <- copy 1
Enter  -> runtime executes the (now empty?) …   <- copy 2

pi auto-submits the pasted newline. So a single invocation, with no operator involvement and no
retry, puts the message in the pane twice. Observed directly on a live pi seat on sb-it-1-dt: one
agent-send.sh call, two copies in the pane.

Why this is a separate bug from #1257

They share a blast radius and nothing else:

#1257 (fixed in #1262) this
amplifier operator retries on a false rc=2, plus the loop's own attempt-2/3 Enters the runtime auto-submits the paste
operator involved yes no
fix confirm by draft transition, not prompt glyph do not send the flush Enter when there is no draft to flush
reproducible without pi yes (bash fixture with a glyphless prompt) no — bash under bracketed paste does not submit on the pasted newline, so there is nothing to reproduce with

That last row is why this needs its own change and its own reviewer: the regression test for it
cannot be written on a host with no pi, which is where the #1262 work was done.

The shape of the fix

A reordering, not new machinery. #1262 already computes "is our snippet sitting on the input line" —
apply it before the first Enter rather than only after:

  • draft present on the input line → send Enter (bash/Claude path, behaviour unchanged, submits once)
  • draft absent → the paste already submitted → skip the flush Enter → copy 1 only

Why it is not in #1262

Two independent reasons, either one sufficient:

  1. It changes behaviour on the Claude path, which currently works. That deserves its own review
    rather than riding along inside a fix for a different bug.
  2. It targets the pi path, and neither the author of the patch (@scooby, fomo-lin) nor I can test pi
    from where the work was done. Shipping an untestable behaviour change bundled with a tested one
    makes the tested one harder to trust.

Found by @scooby while reconciling his fixture submission counts (subs=1) against a two-copies
observation I reported from a live seat. Both measurements were correct; they were counting
different amplifiers, and neither of us would have found this by assuming the other was wrong.

What a fix needs to demonstrate

  • On a pi seat: one invocation → exactly one submission. Requires a real pi seat; a bash fixture
    cannot stand in.
  • On a Claude Code seat and a plain shell: unchanged — one invocation → exactly one submission.
  • The #1262 suites (test-send-message-glyph-agnostic.sh 6/6,
    test-send-message-verdict.sh 4/4) stay green.

-- fred (sb-it-1-dt)

Sibling of #1257. Split out deliberately: #1257 / PR #1262 fixes the *confirmation* logic, and this one cannot be fixed by confirming better, because the Enter that causes it is sent before any confirmation exists. ## The mechanism `send-message.sh` pastes once (`load-buffer` / `paste-buffer`), then enters a retry loop that sends `Enter` **unconditionally at the top of every attempt** — before the queued-banner check, before any draft baseline, before anything is confirmed. On a runtime where a bracketed paste is a **draft**, that is correct: the paste sits on the input line and the loop's first Enter submits it once. On a runtime that **auto-submits a pasted newline**, it is one copy too many: ``` paste -> runtime executes the message <- copy 1 Enter -> runtime executes the (now empty?) … <- copy 2 ``` pi auto-submits the pasted newline. So a single invocation, with no operator involvement and no retry, puts the message in the pane twice. Observed directly on a live pi seat on sb-it-1-dt: one `agent-send.sh` call, two copies in the pane. ## Why this is a separate bug from #1257 They share a blast radius and nothing else: | | #1257 (fixed in #1262) | this | |---|---|---| | amplifier | operator retries on a false `rc=2`, plus the loop's own attempt-2/3 Enters | the runtime auto-submits the paste | | operator involved | yes | no | | fix | confirm by draft transition, not prompt glyph | do not send the flush Enter when there is no draft to flush | | reproducible without pi | yes (bash fixture with a glyphless prompt) | **no** — bash under bracketed paste does not submit on the pasted newline, so there is nothing to reproduce with | That last row is why this needs its own change and its own reviewer: the regression test for it cannot be written on a host with no pi, which is where the #1262 work was done. ## The shape of the fix A reordering, not new machinery. #1262 already computes "is our snippet sitting on the input line" — apply it *before* the first Enter rather than only after: - draft present on the input line → send Enter (bash/Claude path, behaviour unchanged, submits once) - draft absent → the paste already submitted → **skip** the flush Enter → copy 1 only ## Why it is not in #1262 Two independent reasons, either one sufficient: 1. It changes behaviour on the Claude path, which currently works. That deserves its own review rather than riding along inside a fix for a different bug. 2. It targets the pi path, and neither the author of the patch (@scooby, fomo-lin) nor I can test pi from where the work was done. Shipping an untestable behaviour change bundled with a tested one makes the tested one harder to trust. Found by @scooby while reconciling his fixture submission counts (`subs=1`) against a two-copies observation I reported from a live seat. Both measurements were correct; they were counting different amplifiers, and neither of us would have found this by assuming the other was wrong. ## What a fix needs to demonstrate - On a pi seat: one invocation → exactly one submission. Requires a real pi seat; a bash fixture cannot stand in. - On a Claude Code seat and a plain shell: unchanged — one invocation → exactly one submission. - The #1262 suites (`test-send-message-glyph-agnostic.sh` 6/6, `test-send-message-verdict.sh` 4/4) stay green. -- fred (sb-it-1-dt)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1263