Skip to content

feat(nodes): local display names - #7763

Merged
jamesarich merged 10 commits into
mainfrom
feat/local-display-names
Oct 25, 2026
Merged

jamesarich merged 10 commits into
mainfrom
feat/local-display-names

Conversation

@jamesarich

@jamesarich jamesarich commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

Brings Android in line with design#170 - people can give any node a local display name, and node details keeps the broadcast long name readable while one is set. Apple already ships this; Notes stays as is.

🌟 New Features

  • display_name column on nodes (Room 65 → 66 auto-migration), preserved across NodeInfo upserts, identity renumbers and DB merges
  • Node.effectiveLongName is the one resolver for display; share, QR, contact sharing, exports (messages, node DB, GPX, debug log), open-in-maps, the TAK callsign and the avatar stay on user.long_name
  • Edit from a Display name card on node details or the node list menu; empty clears, capped at 36 UTF-8 bytes to match Apple
  • Long Name row under the name in node details, only while a display name is set
  • Display name shown across node list, details, messages and contacts, notifications and shortcuts, maps, widget, traceroute, neighbor info, connections, remote admin and the AI surfaces
  • Search matches either name; alphabetical sort uses the name shown; an exact name shared by two nodes is ambiguous to the AI recipient lookup
  • Own node long press now offers Edit name (User settings) and Share contact alongside Update status

🧹 Chores

  • User docs for display names
  • Node.kt and AirQualityMetrics.kt carry a few reflow-only hunks - spotless reformats the whole file once it's touched

Testing Performed

  • Migration: NodeDisplayNameMigrationTest
  • DAO and data: CommonNodeInfoDaoTest (upsert preservation, alpha sort), CommonNodeIdentityMigrationDaoTest, DatabaseMergerTest, NodeMappingTest, FakeNodeRepositoryTest
  • Resolver and naming: NodeDisplayNameTest, NodeDetailNameUseCaseTest, RouteDiscoveryTest, NeighborInfoHandlerImplTest, ContactsViewModelTest, ConversationShortcutPublisherTest, FuzzyNameResolverTest
  • Never leaves the device: ExportDataUseCaseTest, ExportNodeDatabaseUseCaseTest, GpxTrackNameTest, ToSharedContactTest, MeshNodeCoTConversionTest, TAKMeshIntegrationTest
  • Editing and menus: NodeManagementActionsTest, OwnNodeMenuItemsTest
  • Not run on a device yet

Fixes #7760

Summary by CodeRabbit

  • New Features
    • Set or clear a device-local display name for nodes, including your own. Names are trimmed and limited to 36 UTF-8 bytes.
    • Local display names appear across node lists, details, messages, notifications, maps, and related views. You can also search for nodes by display name.
    • When a name matches multiple nodes, name-based lookup reports the ambiguity instead of choosing one.
  • Bug Fixes
    • Display names are retained when node information is refreshed or merged, and carried across node identity changes when needed.
    • Broadcast names remain in sharing, data exports, and other broadcast-name outputs.
  • Documentation
    • Added guidance on setting display names and where local names differ from broadcast names.

A per-node name that stays on the device, preserved across NodeInfo upserts, renumbers and database merges. Adds the Node resolver and search match.
… row

Edit from the node details card or the node list menu. Node details shows the broadcast long name in its own row while a display name is set.
…s and widget

Share, export, QR and CoT keep the broadcast long name.
…st name

The alpha node sort and the reaction details list used the broadcast name while the rest of the UI shows the display name. A test name with a comma failed Kotlin/Native compilation.
Kotlin/Native rejects commas in backtick test names.
…urfaces

The GPX track name now carries the broadcast long name. The contact list
recomputes when a display name changes. Connections, settings, traceroute
hops, neighbor info and the AI assistant identity use the display name.
Display name limit docs no longer claim to match User.long_name.
Long press on our node now offers Update status, Edit name (opens the device
User settings) and Share contact, each only when available.
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Walkthrough

