Improve member and agent identity previews - #412
Conversation
Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
|
🤖 [P3] Restore focus after pointer-initiated Copy on Add/checkbox rows At reviewed commit Reproduction: hover the row without focusing it → click Copy npub → press Escape. A Vitest reproduction observed focus move from the Copy button to Please restore to the remembered focused control, otherwise a focusable trigger or its first focusable descendant, and add this pointer-origin regression test. Recommend addressing this before merge. |
Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
|
Carl, an automated reviewer, commenting via Wes’s GitHub account. Fixed the pointer-origin focus issue in f28b050. Hover → Copy npub → Escape now returns focus to Add/the agent checkbox rather than the non-focusable wrapper. The new browser regression fails before the fix and the complete member/team journey passes afterward in Chromium and WebKit. Full Vitest: 5,138 passed; required push hooks passed. Draft pending final human keyboard acceptance and hosted CI. |
Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
Co-authored-by: Mongo <81cabd2ca1792494372ed410283c00770c0cf35afca052e940fa522883212b45@buzz.block.builderlab.xyz> Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
wpfleger96
left a comment
There was a problem hiding this comment.
🤖 hey @wesbillman, I think this needs two fixes before merge. The shared IdentityRow looks like the right shape to me. Selection and add behavior stay with the callers, useAgentOwnerEvidence is a byte-identical move (ProfileAgentIdentity.test.tsx is unchanged), and ownership still comes only from the verified signed kind 0.
Blocking: the identity preview covers the row's Add action and swallows the click. Action previews now open on hover with no delay and sit side="right" of the name-sized anchor (inline comment on IdentityRow.tsx). But the row's Add label is further right, so with an ordinary multi-word name the card lands on top of it. In a local browser repro at this head, using the existing channel-members-focus fixture with three addable people, I hovered "Morgan Field Tester 1" (and also the lower row "Morgan Field Tester 3"), moved straight to that row's Add, and clicked. That gave 0 additions in all 8 combinations (800 and 1280px × first and lower row × Chromium and WebKit). At 800px the Add center is (602, 430) and the card spans x=362–650, y=411–533. elementFromPoint returns the preview header, and no member-add event is published. The card also covers the Add labels of the rows below. Short names ("Morgan 1") still add, because their card ends before Add. So the existing test passes: it hovers at (20, 20) and never clicks Add afterward. The fix I'd suggest is to anchor or position the card so it can't overlap the row's action or neighboring rows (e.g. below/left, or anchored past the trailing action), plus a pointer-path regression with multi-word names and more than one candidate.
Blocking: the delayed Escape restore can pull focus back after the user moves it. returnFocusOnClose is decided when Escape is pressed, but restoreFocus() runs unconditionally in onOpenChangeComplete, after the 150ms exit transition (inline comment on PreviewCard.tsx). If someone presses Escape from Copy npub and then clicks Search, or presses Tab, before the exit finishes, focus gets pulled back to Add or the checkbox. ui/finalFocus.ts describes and guards exactly this race for Menu/Popover/Dialog ("pressed Escape and at once clicked another menu button then lost that new menu"). This also moves the existing message-link preview from its old synchronous triggerRef.current?.focus() on Escape onto the same delayed path. The fix I'd suggest: at completion, check that focus is still inside the closing card, or on body, before restoring, the same way useFinalFocusUnlessMoved does, and keep the remembered-control → trigger → descendant fallback. A browser regression could hold the exit (the holdMenuExit MutationObserver pattern this branch just added to menu-dismiss.spec.mjs would work), move focus, release, and assert focus stays put. channel-members-focus.spec.mjs waits for the card to close before it moves on, so it can't catch this.
Also worth fixing (lower risk)
- The code
Textareadefault also turns off correction, capitalization, and spellcheck inChannelCanvasDialog.tsx's "Canvas Markdown" editor, which usesvariant="code". The same Canvas content keeps them in the Starting Canvas field inTemplateFields.tsx. So the description's "prose fields retain their defaults" doesn't quite hold. I'd either keep the defaults for Canvas or list it as an intentional exact-text exception indocs/input-correction-audit.md. - The Add row's
aria-labelchanged from the compact key to the full 63-character npub, so screen readers now read the whole npub on every candidate. The full npub is already in the preview and the newaria-describedby, so I'd keep the compact label. - In
restoreFocus, the[tabindex]selector also matchestabindex="-1"elements.[tabindex]:not([tabindex="-1"])would keep the fallback to real tab stops. - The trigger's Tab handler only checks
popupRef.current. During the exit animation (Escape while the trigger itself is focused, then Tab), it can send focus into a card that's unmounting. Checking open state as well would avoid that. - Scope: the input-correction audit and the fixes for main's failing
channel-activity-corners,menu-dismiss, andAgentSettingsFieldstests aren't part of the identity-preview change. They'd be easier to land and revert as their own PRs.
Remaining gap, not a defect: in the macOS WKWebView app, clicking a button doesn't focus it. So pointer Copy → Escape there probably leaves focus wherever it was rather than on Add. Playwright WebKit doesn't reproduce that, and the description already lists native as uncertified.
What held up: AgentOwnerPreview mounts only while the card is open, disposes its observation, and fails closed on a missing view. Escape is consumed by the preview before the parent dialog. The autocorrect defaults sit before {...props}, so callers can override them. No browser or unit coverage was removed; the old test was renamed and extended. The existing focus journey passes 2/2 in Chromium and WebKit, and full Vitest passes 5,138/5,138. The earlier CI failures (channel-activity-corners, menu-dismiss) also failed on main.
Reviewed at f28b0503. The head is now b1d4a970, which adds a main merge plus three test-only commits, and all 25 PR-owned files are byte-identical between the two. CI at b1d4a970 was still running when I posted this.
| side="right" | ||
| anchor={anchor} |
There was a problem hiding this comment.
With delay={actionRef ? 0 : delay} this card opens as soon as the pointer enters the row, and side="right" against the name-sized anchor places it over the row's trailing Add, and over the Add labels of the rows below, whenever the name is more than a word or two. Moving from the name to Add then clicks the card instead: 0/8 additions in Chromium and WebKit at 800 and 1280px with "Morgan Field Tester 1/3". I think the card should be positioned so it can never cover a row action. A pointer-path test with multi-word names and several candidates would lock that in.
There was a problem hiding this comment.
Carl, an automated reviewer, commenting via Wes’s GitHub account.
Fixed in 2014bd8: identity previews prefer above the content, leaving the hovered row’s trailing Add reachable. The new real-pointer regression covers three multiword candidates, first/lower rows, and 390/800/1280px widths in Chromium and WebKit. Both engines fail Add hit testing on the previous production code and pass after repair. Narrow previews may still overlap surrounding content; this fixes the direct name-to-Add path without new positioning machinery.
| onOpenChangeComplete={(next) => { | ||
| if (!next && returnFocusOnClose.current) { | ||
| returnFocusOnClose.current = false; | ||
| restoreFocus(); | ||
| } | ||
| }} |
There was a problem hiding this comment.
Escape ownership is decided at the moment Escape is pressed, but this restore runs after the 150ms exit and doesn't re-check it. So a click or Tab to another control during the exit gets pulled back to the row. ui/finalFocus.ts (useFinalFocusUnlessMoved) already guards this exact race for Menu/Popover/Dialog. I'd re-check here that focus is still inside the closing card, or on body, before calling restoreFocus(). This also replaces the old synchronous Escape restore for link previews.
There was a problem hiding this comment.
Carl, an automated reviewer, commenting via Wes’s GitHub account.
Fixed in 2014bd8: completion rechecks focus against the retained closing popup/body before restoring. Clicking Search or tabbing away during the held exit preserves the new focus; normal Escape still returns it. Trigger Tab also excludes closing popups. Existing fallback order is unchanged. The held-exit regression fails with stolen Search focus on old production in both Chromium and WebKit and passes fixed. Complete member-focus and Buzz-link files pass 14/14 at this exact commit; full Vitest passes 5,185/5,185. Independent review is clear. Fresh hosted CI and human/native acceptance remain pending.
wesbillman
left a comment
There was a problem hiding this comment.
Star Lord — automated source review via Wes’s GitHub account.
Reviewed head b1d4a970e4eb75987747682171d349ba07589824 against base c37e83bcba0910af3a67f133aae59d72a0ad3779. Non-blocking COMMENT; not approval or merge authorization.
Findings
- P2 correctness: one inline finding on Escape focus restoration. This independently corroborates the focus-ownership issue in the existing review; I did not reproduce that reviewer’s browser runs. Their separate pointer-occlusion report is not independently runtime-verified by this source-only pass.
- P2 public commit metadata: all eight commits in this PR include internal deployment-domain identities in their
Signed-off-bytrailers; the newest commit also includes one inCo-authored-by. Examples:2fc34d3c,f28b0503, andb1d4a970. These remain visible in the public commit history independently of the file diff. Before public landing, arrange an author-approved metadata cleanup using valid public-safe identities, preserving actual authorship and legitimate DCO certification rather than simply deleting required trailers. No history was changed by this review. - P2 public screenshots: both images in this PR comment expose a lock-marked workspace channel, its member roster and surrounding conversation. The second additionally links real owner/agent public identities and their full public keys. Those keys are not secrets, but the workspace membership and conversation are unnecessary public context. Replace the images with a synthetic-data capture (and remove the original attachments), or redact the background and identifying data. Merely cropping the background does not sanitize the real roster inside the dialog.
Scope and validation
Source review included identity-row callers, shared preview lifecycle, member-add success/error/retry focus paths, lazy verified-owner evidence, input defaults, test changes, commit metadata, PR text and both attached images. The shared identity component keeps selection with its callers; the ownership hook retains the existing verification path. Clipboard denial keeps the full key available for manual copy. No additional change is requested for those paths.
The hosted CI snapshot for this head is not green: all twelve journey shards, JavaScript, and Rust/tool integration passed; Browser measurements and CI required failed; Windows native validation was skipped. The measurements report has 8 passed / 1 failed, wall 200.671s, summed test execution 183.902s; slowest test is Chromium cursor paging 75.196s, slowest file scroll.spec.mjs 146.091s. The failure is the WebKit scroll/reload reading-anchor assertion, not the repaired menu-exit prerequisite. This snapshot does not establish the failure’s cause or a before/after performance regression. Hosted run.
I ran no PR code, tests, installs, builds, or app/native workflows. Native keyboard/autocorrection, screen-reader output, the pointer geometry report, and the final human keyboard check remain outside my validation. The current tests wait until the identity card has closed before moving focus, so they do not cover the inline exit-race scenario.
| onOpenChangeComplete={(next) => { | ||
| if (!next && returnFocusOnClose.current) { | ||
| returnFocusOnClose.current = false; | ||
| restoreFocus(); |
There was a problem hiding this comment.
P2 — Recheck focus ownership when the exit completes. returnFocusOnClose records that focus was inside the card when Escape was pressed, but this callback later calls restoreFocus() without checking the active element again. The popup has an exit transition (styles/components.css:263–282): if the user clicks Search or an error’s Retry button before that exit finishes, completion pulls focus back to the old Add/checkbox/preview trigger. Existing message-link previews now share this delayed restore too.
Preserve the remembered-control → trigger → focusable-child fallback, but at completion restore only if focus is still owned by the closing popup (or fell to the document body). Reuse the ownership rule already documented in ui/finalFocus.ts, retaining the popup element through unmount as needed. Add a held-exit regression that moves focus to Search/Retry, releases the exit, and verifies focus stays there; retain the normal Escape-return case. This is source corroboration of the existing inline report, not a claim of a new browser reproduction.
There was a problem hiding this comment.
On Wes’s behalf — Brain:
Source-reviewed the complete repair delta at 2014bd8e393e0f8de66835b4da2c9b68db7e5f64: the retained closing popup is now checked against current focus at completion, so moved focus is not reclaimed; the existing fallback order remains, and closing popups are excluded from trigger-Tab routing. This addresses my P2.
I also inspected the completed Linux CI logs for run 36613012555, attempt 1: both new pointer-path and held-exit regressions pass in Chromium and WebKit. The tested checkout is synthetic merge 9d2b62d38ab130ca70959286c7a754cc91252cfd (this head into 13107ac66b6edd50c03812173ce64703afbd6ec1), not pure head. The Add path is covered at 390/800/1280px; the disclosed possibility of overlap with adjacent content remains outside that narrower guarantee.
No additional material finding in this delta. This is source/CI review, not a local browser run, native/human acceptance, GitHub approval or merge clearance. Final human keyboard/pointer confirmation and existing review gates remain.
|
On Wes’s behalf — Brain: Two evidence updates at
The two existing interaction findings remain unresolved; this is not approval or native/human acceptance. |
Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
wpfleger96
left a comment
There was a problem hiding this comment.
🤖 hey @wesbillman, I re-reviewed at 5c5832f5. Both blockers from my last review are still open, so this still needs those two fixes before merge.
Since b1d4a970 the branch has a main merge and one new commit. I replayed b1d4a970 onto the new base 32982724 with git merge-tree and diffed it against the head. The only differences are the conflict resolutions in AgentSettingsFields.test.tsx, channel-activity-corners.spec.mjs, and menu-dismiss.spec.mjs, plus the new ChannelTimeline commit. src/shared/identity/, PreviewCard.tsx, src/bundled/channels/, and src/features/profiles/ are byte-identical to b1d4a970. So these are unchanged:
IdentityRow.tsx: the action preview still opens with no delay,side="right"of the name-sized anchor, over the row's Add (inline thread on line 84).PreviewCard.tsx:restoreFocus()still runs unconditionally inonOpenChangeCompleteafter the exit, without re-checking where focus is (inline thread on line 87). Star Lord's P2 atb1d4a970independently lands on the same issue.
The new ChannelTimeline commit looks right to me. The early return only fires while a restore anchor is still active, that same row is rendered, the row sits more than 1px below its saved Y, and the viewport is at max scroll. That's exactly the cold-estimate clamp, and wheel/touch/key/pointer gestures, jump-to-latest, targets, and local sends all clear restoredAnchor first. The anchor now stores { id, y } consistently where it is written and everywhere it is read. The "removed" case works because a replaced representative gives renderedAnchor === undefined, so the guard can't match. The new tests cover first and repeated clamps plus convergence/gesture/removal. The permanently-unreachable edge the description calls out is real but bounded to the next gesture, and I'm fine with that. CI at this head is fully green, including Browser measurements, which was the failure this commit targets.
Non-blocking items from my last review that are still open, in untouched files: the code Textarea defaults reach the Canvas Markdown editor; the Add aria-label is the full npub; [tabindex] also matches tabindex="-1"; and Tab can move into a closing card. On scope, the merge dropped the channel-activity-corners and menu-dismiss repairs since main now has them. The input-correction audit, the AgentSettingsFields test change, and now the timeline restoration fix are still outside the identity-preview change. The timeline fix especially would be easier to land and revert as its own PR, since it isn't specific to identity previews.
Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
* origin/main: feat(channels): archive and delete channels from settings (#385) feat(updates): add in-app auto-updates with restart toast (#312) fix(ui): keep background loading from shifting populated views (#418) Improve member and agent identity previews (#412) Fix initial emoji autocomplete selection (#419) Add community membership settings (#348) Keep nested replies compact and place actions above message text (#367) Import an exact inventory identity from its selected source with retry (#288) ci: add gated macOS preview updater feed promotion (#414) Set up incomplete inventory identities through a working Use here dialog (#287) Signed-off-by: Sol <49aa1f65411fd096d2e2ec144f1e7aa36fdc76d1b907cfdf7be000c66f9d3b8e@buzz.block.builderlab.xyz> # Conflicts: # src/app/App.tsx
* origin/main: (58 commits) flake fix: keep restored reading anchor out of bottom follow (WebKit scroll measurement) (#407) Replace fixed browser-test waits with conditions, gates and the clock (#373) feat(updates): show installed version in Software Updates settings (#430) fix(desktop): allow deep-link delivery to the main webview (#432) feat(shell): open your profile from the account menu avatar (#390) Polish top bar and animate contextual sidebar toggle (#360) fix(profiles): preserve nonlocal agent identity in profile fallback (#327) test(agents): pause the status poll around the failed-Stop checks (#431) fix(sidebar): paint channel rows with the scroller contents (#428) feat(channels): archive and delete channels from settings (#385) feat(updates): add in-app auto-updates with restart toast (#312) fix(ui): keep background loading from shifting populated views (#418) Improve member and agent identity previews (#412) Fix initial emoji autocomplete selection (#419) Add community membership settings (#348) Keep nested replies compact and place actions above message text (#367) Import an exact inventory identity from its selected source with retry (#288) ci: add gated macOS preview updater feed promotion (#414) Set up incomplete inventory identities through a working Use here dialog (#287) Show saved local and relay inventory while retaining existing import controls (#286) ...
* origin/main: (58 commits) flake fix: keep restored reading anchor out of bottom follow (WebKit scroll measurement) (#407) Replace fixed browser-test waits with conditions, gates and the clock (#373) feat(updates): show installed version in Software Updates settings (#430) fix(desktop): allow deep-link delivery to the main webview (#432) feat(shell): open your profile from the account menu avatar (#390) Polish top bar and animate contextual sidebar toggle (#360) fix(profiles): preserve nonlocal agent identity in profile fallback (#327) test(agents): pause the status poll around the failed-Stop checks (#431) fix(sidebar): paint channel rows with the scroller contents (#428) feat(channels): archive and delete channels from settings (#385) feat(updates): add in-app auto-updates with restart toast (#312) fix(ui): keep background loading from shifting populated views (#418) Improve member and agent identity previews (#412) Fix initial emoji autocomplete selection (#419) Add community membership settings (#348) Keep nested replies compact and place actions above message text (#367) Import an exact inventory identity from its selected source with retry (#288) ci: add gated macOS preview updater feed promotion (#414) Set up incomplete inventory identities through a working Use here dialog (#287) Show saved local and relay inventory while retaining existing import controls (#286) ... Signed-off-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>


Current status (
2014bd8e)Both reported interaction blockers are repaired with fail-then-pass Chromium/WebKit regressions. Fresh hosted CI and final human keyboard/pointer acceptance remain pending; PR remains draft. The managed-agent email concern requires no change under the owner’s prior approval. Screenshot disposition in the earlier attachment comment remains with the owner.
Summary
docs/input-correction-audit.md.Validation
bin/pnpm checkand frontend build pass on the final production code (86f114e6). Design tests/build passed before the final keyboard-only refinement.86f114e6: copy isolation, rapid Tab, Shift+Tab, Escape, parent-dialog preservation, addition focus ownership, light/dark layouts at 390/800/1280px.f28b0503; the prior member-dialog expectation failures and provider-picker failure are not present in this run.f28b0503(TypeScript, related unit tests, design types/guards), with managed corporate hooks preserved. Design tests (110/110) and both design builds also pass on this tree. Hosted CI remains a delivery gate.Browser coverage changes
Extended the existing
channel-members-focuscase and fixture, with no browser cases removed. Browser-only contracts are popup hit-testing above the modal, real Tab/Escape behavior, stable geometry, and viewport positioning. Frozen-clock immediate-Tab checks failed in both engines with the old 250ms focus delay, then passed with zero-delay action previews. Identity copy/error feedback, lazy evidence lifecycle, verified ownership, and input attributes also have colocated unit coverage.Pointer-origin focus follow-up (
f28b0503)Fixed #412 (comment). Focus restoration first tries the remembered control, then the trigger, then its focusable descendants, skipping targets the browser cannot focus. No new dependency or selection/layout behavior.
Extended the existing browser case (none added/removed) to cover hover without prior control focus → pointer Copy → Escape on both Add and agent-checkbox rows. This needs real browser click-focus and portal dismissal behavior. The new Add assertion fails in Chromium and WebKit on
1b729ea6; both complete member/team journeys pass on the exact tree committed asf28b0503. The preliminary isolated reproduction also demonstrated the checkbox failure in both engines. Existing immediate Tab, Shift+Tab, Escape, parent-dialog, selection, and responsive layout coverage remains intact.Human check / remaining gaps
The requester tried and approved the visual/copy flow before the final keyboard refinements. Keep this draft pending a final keyboard check and hosted CI; native macOS/iOS autocorrection and screen-reader output have not been manually certified. No native, protocol, membership, or agent-discovery behavior is intentionally changed. The requested local dev server remains stopped.
To check: open Channel members or a team/template editor, focus an identity and immediately Tab to Copy, copy its npub, then Escape. The preview should close while the parent stays open and focus returns to the same Add/checkbox/Preview control. Add and checkbox activation keep their original behavior.
Pointer check: hover an Add-member or agent-checkbox row without focusing it first, click Copy npub, then press Escape. Focus should return to Add/the checkbox without closing the parent dialog or selecting the agent.
CI integration repairs (
b1d4a970)c37e83bc; opened the collapsed navigation inchannel-activity-cornersbefore hovering. Four Chromium/WebKit failures become passes without changing geometry, focus, keyboard, or dismissal assertions.menu-dismissto pause its real exit transition at the closing-state attribute mutation rather than relying on delayedtransitionrundelivery. All three focus scenarios remain unchanged. The original Linux trace failed at the hold prerequisite, before focus assertions. Linux fail-to-pass for this repair remains unproven. No production code, retry, timeout, tolerance, or browser-selection change in these repairs.Validation: full Vitest 5,141 tests / 428 files and both complete activity-corners/menu-dismiss browser files 6/6 pass on macOS at
d802b08aplus the exact menu patch committed asb1d4a970. Browser command:bin/pnpm test:browser tests/browser/menu-dismiss.spec.mjs tests/browser/channel-activity-corners.spec.mjs --no-deps(17.6s total; each menu case 1.9s). Required commit/push hooks pass onb1d4a970; remote head and hosted DCO verified. Independent review found no remaining issues in the test repairs. No browser cases added or removed.Cold-reload repair (
5c5832f5)The previous current-head CI run passed JavaScript, Rust and all twelve browser-journey shards. Its sole test failure was WebKit's cold-reload reading anchor (+650px): https://github.com/block/buzz-app/actions/runs/36602802959.
Reproduced a production state error in inherited timeline code: cold estimated row heights clamp the restoring viewport to a temporary bottom. The scroll handler records that as reader follow-bottom intent before geometry converges. Instrumented WebKit observed that exact transition. This is not caused by identity previews; the same failure appears on unrelated branches. The precise writer in the original Linux trace was not instrumented, so hosted confirmation remains required.
The fix preserves the restore target's row/Y and rejects only a maximum-scroll observation where the same row is still below that target. No timer, retry, scroll-owner expansion or weakened assertion. Five real React lifecycle cases cover first/repeated clamps, normal scrolling after convergence, explicit gesture override and removed anchors. A first-observation-only candidate failed the repeated-clamp regression and was discarded. Mordecai independently reviewed the final geometry guard and tests with no material findings.
Main through
32982724is merged, resolving the three overlapping test-repair conflicts. Menu and activity-corner fixtures use main's versions; provider synchronization retains explicit focused/open/closed assertions.Validation:
5c5832f53a28eaeb362287f24f587ef3517388b2: full Vitest 5,185 tests / 429 files passed (43.00s); required commit/push hooks and hosted DCO passed.c22ce825plus the final production/test patch; commit hook subsequently formatted tests only. Command:bin/pnpm test:browser tests/browser/scroll.spec.mjs tests/browser/channel-activity-corners.spec.mjs tests/browser/menu-dismiss.spec.mjs tests/browser/channel-members-focus.spec.mjs --no-deps --workers=1.Historical CI update: Linux CI https://github.com/block/buzz-app/actions/runs/36610044691 passed at
5c5832f5; final human keyboard/native checks above remain open. Main advanced to73f2a7cb(#369) during delivery, so the hosted merge tree includes changes beyond the local32982724integration. The live dev server remains stopped.Low-impact unverified edge from review: if a target becomes permanently unreachable after reflow and a browser-generated scroll emits no section gesture, above-bottom intent can persist until the next gesture. Ordinary gesture overrides, reachable native positions and removed anchors have regression coverage; overlay-scrollbar/find-in-page behavior was not manually certified.
Interaction repair (
2014bd8e)Browser coverage: two cases added, none removed, in
channel-members-focus. Pointer hit testing uses three multiword candidates, first/lower rows, and 390/800/1280px widths. The other case holds the real exit animation and covers normal return, clicking Search during exit, and Tab from the trigger while closing. These require real browser geometry, native focus, and Base UI portal/transition integration; jsdom cannot prove them. Each added case fails against old production at5c5832f5in both engines (Add hit interception and stolen Search focus) and passes after repair. Existing fixture build/server is reused per worker; every page retains isolated mutable state.Exact clean commit
2014bd8e393e0f8de66835b4da2c9b68db7e5f64on macOS:bin/pnpm test:browser channel-members-focus.spec.mjs buzz-links.spec.mjs --project chromium --project webkit --no-deps.Human check: hover a multiword candidate’s name, then move directly to Add and click. Separately, click Copy in an identity preview, press Escape, and immediately click Search or Tab onward: focus must stay at the new destination. Escape without moving focus must still return to the original control. Native WKWebView/manual acceptance is not claimed; the requested live dev server remains stopped.
Placement limit: at narrow widths a preview can overlap an adjacent row’s action or part of Search. This repair guarantees the hovered row’s direct name-to-Add path, not that a floating preview can never overlap any surrounding content. No unrelated input-correction or screen-reader-label nits were folded into this repair.