Skip to content

perf(search): fold people names once across palette keystrokes - #2570

Merged
kalvinnchau merged 3 commits into
mainfrom
peon/rg-search-people
Nov 6, 2026
Merged

kalvinnchau merged 3 commits into
mainfrom
peon/rg-search-people

Conversation

@kalvinnchau

@kalvinnchau kalvinnchau commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Each Cmd+K keystroke ranks every cached profile against the typed text. personMatch calls matchPerson for each of a person's shown and hidden names. matchPerson folds the whole name on every call: NFKD, two regex replaces and a lowercase per code point, plus array spreads. It also folds the query again for every name. #2322 added a verified full name and profile names to each person. #2269 raised the profile cache ceiling from 1,024 to 10,240. Together they made this per-keystroke pass several times larger, and nearly all of it re-folds names that did not change since the previous keystroke.

Change

  • matchTier returns the tier matchPerson would give. It reads folded names from a module-level cache that holds at most 65,536 names and is cleared when full. Names that fold to more than 128 code points are not cached.
  • matchPerson and matchTier share the matching body (search), so tier rules live in one place. matchPerson still builds its own fold with origins for underlining.
  • rankPeople folds the query once per ranking and passes it to personMatch, which uses matchTier. Before, personMatch refolded the same query for every person: 10,240 folds per keystroke with a full profile cache, about 2.4–4.4 ms for a 2–4 character query in a Node micro-benchmark. This last step is not in the table below.
  • nameStarts and the cache share one fold helper.

No behavior changes

matchTier runs the same search over the same folded characters as matchPerson, so people rank exactly as before. A new test checks that matchTier gives matchPerson's tier for repeated names and changing queries, including accented, compatibility, final-sigma and padded names. Underlined positions still come from matchPerson.

Evidence

Two benchmarks compare main and this PR:

  • Browser. A production build runs in Chromium at 4× CPU throttling. The rows are keydown → next-paint medians (Event Timing) for typing in Cmd+K, with names that miss and names that match people, and for typing in the composer. Main 8c0cb0c1e and this PR were run as six serial, interleaved pairs on one Linux and one macOS workstation. All keys matched in every run.
  • Render. SearchResults renders in jsdom with 1,700, 5,000 or 10,240 cached profiles (accented and plain names, half with verified full names). It types a, al, ale, alex (cold), then repeats the same keystrokes (warm). Values are the median time to render one keystroke. Main and this PR were interleaved on 2 Linux and 2 macOS workstations, with 16 samples per cell.
metric Linux: main Linux: this PR Linux Δ % macOS: main macOS: this PR macOS Δ %
browser: Cmd+K, names that miss 128 ms 104 ms −18.8% 88 ms 72 ms −18.2%
browser: Cmd+K, people 144 ms 112 ms −22.2% 96 ms 80 ms −16.7%
browser: composer, @ mention 448 ms 440 ms −1.8% (noise) 272 ms 272 ms 0%
browser: composer, plain prose 24 ms 24 ms 0% 16 ms 16 ms 0%
render: 1,700 profiles, cold 23.0 ms 16.0 ms −30.4% 13.8 ms 10.0 ms −27.8%
render: 1,700 profiles, warm 16.3 ms 9.5 ms −41.8% 9.7 ms 6.0 ms −38.3%
render: 5,000 profiles, cold 39.3 ms 22.5 ms −42.6% 22.2 ms 13.0 ms −41.5%
render: 5,000 profiles, warm 34.7 ms 15.5 ms −55.4% 19.9 ms 9.3 ms −53.1%
render: 10,240 profiles, cold 69.1 ms 32.7 ms −52.6% 39.5 ms 19.8 ms −49.8%
render: 10,240 profiles, warm 65.8 ms 25.7 ms −61.0% 37.5 ms 15.5 ms −58.6%

Lower is better.

  • Event Timing rounds durations to 8 ms, so the Linux mention change is one rounding step and counts as noise.
  • The render benchmark ran before two changes: the bypass for names over 128 code points and the shared fold helper. Neither affects names as short as these.

Checks: the search, mentions, shell and channel-members unit suites pass, along with tsc and biome.

