Skip to content

Add chat members in one batch before single adds - #1602

Closed
baxen wants to merge 1 commit into
mbot/chat-link-sharing-wordingfrom
mbot/batch-chat-access
Closed

baxen wants to merge 1 commit into
mbot/chat-link-sharing-wordingfrom
mbot/batch-chat-access

Conversation

@baxen

@baxen baxen commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #1591, which is stacked on #1529. Relay side: block/buzz#8575.

What changes

Sharing a chat used to send one kind 9000 per person and read the roster after each one. grantSoloChatAccess now:

  1. Sends one kind 9000 naming every fresh person. Agents carry bot as the p tag's third element.
  2. Reads the roster once.
  3. Gives anyone the roster doesn't show today's single add, which also reports that person's own failure.

It does this only when two or more people are fresh. A fresh person is valid, not already a member, not archived, has no addition already under way, and is not an agent being added where single adds would refuse agents.

Works on today's relays

A relay without #8575 adds only the first p, and reads the role only from the event's role tag. So:

  • Humans go first and a mixed batch carries no event-wide role, so that first person is added as a plain member.
  • A batch of only agents also carries ["role", "bot"].
  • The client trusts the roster rather than the OK message, so everyone the old relay skipped falls back to single adds.

Failure handling (from agent review)

  • Best effort: a failed outbox, roster read or send leaves everyone to the single path rather than failing the share. Only an abort, or a stop from beforeDispatch, ends it.
  • Receipts:
    • Each batch has its own recovery key (member-add:batch:<uuid>).
    • Single adds never resume a batch receipt.
    • A settled batch is acknowledged in Outbox, and so is one left behind by a reload. Neither can block later additions.

Tests

share.test.ts:

  • Relay fixture: it now models both relay kinds. By default it adds only the first p; setup({ batch: true }) adds them all.
  • New tests:
    • Everyone is added in one event.
    • A batch of only agents carries the event-wide bot role.
    • Only the people a batch missed are retried, and each reports their own reason.
    • A failed roster read after a batch falls back instead of failing the share.
    • A single add doesn't resume another share's batch that is still in flight.
  • Fail-then-pass: each new test fails with the batch path disabled or the fix reverted, and passes now.
  • Updated: the existing agent test now asserts the old-relay fallback (batch, then a single add with role=bot). Its onConfirmed check now ignores order, since batch order puts humans first.

Validation:

  • Full vitest run at 1ca91f57e: 736 files passed, 0 failed.
  • tsc is clean.
  • Not yet exercised in the app or against a relay running #8575.

🤖 Generated with Claude Code

Sharing a chat with a channel sent one kind 9000 per person and read the
roster after each. Send one kind 9000 naming every fresh person instead,
with per-person roles in the p tags, then read the roster once.

A relay without batch support adds only the first p and reads only the
event's role tag, so humans go first and an all-agent batch also carries
role=bot. Whoever the roster doesn't show falls back to today's single
add, which reports that person's own failure.

The batch is best effort: a failed read or send leaves everyone to the
single path rather than failing the share. Each batch has its own
receipt key, single adds never resume a batch receipt, and a settled or
left-over batch is acknowledged so it can't block later additions.

Relay side: block/buzz#8575.

Co-authored-by: mbot <3754f8729004d95654c46dbab3129e4ab9ef05cc2534e2a3fbfc155983bd637b@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Bradley Axen <[email protected]>
@baxen baxen closed this Oct 24, 2026
morgmart added a commit that referenced this pull request Nov 4, 2026
Relay side: block/buzz#8575 (merged). Replaces the closed #1602, rebuilt
on current `main`.

## What

When you add several people to a chat at once, Buzz now sends one relay
write for all of them instead of one per person, then checks the member
list once.

This covers every place the app adds several people together:

- Sharing a chat with a channel or DM
- **Add team** in Members
- Inviting people you mentioned who aren't in the channel
- Bringing several agents in from another community

## How it behaves

- **One write per role, up to 100 people each.** People and agents go in
separate writes because they join with different roles. The relay
accepts at most 100 people in one write, so bigger groups are split.
- **The member list decides.** After the writes, Buzz reads the member
list once. Anyone not on it gets today's one-person add, which shows
their own error and Retry. Older relays that only add the first person
in a write still end up with everyone added.
- **A batch is never sent again.** If a batch is left in Outbox (for
example, the app quit mid-add), Retry re-adds each person through the
normal checks. The batch stays in Outbox until everyone it names is in
the chat or has their own saved add, so a failure or restart never loses
anyone. A stale role can't overwrite someone's newer role (#1882,
#1948).
- **Earlier adds keep their own path.** Someone with a one-person add
still pending keeps it. In a Solo chat, agents always get their own add,
so a share that resumes after a restart still finishes the agent's Bot
grant (#1948).
- Members additions made at the same moment for the same channel share a
batch. A single add behaves as before.

## Not included

Tagging several agents in the composer still adds them one at a time.
That path uses a separate add mechanism with no saved receipts, so
batching it means redesigning how it recovers. Better as its own
follow-up.

## Testing

- New tests, each failing on `main` before this change:
- a share to a channel with several members goes out as one write, on a
relay with and without batch support
- 101 people plus an agent become 3 writes: 100 members, 1 member, 1
agent
- a relay that only adds the first person gets the rest added one by one
- additions requested together are batched, and the rest are added
singly
- Outbox Retry of a leftover batch re-adds each person and clears it,
even when one person fails
- inviting mentioned non-members and bringing agents request everyone
together
  - a Solo chat's agents keep their own add
  - a pending one-person add is resumed, not batched again
- If a write fails before it's sent, the member list is still read again
before the next write (fails if that re-read is skipped)
- A guarantee test that also passes on `main`: when a batch fails,
everyone is added singly.
- Rebased on current `main` at `db8491d` and squashed into one commit,
since main now has the guest and Solo member roles (#2107, #2036).
Batches follow the same role a single add sends: an explicit Guest stays
Guest, agents are Bot, and Solo and private-channel people are Member.
Web signing accepts Guest batches. Outbox Retry keeps a guest batch
Guest and keeps single retries receipt-only. A Retry never joins a
batch. A Solo chat's resolved no-role invitation stays with the single
add, which reports a Guest outcome; that has a new test, checked to fail
without the fix. Type check and biome pass. Every test file this PR
touches passes. Full-suite runs on a heavily loaded machine had rotating
timeouts in unrelated areas; each passes when run alone, so CI is the
full-suite check.
- No UI changes; Outbox's Retry button works as before, so there are no
screenshots.
- Not yet done: a human trying it in the running app, and a live run
against a batch-capable relay.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: morgmart <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
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.

1 participant