Skip to content

fix(agents): can't delete an agent belonging to an archived channel - #1560

Merged
johnmatthewtennant merged 4 commits into
mainfrom
jtennant/oliver/delete-skip-archived-channels
Oct 23, 2026
Merged

johnmatthewtennant merged 4 commits into
mainfrom
jtennant/oliver/delete-skip-archived-channels

Conversation

@johnmatthewtennant

@johnmatthewtennant johnmatthewtennant commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Deleting a local agent that is still a member of any archived channel never finishes. Every attempt ends with "Switchboard isn't deleted yet and may still be in some channels. It stays stopped; Delete it again to finish."

Delete removes the agent from every channel whose relay roster lists it, then requires a fresh roster read to confirm it is gone. The relay refuses membership changes in an archived channel (OK false "invalid: channel is archived"), so the archived roster keeps listing the agent and the confirmation can never succeed. On John's production account, Switchboard was a member of 14 channels, all archived Solo chats he owns.

Solution

Collect only unarchived channels when removing an agent's memberships:

  • removeAgentFromChannels passes the loaded channels that list the agent to memberChannels as candidates.
  • memberChannels adds the relay roster hits, reads their fresh relay-signed 39000 metadata, and drops those with archived=true. A loaded row that has not yet seen another client's archive is still skipped.

An archived channel refuses all writes, so the leftover membership is inert. Delete still archives the identity, hiding it from member lists and mentions even if the channel is later unarchived, and deletes the key, so the agent can never act there. The owner can still remove that roster entry later, since removal is signed by the owner. The alternative, unarchiving, removing and re-archiving each channel during Delete, would change the owner's channels as a side effect of deleting an agent.

Reproduction

  1. Add a local agent to a channel you own, then archive the channel.
  2. Delete the agent from Agents.
  3. Before: Delete fails with "isn't deleted yet" on every attempt. After: Delete completes.

Testing

  • New regression in relay-removal.test.ts: one active and one archived channel, in both the relay rosters and the loaded channel list, where the loaded row is stale and does not say archived. Removal publishes 9001 only for the active channel and resolves. Without the fresh metadata check, the relay refuses the archived removal and the test fails. The fixture relay now refuses 9001 in archived channels as the real relay does.
  • John installed the change in his daily-driver app and deleted Switchboard and Monitor on production, both previously stuck on archived channels. No separate agent app run.

buzz-review-completed

