fix(mobile): keep iOS message menu actions responsive after rebuilds - #7758
Conversation
Signed-off-by: Tom Brow <tomb@block.xyz>
🔐 Codex Security Review
|
|
@codex review |
|
@builderbot review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
@buzz-security-review a49b21f |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent
Verdict: APPROVE
Reviewed: 5511b56fcf0047f9d0d4887dc75125b6933a6bbd..a49b21f6ddf3c6a0403a3bb692daeabccb6d4bad (exact live head a49b21f6ddf3c6a0403a3bb692daeabccb6d4bad)
Risk: medium — user-visible iOS input handling across Flutter hook lifecycle and a native platform-view method channel.
Behavior/contracts traced: The per-view method channel is now owned by stable viewId, while a ref dispatches selections to the latest rebuild callback. View replacement and dismissal clear the appropriate handler; late old-view calls have no Dart handler; the existing one-shot selection guard prevents duplicate effects. Native action rows remain the sole accessible button, while decorative icon content no longer intercepts row taps.
Findings: No blocking or non-blocking code defect. The focused Dart regression is causally bound: restoring callback identity to the effect key fails the rebuild case by losing frame4:edit. Independent native mutation evidence likewise shows restoring icon interception fails the whole-row hit-target XCTest.
Author action: none.
Verification owner: CI/release gate for broader RunnerTests.xctest coverage and optional physical-device/VoiceOver dogfood; reviewer/tooling for any additional semantic traversal capture.
Validation at matching clean HEAD:
just mobile-test— PASS: 2,257 tests, 4 skipped; unconfigured-push follow-up 3/3 PASS.just mobile-check— PASS: 577 files formatted, 0 changed; analyzer clean.cd mobile && flutter test test/features/channels/native_message_action_selection_test.dart— PASS 2/2.- Causal mutation restoring
[viewId, onSelected]— expected FAIL: rebuild test lost the second selection; candidate restored cleanly. - Independent focused native XCTest and inverse hit-target mutation — PASS/expected FAIL on iPhone 17 Pro simulator, iOS 26.5.
- Exact-head GitHub Mobile, Mobile Swift, DCO, Semgrep, and zizmor gates — PASS.
Manual/native evidence: The attached before/after recordings show the failure and the repaired keyboard-open long-press → Edit → reopen → Copy → reopen → outside-dismiss journey. Independent simulator proof covered icon, label, and row-edge targets. Physical-device execution and clipboard contents were not independently repeated in this review.
Residual risk: Low. Repository CI builds the iOS simulator/release app but does not run the full RunnerTests.xctest suite; physical-device and VoiceOver traversal remain release/dogfood confidence gaps, not author-actionable defects.
jedwards27
left a comment
There was a problem hiding this comment.
Review verdict: APPROVE
Reviewed base 5511b56fcf0047f9d0d4887dc75125b6933a6bbd → exact live head a49b21f6ddf3c6a0403a3bb692daeabccb6d4bad.
No unresolved author-actionable defects found. Author action: none.
The fix puts selection-handler ownership on the native view identity rather than rebuild callback identity: useEffect(..., [viewId]) keeps one handler for that channel while useRef dispatches to the latest closure. Ordinary rebuilds therefore preserve the handler, view replacement moves it, and dismissal clears it. The native row also disables hit interception on its decorative icon container, preserving the row as the single accessible action while making icon, label, and edge taps reach the control.
Evidence at this exact head:
- Focused Dart lifecycle suite: 2/2 PASS. Restoring the old
[viewId, onSelected]dependency causally failed the rebuild regression; restoring the candidate passed. - Focused native whole-row hit-target XCTest: PASS on an iPhone 17 Pro / iOS 26.5 simulator. Re-enabling icon-container interaction causally failed the test; restoring the candidate passed.
- Focused Dart format/analyze: PASS.
- Attached before/after recordings cover the visible failure and the repaired Edit, Copy, reopen, and outside-dismiss journeys.
- Exact-head Mobile, Mobile Swift domain/results, DCO, Semgrep, and zizmor checks are green.
Non-blocking confidence gaps, owned by release/tooling rather than this author:
- CI does not currently execute
RunnerTests.xctest; the changed focused XCTest was run independently, but not the entire RunnerTests suite. - Physical-device clipboard-content behavior and VoiceOver traversal were not independently repeated. Static ownership/semantics, causal mutation tests, simulator behavior, and the supplied recording leave low residual risk; release/dogfood should retain those checks.
A new head invalidates this approval until its delta is reviewed.
* origin/main: (75 commits) fix(workflows): make deletion persistent and retryable (#7735) fix(mobile): preserve thread replies through refresh failures (#7757) fix(mobile): keep iOS message menu actions responsive after rebuilds (#7758) fix(relay): exclude ephemeral activity from message quota (#7736) release: push gateway chart 0.3.1 (#7749) fix(push): label plaintext push gateway service as HTTP (#7717) Replace personal and internal data in desktop test fixtures (#7748) Add mobile VISION (#7710) fix(mobile): keep relay sessions stable during push lease updates (#7745) fix(desktop): keep managed agent avatars usable across communities (#7732) fix(mobile): fail open when age checks are unavailable (#7714) fix(ci): don't run desktop tests for purely mobile client changes (#7709) fix(mobile): temporarily disable age gating (#7708) feat(db): expose connection setup metrics (#7286) Isolate S3 storage metrics from the relay (#7543) fix(web): route mobile invite downloads to app stores (#7702) feat(mobile): show build number with version in settings (#7697) release(mobile-infra): buzz-push-gateway 0.3.0 (#7685) Add authenticated WebSocket recovery telemetry (#7546) Instrument database pool roles (#7356) ... # Conflicts: # crates/buzz-db/src/runtime/migration.rs
* origin/main: (81 commits) fix(mobile): avoid opening empty threads on message tap (#7756) fix(workflows): make deletion persistent and retryable (#7735) fix(mobile): preserve thread replies through refresh failures (#7757) fix(mobile): keep iOS message menu actions responsive after rebuilds (#7758) fix(relay): exclude ephemeral activity from message quota (#7736) release: push gateway chart 0.3.1 (#7749) fix(push): label plaintext push gateway service as HTTP (#7717) Replace personal and internal data in desktop test fixtures (#7748) Add mobile VISION (#7710) fix(mobile): keep relay sessions stable during push lease updates (#7745) fix(desktop): keep managed agent avatars usable across communities (#7732) fix(mobile): fail open when age checks are unavailable (#7714) fix(ci): don't run desktop tests for purely mobile client changes (#7709) fix(mobile): temporarily disable age gating (#7708) feat(db): expose connection setup metrics (#7286) Isolate S3 storage metrics from the relay (#7543) fix(web): route mobile invite downloads to app stores (#7702) feat(mobile): show build number with version in settings (#7697) release(mobile-infra): buzz-push-gateway 0.3.0 (#7685) Add authenticated WebSocket recovery telemetry (#7546) ... Signed-off-by: Hayt <9e1c23a3fd83f61da34420e4e88ff1b16e45cafcc0cd9019eb07d4ecfa8ca9b0@buzz.block.builderlab.xyz>
* origin/main: (75 commits) fix(workflows): make deletion persistent and retryable (#7735) fix(mobile): preserve thread replies through refresh failures (#7757) fix(mobile): keep iOS message menu actions responsive after rebuilds (#7758) fix(relay): exclude ephemeral activity from message quota (#7736) release: push gateway chart 0.3.1 (#7749) fix(push): label plaintext push gateway service as HTTP (#7717) Replace personal and internal data in desktop test fixtures (#7748) Add mobile VISION (#7710) fix(mobile): keep relay sessions stable during push lease updates (#7745) fix(desktop): keep managed agent avatars usable across communities (#7732) fix(mobile): fail open when age checks are unavailable (#7714) fix(ci): don't run desktop tests for purely mobile client changes (#7709) fix(mobile): temporarily disable age gating (#7708) feat(db): expose connection setup metrics (#7286) Isolate S3 storage metrics from the relay (#7543) fix(web): route mobile invite downloads to app stores (#7702) feat(mobile): show build number with version in settings (#7697) release(mobile-infra): buzz-push-gateway 0.3.0 (#7685) Add authenticated WebSocket recovery telemetry (#7546) Instrument database pool roles (#7356) ...
* origin/main: (75 commits) fix(workflows): make deletion persistent and retryable (#7735) fix(mobile): preserve thread replies through refresh failures (#7757) fix(mobile): keep iOS message menu actions responsive after rebuilds (#7758) fix(relay): exclude ephemeral activity from message quota (#7736) release: push gateway chart 0.3.1 (#7749) fix(push): label plaintext push gateway service as HTTP (#7717) Replace personal and internal data in desktop test fixtures (#7748) Add mobile VISION (#7710) fix(mobile): keep relay sessions stable during push lease updates (#7745) fix(desktop): keep managed agent avatars usable across communities (#7732) fix(mobile): fail open when age checks are unavailable (#7714) fix(ci): don't run desktop tests for purely mobile client changes (#7709) fix(mobile): temporarily disable age gating (#7708) feat(db): expose connection setup metrics (#7286) Isolate S3 storage metrics from the relay (#7543) fix(web): route mobile invite downloads to app stores (#7702) feat(mobile): show build number with version in settings (#7697) release(mobile-infra): buzz-push-gateway 0.3.0 (#7685) Add authenticated WebSocket recovery telemetry (#7546) Instrument database pool roles (#7356) ... Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…p-20260915 * origin/main: (28 commits) fix(mobile): avoid opening empty threads on message tap (block#7756) fix(workflows): make deletion persistent and retryable (block#7735) fix(mobile): preserve thread replies through refresh failures (block#7757) fix(mobile): keep iOS message menu actions responsive after rebuilds (block#7758) fix(relay): exclude ephemeral activity from message quota (block#7736) release: push gateway chart 0.3.1 (block#7749) fix(push): label plaintext push gateway service as HTTP (block#7717) Replace personal and internal data in desktop test fixtures (block#7748) Add mobile VISION (block#7710) fix(mobile): keep relay sessions stable during push lease updates (block#7745) fix(desktop): keep managed agent avatars usable across communities (block#7732) fix(mobile): fail open when age checks are unavailable (block#7714) fix(ci): don't run desktop tests for purely mobile client changes (block#7709) fix(mobile): temporarily disable age gating (block#7708) feat(db): expose connection setup metrics (block#7286) Isolate S3 storage metrics from the relay (block#7543) fix(web): route mobile invite downloads to app stores (block#7702) feat(mobile): show build number with version in settings (block#7697) release(mobile-infra): buzz-push-gateway 0.3.0 (block#7685) Add authenticated WebSocket recovery telemetry (block#7546) ... Signed-off-by: Brainy Bumble <0ed7657b57c0e8a9f5288390dd6c8d5d0a3a06abe9b01b9006814f52077d6cdf@buzz.block.builderlab.xyz>
…ecurity * origin/main: (22 commits) feat(relay): add admin HTTP routes for member restriction management (#7302) fix(relay): fire kick live side effects at convergence; persist target; fence re-add race with held lock (#7298) feat(relay): add atomic complete read-state snapshots (#7572) fix(desktop): register macOS badges for new and existing installs (#7783) fix(mobile): avoid opening empty threads on message tap (#7756) fix(workflows): make deletion persistent and retryable (#7735) fix(mobile): preserve thread replies through refresh failures (#7757) fix(mobile): keep iOS message menu actions responsive after rebuilds (#7758) fix(relay): exclude ephemeral activity from message quota (#7736) release: push gateway chart 0.3.1 (#7749) fix(push): label plaintext push gateway service as HTTP (#7717) Replace personal and internal data in desktop test fixtures (#7748) Add mobile VISION (#7710) fix(mobile): keep relay sessions stable during push lease updates (#7745) fix(desktop): keep managed agent avatars usable across communities (#7732) fix(mobile): fail open when age checks are unavailable (#7714) fix(ci): don't run desktop tests for purely mobile client changes (#7709) fix(mobile): temporarily disable age gating (#7708) feat(db): expose connection setup metrics (#7286) Isolate S3 storage metrics from the relay (#7543) ... Signed-off-by: Alex Rosenzweig <arosenzweig@squareup.com>
…ness-overload * origin/main: (74 commits) feat(relay): add admin HTTP routes for member restriction management (#7302) fix(relay): fire kick live side effects at convergence; persist target; fence re-add race with held lock (#7298) feat(relay): add atomic complete read-state snapshots (#7572) fix(desktop): register macOS badges for new and existing installs (#7783) fix(mobile): avoid opening empty threads on message tap (#7756) fix(workflows): make deletion persistent and retryable (#7735) fix(mobile): preserve thread replies through refresh failures (#7757) fix(mobile): keep iOS message menu actions responsive after rebuilds (#7758) fix(relay): exclude ephemeral activity from message quota (#7736) release: push gateway chart 0.3.1 (#7749) fix(push): label plaintext push gateway service as HTTP (#7717) Replace personal and internal data in desktop test fixtures (#7748) Add mobile VISION (#7710) fix(mobile): keep relay sessions stable during push lease updates (#7745) fix(desktop): keep managed agent avatars usable across communities (#7732) fix(mobile): fail open when age checks are unavailable (#7714) fix(ci): don't run desktop tests for purely mobile client changes (#7709) fix(mobile): temporarily disable age gating (#7708) feat(db): expose connection setup metrics (#7286) Isolate S3 storage metrics from the relay (#7543) ... Signed-off-by: tornquist <tornquist@squareup.com>
…rcement * origin/main: (87 commits) feat(relay): add admin HTTP routes for member restriction management (#7302) fix(relay): fire kick live side effects at convergence; persist target; fence re-add race with held lock (#7298) feat(relay): add atomic complete read-state snapshots (#7572) fix(desktop): register macOS badges for new and existing installs (#7783) fix(mobile): avoid opening empty threads on message tap (#7756) fix(workflows): make deletion persistent and retryable (#7735) fix(mobile): preserve thread replies through refresh failures (#7757) fix(mobile): keep iOS message menu actions responsive after rebuilds (#7758) fix(relay): exclude ephemeral activity from message quota (#7736) release: push gateway chart 0.3.1 (#7749) fix(push): label plaintext push gateway service as HTTP (#7717) Replace personal and internal data in desktop test fixtures (#7748) Add mobile VISION (#7710) fix(mobile): keep relay sessions stable during push lease updates (#7745) fix(desktop): keep managed agent avatars usable across communities (#7732) fix(mobile): fail open when age checks are unavailable (#7714) fix(ci): don't run desktop tests for purely mobile client changes (#7709) fix(mobile): temporarily disable age gating (#7708) feat(db): expose connection setup metrics (#7286) Isolate S3 storage metrics from the relay (#7543) ... Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com> # Conflicts: # crates/buzz-auth/src/nip98.rs # crates/buzz-relay/Cargo.toml
…-dev * origin/main: fix(desktop): bound startup request bursts and recover quota refusals (#7790) fix(audit): frame hash inputs with TLV (#7492) fix(admin): allow cold storage worker DB startup (#7770) feat(relay): add admin HTTP routes for member restriction management (#7302) fix(relay): fire kick live side effects at convergence; persist target; fence re-add race with held lock (#7298) feat(relay): add atomic complete read-state snapshots (#7572) fix(desktop): register macOS badges for new and existing installs (#7783) fix(mobile): avoid opening empty threads on message tap (#7756) fix(workflows): make deletion persistent and retryable (#7735) fix(mobile): preserve thread replies through refresh failures (#7757) fix(mobile): keep iOS message menu actions responsive after rebuilds (#7758) fix(relay): exclude ephemeral activity from message quota (#7736) release: push gateway chart 0.3.1 (#7749) fix(push): label plaintext push gateway service as HTTP (#7717) Replace personal and internal data in desktop test fixtures (#7748) Add mobile VISION (#7710) fix(mobile): keep relay sessions stable during push lease updates (#7745) Signed-off-by: Tom Brow <tomb@block.xyz>
Long-pressing a message while the keyboard dismissed could leave the iOS action menu visible but unresponsive. Rebuilds installed a new selection handler before the previous hook's cleanup removed it. Keep that handler for the native view's lifetime and dispatch to the latest callback. Also let taps on decorative action icons reach the row control.
Added regression coverage for callback rebuilds, view replacement/dismissal, and native icon/label/edge hit targets. The callback regression fails before the fix and passes after it.
Validation: all 2,257 mobile tests (4 skipped), three unconfigured-push tests, mobile analysis, 42 focused action/handler tests, and three native XCTest checks passed. Physical iOS 26.5 taps verified keyboard-open long press, Edit, Copy (including clipboard contents), repeated opening, and outside dismissal. Desktop tests/builds, Tauri checks/tests, and the web build passed. The full local gate encountered unrelated Rust agent timeout failures; all 105 tests in the affected ACP test module passed when rerun serially.
GitHub CI passed, including mobile tests, Swift tests, Android build, and iOS simulator/release builds. Codex code review completed without findings.
No matching open issue or PR found.
Before
Synthetic message using the production long-press/menu components: Edit and Copy taps leave the menu open; tapping outside still dismisses it.
buzz-menu-before.mp4
After
With the keyboard open, the first Edit icon tap opens the editor. Reopening and tapping Copy copies the message and dismisses the menu.
buzz-menu-after.mp4