Files
buzz/mobile/test/features
Tom Brow 9e18d17a36 fix(mobile): open new DMs without waiting for a full channel reload (#8638)
## Summary

Starting a DM from the mobile **New message** sheet could look broken:
after picking a person and pressing Done, the sheet kept spinning, so it
seemed like the picker could only add people. The DM was being created,
but `openDm` reloaded the whole channel list (memberships, metadata,
hidden DMs, huddles, names, latest messages) before returning. On a
large account or slow connection that can take many seconds.

Interactive opens (New message sheet, Search, profile sheet) now open
the DM from its own metadata and roster, the same targeted read Solo
chat creation uses, and refresh the channel list in the background. The
sidebar still picks up the DM once that refresh lands. When the open
reopens a hidden DM, the fast path also reads the caller's visibility
snapshot in the same round trip and fails visibly if the relay accepted
the open but didn't unhide it, so Done can retry instead of opening a DM
the sidebar keeps hidden. Search and the profile sheet now push the DM
as an ordinary route, as New message already did, so it doesn't sit on a
spinner while Solo groups load. Hidden-DM resurfacing from Activity
keeps the old behavior (wait for the full list), because that reload is
what clears its hidden state and its retry coalescing depends on it.

The fast open also records the DM it read on the channel list notifier,
which falls back to it until the list catches up. Both composers
(channel and thread) look the DM up through it, so a selected mention in
a just-opened DM doesn't wait on, or fail against, the list, and thread
replies there keep their DM recipients.

`findJoinedChannel` now also carries the DM's participant pubkeys so the
opened DM gets its proper title ("Pat Peer", not "DM") before the list
catches up. It also queries metadata and roster separately instead of
under one shared limit, so a lingering pre-backfill metadata revision on
an older DM can't crowd out the roster.

### Related issue

N/A (reported in Buzz #buzz-mobile).

### Validation

- Added tests: `dm_open_latency_test.dart`, a regression test with the
full channel-list load stalled. The interactive open finishes within 2s
with the right channel id, DM flag, membership, and participants. It
publishes exactly one kind 41010, then the background list refresh runs
once the stall clears. The fake serves events like a relay (newest
first, one limit across kinds) and keeps a stale metadata revision
around; the shared-limit read fails it. The test also covers: a DM the
caller can't read fails visibly, a reopen whose unhide snapshot failed
fails visibly, the default (resurfacing) path still waits for the list,
and a community switch mid-read cancels the open.
- Added test (compose bar journey): with the channel list still loading,
a fast-opened DM sends a selected participant mention as a recipient
instead of failing "could not check who is in this channel". It fails if
the composer ignores the opened DM.
- Added test (thread): a thread reply in a DM opened ahead of the list
sends with the DM channel, so it keeps DM recipient semantics. It fails
if the thread page ignores the opened DM. The latency test also checks
the open records the DM before the list has it.
- Mutation checks: the test fails if the background refresh is removed,
if the default path stops waiting, if the interactive path waits, if
participant pubkeys are dropped, or if the still-hidden check is
removed.
- Added tests (Search and profile journeys): with Solo groups still
loading, tapping a person result or the profile's Message button opens
the DM with its composer, not a placement spinner. Each fails if its
call site drops the ordinary placement.
- Full mobile suite: `just mobile-check` clean, 3847 tests passed (23
skipped), plus the unconfigured-push suite.
- iOS simulator (iPhone 17 Pro) against a local relay: New message, pick
Pat Peer, Done. The sheet closed and the DM opened titled "Pat Peer" in
about 1s. Reopening the existing DM took about 0.8s. The DM appeared in
the sidebar after the background refresh. With 400 ms of added one-way
latency (800 ms RTT) through the local proxy, the same flow opened the
DM in 2.5s.
- Re-ran on the simulator at the final head (84444d2): a new DM with a
second user opened in 0.9s, reopening the existing DM opened in 0.8s,
and both appeared in the sidebar. The hidden-DM reopen case couldn't be
run in the simulator because mobile has no hide action, so it is covered
by the regression test only.
- Simulator at ea4fade: reopened the Pat Peer DM, selected a mention of
Pat Peer, and sent it; the message posted with the mention.
- Simulator at
[d7329ae](d7329aecd2):
reopened the Pat Peer DM from New message (about 1s), opened a thread,
selected a mention of Pat Peer, and sent the reply. It posted, and the
relay stored it with Pat as the `p` recipient.
- Simulator at
[1fe2e35](1fe2e35fc1):
searched for Sim Tester and tapped the person result. The DM opened with
its composer in about 1s.
- Limitation: I couldn't reproduce the reporter's account size, so there
is no before/after timing on a real slow account. The stalled-list test
is the before/after evidence for the latency.
- Mobile human-test step: N/A under the mobile testing exception.

| Person picked | Done: DM opens | DM in sidebar |
| --- | --- | --- |
| <img
src="https://raw.githubusercontent.com/block/buzz/021ab77313319e51606f75cc4c8070fc82a2bcbc/pr-8638--1-picker-selected.png"
width="240"> | <img
src="https://raw.githubusercontent.com/block/buzz/021ab77313319e51606f75cc4c8070fc82a2bcbc/pr-8638--2-dm-opened.png"
width="240"> | <img
src="https://raw.githubusercontent.com/block/buzz/021ab77313319e51606f75cc4c8070fc82a2bcbc/pr-8638--3-sidebar.png"
width="240"> |

buzz-review-completed

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

---------

Signed-off-by: Tom Brow <tomb@block.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 10:03:41 -07:00
..