Skip to content

fix(mobile): qualify every namesake mention and keep authored mention casing - #9325

Merged
kalvinnchau merged 9 commits into
mainfrom
peon/mobile-namesake-mentions
Nov 13, 2026
Merged

kalvinnchau merged 9 commits into
mainfrom
peon/mobile-namesake-mentions

Conversation

@kalvinnchau

@kalvinnchau kalvinnchau commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

problem

When a message mentions two different identities that share a display name, the mobile composer qualified only the later selection as @Name (<64-hex>) and left the first one bare. A qualified occurrence denies the plain name on render, so the first mention rendered as plain text on mobile and desktop. MessageContent also displayed every mention in the lowercased binding key rather than its authored spelling.

change

  • mention_bindings.dart:
    • selectedMentionLabel qualifies a selection whenever another selected identity shares its name, without regard to case.
    • namesakeRequalifications and renameMentions qualify earlier plain selections. Each occurrence keeps its authored spelling, and occurrences in code stay as typed.
  • compose_bar/helpers.dart and compose_bar_widget.dart:
    • Selecting a namesake qualifies earlier same-name mentions before the new label is inserted, keeping the caret in place.
    • Occurrences inside code that the composer styles are skipped: single-backtick spans and closed triple-backtick fences, found by the same walk the editor uses to draw them. A key whose occurrence stays in code remains bound beside its qualified label, so its recipient still sends.
  • agent_mention_prefill.dart: automatic addressing qualifies every same-name agent it inserts.
  • message_content.dart: mentions render in their authored spelling, and bindings still resolve case-insensitively.
  • docs/mention-editor.md: describes the behavior, including that Markdown code forms the composer does not style (tilde fences, indented code) are qualified like prose.

tests

  • mention_bindings_test.dart: requalification, spelling preservation and code exclusion.
  • Composer journeys:
    • picker selections qualify both namesakes and send both keys;
    • styled code (fences, list fences, spans, spans after bold or italics) stays as typed while surrounding prose is qualified;
    • a selection left only in code keeps its recipient;
    • automatic prefill of two same-name agents qualifies both.
  • message_content_exact_mentions_test.dart: authored casing with case-insensitive resolution.
  • just mobile-check mobile-test passes.
  • Real relay: composed bodies exchanged through a local relay render as correctly targeted chips in desktop and in Flutter MessageContent.

@kalvinnchau
kalvinnchau force-pushed the peon/mobile-namesake-mentions branch from bf2e3c3 to e664a37 Compare November 12, 2026 00:32

@brow brow left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 The pre-review recommends landing this with one small fix, #9438 namesake requalification fixes: without it, picking a second same-named member rewrites the prefix of a typed longer mention such as @Scout Leader and silently drops that recipient from the send, and it unbinds an earlier pick whose only remaining plain occurrence is inside backticks, so the send is later rejected as ambiguous. Please merge the fix into your branch (it needs no approval there: block/buzz's review rules cover only main and the mobile release branches), and this PR is then approved and merged on Tom's go-ahead.

buzz://message?channel=e71f9a2a-ac46-473d-a24e-5e16fd8cb7b1&id=d876dac2fea8b7a9580557a42b87ff0c27eea9669f9e2717259848d59ea246c6

kalvinnchau and others added 9 commits November 12, 2026 18:14
… casing

- selectedmentionlabel qualifies any mention whose name is shared by another
  selected identity; insertmention requalifies earlier plain namesake
  selections (map keys and draft text) when a namesake is added
- a qualified occurrence denies the plain name on render, so a lone plain
  namesake never resolved; all namesakes now carry the pubkey qualifier
- message_content pre-pass keeps the authored text of each mention range
  instead of the lowercased binding key (binding lookup lowercases itself)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Kalvin Chau <[email protected]>
selecting a second same-name identity now requalifies earlier selections too.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Kalvin Chau <[email protected]>
…dget

keeps compose_bar_widget.dart within the mobile file size ratchet.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Kalvin Chau <[email protected]>
- mention-bindings: renameMentions appends the qualifier to each matched
  spelling and skips excluded spans, reporting renamed and kept keys
- compose-bar: requalification excludes inline and fenced code; a key left
  in code stays bound beside its qualified label, so its recipient still
  sends and the send-time resolver sees no ambiguous bare name
- agent-mention-prefill: qualify every same-name agent, including the first
- docs/mention-editor: describe casing, code and prefill behavior

Co-authored-by: goose-wayne <ae6b377e5b6d090ee22558d19246413a5731628a127e25371111badfd4861535@buzz.block.builderlab.xyz>
Signed-off-by: Kalvin Chau <[email protected]>
requalification skipped occurrences by independent per-rule code matches,
which paired backticks that bold or italics consume. code the editor
styled could gain a qualifier and editor prose could stay bare.

- markdown-editing-controller: _styledCodeRanges repeats the editor
  leftmost-rule walk and returns the code spans and fences it draws;
  _isInCode keeps gating link chips unchanged
- compose-bar: requalification excludes those ranges
- tests: composer journeys for fences, list fences, list spans, spans
  after bold and italics, and prose around code and list text
- docs/mention-editor: unstyled markdown code forms are qualified like
  prose

Co-authored-by: goose-wayne <ae6b377e5b6d090ee22558d19246413a5731628a127e25371111badfd4861535@buzz.block.builderlab.xyz>
Signed-off-by: Kalvin Chau <[email protected]>
keeps compose_bar_widget within the mobile file size limit; behavior is
unchanged.

