镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

feat(messages): name background send destinations and attach the files that fit - #2406

Merged
matt2e merged 6 commits into
mainfrom
composer-error-issues
Nov 6, 2026
Merged

matt2e merged 6 commits into
mainfrom
composer-error-issues

Conversation

@matt2e

@matt2e matt2e commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

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

  • The pill reads "Uploading to #Design", plus "and N more" while several sends run. It stays on one line, and Cancel stays at the end of the row as the text changes. Cancel's accessible name names the send it stops: "Cancel upload to #Random".
  • Failure toasts are titled "Upload to #Design failed" or "Message to #Design failed to send", with the reason as the description. The recovery notices name the conversation too.
  • Notices offer Open #Design, or Open thread in #Design for a reply, when that conversation isn't on screen. Huddles get no Open, because a huddle opens only from its entry point.
  • Names follow channelText, so DMs, Solo chats and private channels get no #.

Multi-file picks

  • Picking, pasting or dropping several files attaches the ones that fit, in pick order. A file is left out if it's empty, past 10 per message (counting chips already attached), over the size limit, or past the 1,000 MiB drafts budget.
  • The toast names what was left out, with one sentence per reason and up to three names plus a count. For example: "Could not attach 1 of 5 files / cloud-placeholder.png is empty."
  • A single file or voice note that doesn't fit is refused as before. The one change: an empty file now says " is empty." instead of claiming to exceed the size limit.

Docs: buzz-help.md describes the named pill, Cancel and notices, and when Open appears. It also says the files that fit attach and the rest are named. contributing.md no 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

  • Cancel still stops the newest send, as Desktop does. So in #Design the pill can read "Uploading to #Random and 1 more". The label is now accurate. Stopping only the current conversation's sends is a product call, left for a follow-up.
  • Open isn't gated on canOpenLink. That predicate reports registered panel targets only, so it's false for buzz://channel and buzz://message links and would hide Open in every channel host.
  • Attaching the first files in pick order, up to the limit, is a judgement call. The alternative was to refuse the whole pick and say how many more fit.

Known follow-ups

  • Cancel during publish restores sent files (predates this branch). Cancel doesn't stop a publish already in flight. The message sends, then its caption and chips come back, which invites a double send.
  • The refusal toast covers Send (predates this branch). This matters more now that the files that fit stay attached.
  • A covered main-pane tab hides Open. When a thread tab in the main pane covers the channel's own composer, Open doesn't show, though the toast still names the conversation. Fixing it means passing shown to that composer, which also changes mention and agent reseeding.

Before and after

Left: before, on main at 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

  • Vitest: BackgroundUploadStatus, MessageComposer, attachment-draft and attachment-panes. Each new case was shown to fail before its fix.
  • Browser: no cases were added or removed. In 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.
  • Not checked: the native desktop app, a real drag and drop, dark theme, and a real 4xx/5xx upload failure. Thread replies, huddles and the recovery notices have unit tests only.

🤖 Generated with Claude Code

matt2e and others added 5 commits November 4, 2026 16:15
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>
@matt2e
matt2e marked this pull request as ready for review November 4, 2026 07:13
@matt2e
matt2e requested a review from a team as a code owner November 4, 2026 07:13

@kalvinnchau kalvinnchau left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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 wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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.

@matt2e
matt2e merged commit 502aac4 into main Nov 6, 2026
42 checks passed
@matt2e
matt2e deleted the composer-error-issues branch November 6, 2026 03:12
tlongwell-block added a commit that referenced this pull request Nov 6, 2026
* 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
wpfleger96 added a commit that referenced this pull request Nov 6, 2026
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants