From 6e0e981048b43f447a20348ad0f805af0ecaa816 Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Wed, 9 Sep 2026 16:22:04 +0200 Subject: [PATCH] fix(companion): arm the "Relayed by" tracker for bot-originated channel posts Remote Bot's channel trigger reply, channel command reply, and !gps fix result all mirrored their send into the on-device history with addOwnChannelMsg() but never called armChannelRelay() afterward, unlike the app's CMD_SEND_CHANNEL_TXT_MSG send which already did both -- so a bot's own channel posts never showed which repeaters echoed them back, while everything else did. Factor the always-together pair (mirror into history, then arm relay tracking from the send sendGroupMessage's sendFloodScoped already tracked) into MyMesh::mirrorOwnChannelMsg(), and route all four call sites through it instead of pairing the two calls by hand -- the bot bug was exactly a dropped second call, so a new call site can no longer add the first half without the second. Co-Authored-By: Claude Sonnet 5 --- examples/companion_radio/MyMesh.cpp | 18 +++++------------- examples/companion_radio/MyMesh.h | 16 ++++++++++++++++ examples/companion_radio/MyMeshBot.h | 6 +++--- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index dc59f454..c2d55bb5 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -2039,19 +2039,11 @@ void MyMesh::handleCmdFrame(size_t len) { // so it must never bump the channel's unread badge even though the // device's own UI isn't necessarily showing this channel right now // (unlike an on-device compose, which is always looking at the - // channel it just sent to). - if (_ui) { - int tlen = len - i; - if (tlen > MAX_TEXT_LEN) tlen = MAX_TEXT_LEN; - int pos = _ui->addOwnChannelMsg(channel_idx, text, tlen, msg_timestamp); - // Same "relayed into mesh" marker an on-device channel send arms (see - // MessagesScreen::afterSend): sendGroupMessage above already went - // through sendFloodScoped(GroupChannel&, ...), which calls - // trackRelaySend() unconditionally, so lastChannelRelaySeq() is - // already the seq for the send that was just made -- this just - // attaches it to the matching history entry. - if (pos >= 0) _ui->armChannelRelay(pos, lastChannelRelaySeq()); - } + // channel it just sent to). mirrorOwnChannelMsg also arms the + // "Relayed by" tracker on the new entry -- see its own comment. + int tlen = len - i; + if (tlen > MAX_TEXT_LEN) tlen = MAX_TEXT_LEN; + mirrorOwnChannelMsg(channel_idx, text, tlen, msg_timestamp); #endif } else { writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 662fb688..04f3fbf5 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -228,6 +228,22 @@ public: // Seq of the most recently tracked channel send — the UI records it on the // outgoing history entry so a heard echo (onChannelRelayed) can match it back. uint32_t lastChannelRelaySeq() const { return _last_relay_seq; } + + // Mirror a channel post this device just originated (sendGroupMessage + // already succeeded) into the on-device history AND arm its "Relayed by" + // tracker in one call -- every caller (CMD_SEND_CHANNEL_TXT_MSG, the three + // Remote Bot reply/command/locfix paths) needs both, always in this order, + // and a caller that adds the history entry without arming the tracker + // right after (an easy line to forget) silently never shows repeater + // confirmations for that message. sendGroupMessage's sendFloodScoped( + // GroupChannel&, ...) already calls trackRelaySend() unconditionally, so + // lastChannelRelaySeq() is already the seq for the send just made. + int mirrorOwnChannelMsg(uint8_t channel_idx, const char* text, int text_len = -1, uint32_t timestamp = 0) { + if (!_ui) return -1; + int pos = _ui->addOwnChannelMsg(channel_idx, text, text_len, timestamp); + if (pos >= 0) _ui->armChannelRelay(pos, lastChannelRelaySeq()); + return pos; + } private: // DataStoreHost methods diff --git a/examples/companion_radio/MyMeshBot.h b/examples/companion_radio/MyMeshBot.h index 7479e134..36f6fc5b 100644 --- a/examples/companion_radio/MyMeshBot.h +++ b/examples/companion_radio/MyMeshBot.h @@ -199,7 +199,7 @@ void MyMesh::tryBotReplyChannel(uint8_t channel_idx, const char* text, uint8_t h _bot_last_ch_reply_ms = millis(); _bot_reply_count++; #ifdef DISPLAY_CLASS - if (_ui) _ui->addOwnChannelMsg(channel_idx, expanded); + mirrorOwnChannelMsg(channel_idx, expanded); #endif } } @@ -492,7 +492,7 @@ bool MyMesh::tryBotChannelCommand(uint8_t channel_idx, const char* text, uint8_t _bot_last_ch_reply_ms = millis(); _bot_reply_count++; #ifdef DISPLAY_CLASS - if (_ui) _ui->addOwnChannelMsg(channel_idx, out); + mirrorOwnChannelMsg(channel_idx, out); #endif if (_locfix_requested) startLocFix(LOCFIX_DEST_CHANNEL, nullptr, channel_idx); applyPendingBotActions(); @@ -647,7 +647,7 @@ void MyMesh::sendLocFixResult(const char* msg) { _bot_last_ch_reply_ms = millis(); _bot_reply_count++; #ifdef DISPLAY_CLASS - if (_ui) _ui->addOwnChannelMsg(_loc_fix.channel_idx, msg); + mirrorOwnChannelMsg(_loc_fix.channel_idx, msg); #endif } } else { // LOCFIX_DEST_CONTACT -- DM or room, both go through sendMessage