Skip to content

fix(buzz-mcp): page channel reads past the relay limit - #1131

Merged
kalvinnchau merged 3 commits into
mainfrom
cid/channel-name-lookup
Oct 14, 2026
Merged

kalvinnchau merged 3 commits into
mainfrom
cid/channel-name-lookup

Conversation

@kalvinnchau

@kalvinnchau kalvinnchau commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

The channels tool queried only the newest 500 memberships and channel metadata events, hiding older accessible channels from listings and name searches. Discovery now pages through the relay while bounding both scanning and replies.

Change

  • Scan memberships and metadata with the relay's until/before_id ordering, up to 10,000 events per stream plus a one-event exhaustion probe. Apply q while visiting metadata pages instead of retaining every event.
  • Bound replies to 500 channel rows and 16,384 UTF-8 bytes, including the partial-result notice. Oversized details retain a usable ID when it fits.
  • Return available results with explicit partial-result guidance at membership, metadata, or output limits. Exactly 10,000 scanned events can complete; more produces partial results rather than an overflow error. Transport failures still fail the call.
  • Preserve joined-channel #d scope and relay access checks on every page. Membership checks use a Set. With all, IDs absent from an incomplete membership scan say membership unknown, not not joined.
  • Refuse canvas reads and writes when neither an existing canvas nor visible channel metadata establishes the target. Visible channels without a canvas still return No canvas. Missing-metadata errors explain that the channel may not be visible yet; name-to-ID guidance is conditional on having supplied a name. Channel arguments remain IDs.

Verification

At 0951373deb08b3dde3ba2ef16bdcc60d206e83c6:

  • MCP tests: 74 passed. Coverage includes discovery beyond 500 channels, same-timestamp cursor ordering, 9,999/10,000/10,001 events for both membership and metadata searches, no-match partial searches, joined scope, incomplete membership labels, 500/501 rows, and transport errors.
  • MCP response tests cover the exact UTF-8 output boundary and adjacent bytes, plus long ASCII, multibyte, emoji, and escaped names. Existing-canvas reads skip metadata; writes wait past the current canvas timestamp; first writes require visible metadata before publication.
  • Explicit pre-commit checks passed. Pre-push checks passed: TypeScript, 289 related tests across 13 files, design types and guards. Rust Clippy was skipped because no Rust inputs changed.
  • A full Vitest run during the fix passed 9,021 tests and hit nine 5-second timeouts across six UI files (one test skipped). All six files then passed at this head with one worker: 186 tests, unchanged assertions and timeouts.
  • Independent code review found no code defects; minimalness, elegance, and correctness each scored 9/10.

Earlier branch revisions were exercised through the bundled stdio MCP server against a local relay with ephemeral identities: a private channel older than 520 newer channels was found by name and opened by ID; a non-member could not discover or read it. Those runs predate this output-bound fix and do not validate the current reply limits.

Not exercised at this head: live relay behavior or the native in-app agent host. Hosted CI is tracked by the PR checks.

kalvinnchau and others added 2 commits October 14, 2026 14:50
channels read memberships and channel metadata with one 500-event
query and filtered q locally, so an accessible channel older than the
newest page was missing from listings and name searches. follow the
relay until/before_id cursor until a short page, bounded at 10000.

canvas now reports a channel the agent cannot see instead of "no
canvas", and channel-not-found errors point to channels q for finding
an id by name.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Kalvin Chau <[email protected]>
check the 10000-event budget after each page instead of before the
exhaustion read, so a read of exactly 10000 events completes and a
short page past the budget still fails.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Kalvin Chau <[email protected]>
@kalvinnchau
kalvinnchau requested a review from a team as a code owner October 14, 2026 21:53

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

🤖 Carl, an automated reviewer, commenting via Wes’s GitHub account.

Reviewed head 3aa5bf15 against main 9c90857e. One recommended blocker: channels now has no bound on its reply size, and once more than 10,000 events match it fails outright instead of returning a list. The other comments are optional.

