mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 14:58:12 +00:00
docs(companion): make the entity-reference cleanup contract explicit
The onContactRemoved/onChannelRemoved hooks already clear every NodePrefs field keyed on a contact pubkey or channel index (verified complete), but the convention was opt-in with no reminder — new per-entity state could silently forget to register, the class of bug fixed earlier this session. Add a CONTRACT comment above each hook listing what it covers and instructing additions to land there, plus a terse [del->onContactRemoved] / [del->onChannelRemoved] tag on each of the eight keyed fields in NodePrefs.h. Now editing either side (struct field or hook) points at the other. Comments only; no behaviour change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -87,7 +87,7 @@ struct NodePrefs { // persisted to file
|
||||
uint16_t home_pages_mask; // bitmask of visible home pages (bit0=Clock..bit8=Shutdown); 0=all visible
|
||||
uint8_t bot_enabled; // 0=disabled, 1=DM bot active (responds to all DMs)
|
||||
uint8_t bot_channel_enabled; // 0=disabled, 1=channel bot active for bot_channel_idx
|
||||
uint8_t bot_channel_idx; // channel index for channel bot
|
||||
uint8_t bot_channel_idx; // channel index for channel bot [del→onChannelRemoved]
|
||||
char bot_trigger[64]; // DM trigger phrase (case-insensitive contains; "*" = any DM)
|
||||
char bot_reply_dm[140]; // auto-reply text for DM
|
||||
char bot_reply_ch[140]; // auto-reply text for channel
|
||||
@@ -100,7 +100,7 @@ struct NodePrefs { // persisted to file
|
||||
uint8_t buzzer_auto; // 0=manual (default), 1=auto-mute when BT connected
|
||||
struct DmNotifEntry { uint8_t prefix[4]; uint8_t state; }; // state: 0=default,1=muted,2=force-on
|
||||
static const int DM_NOTIF_TABLE_MAX = 16;
|
||||
DmNotifEntry dm_notif[DM_NOTIF_TABLE_MAX]; // 16*5 = 80 bytes
|
||||
DmNotifEntry dm_notif[DM_NOTIF_TABLE_MAX]; // 16*5 = 80 bytes [del→onContactRemoved]
|
||||
uint8_t dashboard_fields[3]; // 0=None,1=Batt V,2=Temp,3=Hum,4=Pres,5=GPS,6=Alt,7=Lux,8=CO2,9=Nodes,10=Msgs,11=Batt %
|
||||
uint32_t advert_auto_interval_sec; // periodic 0-hop advert with GPS: 0=off, else seconds
|
||||
// Second melody slot (same packing as ringtone_*)
|
||||
@@ -114,12 +114,12 @@ struct NodePrefs { // persisted to file
|
||||
// Advert sound filter: 0=all adverts, 1=zero-hop only
|
||||
uint8_t advert_sound_scope;
|
||||
// Per-channel melody override (2 bitmasks, 1 bit per channel)
|
||||
uint64_t ch_notif_melody_set; // bit i = channel i has explicit melody
|
||||
uint64_t ch_notif_melody_set; // bit i = channel i has explicit melody [del→onChannelRemoved]
|
||||
uint64_t ch_notif_melody_2; // bit i = use melody 2 (else melody 1, when set bit is set)
|
||||
// Per-DM melody table
|
||||
struct DmMelodyEntry { uint8_t prefix[4]; uint8_t slot; }; // slot: 0=global,1=melody1,2=melody2
|
||||
static const int DM_MELODY_TABLE_MAX = 16;
|
||||
DmMelodyEntry dm_melody[DM_MELODY_TABLE_MAX];
|
||||
DmMelodyEntry dm_melody[DM_MELODY_TABLE_MAX]; // [del→onContactRemoved]
|
||||
uint8_t use_lemon_font; // 0=default Adafruit font, 1=Lemon font (Unicode, pixel-accurate wrap)
|
||||
uint8_t display_rotation; // 0-3; only used on e-ink displays
|
||||
// Home screen page order: each byte = HomePageBit + 1. 0 terminates the list.
|
||||
@@ -138,7 +138,7 @@ struct NodePrefs { // persisted to file
|
||||
// Layout transposes between landscape (3×2) and portrait (2×3).
|
||||
static const uint8_t FAVOURITES_COUNT = 6;
|
||||
static const uint8_t FAVOURITE_PREFIX_LEN = 6;
|
||||
uint8_t favourite_contacts[FAVOURITES_COUNT][FAVOURITE_PREFIX_LEN];
|
||||
uint8_t favourite_contacts[FAVOURITES_COUNT][FAVOURITE_PREFIX_LEN]; // [del→onContactRemoved]
|
||||
|
||||
// GPS trail cadence. Logging on/off is a runtime state (Tools › Trail),
|
||||
// not a persisted preference.
|
||||
@@ -229,8 +229,8 @@ struct NodePrefs { // persisted to file
|
||||
// Configured from the Map (Trail screen) "Live share" menu.
|
||||
uint8_t loc_share_enabled; // 0=off (default), 1=auto-sharing on
|
||||
uint8_t loc_share_target_type; // 0=channel, 1=DM contact
|
||||
uint8_t loc_share_channel_idx; // target channel index (when target_type==0)
|
||||
uint8_t loc_share_dm_prefix[6]; // target contact pubkey prefix (when target_type==1)
|
||||
uint8_t loc_share_channel_idx; // target channel index (when target_type==0) [del→onChannelRemoved]
|
||||
uint8_t loc_share_dm_prefix[6]; // target contact pubkey prefix (when target_type==1) [del→onContactRemoved]
|
||||
uint8_t loc_share_move_idx; // movement gate level (index into locShareMoveMeters)
|
||||
uint8_t loc_share_interval_idx; // min send interval (index into locShareIntervalSecs)
|
||||
uint8_t loc_share_heartbeat_idx; // stationary heartbeat (index into locShareHeartbeatSecs)
|
||||
@@ -251,7 +251,7 @@ struct NodePrefs { // persisted to file
|
||||
// re-reads the latest [LOC] position each evaluation (keyed by pubkey prefix),
|
||||
// so the geofence follows a moving person ("alert when my friend is near").
|
||||
uint8_t locator_target_kind; // 0=waypoint (static), 1=live contact
|
||||
uint8_t locator_key[6]; // contact pubkey prefix when target_kind==1
|
||||
uint8_t locator_key[6]; // contact pubkey prefix when target_kind==1 [del→onContactRemoved]
|
||||
|
||||
// Trail auto-pause — when tracking, automatically freeze the trail (timer +
|
||||
// sampling) after the device has sat still for this long, and resume on the
|
||||
|
||||
@@ -2406,6 +2406,12 @@ void UITask::clearTargetIfWaypoint(int32_t lat_1e6, int32_t lon_1e6) {
|
||||
the_mesh.savePrefs();
|
||||
}
|
||||
|
||||
// CONTRACT: every NodePrefs field that keys on a contact pubkey/prefix is
|
||||
// cleared here, so a removed contact can't leave a dangling reference. If you
|
||||
// add such a field, add its cleanup below (and mark the field in NodePrefs.h).
|
||||
// Currently covered: favourite_contacts, locator_key, loc_share_dm_prefix,
|
||||
// dm_notif[], dm_melody[]. Called for both explicit removal and silent
|
||||
// auto-eviction (see MyMesh CMD_REMOVE_CONTACT / onContactOverwrite).
|
||||
void UITask::onContactRemoved(const uint8_t* pub_key) {
|
||||
if (!_node_prefs || !pub_key) return;
|
||||
bool changed = false;
|
||||
@@ -2445,6 +2451,10 @@ void UITask::onContactRemoved(const uint8_t* pub_key) {
|
||||
if (changed) the_mesh.savePrefs();
|
||||
}
|
||||
|
||||
// CONTRACT: every NodePrefs field that keys on a channel index is cleared here,
|
||||
// so a channel re-added at a freed slot can't inherit the old one's settings.
|
||||
// If you add such a field, add its cleanup below (and mark it in NodePrefs.h).
|
||||
// Currently covered: bot_channel_idx, loc_share_channel_idx, ch_notif_melody_*.
|
||||
void UITask::onChannelRemoved(uint8_t channel_idx) {
|
||||
if (!_node_prefs) return;
|
||||
bool changed = false;
|
||||
|
||||
Reference in New Issue
Block a user