fix(meshcore): seed in-memory contacts from DB so the DM list isn't empty on a flaky source#3554
Conversation
The DM contact list is sourced from getContacts() (the in-memory this.contacts map), which is only populated by the live device get_contacts. On a flaky/slow companion that returns empty or times out — and refreshContacts deliberately won't wipe on an empty result — the in-memory list stayed nearly empty. So the DM page showed a handful of unnamed entries while the node/map view (DB-backed getAllNodes) showed the full set. This was visible per-source: a healthy companion's DM list was fine; a flaky one's was sparse. Add seedContactsFromDb(), called in connect() right before the live refreshContacts(): it pre-fills this.contacts from the persisted node list (the same DB the map reads), skipping the local node and never clobbering a fresher in-memory entry. A successful live refresh still replaces it with the device-authoritative list; a degraded one keeps the DB-seeded contacts so the DM and map views stay consistent. Companion-only; non-fatal on DB error. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @Yeraze's task —— View job PR Review: fix(meshcore): seed in-memory contacts from DBTasks:
SummaryThis PR correctly addresses a real bug: the DM contact list ( The implementation is clean and the logic is sound. A few observations: Code Quality
The implementation is well-structured. Minor observations:
Potential Issue: Reconnect Scenario
This works correctly. However, if a reconnect happens while Test Coverage
The test file covers the four key behaviors well:
One gap: no test for the DB error path (the Test design note: Using No Security or Performance Concerns
VerdictApprove. The fix is correct, minimal, and well-tested. The one recommended addition (error-path test) is optional but would be a nice follow-up. |
|
Thanks for the review! On the optional DB-error-path test: I did write one initially, but it trips vitest's spy error-surfacing — a |
Summary
On multi-source MeshCore, the map page showed a full node list but the DM page showed only a handful of unnamed entries for one source. Root cause:
getAllNodes()→databaseService.meshcore.getNodesBySource()(DB-backed) → full list ✓getContacts()→this.contacts(in-memory only), which is populated solely by the live deviceget_contacts.this.contactswas never seeded from the DB. On a flaky/slow companion whoseget_contactsreturns empty or times out — andrefreshContacts()deliberately won't wipe the list on an empty result (the "node list collapses to 1" guard) — the in-memory map stayed nearly empty, with only stray advert-push entries (often withoutadvName, hence the unnamed "ID#" rows). Meanwhile the DB still held the full set, so the map looked fine. That's why it was per-source: a healthy companion's DM list worked; a flaky one's didn't.(Observed on a source that was logging
Native command timeout: get_channels.)Fix
Add
seedContactsFromDb(), called inconnect()immediately before the liverefreshContacts():this.contactsfrom the persisted node list (the same DB the map reads).Mirrors the existing message-seeding-from-DB pattern already in
connect().Testing
meshcoreManager.seedContacts.test.ts: seeds named contacts, skips the local node, doesn't clobber a live in-memory entry, and is a no-op for repeater sources.tscclean.Relation to #3550
Independent of the "define a path by name" PR (#3550). That PR touched the path editor; this touches contact loading. Branched off
main.🤖 Generated with Claude Code