🤖 Generated with Claude Code

@kalvinnchau
kalvinnchau marked this pull request as ready for review November 5, 2026 22:08
@kalvinnchau
kalvinnchau requested a review from a team as a code owner November 5, 2026 22:08

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

🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot reviews.

Reviewed head 1f86b64098ff497cad63ebc3c2ce80c9598e18fe against base f27e3089a261db1e63860fd28503c93e26eb98be. No required changes found. The shared search preserves matching tiers and underline origins, while raw-name cache keys avoid stale folding when profiles change. Minimalness, elegance and correctness meet the 9/10 source-review bar. One optional cache-memory suggestion is inline.

Source-only: no tests, builds, app workflows or benchmarks were run. The PR’s jsdom timing and test results remain author-provided evidence; browser/native latency, retained-memory size and rendered focus/accessibility were not validated. The public PR description and commit were inspected; no image attachments were present.

Comment thread src/features/search/person-match.ts Resolved

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 ranking is unchanged: matchTier and matchPerson share search over the same folded characters, and only people-rank.ts moves to matchTier. one small thing on the cache key bound inline, otherwise this looks good

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

🤖 Star Lord’s automated source follow-up via Wes’s account, integrating independent Rocket, Mantis and Groot reviews.

Reviewed 3c5e54eb379bba27dc9229192651f93278bf08d2 against unchanged base f27e3089a261db1e63860fd28503c93e26eb98be, focusing on the change since reviewed 1f86b64098ff497cad63ebc3c2ce80c9598e18fe. The earlier optional raw-key retention concern is resolved: names above 128 UTF-16 code units bypass caching, alongside the existing folded-value limit. Long names still receive the complete fold and unchanged matching; underline generation is unchanged. No new findings or required changes. The small repair meets the 9/10 source-review bar.

Source-only: no tests, app workflows or performance/memory measurements were run. The existing parity test uses short names and does not directly exercise the new length boundary. The public description and follow-up commit were inspected; no attachments were present.

@kalvinnchau
kalvinnchau force-pushed the peon/rg-search-people branch from 3c5e54e to ba3ae52 Compare November 5, 2026 23:02

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

🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot reviews.

Reviewed head ba3ae528491a6860e36de31057716ab6963a29d3 against base 1c3047558547e76bd006c2dc76951b3f1d601c5d. No new findings or required changes. Both feature commits and all three feature files are preserved from reviewed 3c5e54eb379bba27dc9229192651f93278bf08d2; the earlier raw-key concern remains resolved. This follow-up checked the rebased callers: recipient identity and exact-name completion remain separate from cached folding, highlights retain their origin mapping, and the per-render channel-rank cache and unread-first suggestions do not reuse stale people ranks. The change continues to meet the 9/10 source-review bar.

Source-only: no tests, builds, app workflows or performance/memory measurements were run. Existing parity coverage uses short names and does not directly exercise the raw-length boundary. The public PR description was inspected; no image attachments were present.

@kalvinnchau
kalvinnchau force-pushed the peon/rg-search-people branch from ba3ae52 to 8bc8355 Compare November 6, 2026 08:15

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

🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot reviews.

Reviewed head 8bc8355bc2d4c871b14437251a744e028a7bb4a9 against base 8c0cb0c1efb68068b89c813ad6f890d8b8f07401. No new findings or required changes. Both feature patches and all three feature files are unchanged from reviewed ba3ae528491a6860e36de31057716ab6963a29d3; the earlier raw-key retention concern remains resolved.

This follow-up checked the rebased name-preference, profile-retention and search callers. Current labels feed freshly computed ranks; cached folds retain neither identity nor authority and cannot restore evicted candidates. Channel-member verified-only results and direct-message profile results keep their distinct upstream paths, with equivalent matching tiers. Highlight origins and collision-label ownership remain intact. Minimalness, elegance and correctness continue to meet the 9/10 source-review bar.

