Mobile: DM auto-mention silently skipped in thread replies when channel list hasn't loaded yet
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## Summary
In the mobile app, a thread reply in a group DM can go out with **zero** `p` tags — same visible symptom as #6027, but a distinct root cause in a different (Flutter) codebase, not the desktop bug recurring.
## Root cause
`SendMessage.call()` (`mobile/lib/features/channels/send_message_provider.dart:62-72`) only adds DM-recipient auto-mentions when a non-null `channel` object is passed in *and* `channel.isDm == true`:
```dart
final dmRecipientPubkeys = channel?.isDm == true
? await _fetchDmRecipientPubkeys(channelId, channel!, authorPubkey)
: null;
final resolvedMentions = dmRecipientPubkeys != null
? messageMentionPubkeys(...)
: explicitMentions; // <-- silent fallback, no DM auto-mention at all
```
`ThreadDetailPage` (`mobile/lib/features/channels/thread_detail_page.dart:527-530`) derives `channel` from a nullable async provider:
```dart
final channelsAsync = ref.watch(channelsProvider);
final channel = channelsAsync.value
?.where((candidate) => candidate.id == channelId)
.firstOrNull;
```
`channelsAsync.value` is `null` whenever the channel list hasn't loaded yet in this session — cold start, a notification/deep-link tap straight into a thread, or any brief loading window. When that happens, `channel` is `null`, `dmRecipientPubkeys` stays `null`, and `SendMessage.call()` silently falls back to `explicitMentions` only. A plain-text reply with no `@name` in it (the common case) then goes out with **no `p` tags at all** — identical failure signature to #6027 (`h` and `e` tags only), but this is Flutter, not the TS union-of-two-sources bug already fixed there.
`ChannelDetailPage` does **not** have this gap — its `channel` is a required, always-non-null constructor field (`channel_detail_page.dart:126,132`), passed in directly by the caller rather than re-derived from a nullable provider. This is why the bug is specifically a **thread-reply** issue, not a top-level-channel-message issue, which matches the live incident it was found from (a silently-dropped thread reply in a group DM, mobile-only, reported working fine from desktop for the same conversation).
## Secondary, lower-severity gap
Even when `channel` is non-null, `_fetchDmRecipientPubkeys()` (`send_message_provider.dart:116-139`) falls back to `channel.participantPubkeys` — a static snapshot parsed once from channel metadata — whenever `_fetchMembers()` throws. Same staleness risk as desktop's `participant_pubkeys` path in #6027: a member added to the DM after that metadata snapshot won't be in the fallback list.
## Suggested fix
Pass the already-known `Channel` object down into `ThreadDetailPage` from its caller (`ChannelDetailPage` already holds a non-null `Channel`) instead of re-deriving it from `channelsProvider` inside the thread page. That removes the null-channel window entirely for the primary path. The metadata-fallback staleness (secondary gap) is the same shape as #6027's open question and can likely share whatever fix lands there.
## Related
- #6027 / PR #6030 — the desktop version of "group DM message goes out with zero p-tags," different root cause (async `member_pubkeys` query racing a static `participant_pubkeys` parse), same visible symptom.
Contributor guide
Assessment
This issue has not been assessed yet.