From 43c3f43e106501f30b4c2b3874d8506dde1f7c2f Mon Sep 17 00:00:00 2001 From: MarekZegare4 Date: Sat, 27 Jun 2026 00:31:06 +0200 Subject: [PATCH] fix(companion): also clear stale contact refs on silent auto-eviction onContactOverwrite() (the contact-table-full LRU eviction path) deleted the contact's blob and notified the companion app, but never called the new onContactRemoved() cleanup -- so a Favourites Dial slot, Locator target, or Live Share target could still go stale, just via the silent auto-evict path instead of an explicit removal. This is likely the main real-world cause of the "(gone)" tile the docs described, since auto-eviction happens far more often than an explicit CMD_REMOVE_CONTACT. Also sync the two docs that described the old (now wrong) behaviour: Locator's "survives delete" claim, and Favourites Dial's "(gone) until reassigned" claim. Co-Authored-By: Claude Sonnet 4.6 --- docs/solo_features/favourites_dial/favourites_dial.md | 2 +- docs/solo_features/tools_screen/tools_screen.md | 2 +- examples/companion_radio/AbstractUITask.h | 8 +++++--- examples/companion_radio/MyMesh.cpp | 1 + 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/solo_features/favourites_dial/favourites_dial.md b/docs/solo_features/favourites_dial/favourites_dial.md index e71b2815..6f636aff 100644 --- a/docs/solo_features/favourites_dial/favourites_dial.md +++ b/docs/solo_features/favourites_dial/favourites_dial.md @@ -29,7 +29,7 @@ Navigate tiles with **UP / DOWN / LEFT / RIGHT**. Pressing a directional key at Filled tiles show an unread message count in the top-right corner when there are unread DMs from that contact. The contact name is ellipsized to make room for the badge. -If a pinned contact has been removed from the contacts list, the tile shows `(gone)` until the slot is reassigned. +If a pinned contact is removed from the contacts list — explicitly, or auto-evicted to make room when the table is full — its slot is freed automatically and goes back to an empty `+` tile. --- diff --git a/docs/solo_features/tools_screen/tools_screen.md b/docs/solo_features/tools_screen/tools_screen.md index 4673c5c1..0cd842f6 100644 --- a/docs/solo_features/tools_screen/tools_screen.md +++ b/docs/solo_features/tools_screen/tools_screen.md @@ -253,7 +253,7 @@ The tool holds both directions of sharing in one flat list. Navigate with **UP/D -A single **geofence** that beeps and shows an alert when you cross **into** or **out of** a radius. The target can be a **saved waypoint** (a fixed place — "tell me when I'm back at camp") or a **live contact** (a person sharing their position via Live Share — "alert me when my friend gets near / falls behind"). A waypoint target is a **snapshot** (coordinate + label copied), so it keeps working even if you later edit or delete that waypoint; a contact target follows the person's latest shared position. +A single **geofence** that beeps and shows an alert when you cross **into** or **out of** a radius. The target can be a **saved waypoint** (a fixed place — "tell me when I'm back at camp") or a **live contact** (a person sharing their position via Live Share — "alert me when my friend gets near / falls behind"). A waypoint target is a **snapshot** (coordinate + label copied), so it keeps working even if you later edit that waypoint; a contact target follows the person's latest shared position. **Deleting** the target's waypoint, or the target contact being removed from the contacts list, clears the Locator target back to `none` instead of leaving it pointed at something that's gone. Navigate with **UP/DOWN**, change a value with **LEFT/RIGHT** (or **Enter**); **Cancel/Back** saves and returns to Tools. diff --git a/examples/companion_radio/AbstractUITask.h b/examples/companion_radio/AbstractUITask.h index 88bc0fec..f1ac9024 100644 --- a/examples/companion_radio/AbstractUITask.h +++ b/examples/companion_radio/AbstractUITask.h @@ -73,9 +73,11 @@ public: virtual void onSharedLocation(const uint8_t* pub_key, const char* name, int32_t lat_1e6, int32_t lon_1e6, uint32_t ts, bool verified) {} - // A contact was removed (companion app / CLI command). Lets UI state that - // references contacts by pubkey (favourite slots, the Locator/Live Share - // target) drop a reference that would otherwise dangle. Default no-op. + // A contact is gone — removed explicitly (companion app / CLI command) or + // silently auto-evicted to make room when the contact table is full. Lets + // UI state that references contacts by pubkey (favourite slots, the + // Locator/Live Share target) drop a reference that would otherwise dangle. + // Default no-op. virtual void onContactRemoved(const uint8_t* pub_key) {} virtual void loop() = 0; }; diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 1288aa6f..12a08769 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -352,6 +352,7 @@ uint8_t MyMesh::getAutoAddMaxHops() const { void MyMesh::onContactOverwrite(const uint8_t* pub_key) { _store->deleteBlobByKey(pub_key, PUB_KEY_SIZE); // delete from storage + if (_ui) _ui->onContactRemoved(pub_key); // same cleanup as an explicit CMD_REMOVE_CONTACT if (_serial->isConnected()) { out_frame[0] = PUSH_CODE_CONTACT_DELETED; memcpy(&out_frame[1], pub_key, PUB_KEY_SIZE);