Source-only: no tests, builds, app workflows or performance/memory measurements were run. The PR’s benchmark and test claims remain author-provided evidence; rendered focus/accessibility and preference changes in a running app were not validated. The existing matcher parity test uses short names and does not directly exercise the raw-length boundary. The public PR description was inspected; no image attachments were present.

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 matching is unchanged: matchTier and matchPerson run the same search over the same folded characters, and the cache bounds look right. one nonblocking suggestion inline

Comment thread src/features/search/people-rank.ts Resolved
@kalvinnchau
kalvinnchau force-pushed the peon/rg-search-people branch from c5456ad to 4011e26 Compare November 6, 2026 16:17

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

🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot checks.

Reviewed head 4011e26b050ead7de1b6b5ada17e82112fb305d7 against base 5a4cdc0a5599076d74b7277d02d1a6d5ef7de904, preserving prior coverage at 8bc8355b.

No new findings or required changes. The final commit folds the query once per rankPeople call and passes a local, read-only array through matching. It preserves the distinction between whitespace-only queries and nonblank text that folds empty, shown/hidden name tiers, and the inherited exact-public-key rank override. Removing the personMatch export has no other consumer in the pinned repository. Highlighting remains on matchPerson; the previously reviewed raw-key and folded-value cache bounds remain intact. Minimalness, elegance and correctness continue to meet the 9/10 source-review bar.

Source-only: no tests, builds, app workflows or benchmarks were run. The final commit adds no test; the existing matcher parity loop does not cover a nonblank folded-empty query or the raw-length boundary. Browser/jsdom results and the separate Node estimate remain author-provided evidence; the PR explicitly excludes the final query-fold optimization from its benchmark table. The public description was inspected; no image attachments were present.

kalvinnchau and others added 3 commits November 6, 2026 08:41
personmatch re-folded every name and the query on each call, so cmd+k ran
nfkd and regex per code point over every cached profile on every
keystroke. add matchtier, which shares the matchperson search over a
bounded cache of folded names; personmatch folds the query once and uses
matchtier. matchperson keeps its positions. ranking is unchanged.

Signed-off-by: Kalvin C <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
a letter followed by thousands of combining marks folds to one
character, so the folded-length guard alone kept a multi-kb raw key in
a cache that outlives profile eviction. bypass the cache when the raw
name exceeds 128 code units too; matching is unchanged.

Signed-off-by: Kalvin C <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
rankpeople called personmatch per person, and personmatch folded the same
query each time, so 10,240 cached profiles meant 10,240 folds per
keystroke. fold it once in rankpeople and pass the folded code points in.
personmatch has no other caller, so it is no longer exported.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Kalvin Chau <[email protected]>
@kalvinnchau
kalvinnchau force-pushed the peon/rg-search-people branch from 4011e26 to a13d00f Compare November 6, 2026 16:42
@kalvinnchau
kalvinnchau merged commit 06d8c03 into main Nov 6, 2026
112 of 117 checks passed
@kalvinnchau
kalvinnchau deleted the peon/rg-search-people branch November 6, 2026 17:50
ravarora2 added a commit that referenced this pull request Nov 6, 2026
Co-authored-by: BuzzPRReviewAssistant1 <a581a7e8115222acdc32ffb14bfce55d48c24478d98e155f8eba126b69b83c7b@buzz.block.builderlab.xyz>