johnmatthewtennant and others added 2 commits October 22, 2026 14:39
The relay refuses membership changes in an archived channel ("invalid:
channel is archived"), but Delete required a fresh roster read to show
the agent in none of its channels. An agent left in any archived
channel could therefore never be deleted. Skip archived channels when
collecting the memberships to remove: the relay keeps them inert, and
Delete still archives the identity and removes its key.

Co-authored-by: Oliver <e78152627ea32fbacb070e5047afcfb8e409fa3343d9e618227baacca5b5e607@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: John Tennant <jtennant@block.xyz>
Test the loaded-channel filter as well as the roster lookup, and say in
the Delete flow docs that archived channels keep the agent.

Co-authored-by: Oliver <e78152627ea32fbacb070e5047afcfb8e409fa3343d9e618227baacca5b5e607@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: John Tennant <jtennant@block.xyz>
@johnmatthewtennant
johnmatthewtennant marked this pull request as ready for review October 23, 2026 14:31
@johnmatthewtennant
johnmatthewtennant requested a review from a team as a code owner October 23, 2026 14:31
@johnmatthewtennant johnmatthewtennant changed the title fix(agents): let Delete finish when the agent is in archived channels fix(agents): couldn't delete an agent that belonged to an archived channel Oct 23, 2026
@johnmatthewtennant johnmatthewtennant changed the title fix(agents): couldn't delete an agent that belonged to an archived channel fix(agents): can't delete an agent that belonged to an archived channel Oct 23, 2026
@johnmatthewtennant johnmatthewtennant changed the title fix(agents): can't delete an agent that belonged to an archived channel fix(agents): can't delete an agent with archived channel membership Oct 23, 2026
@johnmatthewtennant johnmatthewtennant changed the title fix(agents): can't delete an agent with archived channel membership fix(agents): can't delete an agent belonging to an archived channel Oct 23, 2026
johnmatthewtennant and others added 2 commits October 23, 2026 11:20
…e-skip-archived-channels

* origin/main:
  Bump tokio to 1.53.3 for RUSTSEC-2026-0386 (#1581)
  Unify attachment cards with neutral icon tiles (#1548)
  Polish edit context, channel join and profile actions (#1545)
  fix(claude-code): keep context across channel threads (#1516)
  fix(builderlab): let Create agent cancel a pending browser sign-in (#1526)
  test(sidebar-filters): start the focus journey on General (#1555)
  Add opt-in native MCP for macOS tests (#1528)
  Show unreads for channels after access changes (#1550)
  Deliver artifact changes through shared live routes (#1480)
  condense photo and video attachments into a compact grid (#1549)

Signed-off-by: John Tennant <jtennant@block.xyz>
A loaded channel row can still read as unarchived after another client
archived it. Delete then sent a removal the relay refuses, and every
retry failed the same way. memberChannels now applies the fresh relay
archive check to the loaded candidates as well as to the relay's
rosters.

Co-authored-by: Oliver <e78152627ea32fbacb070e5047afcfb8e409fa3343d9e618227baacca5b5e607@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: John Tennant <jtennant@block.xyz>

@loganj loganj 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.

🤖 Larry and Rbot: an independent adversarial review of 4aaf864. Source review only; we did not run the tests locally. Hosted CI is green.

Approve. We found nothing that needs a change.

What we checked:

  • Both callers of the Delete cleanup (relay-removal.ts:33 and service.ts:3355) go through removeAgentFromChannels, so the archive skip covers every delete path. memberChannels has no other caller.
  • The relay does refuse membership writes in an archived channel (buzz-relay/src/handlers/ingest.rs, "invalid: channel is archived"), so skipping those channels is the only way the fresh-roster confirmation can succeed.
  • The archive check is one batched, fresh 39000 read for all candidates, not one read per channel. A channel with no readable metadata stays in the removal set, which is the safe default. A stale loaded row that does not show the archive is still skipped, and the new test covers that case.
  • Race: if a channel is archived between the metadata read and the 9001, the 9001 is refused and Delete reports "isn't deleted yet"; a second Delete then skips it. That is acceptable.

Advice (no change needed): exactLifecycleTag throws on a malformed archived tag, so one malformed relay-signed 39000 would now fail the whole Delete, where before it was not read. The relay signs these, so this is very unlikely.

@johnmatthewtennant
johnmatthewtennant merged commit eaaa3d8 into main Oct 23, 2026
37 checks passed
@johnmatthewtennant
johnmatthewtennant deleted the jtennant/oliver/delete-skip-archived-channels branch October 23, 2026 15:50
morgmart added a commit that referenced this pull request Oct 23, 2026
Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
Co-authored-by: Carl <c217fe6b9d958f41c3a5e030dccc7f626775a923089cb6491305eade75ea1f1b@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* origin/main: (24 commits)
  Unify chat and channel access, tidy the Solo chat menu (#1446)
  fix(todos): render nested TODOs with collapsible hierarchy and Markdown (#1483)
  fix(agents): Allow agents to propose updates to agents (#1478)
  fix(composer): prevent plugins from updating the recipient on a WIP draft message (#1497)
  fix(agents): can't delete an agent belonging to an archived channel (#1560)
  Bump tokio to 1.53.3 for RUSTSEC-2026-0386 (#1581)
  Unify attachment cards with neutral icon tiles (#1548)
  Polish edit context, channel join and profile actions (#1545)
  fix(claude-code): keep context across channel threads (#1516)
  fix(builderlab): let Create agent cancel a pending browser sign-in (#1526)
  test(sidebar-filters): start the focus journey on General (#1555)
  Add opt-in native MCP for macOS tests (#1528)
  Show unreads for channels after access changes (#1550)
  Deliver artifact changes through shared live routes (#1480)
  condense photo and video attachments into a compact grid (#1549)
  Add page-owned sidebar contributions (#844)
  fix(channels): confirm a requested member when the relay stores bot (#1519)
  test(browser): settle dialog motion and startup errors before strict checks (#1492)
  perf(messages): measure read-tracking rows once per frame (#1527)
  fix(settings): keep the chosen plugin row in place when details open or close (#1551)
  ...
joelrobotham pushed a commit to joelrobotham/buzz-app that referenced this pull request Oct 24, 2026
…ocus

* origin/main: (35 commits)
  fix(goose): say a provider isn't set up instead of offering placeholder models (block#1543)
  fix(agent-activity): note under a message when its agent was stopped (block#1544)
  feat(messages): show whose agent wrote a message (block#1502)
  feat(agents): put main agent choice in the card's actions menu (block#1530)
  fix(relay): let live dev connections save config artifacts (block#1583)
  feat(builderlab): let local agents create, deploy, share and open Builderlab apps (block#1340)
  Unify chat and channel access, tidy the Solo chat menu (block#1446)
  fix(todos): render nested TODOs with collapsible hierarchy and Markdown (block#1483)
  fix(agents): Allow agents to propose updates to agents (block#1478)
  fix(composer): prevent plugins from updating the recipient on a WIP draft message (block#1497)
  fix(agents): can't delete an agent belonging to an archived channel (block#1560)
  Bump tokio to 1.53.3 for RUSTSEC-2026-0386 (block#1581)
  Unify attachment cards with neutral icon tiles (block#1548)
  Polish edit context, channel join and profile actions (block#1545)
  fix(claude-code): keep context across channel threads (block#1516)
  fix(builderlab): let Create agent cancel a pending browser sign-in (block#1526)
  test(sidebar-filters): start the focus journey on General (block#1555)
  Add opt-in native MCP for macOS tests (block#1528)
  Show unreads for channels after access changes (block#1550)
  Deliver artifact changes through shared live routes (block#1480)
  ...

Signed-off-by: user-kWN3CIVowEvEo3RM <joelrobotham+bbprod@gmail.com>

# Conflicts:
#	tests/browser/github-body.spec.mjs
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.

2 participants