feat(mobile): show contextual names in lists, Search and Pulse - #7896
Conversation
8a7f321 to
2d3c800
Compare
521a996 to
3ec5bd4
Compare
2d3c800 to
4ff5780
Compare
3ec5bd4 to
4bed207
Compare
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent — blocking review
Reviewed base 4ff57804eb8f1c2e2b0ab07971caef3f10664e2c → exact head 4bed207522537f0bce779e29d995ddd86f96918d.
1. Pulse does not disambiguate collisions between shown non-author identities
mobile/lib/features/pulse/pulse_page.dart:173-181 builds the shared IdentityNames comparison context from timeline authors only, then passes it to every NoteCard (:212-222). NoteCard uses that object for reply targets and mentions (mobile/lib/features/pulse/note_card.dart:54-62,175-188). For a key outside the context, IdentityNames.resolve evaluates context + that one key independently (mobile/lib/shared/identity_names/identity_names.dart:94-97,117-123).
Consequently, two visible notes that reply to or mention two different non-author identities both named Scout render both identities as plain Scout: neither outsider is compared with the other. That leaves Pulse ambiguous despite this PR’s stated contract that identities shown together are compared together.
The added Pulse test bypasses the broken production seam by manually constructing a context containing both keys and injecting it into one NoteCard (mobile/test/features/pulse/note_card_test.dart:25-31,52-59). It therefore cannot catch the author-only wiring in PulsePage.
Author action: Build the Pulse collection context from every visibly named identity across the rendered notes—authors plus reply-parent/mention pubkeys—and add a PulsePage-level regression with two distinct, same-name non-author targets. Prove the test fails when candidate construction is mutated back to authors-only.
Verification owner: author for the fix and falsifiable regression; reviewer to re-read the exact-head delta and rerun the mobile gate.
2. Add Members preloads the entire existing roster when the sheet opens or searches
mobile/lib/features/channels/add_members_sheet.dart:45-71 adds every existing member to the generic displayed-collection resolver along with visible choices. watchIdentityNames preloads every uncached candidate (mobile/lib/shared/identity_names/identity_names_provider.dart:50-62), and UserCacheNotifier drains those keys through sequential relay profile queries in pages of 1,000 (mobile/lib/shared/profile/user_cache_provider.dart:60-73,121-177).
Opening the picker with an empty query can therefore enqueue profile history for the whole channel roster, and changed result sets repeatedly resolve against that roster. This makes an interactive picker pay O(roster) network/background work for O(visible choices), contrary to the bounded-work mobile contract in VISION_MOBILE.md:28-29. The channel-scoped resolver already avoids generic candidate preloading and is the appropriate ownership boundary (mobile/lib/features/channels/channel_identity_names_provider.dart:18-45).
Author action: Use channel-scoped naming/cache ownership without passing the full roster through watchIdentityNames, or add an explicitly bounded and deduplicated collision lookup. Add a production-seam regression proving opening/searching the picker does not preload the entire existing roster while a visible candidate colliding with a member remains disambiguated.
Verification owner: author for the fix/regression; reviewer to inspect the preload seam and rerun the mobile gate.
Verification and confidence gaps
git diff --check: pass at exact head.just mobile-check: pass — 593 files formatted, 0 changed; Flutter analyze found no issues.- Exact-head CI:
Clients / Mobile, finalMobile, DCO, Semgrep, and zizmor are green. just mobile-test: blocked before test execution by this reviewer host’s unaccepted Xcode license; theobjective_cnative-asset hook failed while obtaining the SDK path. This is a reviewer-environment confidence gap, not author rework.- Native visual/accessibility checks for long labels, text scaling, truncation, and VoiceOver remain outstanding verification, not separate code blockers.
No other material systems/integration blocker was found in the traced Search presentation binding, community/account isolation, canonical pubkey actions, or update lifecycle.
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent
Verdict: REQUEST CHANGES
Reviewed: 4ff57804eb8f1c2e2b0ab07971caef3f10664e2c..4bed207522537f0bce779e29d995ddd86f96918d (exact head 4bed207522537f0bce779e29d995ddd86f96918d)
Risk: medium — user-visible naming across large list, Search, Activity, huddle, and Pulse surfaces, with profile-loading implications.
Blocking findings
-
mobile/lib/features/pulse/pulse_page.dart:173-181builds the shared naming context from timeline authors only, whilemobile/lib/features/pulse/note_card.dart:54-62,175-188uses that context for reply targets and mentions. Outsiders are each resolved againstauthors + that one key(mobile/lib/shared/identity_names/identity_names.dart:117-123). Two visible notes replying to or mentioning distinct non-author identities with the same name therefore both render the same plain label. The newNoteCardtest manually supplies a correct context and bypasses the faultyPulsePagecollection seam.- Author action: include every visibly named identity across the rendered Pulse collection—authors, reply-parent authors, and mention pubkeys—in the shared context. Add a
PulsePage-level regression with two same-name non-author targets and mutation-prove that reverting to authors-only fails. - Verification owner: author for fix/test; reviewer for exact-new-head delta and mobile gates.
- Author action: include every visibly named identity across the rendered Pulse collection—authors, reply-parent authors, and mention pubkeys—in the shared context. Add a
-
mobile/lib/features/channels/add_members_sheet.dart:45-71feeds every existing channel member intowatchIdentityNames; that helper preloads every uncached candidate profile (mobile/lib/shared/identity_names/identity_names_provider.dart:50-62). Opening or searching Add Members on a large uncached channel can therefore enqueue full-roster sequential relay profile reads and repeatedly resolve O(roster) identities for O(visible choices), violating the bounded background/network-work contract inVISION_MOBILE.md:28-29.- Author action: use channel-scoped naming/cache ownership without sending the full roster through the generic preload helper, or add a bounded/deduped collision lookup. Add a production-seam regression proving sheet open/search does not preload the entire roster while still disambiguating a visible candidate that collides with a member.
- Verification owner: author for fix/test; reviewer for preload-seam inspection and exact-head gates.
Behavior/contracts traced: Search people/messages, Activity, channel lists/details/members/add-members, huddle surfaces, Pulse authors/replies/mentions, profile cache and community isolation, identity-bound actions, stack scope, accessibility/layout. No other concrete defect was found.
Validation: just mobile-check passed (593 files formatted, 0 changed; flutter analyze clean); git diff --check passed. Exact-head GitHub Mobile/Clients, DCO, Semgrep, and zizmor checks are green. Local just mobile-test could not start because this reviewer host's Xcode license is unaccepted (xcrun --show-sdk-path exits 69); that is a tooling confidence gap, not additional author action.
Manual/native evidence: author supplied Android-emulator Search evidence; native long-label, text-scale, and screen-reader behavior was not independently reproduced.
Residual risk: local full-suite/native observation remains reviewer/tooling owned. Any new head expires this review.
brow
left a comment
There was a problem hiding this comment.
🤖 One additional P2 finding below at 4bed2075. I also independently reproduced both issues in Jude’s existing review, so I am retaining those existing findings rather than adding duplicate correction comments. A real PulsePage test displayed two identical “Replying to Scout” labels for distinct nonauthor targets; an empty Add Members sheet queued all 200 uncached existing-member profile keys. Those are 200 keys passed to the batch loader, not 200 network requests.
Across the cumulative stack, 479 focused existing tests passed and all four new intended-behavior regression assertions failed at the production seams described in these reviews. No full local suite or native-device/accessibility verification is claimed.
4ff5780 to
2f9668c
Compare
4bed207 to
63a1511
Compare
|
Response to Jude's review. Both findings are fixed in 63a1511:
The whole context is resolved once per build, not once per choice. The stack is rebased on main |
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent — approved re-review
Reviewed base 2f9668c46fbf63cd08594add8342fcf2db6dd033 → exact head 63a151150992168757f2dbd3c8d78894ca391098. No unresolved author-actionable defect was established across the systems/integration and product/adversarial lanes.
Prior blockers are resolved
- Pulse comparison context:
pulseNamedIdentities(notes)now includes authors, reply-parent authors, and mentions, andPulsePagepasses that shared context into ordinary and grouped cards (mobile/lib/features/pulse/pulse_page.dart:173-222;mobile/lib/features/pulse/note_card.dart:338-346). The production-seam widget regression renders two notes with distinct same-name non-author reply targets and requires distinct labels (mobile/test/features/pulse/pulse_page_test.dart:27-80). Routed reply composition also refreshes the supplied comparison context from live naming sources. - Bounded Add Members loading: the full loaded roster still participates in collision comparison, but
shownrestricts profile/owner preloading to visible or selected choices (mobile/lib/features/channels/add_members_sheet.dart:60-82;mobile/lib/shared/identity_names/identity_names_provider.dart:35-70). The 200-member production-seam test requires both correctScout (agent)disambiguation and exactly the visible agent key to be preloaded (mobile/test/features/channels/add_members_sheet_names_test.dart:27-72).
The complete delta was also traced across Search people/messages, Activity, channel and DM lists/details, member and Huddle labels, Pulse, profile sheets, and identity-bound actions. Contextual labels remain presentation-only; navigation, DMs, membership writes, and other actions retain canonical pubkeys. No material community/cache lifecycle, authorization, accessibility-source, or cross-surface consistency defect was found.
Verification
git diff --check: pass at exact head.just mobile-check: pass in both independent review lanes; formatting unchanged and Flutter analyze clean.- Exact-head CI:
Clients / Mobile, finalMobile, Mobile Swift results, DCO, Semgrep, and zizmor pass. - Exact-head freshness was rechecked immediately before this review.
Confidence gaps / residual risk
Local Flutter tests did not execute on the reviewer hosts because the objective_c native-asset hook could not discover the Apple SDK on machines with an unaccepted Xcode license. Hosted Mobile CI passed the full gate at this exact head. Independent native Android/iOS visual, large-text, truncation, and screen-reader observation was not repeated. These are verification gaps with no author action, not evidence of a PR defect.
Any head movement expires this approval.
jedwards27
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Reviewed: 2f9668c46fbf63cd08594add8342fcf2db6dd033..63a151150992168757f2dbd3c8d78894ca391098 (exact head 63a151150992168757f2dbd3c8d78894ca391098)
Risk: medium — contextual naming across lists, Search, Pulse, and interactive member selection.
Behavior/contracts traced: Pulse authors/reply targets/mentions, routed composer refresh, Add Members comparison-vs-preload ownership, Search scopes, canonical-key action authority, tenant/cache isolation, and accessibility/layout source behavior.
Findings: no unresolved author-actionable defect. Both prior blockers are resolved. Pulse now builds one comparison context from authors, reply-parent authors, and mentions, with a PulsePage production-seam regression. Add Members compares against the roster while restricting profile preload to shown choices, with a 200-member production-seam regression.
Author action: none.
Verification owner: CI/reviewer tooling for residual native observation.
Validation: exact-head formatting/analyze (just mobile-check) and git diff --check passed; hosted Mobile Swift, DCO, Semgrep, and zizmor passed. Exact-head Clients / Mobile was still running at the final lane poll; no PR-caused failure was established. Local Flutter tests did not execute because the reviewer host's Apple SDK/native-asset setup is broken; this is a confidence gap, not author rework.
Manual/native evidence: no independent device/simulator pass.
Residual risk: native large-text/truncation/VoiceOver behavior and independent mutation execution remain unwitnessed.
— :bot: Jude’s code review agent
63a1511 to
bff4746
Compare
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent — APPROVE at exact head bff4746dfa7d27d9fbd8a84c0d2fccf3071ccdde against base 5535d183f08114cc9a76655545b2dc68f58d2c55.
No unresolved author-actionable defect was established.
Reviewed the rebased delta and the previously blocking seams:
- Pulse now constructs one complete contextual-name comparison set across authors, off-timeline reply targets, and both
p/mentionreferences, and shares it with ordinary and grouped cards (mobile/lib/features/pulse/pulse_page.dart:173-222,mobile/lib/features/pulse/note_card.dart:341-349). - Add Members keeps the full loaded roster comparison-only while
shownbounds profile/owner preload work to visible or selected directory choices (mobile/lib/features/channels/add_members_sheet.dart:60-82,mobile/lib/shared/identity_names/identity_names_provider.dart:43-79). Directory results remain capped and pending profile loads are deduplicated. - The rebased profile-sheet contract preserves caller-owned context through
liveIdentityNamesProvider(labels)without importing channel ownership into the profile feature (mobile/lib/features/profile/user_profile_sheet.dart:28-61,107-112). Canonical pubkeys still drive actions; labels remain presentation. - Cross-surface source review covered Search, Pulse, channel/DM/member lists, Add Members, Activity, and Huddle, including constrained-row truncation and accessibility labels. No regression was found.
- The new fix commit is patch-equivalent to the previously reviewed fix; the material adaptation is the correct live-context provider contract on the new base.
Verification at this exact head:
- PASS —
just mobile-check: 596 files formatted, zero changes; Flutter analyze reported no issues. - PASS —
git diff --checkand clean exact-head worktree checks. - PASS — GitHub
Clients / MobileandMobile Swift Domain / Mobile Swift. - PASS — DCO, Semgrep OSS, and zizmor.
Confidence gap, not author rework: the local full Flutter suite could not start because this reviewer host lacks an accepted/usable Apple SDK (xcrun --show-sdk-path exits 69), so independent simulator/device observation for large text, truncation, and screen-reader behavior was unavailable. Source review, production-seam regressions, static gates, and exact-head CI found no defect.
Author action: none. Any head movement invalidates this approval until the delta is reviewed.
🤖
## Summary
When two identities share a display name, Buzz mobile shows the same
label for both. A reader cannot tell a person from an agent, or one
person's agent from another's. For example, a channel can show three
agents and one human all named "murderbot".
This PR adds the naming rules that fix this, without changing any screen
yet. It ports the contextual identity-name contract (v1) from the
desktop app to Dart. Given the identities shown together, the resolver
gives each public key a distinct label:
- A human keeps the plain name. Agents that share it get a qualifier.
- The viewer's own agents are named before other people's agents.
- An agent is qualified by its owner's name first ("Wes's Honey"). A
short public-key suffix is added only if that is still ambiguous
("baxen's murderbot · xa8v").
It also adds two providers that screens will use:
- `channelIdentityNamesProvider` compares names against a channel's
members, plus any referenced non-member such as an old author or an
outside mention.
- `watchIdentityNames` compares a set of identities shown together
outside a channel, and loads their profiles.
The next PRs in this stack connect these to the screens.
Part 1 of 3: #7894 (resolver) → #7895 (conversations) → #7896 (lists,
Search, Pulse).
### Related issue
Related to #2910 (default "Fizz" agents from different users collide in
one channel).
### Testing
- The contract's 31 portable fixture cases run against the production
resolver. The fixture file is copied unchanged from the contract, so
reviewers can skip it.
- Unit tests cover owner and suffix qualification, the viewer's own
identities, and invalid public keys.
- Provider tests check that a channel keeps its names while its roster
reloads, that an offline cached bot still counts as an agent, and that
changing relay or account never shows the old roster.
- `flutter analyze` is clean.
No UI change, so there are no screenshots.
---------
Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
bff4746 to
67f8a78
Compare
5535d18 to
4748300
Compare
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent
Verdict: APPROVE
Reviewed: 4748300e65d22b9c883a6160ebfbaafed4290ad1..67f8a78c7b387ff565925c86d292cc8e28f3653b (exact head 67f8a78c7b387ff565925c86d292cc8e28f3653b)
Risk: medium — shared, user-visible contextual identity rendering across mobile lists, Search, Pulse, Activity, details, and huddles.
Findings: No blocking or non-blocking defect found. The rebase is patch-equivalent to the previously reviewed change; the only overlapping base/PR file has no semantic collision. Context ownership remains bounded and lifecycle-aware, Pulse loading remains capped/coalesced, and labels are presentation-only: navigation, profile, membership, note, DM, and huddle actions continue to use pubkeys as authority. Collision labels cover the intended surfaces; dense labels use bounded/ellipsis layouts, and huddle semantics preserve identity plus speaking/preparing state.
Author action: none.
Verification owner: exact-head automated suite — GitHub Mobile CI (passed); additional native visual/VoiceOver observation — reviewer/release-device tooling.
Validation at matching HEAD:
git diff --check— PASS; clean detached worktree; DCO present.flutter pub get,dart format --output=none --set-exit-if-changed .,flutter analyze, andscripts/test-mobile-gateway-recipes.sh— PASS.- Exact-head CI run 36618243178 —
Clients / Mobile,Mobile Swift Domain / Mobile Swift, both Results jobs, aggregateMobile, DCO, Semgrep, and zizmor PASS. The brief failures in run36618243044are from its cancelled duplicate matrix, superseded by the completed green run. - Live pre-submit check: head/base unchanged, mergeable/CLEAN, zero unresolved review threads.
Manual/native evidence: No fresh native-device visual or VoiceOver observation was obtained. Local full Flutter tests could not start because this host's unaccepted Xcode license prevented the Objective-C native-assets hook from resolving the Apple SDK. This is a reviewer-tooling limitation, not an author defect; the exact-head Mobile CI package gate passed, and the PR includes Android-emulator Search evidence.
Residual risk: Device/text-scale-specific overflow and assistive behavior were not independently observed on native hardware. Source constraints and widget coverage disclosed no concrete failure.
🤖
## Summary
In a channel conversation, two identities with the same display name
looked identical. In the example below, the channel shows "Bad Janet"
twice, for two different identities. A reader cannot tell which one was
added and then removed.
This PR uses the contextual names from the previous PR everywhere a
conversation names someone:
- Message authors, threads, forum posts and replies
- Reactions, the typing indicator, and system rows (joined, added,
removed)
- Inline mentions and the agent activity sheet
- The profile sheet title, which now matches the row that opened it
Names are compared against the channel's members, so a label only gets
longer when a real collision exists in that channel.
The mention picker labels each choice against every candidate, so two
"Honey" choices look different. When you pick one, it still inserts the
identity's own name ("@honey"), so the message text does not change.
Part 2 of 3: #7894 (resolver) → #7895 (conversations) → #7896 (lists,
Search, Pulse).
### Related issue
Related to #2910.
### Testing
- A widget test checks that the profile sheet names an author the same
way the channel does.
- A unit test checks that two same-name mention choices get different
labels but insert the same wire name.
- `flutter analyze` is clean, and the full `flutter test` suite passes.
- Checked on an Android emulator against the live relay, in an archived
channel with two identities named "Bad Janet".
| Before | After |
| --- | --- |
| <img width="300" alt="Before: the channel shows two different
identities both as Bad Janet"
src="https://github.com/user-attachments/assets/c7f6c345-12d8-4e11-9434-bbd2c63722db"
/> | <img width="300" alt="After: the second identity shows as Bad Janet
· sqxl"
src="https://github.com/user-attachments/assets/51c6b9fc-8900-4200-8ce0-ad1887f41dba"
/> |
---------
Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Use contextual identity names on the remaining mobile surfaces: the channel list and DM labels, the new-DM picker, the channel header and details, the members and add-members sheets, huddle avatars and overlays, the Activity inbox, Search results, and Pulse notes, agent cards and reply previews. Channel surfaces compare against the channel's members. Surfaces without a channel (Search, Pulse, the new-DM picker) compare the identities shown together, so two results with the same name still get distinct labels. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
… loads Pulse built its naming context from note authors only, so two notes replying to or mentioning different people named Scout both showed "Replying to Scout". The context now includes reply targets and mentions; these are the identities Pulse already preloads. Add Members sent the whole channel roster through the generic naming helper, which queued a profile read for every uncached member. The sheet now compares choices with the roster's names and bot roles but loads only the shown choices' profiles. The reply composer resolves its opener's context against live naming facts, so a profile that changes while it is open updates the label. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
67f8a78 to
fd6f4e9
Compare
🔐 Codex Security Review
|
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent
Verdict: APPROVE
Reviewed: 4ef23609b7025bc356a9ea078834d57b69ec33cf..fd6f4e9edaa5eb15aaea8e13c6aab1482ad872b7 (exact head fd6f4e9edaa5eb15aaea8e13c6aab1482ad872b7)
Risk: medium — shared, user-visible contextual identity rendering across mobile lists, Search, Pulse, Activity, details, and huddles.
Findings: No blocking or non-blocking defect found. This rewrite has the identical product tree (dc1e8de467ed2800a1c4157000f15e9c490da3e3) as the previously cleared 67f8a78c7b387ff565925c86d292cc8e28f3653b; the old and new bases are also tree-equivalent, patch IDs match, and range-diff maps both commits unchanged. No stacking collision exists behind the rewritten SHAs.
Context ownership remains view-local and lifecycle-aware; live source refreshes preserve candidate and fallback facts without persisting resolved names. Pulse context includes authors, reply-parent authors, and p/mention references for ordinary and grouped cards. Add Members keeps the roster comparison-only while shown bounds profile/owner loading to visible or selected choices. Contextual labels remain presentation-only: profile, reply/follow, DM, reaction, Search, mention, and membership actions continue to use canonical pubkeys. Dense labels are constrained/ellipsized, Add Members semantics expose the resolved label, and existing coverage exercises long labels and 2× text scaling.
Author action: none.
Verification owner: exact-head package suite — GitHub Mobile CI (passed); optional native visual/VoiceOver/large-text observation — reviewer or release-device tooling.
Validation at matching HEAD:
- Clean detached worktree;
git diff --check, DCO trailers, repository preflight, and file-size policy checks — PASS. just mobile-install mobile-checkandbash scripts/test-mobile-gateway-recipes.sh— PASS (601 files formatted with zero changes; analyzer clean; all five gateway probes pass).- Exact-head CI run 36622125417 —
Clients / Mobile, aggregateMobile, Mobile Swift, DCO, Semgrep, and zizmor PASS. - Live pre-submit check: head/base unchanged, mergeable, zero unresolved threads, and zero non-green checks.
Manual/native evidence: No fresh native-device visual, VoiceOver, or large-text observation was obtained. Local just mobile-test reached Flutter but tests did not execute because this host's unaccepted Xcode license/native-assets setup prevented the Objective-C hook from discovering the Apple SDK. This is a reviewer-tooling limitation, not an author defect; the exact-head hosted Mobile package gate passed.
Residual risk: Device-specific visual and assistive behavior was not independently witnessed. Source constraints and widget coverage disclosed no concrete failure.
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent — APPROVE
Reviewed: 4ef23609b7025bc356a9ea078834d57b69ec33cf..fd6f4e9edaa5eb15aaea8e13c6aab1482ad872b7 (exact live head rechecked immediately before submission)
Risk: medium — user-visible identity disambiguation spans mobile lists, Search, Pulse, Activity, channel/DM details, huddles, and membership surfaces, but does not alter relay, persistence, schema, or authorization contracts.
Behavior/contracts traced: both assigned lanes independently checked the rewritten stack, comparison-context ownership/lifecycle, Pulse completeness, Add Members loading bounds, pubkey-authoritative actions, collision labels, long-label/accessibility source behavior, persistence/wire boundaries, regression seams, and exact-head gates.
Findings: no unresolved blocking or non-blocking defect. The live head and previously cleared 67f8a78c7b387ff565925c86d292cc8e28f3653b have the identical product tree; their stable patch IDs match and range-diff maps both commits exactly. Pulse includes authors, reply-parent authors, and mention references in one comparison context. Add Members retains full-roster collision comparison while limiting profile/owner loads to shown or selected identities. Contextual labels remain presentation-only; canonical pubkeys still control profile, reply/follow, DM, participant, membership, navigation, and outbound-event identity.
Author action: none.
Verification owner: hosted Mobile CI owns the package gate and is green; reviewer/device or Mobile release validation owns optional additional native visual and assistive-technology observation.
Validation: at exact head fd6f4e9edaa5eb15aaea8e13c6aab1482ad872b7, clean-worktree validation passed git diff --check, DCO/preflight inspection, just mobile-check (601 files, zero formatting changes, analyzer clean), mobile gateway recipe probes, and file-size policy. Exact-head GitHub Clients / Mobile, aggregate Mobile/Results, Mobile Swift, DCO, Semgrep, and zizmor passed.
Manual/native evidence: the PR includes Android-emulator Search evidence. Independent reviewer device/VoiceOver observation was not obtained; local Flutter tests were blocked before execution by this host’s Xcode/Apple SDK setup while exact-head CI’s full package suite passed.
Residual risk: extreme labels, text scaling, and assistive behavior across the device matrix remain independently unobserved. This is a reviewer/tooling confidence gap, not an author-actionable defect. Any new head expires this approval.
…i-port * origin/main: fix(agents): stop built-in prompts from teaching sleep polling (#7992) feat(relay): add direct staff ban/timeout/delete with staff guard (#7883) fix(ci): gate security review on repo write access (#7986) feat(acp): wrap workers at the subprocess launch boundary (#7985) feat(buzz-relay): idempotent owner community deletion with quota reservation (#7969) feat(mobile): show contextual names in lists, Search and Pulse (#7896) Add Kimi Code's default install path to managed-agent binary discovery (#5997) Co-authored-by: Will Pfleger <wpfleger@block.xyz> Signed-off-by: Will Pfleger <wpfleger@block.xyz>
🤖
Summary
This PR finishes the change on the remaining mobile screens. After it, every place that names a person or agent uses a contextual name:
Screens that belong to a channel compare names against its members. Search, Pulse, and the new-DM picker have no channel, so they compare the identities shown together. In the example below, Search showed four results all named "murderbot". Now the human keeps the plain name, and baxen's three agents are labeled by owner and key suffix.
Part 3 of 3: #7894 (resolver) → #7895 (conversations) → #7896 (lists, Search, Pulse).
Related issue
Related to #2910. The desktop search change in #6483 addresses the same problem in a different app.
Testing
flutter analyzeis clean, and the fullflutter testsuite passes.