* origin/main: (71 commits)
  test(activity): scope preview assertions to the request row (#2843)
  perf(search): fold people names once across palette keystrokes (#2570)
  fix(github): keep PR watches running when localStorage is full (#2699)
  Make drafts and sent part of Messages (#2728)
  fix(canvas): render every Canvas within the save limit (#2839)
  test(messages): wait for the row measurement frame before thread catch-up dwell (#2837)
  Keep agent coordination history readable after work finishes (#2454)
  test(mentions): serve the mentions fixture as a build so cold loads fit (#2776)
  test(browser): let a late publication land after its page closed (#2565)
  test(relay): wait for the verified owner before a guest edits an agent (#2413)
  test: wait for the companion default width measurement (#2750)
  test(browser): preserve conversation scroll while revealing actions (#2715)
  test(browser): wait for link hit-testing after thread close (#2792)
  perf(messages): skip micromark for plain prose bodies (#2780)
  perf(inbox): load the emoji name table on first use (#2774)
  perf(messages): cut main-thread work while a busy channel is open (#2729)
  Refine agent Attention cards, watch details, and status controls (#2717)
  fix(bestie): remove a Bestie from its agent card on any device (#2720)
  feat(agents): preview Builderlab agent card links with Add to Buzz (#2719)
  Restore macOS Cmd-W window closing when no tab handles it (#2443)
  ...

Signed-off-by: Ravneet Arora <[email protected]>
kalvinnchau added a commit that referenced this pull request Nov 6, 2026
…2726)

This PR combines two changes that cut main-thread work in large
channels. The conversation header no longer re-renders its member
avatars and members button on traffic in other channels, and matching
people by name folds each name once instead of on every keystroke. Both
costs grow with the member count.

## Problem

**Header.** #2626 moved `ChannelMemberAvatars` into every conversation
header through `ChannelHeaderIdentity`. It also gave
`ChannelMembersButton` its own subscription to the whole channel list.
Both components re-render on every list publish, which means every live
message in any channel.

On each of those renders, both components run a `list.channels.find`
over every channel. The avatars also join, filter and sort every member
of the open channel. With a 5,080-member channel open, other channels'
traffic keeps re-rendering a header whose content has not changed.

**Name matching.** Typing in the Manage members filter of a large
channel re-scans every member on every keystroke. #2356 raised the
per-member cost: the filter now checks the verified display name,
username and full name, which is about 3 `matchPerson` calls per member
where v0.7.10 made 1. #2585 added a similar scan of every cached profile
to the New message recipient picker.

For each name it checks, `matchPerson` folds every code point through
`normalize("NFKD")`, an accent regex and `toLowerCase`, and folds the
query again on every call. The filter also bech32-encodes each member's
key on every keystroke to match npubs. In a 5,080-member channel this
adds up to seconds of main-thread work while the user types a short
query.

## Change

**Header.**
- `useHeaderChannel` is a new helper in `listed-channel.ts`. It is
`useListedChannel` plus the existing `channels.get` fallback for
channels the list does not hold. Each header component selects only what
it renders through it: members, the Solo flag, or the access summary.
All of these are referentially stable, so unrelated list publishes skip
the render.
- `memberAccess` returns one of four shared frozen objects instead of a
fresh object.
- `ChannelMemberAvatars` memoizes the member key, the agent map and the
preview.

**Name matching.**
- `foldPoint` handles ASCII with a plain `toLowerCase`. ASCII has no
accents, decompositions or final sigma, so the fold is the same.
- `ChannelMembersDialog` folds the query once per render and matches
each name with `matchTier`, which reuses the folded-name cache #2570
added. It also keeps one npub map for as long as it is open, so each
member's npub is encoded at most once.
- Rebased onto #2570: the earlier per-dialog `folds` map in
`matchPerson` was dropped, because #2570's cache already keeps each name
folded across keystrokes.

## No behavior changes

**Header.** The lookup order is the same as before: the list entry
first, then `channels.get`. A membership change still produces a new
`members` array, so the header updates. Previews and activity reuse the
channel summary's `members`, so they no longer re-render the header.

New tests cover three cases:
- An unrelated list publish commits nothing.
- A membership change updates both the button and the avatars.
- A channel missing from the list renders through the fallback, and
still skips renders on unrelated publishes.

**Name matching.** The ASCII path gives the same fold as before.
`matchTier` gives the same tier as `matchPerson` (the #2570 test checks
this), and an empty query still matches at tier 0.

The npub map is dropped when the dialog closes and holds one entry per
member.

## Evidence

The table compares main (`8c0cb0c1e`) with this PR as a whole. All runs
are interleaved, with the same two builds on both sides.
- **Browser:** production Chromium at 4× CPU throttling with 128 DMs,
1,001 participants, read state and a 5,080-member channel, while another
channel receives a message every 200 ms. **Idle** is 3 s with no input
while the 5k channel is open. **Switch** opens Cmd+K, types the channel
name and presses Enter. **Members dialog** opens Manage members for the
5k channel and types a 6-character query one key at a time; 1,000
members have profiles. Two Linux and two macOS workstations, 36 samples
per cell; values are the mean of the per-workstation medians.
- **Typing latency:** the same app with 5,080 cached member profiles
that share name prefixes, a deliberate worst case. Each value is the
median Event Timing duration from keydown to the next paint, over 6
interleaved pairs on one Linux and one macOS workstation. Event Timing
quantizes to 8 ms and only reports events of 16 ms or more. **Mention**
types `@Member004` in the composer, **palette miss** types `zzzzzz` in
Cmd+K, and **prose** types `ordinarytext`. Each key waits for the next
rendering opportunity before the following key.
- **Header micro-benchmark:** renders the header with 400 channels and
5,080 members, then delivers 50 live messages to another channel.
- **Picker micro-benchmark:** runs the New message recipient picker's
profile scan, typing 6 keys.
- Micro-benchmark cells are the mean of two workstations per OS, each
the median of 6 runs.

| metric | Linux: main | Linux: this PR | Linux Δ % | macOS: main |
macOS: this PR | macOS Δ % |
|---|---|---|---|---|---|---|
| idle 5k, script | 226.0 ms | 182.5 ms | −19.2% | 150.8 ms | 126.7 ms |
−15.9% |
| idle 5k, task | 367.5 ms | 323.1 ms | −12.1% | 266.6 ms | 240.5 ms |
−9.8% |
| switch 5k, script | 580.5 ms | 563.1 ms | −3.0% | 325.5 ms | 312.9 ms
| −3.9% |
| switch 5k, blocking | 279.1 ms | 264.3 ms | −5.3% | 116.8 ms | 115.6
ms | −1.0% (noise) |
| members dialog, script | 3,272.1 ms | 1,834.2 ms | −43.9% | 2,643.0 ms
| 1,173.2 ms | −55.6% |
| members dialog, task | 3,455.5 ms | 2,055.1 ms | −40.5% | 2,863.3 ms |
1,321.1 ms | −53.9% |
| members dialog, blocking | 2,764.1 ms | 1,327.0 ms | −52.0% | 2,039.2
ms | 650.7 ms | −68.1% |
| mention typing, keydown to paint | 448 ms | 200 ms | −55.4% | 272 ms |
112 ms | −58.8% |
| palette miss, keydown to paint | 136 ms | 104 ms | −23.5% | 88 ms | 72
ms | −18.2% |
| prose typing, keydown to paint | 24 ms | 24 ms | 0% | 16 ms | 16 ms |
0% |
| header renders for 50 messages | 50 | 0 | −100% | 50 | 0 | −100% |
| header time for 50 messages | 58.2 ms | 1.5 ms | −97.4% | 32.8 ms |
1.1 ms | −96.6% |
| picker scan, 1,000 profiles | 42.4 ms | 17.3 ms | −59.2% | 24.3 ms |
9.8 ms | −59.5% |
| picker scan, 5,000 profiles | 213.3 ms | 86.8 ms | −59.3% | 119.1 ms |
48.8 ms | −59.0% |
| picker scan, 10,000 profiles | 431.0 ms | 178.0 ms | −58.7% | 240.5 ms
| 98.9 ms | −58.9% |

Lower is better. These numbers were measured with the earlier per-dialog
`folds` map, before the rebase onto #2570. Blocking is
long-animation-frame blocking time. Typing rows have 162 mention keys,
108 palette keys and 216 prose keys per build; one Linux palette key of
this PR had no Event Timing entry, so that cell covers 107 keys. The
browser harness runs the built frontend with modeled HTTP, not the
native app.

**Larger rosters.** A standalone Node bench of the whole member
predicate over a typing session takes 0.22–0.40× of the old time. It
covers 5k, 9k, 20k and 50k members, with and without names. The first
keystroke after the dialog opens pays the one-time fold and encode: on
large rosters without names it is up to about 1.2× the old cost, and
later keystrokes are 10× faster or more.

Checks:
- The channels, search, mentions, direct-messages and channel-members
unit suites pass.
- `tsc` and `biome` pass.
- After the rebase: the search and channels suites pass (1,163 tests).

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

---------

Signed-off-by: Kalvin Chau <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
tlongwell-block added a commit that referenced this pull request Nov 6, 2026
* origin/main:
  fix(sidebar): rename Remove from Team to Close conversation (#2845)
  perf(channels): cut header and name-matching work in large channels (#2726)
  fix(browser): silence a browser page once its tab goes away (#2721)
  Community Mesh: shared compute plugin (including agent type) (#941)
  perf(relay): cut main-thread work from profile updates (#2730)
  fix(composer): lead the channel placeholder with its sidebar icon (#2829)
  test(activity): scope preview assertions to the request row (#2843)
  perf(search): fold people names once across palette keystrokes (#2570)
  fix(github): keep PR watches running when localStorage is full (#2699)
  Make drafts and sent part of Messages (#2728)
  fix(canvas): render every Canvas within the save limit (#2839)

Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Co-authored-by: Tyler Longwell <[email protected]>
Signed-off-by: Tyler Longwell <[email protected]>
wpfleger96 added a commit that referenced this pull request Nov 6, 2026
…leanup

* origin/main:
  feat(agents): let app-hosted agents read their owner's channels and members (#2745)
  NEXUS-4271: Expose installed plugin status (#2754)
  fix(menu): stop clipping lifecycle actions behind a hidden scrollbar (#2716)
  feat(agents): give approved external apps the selected agent's full Buzz tools (#2707)
  AIDA-2549: Keep Claude settings drafts in sync (#2841)
  fix(channels): keep a channel's side panels open when returning to it (#2838)
  fix(builderlab): clarify remote-agent account availability (#2764)
  fix(sidebar): rename Remove from Team to Close conversation (#2845)
  perf(channels): cut header and name-matching work in large channels (#2726)
  fix(browser): silence a browser page once its tab goes away (#2721)
  Community Mesh: shared compute plugin (including agent type) (#941)
  perf(relay): cut main-thread work from profile updates (#2730)
  fix(composer): lead the channel placeholder with its sidebar icon (#2829)
  test(activity): scope preview assertions to the request row (#2843)
  perf(search): fold people names once across palette keystrokes (#2570)
  fix(github): keep PR watches running when localStorage is full (#2699)
  Make drafts and sent part of Messages (#2728)
  fix(canvas): render every Canvas within the save limit (#2839)

# Conflicts:
#	.github/workflows/release.yml
cheng-block added a commit to cheng-block/buzz-app that referenced this pull request Nov 6, 2026
…ime-hint

* upstream/main:
  ci: give the native job room for a cold Rust cache (block#2867)
  fix(pairing): refuse unknown communities natively and name the requesting process (block#2835)
  Add per-interest Attention pause and management controls (block#2847)
  feat(drafts): show where unsent drafts wait (block#2853)
  feat(agents): let app-hosted agents read their owner's channels and members (block#2745)
  NEXUS-4271: Expose installed plugin status (block#2754)
  fix(menu): stop clipping lifecycle actions behind a hidden scrollbar (block#2716)
  feat(agents): give approved external apps the selected agent's full Buzz tools (block#2707)
  AIDA-2549: Keep Claude settings drafts in sync (block#2841)
  fix(channels): keep a channel's side panels open when returning to it (block#2838)
  fix(builderlab): clarify remote-agent account availability (block#2764)
  fix(sidebar): rename Remove from Team to Close conversation (block#2845)
  perf(channels): cut header and name-matching work in large channels (block#2726)
  fix(browser): silence a browser page once its tab goes away (block#2721)
  Community Mesh: shared compute plugin (including agent type) (block#941)
  perf(relay): cut main-thread work from profile updates (block#2730)
  fix(composer): lead the channel placeholder with its sidebar icon (block#2829)
  test(activity): scope preview assertions to the request row (block#2843)
  perf(search): fold people names once across palette keystrokes (block#2570)
  fix(github): keep PR watches running when localStorage is full (block#2699)

Signed-off-by: Cheng Peng <[email protected]>
Co-authored-by: Cursor <[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.

3 participants