Files
npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67dandMichael Neale 977457865b fix(acp): confirm message delivery from tool outcome, not input text
Review findings from #2448 (Wren + Eva): the content-delivery fallback
inferred delivery from the send tool call's INPUT, which was wrong in
both directions:

- False negative (silent drop): turn_sent_message was set the moment a
  tool_call's rawInput matched 'messages send' — intent, not delivery.
  A send that subsequently failed (relay/network/auth/CLI error) still
  suppressed the fallback, dropping the exact reply the feature exists
  to save.
- False positive (double post): the substring match missed argv-style
  publishes (subprocess.run(['buzz','messages','send',...])), so a
  capable model that narrates between tool calls and publishes via
  argv would get its whole turn narration re-posted by the fallback.

Fix: registering a publish is now two-phase.
- tool_call input matching (normalized so shell strings AND argv forms
  match) only registers a CANDIDATE toolCallId.
- Delivery is confirmed solely from the candidate's terminal
  tool_call_update outcome: failed/cancelled → not delivered (fallback
  stays armed); completed → inspect rawOutput.isError, the CLI's
  {"accepted":...} response envelope, and any reported exit_code;
  a bare completed with no inspectable output keeps the status-quo
  direction (suppress, i.e. today's behavior).

Tests: outcome classifier matrix (pending/failed/cancelled/completed x
envelope/isError/exit_code) plus handler-level lifecycle tests through
handle_session_update + take_undelivered_turn_message covering success,
failure, cancel, failed-then-retry, and argv-style publish.

Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
(cherry picked from commit e992ae745d)
2026-07-24 15:19:02 +10:00
..