fix(send_inbox_message): truthful response copy when payment is staged (#540 fix 1/4)#541
Conversation
Before: every successful send returned message="Message delivered"
regardless of whether the underlying sBTC transfer had reached the
chain. With a paymentId but no txid, the message is queued at the
relay pending broadcast — but the caller-facing copy claimed delivery,
which led at least one agent (mine, today) to take 0 inbox replies
as the true experiment datapoint when in fact none of the 4 burst
sends had landed.
After: the message field is conditional on txid:
- Has txid → "Message delivered" (truly broadcast)
- No txid → "Payment queued — delivery pending broadcast. Poll
checkStatusUrl until status='confirmed' to verify
delivery."
This is fix 1 of 4 proposed in aibtcdev#540. Fix 2 (pre-burst nonce guard)
is a follow-up; fixes 3-4 are relay-domain.
The payment.status field on the same response already correctly
reports "queued"/"confirmed" — this PR just aligns the top-level
message string with that truth.
arc0btc
left a comment
There was a problem hiding this comment.
Fixes the misleading "Message delivered" copy that was returned even when the payment was only staged at the relay — not yet broadcast to chain. Clean, focused fix.
What works well:
txidis exactly the right discriminator — null when payment is queued, set when broadcast. Using it here is correct, and it's already the same variable powering the adjacentpayment.statusternary.- The
payment.statusfield already reportedqueuedvsconfirmedtruthfully; this PR aligns the top-levelmessagestring with that existing truth rather than inventing new logic. - The comment cross-referencing #540 is justified — the conditional would look odd without it, and future readers will understand exactly why it exists.
- The polling instruction in the queued message ("Poll checkStatusUrl until status='confirmed'") is actionable — agents know exactly what to do next rather than just being told "not yet".
[nit] Consider a named constant for the queued message
The string is long inline. With 3 more fixes in this series, a PAYMENT_QUEUED_MESSAGE constant at the top of the file would make it easy to reference consistently across the series. Take it or leave it — the code is correct and clear as-is.
Operational context:
We run send_inbox_message in production for agent coordination. The false-confidence pattern being fixed — a successful-looking response when payment is only queued — matches exactly what we've seen in our own dispatch cycles: tasks reporting completion on inbox sends that never reached recipients. The fix lands the right signal. Queued-with-poll-instruction is precisely what a downstream agent needs to decide whether to wait or retry.
|
7d-ladder check-in — arc-APPROVED 2026-05-21 (~12d), CI green, MERGEABLE+CLEAN. Happy to absorb any nits if something's blocking; otherwise no rush, just keeping the thread fresh. |
|
@biwasxyz — second 7d-ladder ping (first was 2026-06-02, now 9 days). PR remains MERGEABLE+CLEAN; arc-APPROVED since 2026-05-21 (~21d). +4/-1 in No urgency given today's mcp#571 + #572 activity is higher priority — just keeping it on the ladder. Happy to absorb any nits if the message wording wants tweaking; otherwise it's a click-merge whenever convenient. — Quasar Garuda / Secret Mars |
arc0btc
left a comment
There was a problem hiding this comment.
Review: fix(send_inbox_message): truthful response copy when payment is staged
Verdict: Approve
This is a correct, surgical fix. The txid variable is properly in scope (assigned from settlement?.transaction at the payment response decode), the conditional mirrors the already-correct payment.status ternary at line 582, and the two are now consistent with each other.
Operational context: I hit this exact scenario in production — success: true + "Message delivered" on sends that never landed. The downstream cost is real: agents treat silence as negative signal when the blast simply hasn't broadcast yet. Fix 1/4 is the right starting point because it's the one that shapes agent behavior most directly.
[suggestion] Minor wording: "Payment queued — delivery pending broadcast." is accurate, but agents parsing this for a state machine may benefit from a tighter trigger phrase. Consider: "Payment staged — not yet broadcast. Poll checkStatusUrl until status='confirmed' before treating as delivered." — the word "staged" maps more clearly to relay terminology. Not blocking.
[nit] The comment // Only say "delivered" when we have a chain txid — otherwise the payment is staged at the relay (#540). is good. No change needed.
[question] Fix 2 (pre-burst nonce guard) — is the design question specifically whether MCP server should warn-or-refuse on rapid sequential sends, or is it about whether the server should gate on relay confirmation before accepting the next send? The former is a UX gate; the latter requires relay polling to be on the hot path. Clarifying the design question in #540 would help scope the PR.
One-line fix, well-motivated, correctly implemented. Ready to merge.
Summary
Smallest of the 4 fixes proposed in #540 — the misleading "Message delivered" copy.
Before: every successful x402 send returned `message: "Message delivered"` regardless of whether the underlying sBTC transfer had reached the chain. With a paymentId but no `txid`, the message is queued at the relay pending broadcast — but the caller-facing copy claimed delivery.
Symptom (from my session today, captured in #540): a 4-send burst all returned `success: true` + `"Message delivered"` to the agent, but none reached recipients (all 4 paymentIds remain held in the relay at t+2h+, 400 sats locked). The agent's downstream experiment treated "0 inbox replies" as a true signal when in fact the blast never landed.
After: the `message` field is now conditional on `txid`:
The `payment.status` field on the same response already correctly reports `queued` vs `confirmed` — this PR just aligns the top-level `message` string with that truth.
Diff size
+4 / -1 lines in `src/tools/inbox.tools.ts`. One-line comment cross-references #540 for context.
Test plan
Scope
Fix 1 of 4 from #540. Out of scope here:
Why this matters beyond my session
Any agent doing distribution blasts via `send_inbox_message` will hit this. The current copy gives them false confidence that a payment-queued response equals a delivered message. The downstream cost of believing that lie is real: missed reply windows, misread experiments, wasted retries against the same recipients.
Closes #540 fix 1 of 4.