Skip to content

perf(desktop): share quick-reaction preparation per app session - #7199

Open
wesbillman wants to merge 2 commits into
mainfrom
carl/shared-quick-reactions
Open

perf(desktop): share quick-reaction preparation per app session#7199
wesbillman wants to merge 2 commits into
mainfrom
carl/shared-quick-reactions

Conversation

@wesbillman

@wesbillman wesbillman commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Prepare the three-item quick-reaction tray once per mounted app/community session instead of once per message action bar. Rows consume one content-stable snapshot of resolved emoji and image URLs.

  • Replace the per-row custom-emoji query observers, palette sorting, URL lookup and storage listeners with QuickReactionProvider below the existing keyed community/identity boundary. Remove the old module-global tray cache rather than adding another cache layer.
  • Preserve community-only persistence keys, frozen same-window ranking, external-window storage refresh, unavailable-shortcode/default backfill and URL-only palette updates. A keyed community/identity remount reads persisted recents afresh. Timeline, Home Inbox and the separate Huddle app root inherit the provider through AppReady.
  • Keep the recorder external to provider state and leave reaction handlers, keyboard/pointer behavior, layout and markup unchanged. No Shiki, video classification, media loading, virtualizer or read-state changes.

Related issue

N/A. Search for "quick reaction" found no duplicate of this preparation-sharing change. Closest existing work: #6892 (restored message quick reactions) and #6263 (restored emoji recents).

Testing

Verified at clean commit 4826fd35f20bcd9cdffbd4c2f0df98be09227d68:

  • Normal pre-commit formatting and pre-push gates passed: desktop lint/style guards, TypeScript, differential file-size check and all 5,888 desktop tests. Hooks remained enabled.
  • pnpm test:e2e:smoke quick-reaction-sharing.spec.ts reaction-order.spec.ts inbox-reactions.spec.ts custom-emoji-ui.spec.ts: E2E build and 7 browser cases passed, using this worktree's mock bridge, Chromium and isolated test server.
  • Seven new real-provider/JSDOM cases exercise the production query/provider/recorder: 1→64 consumers, content-identical snapshot reuse, frozen ranking through new mounts and palette changes, matching/other-community storage events, key removal, missing/duplicate/case-insensitive shortcodes, URL updates, keyed identity/community cleanup, legacy null scope and malformed/denied storage. The actual-app browser regression catches missing provider wiring and exercises custom tray buttons, keyboard activation, channel remounts, URL updates and refresh across mounted trays.

Performance evidence and limits: with a 128-emoji fixture, increasing provider consumers from 1 to 64 adds zero palette reads and retains exactly one quick-tray query observer, one storage listener and one shared snapshot. This is deterministic evidence that repeated preparation was removed, not an end-to-end latency benchmark. Other emoji consumers still have their own observers. Native WKWebView cold/warm channel-switch latency, scroll stability and composer responsiveness have not been measured for this branch. Huddle coverage is source/lifetime review, not a native companion-window run.

No intended visual change, so no before/after screenshot comparison. Independent production review found no blocking issue. Full repository-wide just ci was not rerun locally; applicable hook gates and the browser checks above were run, with broader validation left to CI.

Follow-ups deliberately excluded

Video-attachment classification and viewport-based image warming remain separate slices. No claim that quick reactions account for the reported multi-second channel-switch delay.

Implemented by Carl with provider regression tests by Princess Donut, AI agents. Submitted via Wes's GitHub account.

Review follow-up

Commit 827813f2ace0b2b16aaf452db8a220cc4d97e0fc adds a production-bound sharing regression with real MessageActionBars. Across 1→16→16→1→16 bars, it checks actual custom quick buttons, one palette query observer, one storage listener and no additional palette reads. Restoring either a per-row query hook or storage listener fails the new test with 17 versus 1; both mutations were removed. Full desktop suite at this clean head: 5,889/5,889 passed, with normal pre-commit/pre-push gates. Production code is unchanged from the originally tested head above.

Replace per-action-bar palette preparation, query observers and storage
listeners with one content-stable tray snapshot below the keyed community
and identity boundary. Preserve community-scoped recents, frozen session
ranking, external storage refresh and custom emoji availability/URL updates.

Cover shared preparation and lifetime behavior with real-provider tests and
the production action bars with a mock-bridge browser regression.

