Repository navigation
feat(messages): name background send destinations and attach the files that fit - #2406
Conversation
A background send's pill, Cancel and notices did not say where the send was going, so a failure from one conversation surfaced unnamed in whichever conversation was open. - The pill reads "Uploading to #Design" (plus "and N more" when several sends run), and Cancel's accessible name names the send it stops. Cancel still stops the newest send. - Failure toasts read "Upload to #Design failed" or "Message to #Design failed to send", with the reason as the description. Both recovery notices name the conversation too. - Notices offer "Open #Design" through the hosting composer's link handler: buzz://channel/<id>, or the thread's buzz://message link for a reply. Opening dismisses a failure notice; recovery notices stay. - Names follow channelText, so DMs, Solo chats and private channels get no hash prefix. Docs: buzz-help describes the named pill and notices. contributing.md no longer calls Background Send separate work, and says paused draft uploads resume when their composer returns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
Picking, pasting or dropping several files was all-or-nothing: one file over a limit attached none of them, and an empty file was reported as exceeding the size limit without being named. - The attachment draft admits files in pick order and leaves out only those that are empty, over the upload size limit, past 10 files (counting chips already attached and admitted files, not refused ones) or past the shared 1,000 MiB drafts budget. - The "Could not attach file" toast names what was left out, one sentence per reason: "cloud-placeholder.png is empty." and "IMG_0011.png, IMG_0012.png: Attach at most 10 files per message." - A lone file that does not fit still throws its reason and attaches nothing, so single picks and voice notes keep today's messages. The one change is that an empty file now reads "<name> is empty." - The picker's focus handoff waits on the files actually admitted rather than the last files.length chips. Attaching the first files in pick order up to the 10-file limit is a judgement call; the alternative was to refuse the whole pick and say how many more fit. Docs: buzz-help says the files that can't be attached are named and the rest attach. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
Follow-up to review of the background send and partial attach changes. - A huddle send's destination has no link, so its notices offer no Open: a huddle opens only from its entry point, and ChannelsPage refuses its room's buzz://channel link. - Notices offer Open only when the hosting composer shows another conversation. The channel or thread you are in already shows the restored caption and chip, so its notice offers only Dismiss. - The pill's text stays on one line and ends in an ellipsis, and the bar keeps its 64px width. Cancel's accessible name still carries the full destination. - "and N more" counts only sends Cancel can still stop. When every listed send is cancelled but still publishing, Cancel is disabled yet stays focusable, so the composer gets focus back when the pill leaves. - A refusal toast for several files is titled "Could not attach 1 of 5 files", or "Could not attach 2 files" when none attached. Each reason names three files and counts the rest, and empty files share one sentence: "a.png, b.png, c.png and 3 more are empty." A lone file keeps "Could not attach file". Open is not gated on canOpenLink. That predicate reports registered panel targets only (ChannelsPage and ConversationHost), so it is false for buzz://channel and buzz://message links and would hide Open in every channel host. Docs: buzz-help says refusal notices name the first few files, and that Open appears only from elsewhere and never for a huddle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
…ation
A background send's notice hid Open whenever the hosting composer
belonged to the same conversation, even while a covered tab hid that
composer. The notice then offered only Dismiss, and the restored caption
and chip stayed out of sight.
- The composer names its own conversation to BackgroundUploadStatus only
while it is presented, so a composer whose tab is covered offers Open.
ConversationTab passes shown={active}, so this covers its retained
side-pane tabs.
- ChannelsPage's main composer and thread reply composers receive no
shown, and nothing provides ConversationPresentation, so they still
count as presented when a main-pane tab covers them. Giving them a
shown would also change their mention and agent reseeding, so that is
left for a product call.
- Cancel's comment now says a publish in flight is not stopped: the
message sends and the job then restores its draft as if cancelled.
The behaviour itself predates this branch and is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
…nges The pill's text, bar and Cancel sat in a plain flex row, so Cancel ended wherever the text did. When "Uploading to #Random and 1 more" became "Uploading to #Design", Cancel jumped about 70px left, away from the pointer that had just pressed it. Phase changes such as "Preparing upload to" becoming "Uploading to" moved it too. The status text now takes the row's spare width, so the 64px bar and Cancel sit at the row's end whatever the text says. The text still stays on one line and ends in an ellipsis. The background-send browser journey now asserts that Cancel ends the row. Without the fix it fails, with Cancel 535px short of the end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
kalvinnchau
left a comment
There was a problem hiding this comment.
🤖 One test synchronization issue found.
…ible The "offers no Open for a failed send" cases asserted the restored notes.txt chip synchronously, but the chip can still be entering at opacity 0 when the failure notice appears. The Flake check failed the thread case on every iteration. The assertion now waits for the chip to become visible, as the neighbouring restoration tests do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Guardians review — recommend approval; no new blocking findings.
Reviewed the full feature at head 5767d920c2d3b19400e6169ba1bb52587368aee5, target base 9f14241db4f37ebba5eba651b466a241fcfdd655 (merge base 8668dbd46a12d01fb5583c1b520093ff96930a6b).
The prior restored-chip visibility P2 is repaired: MessageComposer.test.tsx:3114–3116 now waits for visibility. Partial attachment admission preserves pick order and existing count/retained-byte limits, charges only admitted files, and returns the actual added IDs. Background sends retain their captured destinations; the label and Cancel action select the same newest live job. Recovery remains with the session-owned draft, and Open uses the existing navigation handler without dismissing a pending recovery.
The disclosed boundaries remain explicit: cancellation after publication starts can restore an already-sent draft, creating a duplicate-send risk; toast overlap with Send predates this patch. The covered main-pane composer can still omit Open because its host does not pass presentation state. Newest-send cancellation can target another conversation, now named accurately. These are not newly discovered regressions or claims that the product tradeoffs have been accepted.
Optional coverage follow-up: exercise Open navigation and focus destination, plus a partial-pick notice, in the real browser journey. Current coverage for these behaviors is at the component level; the browser change checks the Cancel geometry and status labels.
Validation: source-only review; no tests, builds or apps run by reviewers. The inspected hosted snapshot at this head has 41 successful checks and one skipped Windows native check, including successful Vitest flake shards and Chromium/WebKit flake checks. This is CI status evidence, not independent runtime reproduction. The nine videos were not viewed. Native picker/relay-error behavior, screen-reader behavior and narrow/dark rendering remain unverified.
* eva/huddle-audio-fixes: (29 commits) fix(huddle): keep calls flowing under stalled sends and multiple devices fix(channels): wrap unread conversation stepping around the sidebar (#2682) fix(navigation): let bare buzz:// open Buzz without a broken-link notice (#2718) fix(inbox): open DM thread rows as the thread (#2587) test(channels): complete the context navigation fixture (#2783) fix(channels): open a thread's channel at its root message from the #channel link (#2377) fix(people): find people by a pasted npub or hex key (#2396) test(bestie): open the narrow long-history thread with clickRow (#2723) Account-first onboarding and sign-in recovery (#2579) fix(agents): scroll the avatar dock with a mouse wheel (#2567) fix(avatars): keep Done in view when the avatar popup is short (#2706) feat(messages): highlight reactions you've made (#2709) feat(usage): move Usage from the sidebar into Settings (#2742) fix(messages): keep a playing row mounted in the channel timeline (#2695) Fix plugin status declaration closure for author consumers (#2643) fix(navigation): keep empty new chats out of Back history (#1617) [buzz-app] Recover remote agent message outcomes (#2542) feat(messages): name background send destinations and attach the files that fit (#2406) feat(drafts): clear a draft from its row (#2725) Authorize external application identities in Buzz (#2685) ... Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-authored-by: Tyler Longwell <tlongwell@squareup.com> Signed-off-by: Tyler Longwell <tlongwell@squareup.com> # Conflicts: # docs/huddles.md # src-tauri/src/relay/huddle/audio.rs
…leanup * origin/main: (84 commits) Restore macOS Cmd-W window closing when no tab handles it (#2443) Make agent transcripts quieter and link finished replies to activity (#2424) fix(channels): wrap unread conversation stepping around the sidebar (#2682) fix(navigation): let bare buzz:// open Buzz without a broken-link notice (#2718) fix(inbox): open DM thread rows as the thread (#2587) test(channels): complete the context navigation fixture (#2783) fix(channels): open a thread's channel at its root message from the #channel link (#2377) fix(people): find people by a pasted npub or hex key (#2396) test(bestie): open the narrow long-history thread with clickRow (#2723) Account-first onboarding and sign-in recovery (#2579) fix(agents): scroll the avatar dock with a mouse wheel (#2567) fix(avatars): keep Done in view when the avatar popup is short (#2706) feat(messages): highlight reactions you've made (#2709) feat(usage): move Usage from the sidebar into Settings (#2742) fix(messages): keep a playing row mounted in the channel timeline (#2695) Fix plugin status declaration closure for author consumers (#2643) fix(navigation): keep empty new chats out of Back history (#1617) [buzz-app] Recover remote agent message outcomes (#2542) feat(messages): name background send destinations and attach the files that fit (#2406) feat(drafts): clear a draft from its row (#2725) ... # Conflicts: # src/bundled/builderlab/adapter-type/Activity.test.tsx
Composer attachment failures didn't say which file or conversation they were about. A background send that failed in one conversation surfaced unnamed in whichever conversation was open, and a multi-file pick with one bad file attached nothing.
What changed for users
Background sends
channelText, so DMs, Solo chats and private channels get no#.Multi-file picks
Docs:
buzz-help.mddescribes the named pill, Cancel and notices, and when Open appears. It also says the files that fit attach and the rest are named.contributing.mdno longer calls Background Send separate work. It now describes the current behaviour: background send in the main window, and paused uploads resume when their composer returns.Deliberate decisions
canOpenLink. That predicate reports registered panel targets only, so it's false forbuzz://channelandbuzz://messagelinks and would hide Open in every channel host.Known follow-ups
shownto that composer, which also changes mention and agent reseeding.Before and after
Left: before, on
mainat 8668dbd. Right: after, on this branch at 06ab014. Recorded in Chromium against the fixture relay. The upload failure is a 200 response with an unusable{}body. Each side asserts its own expected state.1. A send from #Design fails while #Random is open. Before, the pill says only "Uploading", and the failure is one unnamed line with only Dismiss. You find #Design yourself, and the toast follows you there over Send. After, the pill reads "Uploading to #Design". The toast is titled "Upload to #Design failed" with the reason below, and Open #Design lands on the restored caption and failed chip and closes the toast.
ce01-failed-send-before-after.mp4
2. Two sends running. Before, the pill reads "Uploading" and the button's accessible name is just "Cancel". After, the pill reads "Uploading to #Random and 1 more" and Cancel's accessible name is "Cancel upload to #Random". The video shows that name in a label, since it isn't drawn on screen. On both sides, Cancel in #Design stops #Random's send, the newest, and lunch.png comes back to #Random paused. After, the pill then reads "Uploading to #Design", and Cancel doesn't move under the pointer (0 px measured).
ce02-two-sends-before-after.mp4
3. Mixed picks. Four PNGs plus a 0-byte file: before attaches nothing and calls the empty file over the size limit. After attaches the four and says "cloud-placeholder.png is empty." Eleven photos into an empty composer: before attaches nothing. After attaches ten and names offsite-11.png.
ce03-mixed-picks-before-after.mp4
Single-side videos (960 px wide)
Before: 1. failed send from #Design
ce01-failed-send-named-before.mp4
After: 1. failed send from #Design
ce01-failed-send-named-after.mp4
Before: 2. two sends and Cancel
ce02-two-sends-cancel-named-before.mp4
After: 2. two sends and Cancel
ce02-two-sends-cancel-named-after.mp4
Before: 3. mixed picks
ce03-mixed-picks-before.mp4
After: 3. mixed picks
ce03-mixed-picks-after.mp4
Testing
BackgroundUploadStatus,MessageComposer,attachment-draftandattachment-panes. Each new case was shown to fail before its fix.composer-attachments.spec.mjs, the background-send journey now asserts the named pill, progress bar and Cancel. It also checks a browser-only geometry contract: Cancel ends the row. Without 06ab014 that check fails, with Cancel 535 px short of the row's end. The spec ran in Chromium at the head; WebKit ran only at an earlier commit.🤖 Generated with Claude Code