This change adds device-local display names for nodes, including storage, editing, and display-name-based labels across app surfaces. It also updates node search and sorting, preserves display names during database updates, and retains broadcast names for sharing and export.

Changes: Local display names

Layer / File(s) Summary
Display-name model and naming rules
core/model/..., core/model/src/commonTest/...
Node gains a local display name, helpers for selecting and normalizing names, and search matching. Traceroute labels accept a display name.
Persistence and repository writes
core/database/..., core/data/src/commonMain/kotlin/org/meshtastic/core/data/datasource/..., core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/..., core/repository/..., core/testing/...
The database stores display names, carries them through node updates and identity migration, and sorts by the displayed name. Repository write paths set or clear the name.
Editing from node screens
feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/..., feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/detail/..., feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/list/..., core/resources/...
Node list menus and node details expose name-editing controls. Save handlers normalize the input and forward it to the repository.
Effective names across app surfaces
androidApp/..., core/data/..., core/service/..., core/ui/..., desktopApp/..., feature/connections/..., feature/map..., feature/node/..., feature/settings/..., feature/widget/...
AI output, notifications, connection and map views, node details and metrics, settings, and widgets use effective node names in the described display paths.
Messaging, contacts, and shortcuts
feature/messaging/..., core/service/...
Message and reaction labels and contact names use local display names. Contact and shortcut flows respond to node-name changes.
Search, broadcast-name boundaries, and documentation
core/data/src/commonMain/kotlin/org/meshtastic/core/data/ai/FuzzyNameResolver.kt, feature/connections/..., feature/widget/..., core/domain/..., core/model/..., core/takserver/..., docs/en/user/...
Search includes display names. Tests verify that sharing, exports, and TAK callsigns use broadcast names. User documentation describes local names and their scope.

Priority: Normal

Merge Risk: Low · up to 307a9

After assigning a local name, a user may need to use that name instead of the node’s broadcast name to address an AI message. The remaining test concerns warrant owner follow-up, but the known behavior is bounded.

Pre-merge checks: Passed 5 · Failed 3

Failed Failed checks: 3 warnings