Co-authored-by: Princess Donut <5d97ac8c272fa949af56c71e586146b1706e5c4c3daa125db5b4625e12e0686c@buzz.block.builderlab.xyz>
Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
@wesbillman
wesbillman requested a review from a team as a code owner September 1, 2026 18:10
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is 4365883151698cd30e31cf4091629543b61c2478...827813f2ace0b2b16aaf452db8a220cc4d97e0fc.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 827813f2ace0b2b16aaf452db8a220cc4d97e0fc to authorize a new review.
Any previous review applies only to its recorded range.

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

:bot: Jude’s code review agent — REQUEST CHANGES on exact head 4826fd35f20bcd9cdffbd4c2f0df98be09227d68 against base e17a0d44c379b2ae40b91b8ba43f9a9c5bede90f.

P2 — the per-row observer regression is not causally protected

desktop/src/features/messages/ui/QuickReactionProvider.test.mjs:113-147,207-240 mounts test-only Consumer nodes beneath the provider. This verifies that the provider owns one query observer and storage listener, but it never mounts MessageActionBar, the production row seam from which the observer was removed (desktop/src/features/messages/ui/MessageActionBar.tsx:416-419 in this head's source numbering).

A compiling mutation restored a per-row useCustomEmojiQuery() call in MessageActionBar while retaining the provider. The full Desktop suite still passed 5,888/5,888. That mutation recreates the optimization's core regression—one query observer per mounted action bar—without failing any new test. The current deterministic 1→64 claim therefore applies only to synthetic context consumers. This conflicts with the repository's explicit falsifiability/production-seam requirement in TESTING.md:25-31 and AGENTS.md:188-192.

Author action: add a production-bound regression assertion that mounts multiple real MessageActionBars (or observes the E2E query cache after multiple real action bars mount) and requires the customEmojiQueryKey observer count to remain exactly one. Demonstrate that restoring the per-row observer fails the test, then restore the production code and prove the full Desktop suite green. Bind the storage-listener count to production action bars too if that sharing claim remains part of the protected contract.

Verification owner: review will rerun the mutation and full Desktop suite on the next immutable head.

Integrated review

No implementation or product/accessibility defect was found beyond this test defect:

  • The provider sits below CommunityQueryProvider and inside keyed AppReady; community, reinitialization, pubkey, and signer-epoch changes destroy its observer/listener. The separate Huddle React root receives one provider in its own webview.
  • Cleanup is symmetric, the snapshot changes identity only when rendered emoji/URL content changes, same-window ranking remains frozen, matching external storage events refresh ranking, unavailable custom emoji backfill defaults, and custom URL updates propagate.
  • Existing quick-button markup, labels, styling, and keyboard/pointer/focus handlers are unchanged. The no-intended-visual-change claim is credible.
  • A separate mutation removing the production provider wrapper was killed by quick-reaction-sharing.spec.ts, so actual-app wiring is protected; it does not catch reintroducing work inside each row.

Exact-head evidence: clean full Desktop suite 5,888 passed, pnpm typecheck passed, git diff --check clean, and focused quick-reaction E2E passed. CI was still running Desktop Core/smoke/integration jobs at the final freshness check; completed applicable jobs were green. Missing native WKWebView timing/scroll measurements and a native Huddle companion-window run remain explicitly scoped confidence gaps, not author defects.

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

🤖 Automated review — request changes at head 4826fd35f20bcd9cdffbd4c2f0df98be09227d68 (base e17a0d44c379b2ae40b91b8ba43f9a9c5bede90f).

IMPORTANT — the per-row sharing contract is not bound to the production seam

The optimization's core guarantee — one custom-emoji query observer and one storage listener regardless of mounted action bars — is only asserted against synthetic consumers. QuickReactionProvider.test.mjs mounts a test-only Consumer under the provider for its getObserversCount() assertions (lines 233, 245, 344-355), and quick-reaction-sharing.spec.ts:113-119 checks rendered tray contents across real action bars but never asserts observer or listener counts. Neither new test file references MessageActionBar, the seam this PR removed the per-row useCustomEmojiQuery() call from (MessageActionBar.tsx:419).

Consequence: reintroducing a per-row observer in MessageActionBar compiles and leaves every new test green — the O(mounted rows) preparation this PR removes can silently return. That violates the repo's explicit rule that regression tests must bind the production seam and be falsifiable (TESTING.md:25-31, AGENTS.md Review-Proven Rules #3).

Fix: assert the invariant across multiple mounted real MessageActionBar instances — either a component test mounting several action bars under the provider, or extend the existing E2E via __BUZZ_E2E_QUERY_CLIENT__ to require exactly one customEmojiQueryKey observer (and one storage listener, if that remains part of the protected claim) after multiple trays are mounted. Demonstrate the test fails when a per-row observer is restored.

Three independent assessments converged on this as the sole blocker, including the existing exact-head review with mutation evidence (a restored per-row observer survived the full 5,888-test Desktop suite).

Otherwise clear

No source-level defect found in the implementation itself: the provider sits inside both the community-keyed query boundary and keyed AppReady (App.tsx:643-648), so community/identity/signer-epoch changes tear down the single observer and listener; community-scoped persistence keys, frozen same-window ranking, matching-key external storage refresh, unavailable-shortcode backfill, and URL-only palette propagation are all preserved; snapshot identity changes only with rendered content; the Huddle root inherits its own provider instance. Removing the old module-global session cache rather than layering another cache is the right shape.

CI at review time

Desktop Smoke E2E (2) is red at this head: the hard failure is empty-edit-delete.spec.ts:74 (delete-confirmation alertdialog never appeared; 3/3 attempts), with empty-edit-delete.spec.ts:51 and a file-attachment case flaky-passed. The failing assertion is in the composer-owned delete-confirmation flow this diff does not modify, and the flow passes through the PR-touched action-bar menu successfully before failing — evidence points away from this change, but the shard is required and Desktop Core was still pending, so a green run at this head (or a rerun proving flake) is still needed alongside the fix above.

Mount the production MessageActionBar with its real query/provider/tooltip tree and assert rendered quick buttons, constant palette reads, one query observer and one storage listener across row growth, rerender and remount. Verify teardown releases both resources.

Mutation checks restoring per-row query hooks or storage listeners each fail at 17 resources versus the required one. No production behavior changes.

Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
@wesbillman

Copy link
Copy Markdown
Collaborator Author

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

Addressed the shared production-seam finding from both reviews in 827813f2ace0b2b16aaf452db8a220cc4d97e0fc. This commit changes only QuickReactionProvider.test.mjs; production code and intended behavior are unchanged.

The added case mounts real MessageActionBars under the real query/provider/tooltip tree with reaction callbacks enabled. It asserts real trays and three quick buttons, including the custom image, across 1 → 16 → 16 → 1 → 16 mounted bars. It requires exactly one palette-query observer, one storage listener and no additional palette reads, then verifies both resources are released on teardown. Query fetching is disabled, not the query hook/observer. The picker stays closed because its independently mounted query is outside the quick-tray contract.

Mutation evidence on this immutable head:

  • Restoring useCustomEmojiQuery() inside MessageActionBar fails the new case: real rows must not add palette observers, 17 !== 1.
  • Restoring a per-action-bar storage effect fails the new case: real rows must not add storage listeners, 17 !== 1.
  • Both mutations were restored byte-for-byte; the working tree is clean. Each mutation run fails only the new production-bound case while the seven pre-existing provider cases pass.

Validation at clean 827813f2a: the normal pre-push hook ran the full desktop suite, 5,889/5,889 passed, plus desktop checks, TypeScript and file-size/branch checks. Pre-commit formatting also passed. Independent source review confirmed this is the appropriate production seam. The seven browser cases previously reported remain evidence for 4826fd35f; no browser rerun or native timing claim is being attributed to the test-only follow-up.

The earlier review-reported delete-dialog smoke failure is not changed or claimed fixed by this commit. CI and reviewer verification remain external gates.

@jedwards27 @wpfleger96 Ready for the bounded re-review/mutation verification requested in your reviews.

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

:bot: Jude’s code review agent — APPROVE at exact head 827813f2ace0b2b16aaf452db8a220cc4d97e0fc (base e17a0d44c379b2ae40b91b8ba43f9a9c5bede90f).

The changed-head fix closes the prior causal-coverage defect. The new regression mounts real MessageActionBar rows under the real query/provider/tooltip infrastructure and proves the shared preparation remains bounded through 1→16→16→1→16 row transitions.

Mutation evidence:

  • Reintroducing a per-row useCustomEmojiQuery() observer fails the focused test with 17 !== 1.
  • Reintroducing a per-row storage listener fails it with 17 !== 1.
  • Restoring production source returns the focused suite to green, with a clean tree at the reviewed SHA.

The product/UI lane found no behavior or accessibility regression: real quick buttons and custom emoji render through the production action bar, provider wiring/remount behavior remains correct, and the unchanged callback path was exercised through focused browser journeys. Keeping the picker closed is appropriate because it owns an independent legitimate observer outside the quick-tray sharing invariant.

Exact-head evidence: Desktop package suite 5,889/5,889 passed; typecheck, check, build, focused provider tests, and selected browser journeys passed. Live head still matches the reviewed SHA. At submission, all completed applicable CI checks were green; Desktop Smoke E2E (4) remained in progress.

Residual confidence gaps, not author defects: no native WKWebView timing/scroll measurement, no native Huddle companion-window run, and the reviewer’s capped just ci invocation did not complete although no failure was observed. The exact affected package suite and mutation evidence are complete.

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

:bot: Jude’s code review agent — APPROVE on exact head 827813f2ace0b2b16aaf452db8a220cc4d97e0fc against base e17a0d44c379b2ae40b91b8ba43f9a9c5bede90f.

The prior production-seam test defect is resolved. The changed-head delta is confined to QuickReactionProvider.test.mjs; it now mounts real MessageActionBar instances under the real query/provider/tooltip tree and asserts actual three-button trays, custom emoji image resolution, one palette observer, one storage listener, stable palette-read count across 1 → 16 → 16 → 1 → 16 rows, and zero resources after unmount.

Independent mutation verification killed both targeted regressions:

  • restoring per-row useCustomEmojiQuery() fails real rows must not add palette observers with 17 !== 1;
  • restoring a per-row storage effect fails real rows must not add storage listeners with 17 !== 1.

Both mutations were restored and the exact-head tree was clean. Query fetching is disabled only in the test client's defaults; the production hook and React Query observer are real, and the seeded cache plus palette getter assertions exercise preparation. Keeping the picker closed is correct because its independently mounted observer is outside the quick-tray sharing contract.

No product/UI/accessibility or implementation defect was found. The production handler is unchanged, and exact-head browser validation exercised quick-button callbacks/persistence, custom image propagation, channel remounts, storage refresh, inbox reactions, and picker ordering.

Validation at matching HEAD:

  • full Desktop suite: 5,889/5,889 passed;
  • pnpm typecheck, pnpm check, and pnpm build: passed;
  • production-bound component suite: 8/8 passed;
  • focused smoke E2E: 7/7 passed in the UI lane and 1/1 passed in the systems lane;
  • completed CI checks are green. A rerun of the previously unrelated Desktop Smoke E2E shard remained in progress at final freshness check, so CI owns that confidence gap rather than the author.

No native WKWebView timing/scroll measurement or native Huddle companion-window run was obtained; those remain explicitly scoped confidence gaps, not defects.

Author action: none.

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

🤖 Automated re-review — clear at head 827813f2ace0b2b16aaf452db8a220cc4d97e0fc (base e17a0d44c379b2ae40b91b8ba43f9a9c5bede90f).

Prior blocker resolved

The previous round's IMPORTANT finding (review 5081711599 — sharing guarantee asserted only against synthetic consumers) is closed by the delta commit 827813f2 (test(desktop): bind quick-tray sharing to real action bars, QuickReactionProvider.test.mjs only, +99/−7):

  • The new case mounts the real production MessageActionBar under the real QueryClientProvider → QuickReactionProvider → TooltipProvider tree and proves the production component rendered via its data-testid, three quick buttons, and the seeded custom-emoji image — the exact seam the per-row observer was removed from.
  • The guard is falsifiable at both seams: with 16 mounted real bars it requires exactly one customEmojiQueryKey observer and exactly one storage listener on the same query client — a reintroduced per-row useCustomEmojiQuery() or storage effect fails at 17 vs 1. Instrumented shortcode getters additionally require zero further palette reads across row growth, rerender, and remount, so restored per-row preparation is caught causally, not incidentally. Teardown must return both counts to zero.
  • No weakening and no smuggled production change: the seven prior provider cases are intact (the only structural change on their path is a transparent Fragment wrapper), and the two-commit branch still contains no other production edit.

Two independent review lanes converged on this assessment.

CI

All checks green at this head, including Desktop Smoke E2E (2) — the shard that was red at the prior head in untouched empty-edit-delete.spec.ts cases now passes, confirming that failure was unrelated to this change. The new production-seam regression executes in Desktop Core at this head.

Prior-round non-findings re-verified and unchanged: provider lifetime under the keyed community/identity boundary, community-scoped persistence, frozen same-window ranking, external storage refresh, backfill and URL-only palette propagation, Huddle-root inheritance.

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