diff --git a/extensions/buzz/src/buzz-bus.lifecycle.test.ts b/extensions/buzz/src/buzz-bus.lifecycle.test.ts index a7ef87040786..8e685b27a4d8 100644 --- a/extensions/buzz/src/buzz-bus.lifecycle.test.ts +++ b/extensions/buzz/src/buzz-bus.lifecycle.test.ts @@ -343,6 +343,22 @@ describe("Buzz bus lifecycle", () => { expect(relayMocks.close).toHaveBeenCalledOnce(); }); + it("closes a standalone relay when mention preflight rejects the message", async () => { + relayMocks.auth.mockResolvedValue("ok"); + + await expect( + sendBuzzTextOneShot({ + relayUrl: "wss://buzz.example.com", + privateKey: PRIVATE_KEY, + channelId: CHANNEL_ID, + text: "Hello @Missing", + }), + ).rejects.toThrow('Buzz mention "@missing" does not match a current room member'); + + expect(relayMocks.publish).not.toHaveBeenCalled(); + expect(relayMocks.close).toHaveBeenCalledOnce(); + }); + it("resolves active-bus mentions for proactive sends and agent replies", async () => { relayMocks.auth.mockResolvedValue("ok"); relayMocks.profileEvents = [ diff --git a/extensions/buzz/src/mentions.test.ts b/extensions/buzz/src/mentions.test.ts index 65c74ac56516..82839000e17f 100644 --- a/extensions/buzz/src/mentions.test.ts +++ b/extensions/buzz/src/mentions.test.ts @@ -89,4 +89,22 @@ describe("Buzz outbound mentions", () => { ).toEqual([]); expect(hasBuzzMentionSyntax("mail user@example.com")).toBe(false); }); + + it("rejects messages above the native mention limit", () => { + const mentionedMembers = Array.from({ length: 51 }, (_, index) => { + const publicKey = (index + 1).toString(16).padStart(64, "0"); + return { + publicKey, + displayName: `Member${index + 1}`, + }; + }); + + expect(() => + resolveBuzzMessageMentions({ + text: mentionedMembers.map((member) => `@${member.displayName}`).join(" "), + members: members(...mentionedMembers), + senderPublicKey: BOT_PUBLIC_KEY, + }), + ).toThrow("Buzz messages support at most 50 mentions"); + }); });