The pager itself checks out. Both BuzzClient.query paths pass filters through unchanged to the relay: standalone over /query, and in-app through Tauri as untyped JSON, which keeps before_id. The relay orders created_at DESC, id ASC, uses id > before_id at ties, clamps limit at 1,000 (above PAGE), and applies access scope on every page. The 10,000-value #d filter fits under /query's 1 MiB body limit. The visibility gate shared by canvas and channel matches the relay's accessible-channel set: DMs, archived channels and unjoined open channels pass; deleted channels and private non-member channels fail. CI is green.

Merge criteria: a bounded channels reply that does not throw for q in a large community, with a test at the boundary.

Comment thread src/buzz-mcp/tools.ts Resolved
Comment thread src/buzz-mcp/tools.ts Resolved
Comment thread src/buzz-mcp/tools.test.ts Resolved
filter channel rows during pagination and cap utf-8 output at 16 kib. return partial-result guidance at membership, metadata, or output limits while preserving relay scope and cursor ordering.

clarify missing-metadata errors and cover scan, byte, and canvas ordering boundaries.

Co-authored-by: Kalvin Chau <[email protected]>
Signed-off-by: am <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>

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

🤖 Carl, an automated reviewer, commenting via Wes’s GitHub account.

Re-reviewed 0951373d, the one-commit delta from 3aa5bf15. No blockers remain.

  • The prior blocker is closed. channels replies are bounded to 16,384 UTF-8 bytes and 500 rows. The notice space is reserved up front and each newline is counted. q is applied while scanning, and hitting either cap returns a labelled partial list instead of throwing. scan stops correctly at 9,999 (short page), at 10,000 (complete after an empty one-event probe), and at 10,001 (partial). Transport errors still propagate. A truncated membership scan reports membership unknown instead of claiming not joined.
  • The two optional findings are also addressed: the not-found wording and the canvas tests. The canvas tests are deterministic, using a fake clock for the timestamp wait.

Optional, cosmetic: with real 36-character IDs the byte cap always binds before the 500-row cap, and the details omitted row also appears at an ordinary budget edge, not only for oversized names. Neither affects correctness.

CI is green at this head. Not an approval.

@kalvinnchau
kalvinnchau merged commit 8323c40 into main Oct 14, 2026
32 checks passed
@kalvinnchau
kalvinnchau deleted the cid/channel-name-lookup branch October 14, 2026 22:53
johnmatthewtennant added a commit that referenced this pull request Oct 15, 2026
…-drag

* origin/main: (34 commits)
  fix(channels): resolve template agents from ready inventory (#922)
  [buzz-app] Fit uploaded videos to the relay's 4K envelope and name video rejections (#1129)
  feat(github): reveal the PR comment a link points at (#947)
  fix(messages): stop WebKit freeze from muted composer video previews (#1143)
  test(browser): fix route-unroute and virtua-hold webkit flakes (#1149)
  test(browser): let dnd-kit see its first resize before text shrinks (#1150)
  fix(previews): keep a hovered preview through scroll anchoring (#1138)
  Unify owned agent profile panels (#1083)
  feat(agents): import old Buzz teams from the Teams tab (#985)
  Mark Me chats as personal in the session description for remote agents (#1058)
  feat(messages): optional way to open buzz message links in a thread tab (#1113)
  Distinguish thread originals and tighten conversation spacing (#929)
  fix(buzz-mcp): page channel reads past the relay limit (#1131)
  fix(inbox): show a session's top-level timeline as one conversation (#1094)
  feat: reorder sidebar groups by dragging their headers (#1118)
  fix(avatars): request the cached relay thumbnail at every avatar site (#1054)
  fix(messages): soften quote styling and tighten spacing (#1098)
  fix(emoji): shrink and raise inline custom emoji (#1097)
  fix: follow host theme in media review chrome (#1117)
  Highlight an already-open thread tab when reopening it (#1050)
  ...

Signed-off-by: John Tennant <[email protected]>
Co-authored-by: Claude Worker <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>

# Conflicts:
#	src/features/channel-navigation/ChannelSidebarDnd.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.

2 participants