Repository navigation
fix(relay): show the relay's reason when it refuses a write - #2031
Conversation
3d805eb to
0075cf4
Compare
A write the relay refused over HTTP (400, 401, 403, 404, 413, 422) showed
"Relay rejected the message (400)". The relay's own text, for example
`invalid: an open channel named "Launch" already exists`, was kept only
in PublishRejected.reason, and on the signed transport admission reduced
it to a status summary before acceptPublish saw it.
- acceptPublish now shows the relay's text without its NIP-01 prefix
(invalid, blocked, restricted, error, pow, duplicate), for example
`An open channel named "Launch" already exists`. `reason` keeps the
raw text for writers that classify it. Text with another prefix
(conflict:, rate-limited:) is shown as sent. With no text, the status
summary stays.
- The signed publish asks admission to keep the relay's {error} text,
only for those refusal statuses, through the existing caller-allowed
reason hook. readApiFailure still bounds it.
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
A gateway or VPN edge can answer 400-422 with JSON {error}, and that
text was shown as if the relay had refused. Show refusal text only when
it starts with a NIP-01 prefix, and let admission keep only that text on
the signed path. Otherwise show the status summary, the same on both
publish paths. `reason` still holds the raw text for classification.
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
The dev broker publishes over WebSocket and answered every proven refusal with 503 "Socket publication could not be confirmed", so `just desktop` still showed "Relay request failed (503)" for a taken channel name. A proven `invalid:` refusal now answers 400 with the relay's bounded text, as the relay's HTTP API does, so the broker and signed paths show the same reason. Logs keep only the safe summary. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
0075cf4 to
2caec1d
Compare
kazemek21
left a comment
There was a problem hiding this comment.
Kyle reviewed this PR and the Nexus review-tracker notes and approved with no comments.
Posted by Codex (gpt-6.1-sol) on behalf of kylez
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account.
No actionable findings in the reviewed change. The signed path preserves bounded, relay-shaped refusal text through admission; the broker exposes proven invalid refusals to the requesting client while retaining sanitized diagnostic summaries. Raw reasons remain available to classifying writers. Conflict, quota and uncertain-delivery handling remain distinct.
Reviewed head: 2caec1d
Base: 6f341ce
Independent Rocket, Mantis and Groot lanes completed, with Star Lord integration. Source-only review of the seven-file diff, supporting transport/outbox/create-channel callers, tests and public PR material. No tests, builds, apps or live-relay workflows were run, and CI was not assessed. Actual error/retry focus, native/browser rendering and human acceptance remain unverified. This COMMENT is not approval or merge authorization.
* origin/main: (26 commits) fix(identity): read FI backup status through the native forwarder (#2344) fix(relay): show the relay's reason when it refuses a write (#2031) perf(relay): look up archived identities in a per-snapshot set (#2359) fix(messages): keep link previews clear of message hover actions (#2351) fix(security): close workflow, Canvas, upload, and broker gaps (#2360) fix: prevent false leave failures after membership updates (#2310) feat(bestie): remove your Bestie, and let remote agents be Bestie after a warning (#2041) feat(messages): open the sender's profile from the byline name (#2253) feat(native-mcp): one-command launcher and MCP registration for agent driving (#2272) perf(composer): stop per-keystroke chip re-renders and reparses in long rich drafts (#2251) fix(agents): prevent history from forging prompt requests (#2223) Enable automatic key backup in preview releases (#2325) feat(read-state): n-blob NIP-RS sync with a 30-day floor, frontier only (#1286) feat(huddles): provide read-only huddleStatus for optional consumers (#2327) feat(search): show verified names in people search (#2322) Fix voice-note sending and restore waveform previews (#2283) Preserve Solo queued messages across restarts (#1704) feat(plugins): resolve attachment renderers by order, like panels and links (#2284) fix(channels): keep muted DM names from becoming bold (#2184) fix: command-click opening desktop message links in the browser (#2288) ... Co-authored-by: Codex <noreply@openai.com> Co-authored-by: Tyler Longwell <tlongwell@squareup.com> Signed-off-by: Tyler Longwell <tlongwell@squareup.com> # Conflicts: # src/bundled/huddles/index.tsx # src/features/huddle/service.test.ts
Summary
When the relay refuses a write, buzz-app showed
Relay rejected the message (400)or, on the web broker path,Relay request failed (503). The relay's own reason never reached the user. For example, the relay refuses to create an open channel with a taken name (block/buzz#8782) withinvalid: an open channel named "Launch" already exists. The create dialog showed only a status summary.Now the create dialog shows
An open channel named "Launch" already exists, on the signed path (packaged and native builds) and on the development broker path (just desktop/just webwithBUZZ_DEV_VIEWER). On the signed path this holds for every relay-shaped refusal. On the broker path it holds for validation (invalid:) refusals only;restricted:andblocked:still show a status summary there, as before this PR.Details
acceptPublish(src/features/relay/transport.ts){error}text, but only when the text is relay-shaped, that is, it starts with a NIP-01 prefix (invalid,blocked,restricted,error,pow,duplicate). It removes the prefix and capitalizes the first letter.{"error": "Forbidden by proxy"}) still showsRelay rejected the message (<status>). The prefix is a shape check, not proof of origin.PublishRejected.reasonkeeps the raw text, so writers that classify by prefix (agent-config-artifacts.ts) work as before.conflict:,rate-limited:,auth-required:) is shown exactly as sent.accepted:falseis unchanged; the name refusal comes as an HTTP 400, not on that path.src/features/relay/http-admission.ts)Relay request failed (400)beforeacceptPublishsaw it.reasonhook to keep relay-shaped{error}text for the refusal statuses above.readApiFailurestill bounds it. The hook's callback now also receives the HTTP status; existing callers are unaffected.browser-host/relay-broker.mjs,src/features/relay/socket-requests.ts)Socket publication could not be confirmed.invalid:refusal now answers 400 with the relay's text (bounded at 16 KB by the socket receipt check), as the relay's HTTP API does. So both paths reach the sameacceptPublishbranch.publicationRefusal), never the relay's text.restricted:,blocked:,rate-limited:,conflict:, the read-state timestamp refusal and unconfirmed outcomes keep their current answers.Testing
transport.test.ts:relay-broker-live.test.mjs(the real broker, with a scripted relay socket):PublishRejectedwithAn open channel named "Launch" already exists.invalid:refusals, and still checks that the log line holds only the safe summary and no private text.native.test.ts: one fixture now uses relay-shaped text.tsc --noEmitandbiome checkpass.vitest run browser-host src/features/relay src/features/developer src/features/agents src/features/channel-members src/bundled/channels src/bundled/workflowspasses (5,432 tests) after the rebase onto main.wss://andhttps://relay origins, and both dev paths use the developer's own account credential.🤖 Generated with Claude Code