Check name Status Explanation Resolution
Sibling Call Sites And Presence Semantics Warning The prior failure remains. Node.matchesSearch now matches displayName, and the live-update and widget search paths do too. However, FakeNodeRepository.filterNode at `core/testing/src/commonMain/… Update FakeNodeRepository.filterNode to match node.displayName or delegate to Node.matchesSearch while preserving the existing filters. Add a test that getNodes(filter = ...) finds a node by its local display name.
Tests Prove The Path, Not The End State Warning The prior failure remains unresolved. FakeNodeRepositoryTest.kt:153-161 calls setNodeDisplayName and reads nodeDBbyNum. Four NodeManagementActionsTest cases at lines 183-218 seed `FakeNodeRepo… Replace the four NodeManagementActionsTest cases with a mocked NodeRepository and use verifySuspend to assert Mine, the empty string, the capped ASCII value, and the multibyte-safe capped value. Replace `FakeNodeRepositoryTest.setNo…
Regression Coverage For Changed Behavior Warning FAIL — Regression coverage remains incomplete. The reviewed diff adds tests for model behavior, DAO persistence, migration, exports, protocol isolation, resolver ambiguity, neighbor naming, contact up… Add direct regression tests for each listed path. Use nodes whose displayName and user.long_name differ, then assert the local display name on display surfaces and the broadcast long name on export/protocol surfaces. Add Compose tests f…
Passed Passed checks: 5 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely summarizes the main change: adding local display names for nodes.
Linked Issues check Passed The PR meets the coding requirements in [#7760]. Node stores a local displayName, resolves effectiveLongName, matches searches on both names, and preserves the broadcast short name and export id…
Out of Scope Changes check Passed The changes stay within [#7760]. Production changes implement local-name storage, editing, persistence, display propagation, search, sorting, broadcast-name preservation, or supporting UI and document…
Moved Code Diffed Against Its Original Passed PASS: The PR does not move or extract an existing production type or function. The authoritative diff has no deleted source files, renames, or high-similarity copies. The few deleted declarations are …
Full details: Linked Issues check

Explanation

The PR meets the coding requirements in [#7760]. Node stores a local displayName, resolves effectiveLongName, matches searches on both names, and preserves the broadcast short name and export identity. The Room 65→66 migration, DAO upserts, identity renumbering, and database merge preserve display names. Editing supports remote nodes and the own node, clears empty input, and limits names to 36 UTF-8 bytes. The changed node, message, contact, notification, map, traceroute, neighbor, widget, connection, remote-admin, and AI surfaces use the effective name. Sharing, QR/contact data, exports, GPX, and TAK tests retain broadcast names and exclude the local name. The reported automated tests cover these requirements.

Full details: Out of Scope Changes check

Explanation

The changes stay within [#7760]. Production changes implement local-name storage, editing, persistence, display propagation, search, sorting, broadcast-name preservation, or supporting UI and documentation. The focused AdministrationSection diff changes only the metadata request label to effectiveLongName; it does not add unrelated remote-shell behavior. Added tests verify the feature and its privacy boundaries. Formatting-only changes do not establish unrelated scope.

Full details: Moved Code Diffed Against Its Original

Explanation

PASS: The PR does not move or extract an existing production type or function. The authoritative diff has no deleted source files, renames, or high-similarity copies. The few deleted declarations are signature/body edits in the same files, including limitToBytes, tracerouteHopName, LocalNodeContextMenu, and the local getUsername; the added files contain new display-name features and tests. Therefore this moved-code check is not applicable.

Full details: Sibling Call Sites And Presence Semantics

Explanation

The prior failure remains. Node.matchesSearch now matches displayName, and the live-update and widget search paths do too. However, FakeNodeRepository.filterNode at core/testing/src/commonMain/kotlin/org/meshtastic/core/testing/FakeNodeRepository.kt:120-123 still checks only user.long_name and user.id. This unfixed sibling can omit nodes found by local display name. No new physical metric field defaults to 0; Node.displayName defaults to an empty string.

Resolution

Update FakeNodeRepository.filterNode to match node.displayName or delegate to Node.matchesSearch while preserving the existing filters. Add a test that getNodes(filter = ...) finds a node by its local display name.

Full details: Tests Prove The Path, Not The End State

Explanation

The prior failure remains unresolved. FakeNodeRepositoryTest.kt:153-161 calls setNodeDisplayName and reads nodeDBbyNum. Four NodeManagementActionsTest cases at lines 183-218 seed FakeNodeRepository, invoke the action, and assert values from the fake backing map. These tests do not verify that NodeManagementActions issued the intended normalized repository request. The repository failure test correctly uses verifySuspend, but it does not replace the four backing-store tests.

Resolution

Replace the four NodeManagementActionsTest cases with a mocked NodeRepository and use verifySuspend to assert Mine, the empty string, the capped ASCII value, and the multibyte-safe capped value. Replace FakeNodeRepositoryTest.setNodeDisplayName persists and clears the display name with a consumer-level test that verifies an observable side effect or a requested write instead of reading nodeDBbyNum after the fake mutates it.

Full details: Regression Coverage For Changed Behavior

Explanation

FAIL — Regression coverage remains incomplete. The reviewed diff adds tests for model behavior, DAO persistence, migration, exports, protocol isolation, resolver ambiguity, neighbor naming, contact updates, shortcut renaming, normalization, detail titles, menu predicates, and GPX names. It does not add direct tests for these changed paths: - DisplayNameDialog, DisplayNameSection, NodeContextMenu, NodeListScreen, NodeDetailContent, and NodeDetailsSection: Compose save/clear, IME completion, dismissal, callback wiring, menu gating, and conditional broadcast-name-row rendering are untested. OwnNodeMenuItemsTest checks only a predicate, and the existing local-menu UI test covers only update status. - MessageScreen, MessageViewModel.getLongName, MessageItem, MessageListPaged, and ReactionDialog: no test uses different local and broadcast names to verify title recomposition after a node-flow update, unread sender text, sender and mention labels, or local and remote reaction labels. - MeshNotificationManagerImpl and DesktopMeshNotificationManager: existing notification tests use broadcast-name fixtures. No test inspects Android notification text, Person names, new-node text, low-battery text, or desktop notification messages with a distinct local display name. - AiFunctionProviderImpl, GeofenceMonitor, MeshDataHandlerImpl, and TracerouteHandlerImpl: the added resolver and neighbor tests do not verify AI results, geofence notification names, message-event notification names, or rendered traceroute output with a local display name and blank-name fallback. - filterLiveUpdateCandidates, connected/live-update UI adapters, nodesToFeatureCollection, toSitePlannerParams, HudSubject.spokenName, and widget candidate/config/state paths: existing fixtures do not set a local display name, so local-name search and labels are untested. The Google GeminiNanoDocAssistant and MapView consumers also have no local-name regression tests. - NodeDetailViewModel, NodeListViewModel, MetricsViewModel, CompassViewModel, and RemoteShellViewModel: existing tests assert broadcast-name behavior or unrelated metrics. They do not capture every changed request argument or output label with distinct local and broadcast names, nor verify blank-name fallback. - NodeRepositoryImpl and SwitchingNodeInfoWriteDataSource: no test invokes the production write chain for setNodeDisplayName; current repository tests mock the write data source and current switching tests cover other operations. Database backup tests do not restore a database containing a non-empty display_name.

Resolution

Add direct regression tests for each listed path. Use nodes whose displayName and user.long_name differ, then assert the local display name on display surfaces and the broadcast long name on export/protocol surfaces. Add Compose tests for editing, dismissal, menu callbacks, gating, and the broadcast-name row. Add messaging recomposition and reaction tests, Android and desktop notification output tests, AI/event-handler tests, map/connection/HUD/widget adapter tests, and request/metrics label tests with blank-name fallbacks. Add Google-flavor tests for the AI prompt and map cluster snippet. Add an integration test through NodeRepositoryImpl and SwitchingNodeInfoWriteDataSource, plus a version-66 backup/restore test that preserves display_name.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added desktop Desktop target enhancement New feature or request labels Oct 25, 2026
@jamesarich
jamesarich marked this pull request as ready for review October 25, 2026 15:13

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments: 2
core/database/src/commonTest/kotlin/org/meshtastic/core/database/dao/CommonNodeInfoDaoTest.kt: 1

134-149: Trivial · Functional Correctness · Quick win

Make the alpha-sort test set longName explicitly.

The entity helper does not pass longName, so the long_name column keeps the NodeEntity default of null. For nodes 2 and 3, the alpha sort key then evaluates to NULL. Their order does not depend on "Bravo" or "Charlie". A broken ELSE long_name branch would produce the same result, so the test cannot detect it.

Pass the long name explicitly, and use names whose alphabetical order differs from the node number order:

🧪 Suggested fix
         fun entity(num: Int, longName: String, displayName: String = "") = NodeEntity(
             num = num,
+            longName = longName,
             user =
             User.Builder()
                 .also { wb ->
                     wb.id = "!$num"
                     wb.long_name = longName
                     wb.short_name = "n$num"
                 }
                 .build(),
             displayName = displayName,
         )
-        dao.putAll(listOf(entity(1, "Alpha", displayName = "Zulu"), entity(2, "Bravo"), entity(3, "Charlie")))
+        dao.putAll(listOf(entity(1, "Alpha", displayName = "Zulu"), entity(2, "Charlie"), entity(3, "Bravo")))

         val order = dao.getNodes("alpha", true, false, -1).first().map { it.node.num }
-        assertEquals(listOf(2, 3, 1), order)
+        assertEquals(listOf(3, 2, 1), order)
core/database/src/commonMain/kotlin/org/meshtastic/core/database/DatabaseMerger.kt: 1

136-137: Trivial · Performance & Scalability · Low value

Reuse the destination node snapshot.

The merge runs once per newly associated secondary transport, so this is not a material hot-path regression. However, the PR expands the existing notes-only single-row lookup to display-name nodes. Reuse the already loaded snapshot to remove this N+1 query pattern.

♻️ Suggested change
-        val destNums = dest.nodeInfoDao().getAllNodesSnapshot().mapTo(mutableSetOf()) { it.num }
+        val destByNum = dest.nodeInfoDao().getAllNodesSnapshot().associateBy { it.num }
         source.nodeInfoDao().getAllNodesSnapshot().forEach { node ->
+            val existing = destByNum[node.num]
             when {
-                node.num !in destNums -> dest.nodeInfoDao().upsert(node)
+                existing == null -> dest.nodeInfoDao().upsert(node)

                 node.notes.isNotBlank() || node.displayName.isNotBlank() -> {
-                    val existing = dest.nodeInfoDao().getNodeByNum(node.num)?.node
-                    if (existing != null) {
-                        if (node.notes.isNotBlank() && existing.notes.isBlank()) {
-                            dest.nodeInfoDao().setNodeNotes(node.num, node.notes)
-                        }
-                        if (node.displayName.isNotBlank() && existing.displayName.isBlank()) {
-                            dest.nodeInfoDao().setNodeDisplayName(node.num, node.displayName)
-                        }
+                    if (node.notes.isNotBlank() && existing.notes.isBlank()) {
+                        dest.nodeInfoDao().setNodeNotes(node.num, node.notes)
+                    }
+                    if (node.displayName.isNotBlank() && existing.displayName.isBlank()) {
+                        dest.nodeInfoDao().setNodeDisplayName(node.num, node.displayName)
                     }
                 }
             }

Review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 1bedc5d and 720cb5e.

Files selected for processing: 98
  • .skills/compose-ui/strings-index.txt
  • androidApp/src/google/kotlin/org/meshtastic/app/ai/GeminiNanoDocAssistant.kt
  • androidApp/src/google/kotlin/org/meshtastic/app/map/MapView.kt
  • core/data/src/commonMain/kotlin/org/meshtastic/core/data/ai/AiFunctionProviderImpl.kt
  • core/data/src/commonMain/kotlin/org/meshtastic/core/data/ai/FuzzyNameResolver.kt
  • core/data/src/commonMain/kotlin/org/meshtastic/core/data/datasource/NodeInfoWriteDataSource.kt
  • core/data/src/commonMain/kotlin/org/meshtastic/core/data/datasource/SwitchingNodeInfoWriteDataSource.kt
  • core/data/src/commonMain/kotlin/org/meshtastic/core/data/manager/GeofenceMonitor.kt
  • core/data/src/commonMain/kotlin/org/meshtastic/core/data/manager/MeshDataHandlerImpl.kt
  • core/data/src/commonMain/kotlin/org/meshtastic/core/data/manager/NeighborInfoHandlerImpl.kt
  • core/data/src/commonMain/kotlin/org/meshtastic/core/data/manager/TracerouteHandlerImpl.kt
  • core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/NodeRepositoryImpl.kt
  • core/data/src/commonTest/kotlin/org/meshtastic/core/data/manager/NeighborInfoHandlerImplTest.kt
  • core/database/schemas/org.meshtastic.core.database.MeshtasticDatabase/66.json
  • core/database/src/commonMain/kotlin/org/meshtastic/core/database/DatabaseBackup.kt
  • core/database/src/commonMain/kotlin/org/meshtastic/core/database/DatabaseMerger.kt
  • core/database/src/commonMain/kotlin/org/meshtastic/core/database/MeshtasticDatabase.kt
  • core/database/src/commonMain/kotlin/org/meshtastic/core/database/dao/NodeInfoDao.kt
  • core/database/src/commonMain/kotlin/org/meshtastic/core/database/entity/NodeEntity.kt
  • core/database/src/commonTest/kotlin/org/meshtastic/core/database/DatabaseMergerTest.kt
  • core/database/src/commonTest/kotlin/org/meshtastic/core/database/dao/CommonNodeIdentityMigrationDaoTest.kt
  • core/database/src/commonTest/kotlin/org/meshtastic/core/database/dao/CommonNodeInfoDaoTest.kt
  • core/database/src/commonTest/kotlin/org/meshtastic/core/database/entity/NodeMappingTest.kt
  • core/database/src/jvmTest/kotlin/org/meshtastic/core/database/NodeDisplayNameMigrationTest.kt
  • core/domain/src/commonTest/kotlin/org/meshtastic/core/domain/usecase/settings/ExportDataUseCaseTest.kt
  • core/domain/src/commonTest/kotlin/org/meshtastic/core/domain/usecase/settings/ExportNodeDatabaseUseCaseTest.kt
  • core/model/src/commonMain/kotlin/org/meshtastic/core/model/HamName.kt
  • core/model/src/commonMain/kotlin/org/meshtastic/core/model/Node.kt
  • core/model/src/commonMain/kotlin/org/meshtastic/core/model/RouteDiscovery.kt
  • core/model/src/commonTest/kotlin/org/meshtastic/core/model/NodeDisplayNameTest.kt
  • core/model/src/commonTest/kotlin/org/meshtastic/core/model/RouteDiscoveryTest.kt
  • core/model/src/commonTest/kotlin/org/meshtastic/core/model/util/ToSharedContactTest.kt
  • core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/NodeRepository.kt
  • core/resources/src/commonMain/composeResources/values/strings.xml
  • core/service/src/androidMain/kotlin/org/meshtastic/core/service/ConversationShortcutPublisher.kt
  • core/service/src/androidMain/kotlin/org/meshtastic/core/service/MeshNotificationManagerImpl.kt
  • core/takserver/src/commonTest/kotlin/org/meshtastic/core/takserver/MeshNodeCoTConversionTest.kt
  • core/takserver/src/commonTest/kotlin/org/meshtastic/core/takserver/TAKMeshIntegrationTest.kt
  • core/testing/src/commonMain/kotlin/org/meshtastic/core/testing/FakeNodeRepository.kt
  • core/testing/src/commonTest/kotlin/org/meshtastic/core/testing/FakeNodeRepositoryTest.kt
  • core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/NodeItem.kt
  • core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/NodeItemCompact.kt
  • desktopApp/src/main/kotlin/org/meshtastic/desktop/notification/DesktopMeshNotificationManager.kt
  • docs/en/user/nodes.md
  • docs/en/user/settings-radio-user.md
  • feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/LiveUpdateViewModel.kt
  • feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/components/CurrentlyConnectedInfo.kt
  • feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/components/DeviceListItem.kt
  • feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/components/LiveUpdateCard.kt
  • feature/map-maplibre/src/commonMain/kotlin/org/meshtastic/feature/map/maplibre/geojson/NodeFeatures.kt
  • feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/SitePlannerLaunch.kt
  • feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/hud/HudChips.kt
  • feature/messaging/src/commonMain/kotlin/org/meshtastic/feature/messaging/Message.kt
  • feature/messaging/src/commonMain/kotlin/org/meshtastic/feature/messaging/MessageListPaged.kt
  • feature/messaging/src/commonMain/kotlin/org/meshtastic/feature/messaging/MessageViewModel.kt
  • feature/messaging/src/commonMain/kotlin/org/meshtastic/feature/messaging/component/MessageItem.kt
  • feature/messaging/src/commonMain/kotlin/org/meshtastic/feature/messaging/component/Reaction.kt
  • feature/messaging/src/commonMain/kotlin/org/meshtastic/feature/messaging/ui/contact/ContactsViewModel.kt
  • feature/messaging/src/commonTest/kotlin/org/meshtastic/feature/messaging/ui/contact/ContactsViewModelTest.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/compass/CompassViewModel.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/AdministrationSection.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/DisplayNameDialog.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/DisplayNameSection.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/LinkedCoordinatesItem.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/NodeContextMenu.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/NodeDetailsSection.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/detail/NodeDetailContent.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/detail/NodeDetailPreviews.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/detail/NodeDetailScreens.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/detail/NodeDetailViewModel.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/detail/NodeManagementActions.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/domain/usecase/CommonGetNodeDetailsUseCase.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/list/NodeListScreen.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/list/NodeListViewModel.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/AirQualityMetrics.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/DeviceMetrics.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/EnvironmentMetrics.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/HostMetricsLog.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/MetricsViewModel.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/NeighborInfoLog.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PaxMetrics.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PositionLogScreens.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PowerMetrics.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/SignalMetrics.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteLog.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/TracerouteMapScreen.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/terminal/RemoteShellViewModel.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/navigation/AdaptiveNodeListScreen.kt
  • feature/node/src/commonTest/kotlin/org/meshtastic/feature/node/detail/NodeManagementActionsTest.kt
  • feature/node/src/commonTest/kotlin/org/meshtastic/feature/node/domain/usecase/NodeDetailNameUseCaseTest.kt
  • feature/node/src/commonTest/kotlin/org/meshtastic/feature/node/list/OwnNodeMenuItemsTest.kt
  • feature/node/src/commonTest/kotlin/org/meshtastic/feature/node/metrics/GpxTrackNameTest.kt
  • feature/settings/src/androidMain/kotlin/org/meshtastic/feature/settings/SettingsScreen.kt
  • feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/component/RadioAdminAppBar.kt
  • feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/ShutdownConfirmationDialog.kt
  • feature/widget/src/main/kotlin/org/meshtastic/feature/widget/NodeTrackerCandidates.kt
  • feature/widget/src/main/kotlin/org/meshtastic/feature/widget/NodeTrackerConfigActivity.kt
  • feature/widget/src/main/kotlin/org/meshtastic/feature/widget/NodeTrackerWidgetState.kt

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.

Comment thread docs/en/user/nodes.md Outdated
- AI recipient lookup treats an exact name shared by two nodes as ambiguous
- DM shortcuts republish when only a display name changes
- Open-in-maps passes the broadcast name to the external app
- Name fields trim leading whitespace before the byte cap; the node details draft is keyed by node
- User docs cover backups, the maps handoff and own-node Edit name

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

Minor · Keep the broadcast long name resolvable. · FuzzyNameResolver.kt:43

core/data/src/commonMain/kotlin/org/meshtastic/core/data/ai/FuzzyNameResolver.kt:43
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the broadcast long name resolvable.

When a node has a different local display name, resolveNodeName removes its broadcast long name from the candidate list. A query using the broadcast long name can now return NotFound, although that query resolved before this change. Include both names as aliases for the same node. Deduplicate matches by node number so aliases do not create false ambiguity. As per path instructions, report “behaviour that contradicts ... an existing contract.”

Source: Path instructions


Review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 720cb5e and 307a98c.

Files selected for processing: 7
  • core/data/src/commonMain/kotlin/org/meshtastic/core/data/ai/FuzzyNameResolver.kt
  • core/data/src/commonTest/kotlin/org/meshtastic/core/data/ai/FuzzyNameResolverTest.kt
  • core/service/src/androidHostTest/kotlin/org/meshtastic/core/service/ConversationShortcutPublisherTest.kt
  • core/service/src/androidMain/kotlin/org/meshtastic/core/service/ConversationShortcutPublisher.kt
  • docs/en/user/nodes.md
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/DisplayNameDialog.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/DisplayNameSection.kt
Files skipped from review as they are similar to previous changes: 4
  • core/service/src/androidMain/kotlin/org/meshtastic/core/service/ConversationShortcutPublisher.kt
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/DisplayNameDialog.kt
  • docs/en/user/nodes.md
  • feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/component/DisplayNameSection.kt

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 2 remain after this review.

@jamesarich
jamesarich added this pull request to the merge queue Oct 25, 2026
Merged via the queue into main with commit bf7e115 Oct 25, 2026
18 checks passed
@jamesarich
jamesarich deleted the feat/local-display-names branch October 25, 2026 20:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

desktop Desktop target enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local display names for nodes

1 participant