perf(desktop): parallelize relay agent directory rebuild - #6258
Conversation
57a5a30 to
34df8c2
Compare
wesbillman
left a comment
There was a problem hiding this comment.
Source review: the change preserves the existing exact-author filters and downstream conversion, but replaces 10 sequential directory/profile batch rounds plus sequential policy rounds with a shared 8-permit budget. For ~95 candidates that reduces the dominant work from roughly 20 network-latency rounds to about 5 while preserving the prior all-or-error behavior. The same semaphore is shared by the concurrently-polled directory/profile phases, and each permit lives through query_relay, so a rebuild cannot exceed eight in-flight /query calls. Scoped send-time revalidation still filters membership before constructing these queries, so its 1–3-agent path remains one batch per phase.
I found no correctness or merge-safety defect. CI at head 34df8c2af3a2b928fde13e930aa94ab2810c428c is green, including Desktop Core (2552 passed), Rust lint, macOS/Windows builds, and desktop E2E.
Review limitation: per the strict code-review channel contract I did not run a build, test, relay, or app locally. The reported production timing and byte-identical result set therefore remain author-provided performance evidence rather than an independent runtime measurement.
wesbillman
left a comment
There was a problem hiding this comment.
Carl, an automated reviewer, commenting via Wes’s GitHub account.
The concurrency change itself is sound: it preserves the exact 10-filter request partition and all-or-error behavior, shares one 8-permit budget across the concurrently-polled directory/profile phases, and leaves selected-pubkey send revalidation scoped. The reported 6.5–8.4s to 2.0–3.4s result is structurally consistent with reducing roughly 20 serialized request waves to about 5, though I did not independently repeat the production benchmark. CI is green at 34df8c2af3a2b928fde13e930aa94ab2810c428c.
One small required fix before merge: query_filter_batches adds a production .expect(...) when acquiring the semaphore. AGENTS.md explicitly prohibits new unwrap()/expect() calls in production paths. The local semaphore is never closed, so this is not a demonstrated runtime bug, but it is unnecessary and violates the repository contract. Please propagate the acquisition error instead, for example:
let _permit = semaphore
.acquire()
.await
.map_err(|error| format!("directory concurrency semaphore closed: {error}"))?;With that mechanical cleanup, I found no correctness, authorization, ordering, stale-state, or load-bound blocker and consider the change safe to merge.
The shared-agent directory rebuild fans dozens of exact-author query batches across the relay to resolve runtime directories, owner profiles, and managed policies for every candidate. Issuing those batches serially made a ~100-agent rebuild take 6.5-8.4s, which dominated @mention autocomplete latency. Run the batches with bounded concurrency via a shared query_filter_batches helper. A single tokio Semaphore caps /query requests at 8 across every phase, so the runtime-directory and owner-profile phases that run concurrently under one try_join! never exceed the ceiling together. Same events, keyed by pubkey downstream so order is irrelevant. Live-measured on the production relay (95 agents, identical returned pubkey set): 6.5-8.4s -> 2.0-3.4s. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
34df8c2 to
3dd99d1
Compare
wesbillman
left a comment
There was a problem hiding this comment.
Carl, an automated reviewer, commenting via Wes’s GitHub account.
Royal Court verdict: APPROVE
Reviewed exact head 3dd99d1bfa45fde27085ddb15fb49b6872ef212b. The requested cleanup is complete: semaphore acquisition now propagates a labeled error with map_err(...)? instead of using production .expect(...). The error label remains attached to both acquisition and relay-query failures, and the concurrency, filtering, ordering, cancellation, and fail-closed behavior reviewed at the prior head is otherwise unchanged.
git diff --check passes for the corrective delta. Rust lint, DCO, release candidate, changed-path guard, dead-token guard, Desktop E2E relay, and one integration shard are already green at this head; remaining exact-head Desktop, smoke, integration, Windows, and macOS jobs were still running when this approval was submitted. Merge after required CI completes successfully.
This approval expires if HEAD moves.
* origin/main: (43 commits) perf(desktop): parallelize relay agent directory rebuild (block#6258) Refine the mobile emoji picker (block#5853) fix(desktop): exclude archived agents from nest, order regeneration (block#5905) Add font size and conversation density preferences (block#5644) fix(desktop): emit camelCase config-write payload fields (block#6062) fix(desktop): downscale large avatars for agent-share PNG body (block#6260) fix(desktop): preserve early relay auth challenges (block#3320) Polish mobile message actions (block#5873) Refine mobile pairing confirmation (block#6018) chore(scripts): add buzz-adopt-prod-agents.sh (block#6250) feat(managed-agents): close five Claude Code agent-config gaps (block#4557) chore(hooks): keep mobile analysis out of pre-commit (block#6236) fix(shared-ui): delay hover disclosures by default (block#5821) fix(desktop-chrome): preserve balanced layout when sidebar collapses (block#6000) Polish mobile timeline navigation (block#5874) chore(release): release Buzz Desktop version 0.5.17 (block#6234) fix(prompt): simplify pickup follow-through (block#6186) fix(mcp): scope todo usage (block#6216) fix(desktop): bound remote agent mention authorization (block#6224) fix: bump h2 for RUSTSEC-2026-0258 (block#6222) ... Signed-off-by: Princess Donut <3cb959c7eb65d61f634e61df318e450f18f82fa0e01849e7010b82666ead0587@buzz.block.builderlab.xyz> # Conflicts: # desktop/src/main.tsx # mobile/ios/Podfile.lock
The shared-agent directory rebuild resolves runtime directories, owner profiles, and managed policies for every candidate agent via dozens of exact-author query batches. Issuing those batches serially made a ~100-agent rebuild take 6.5–8.4s, which dominated @mention autocomplete latency.
#6224 already scoped the send-path revalidation (
revalidate_relay_agents) to just the mentioned pubkeys, so the send stall is fixed. But the autocomplete directory (list_relay_agents) still rebuilds the full membership set serially — this PR removes that remaining cost.Change
Run the query batches with bounded concurrency via a shared
query_filter_batcheshelper. Each directory rebuild constructs onetokio::sync::Semaphore(8 permits) and shares it across all of that rebuild's phases, so the runtime-directory and owner-profile phases that run concurrently under onetry_join!never exceed 8/queryrequests in flight together — the bound is per-rebuild. The policy phase reuses the same budget. Same events, keyed by pubkey downstream so ordering is irrelevant.Both
list_relay_agents(autocomplete) andrevalidate_relay_agents(scoped send-path check from #6224) funnel throughlist_relay_agents_for_selection, so the helper is a no-op for the tiny 1–3-mention revalidation set and only the full autocomplete rebuild sees the win — the scoped send path is untouched.Measurement
Live on the production relay, warm connection, full
list_relay_agents:Returned pubkey set is byte-identical pre/post. The 8-permit ceiling holds under saturation (24 batched requests → peak exactly 8, zero failures, zero requests left in flight).