Co-authored-by: goose-wayne <ae6b377e5b6d090ee22558d19246413a5731628a127e25371111badfd4861535@buzz.block.builderlab.xyz>
Signed-off-by: Kalvin Chau <[email protected]>
…icks

Requalifying namesakes dropped the earlier plain binding when its only
remaining occurrence sat directly against code backticks, because the
occurrence matcher does not see a backtick-adjacent mention. Draft
persistence still counted it, so unformatting that code later left an
ambiguous unbound name. Keep the binding using persistence's presence rule.

Signed-off-by: Tom Brow <[email protected]>
…esakes

Requalification only knew the selected labels, so picking a second Scout
also qualified the @scout prefix of a typed @scout Leader, breaking that
mention and silently dropping Scout Leader from the send. Give the typed
member labels the send resolves to the longest-occurrence walk, after the
selected keys, so only the earlier selection's own occurrences are
rewritten. The send path and requalification now share one builder.

Signed-off-by: Tom Brow <[email protected]>
the helper doc already describes the typed member candidates.

Co-authored-by: peon <9ac6794b000690b7e814eb1805ad32405d0bec7d52838de3a86cf967565dacc0@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Kalvin Chau <[email protected]>
@kalvinnchau
kalvinnchau merged commit 3c0adc1 into main Nov 13, 2026
51 of 52 checks passed
@kalvinnchau
kalvinnchau deleted the peon/mobile-namesake-mentions branch November 13, 2026 03:11
bostonaholic added a commit that referenced this pull request Nov 13, 2026
Co-authored-by: mboston.Engineer <932d3b6ebea6cc83e091551ae46d1c7e7f8f7d0fa8e9cef5e6facc8544af413b@buzz.block.builderlab.xyz>

* origin/main:
  fix(mobile): require Builderlab consent for existing identities (#8823)
  feat(mobile): use HTTP/2 on iOS through app-wide URLSessions (#8897)
  fix(relay): publish a git push only when refs changed; check the protocol by refinement (#9425)
  fix(mobile): show shared chats under Solo (#9348)
  chore(release): release Buzz Desktop version 0.5.29 (#9456)
  feat(mobile): render messages with gpt_markdown 1.3.4 plusparse (#8945)
  fix(acp): bound observer retention by bytes (#7987) (#9436)
  Tune release codegen for faster/smaller binaries (#9434)
  feat(desktop): add dismissible banner pointing to the new buzz app (#9379)
  fix(mobile): keep publishing presence while the app is open (#9441)
  feat(mobile): share into Buzz from the iOS share sheet (#9433)
  fix(mobile): qualify every namesake mention and keep authored mention casing (#9325)
  fix(mobile): match browser GIF timing in the iOS reaction sheet (#9437)
  fix(mobile): play short-delay animation frames at browser speed (#9432)
  buzz-search: read profile names without the profile_name_fields function (#9397)
  buzz-db: build the community deletion lock key in Rust (#9396)
  fix(cli): pair for the active community, skip stopped desktops, accept a bare relay host (#9417)
  test(mobile): run push tests without a gateway dart-define (#9423)
  fix(mobile): never pop Home when archiving from channel settings (#9387)
  perf(acp): reduce observer CPU and lock overhead (#9381)

Signed-off-by: Matthew Boston <[email protected]>
bostonaholic added a commit that referenced this pull request Nov 13, 2026
…count-backfill

Co-authored-by: mboston.Engineer <932d3b6ebea6cc83e091551ae46d1c7e7f8f7d0fa8e9cef5e6facc8544af413b@buzz.block.builderlab.xyz>

* bostonaholic--agent-reply-count:
  fix(mobile): require Builderlab consent for existing identities (#8823)
  feat(mobile): use HTTP/2 on iOS through app-wide URLSessions (#8897)
  fix(relay): publish a git push only when refs changed; check the protocol by refinement (#9425)
  fix(mobile): show shared chats under Solo (#9348)
  chore(release): release Buzz Desktop version 0.5.29 (#9456)
  feat(mobile): render messages with gpt_markdown 1.3.4 plusparse (#8945)
  fix(acp): bound observer retention by bytes (#7987) (#9436)
  Tune release codegen for faster/smaller binaries (#9434)
  feat(desktop): add dismissible banner pointing to the new buzz app (#9379)
  fix(mobile): keep publishing presence while the app is open (#9441)
  feat(mobile): share into Buzz from the iOS share sheet (#9433)
  fix(mobile): qualify every namesake mention and keep authored mention casing (#9325)
  fix(mobile): match browser GIF timing in the iOS reaction sheet (#9437)
  fix(mobile): play short-delay animation frames at browser speed (#9432)
  buzz-search: read profile names without the profile_name_fields function (#9397)
  buzz-db: build the community deletion lock key in Rust (#9396)
  fix(cli): pair for the active community, skip stopped desktops, accept a bare relay host (#9417)
  test(mobile): run push tests without a gateway dart-define (#9423)
  fix(mobile): never pop Home when archiving from channel settings (#9387)
  perf(acp): reduce observer CPU and lock overhead (#9381)

Signed-off-by: Matthew Boston <[email protected]>

This branch was successfully deployed

No deployments
codex-review — fa4032d9 Deployed Nov 13, 2026 by kalvinnchau via Run Codex Security Review #14804
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants