forge: add patch 9 — widen hop-step + drop "ack " from test response

- BOT_HOP_STEP_MILLIS_DEFAULT 1500 -> 2500
- BOT_HOP_BIAS_MAX_MILLIS 8000 -> 12000
- BOT_RESPONSE_PENDING_TTL_MILLIS 45000 -> 60000
- BOT_PREFS_VERSION 3 -> 4 (forces re-default of hop_step_ms on existing
  bots that saved the old 1500 value)
- writeAckResponse + executeTest: drop the literal "ack " prefix so test
  responses now start with "@[sender] ..."

Field test showed two bots with token-matching `[1865]` responses both
firing because the far bot scheduled its reply before the near bot's
reply could propagate back through the mesh. New hop step gives ~5-8 s
of margin at the 4-hop boundary.
This commit is contained in:
cj-vana
2026-05-16 20:05:31 -06:00
parent 064904e596
commit b7cc1dc0ca
11 changed files with 106 additions and 14 deletions

View File

@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: cj-vana <cj@depth23.online> From: cj-vana <cj@depth23.online>
Date: Fri, 15 May 2026 11:44:21 -0600 Date: Fri, 15 May 2026 11:44:21 -0600
Subject: [PATCH 1/8] Add companion radio firmware bot command parity Subject: [PATCH 1/9] Add companion radio firmware bot command parity
--- ---
.../companion_radio/BotCommandRegistry.cpp | 121 ++ .../companion_radio/BotCommandRegistry.cpp | 121 ++

View File

@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: cj-vana <cj@depth23.online> From: cj-vana <cj@depth23.online>
Date: Fri, 15 May 2026 19:58:42 -0600 Date: Fri, 15 May 2026 19:58:42 -0600
Subject: [PATCH 2/8] Harden firmware bot response coordination Subject: [PATCH 2/9] Harden firmware bot response coordination
--- ---
examples/companion_radio/BotCommands.cpp | 2 +- examples/companion_radio/BotCommands.cpp | 2 +-

View File

@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: cj-vana <cj@depth23.online> From: cj-vana <cj@depth23.online>
Date: Fri, 15 May 2026 20:09:58 -0600 Date: Fri, 15 May 2026 20:09:58 -0600
Subject: [PATCH 3/8] Allow prefixless firmware bot DMs Subject: [PATCH 3/9] Allow prefixless firmware bot DMs
--- ---
examples/companion_radio/BotPolicy.cpp | 2 +- examples/companion_radio/BotPolicy.cpp | 2 +-

View File

@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: cj-vana <cj@depth23.online> From: cj-vana <cj@depth23.online>
Date: Sat, 16 May 2026 04:12:02 +0000 Date: Sat, 16 May 2026 04:12:02 +0000
Subject: [PATCH 4/8] Align firmware bot commands with upstream behavior Subject: [PATCH 4/9] Align firmware bot commands with upstream behavior
--- ---
.../companion_radio/BotCommandRegistry.cpp | 25 +- .../companion_radio/BotCommandRegistry.cpp | 25 +-

View File

@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: cj-vana <cj@depth23.online> From: cj-vana <cj@depth23.online>
Date: Sat, 16 May 2026 12:38:13 -0600 Date: Sat, 16 May 2026 12:38:13 -0600
Subject: [PATCH 5/8] Add hop-aware bot coordination, utility commands, and Subject: [PATCH 5/9] Add hop-aware bot coordination, utility commands, and
bounded delays bounded delays
Adds new utility commands (TIME, LORA, ID, NEIGHBORS), neighbor tracking, Adds new utility commands (TIME, LORA, ID, NEIGHBORS), neighbor tracking,

View File

@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: cj-vana <cj@depth23.online> From: cj-vana <cj@depth23.online>
Date: Sat, 16 May 2026 18:58:28 -0600 Date: Sat, 16 May 2026 18:58:28 -0600
Subject: [PATCH 6/8] Mark bot adverts, speed up initial advert, default Subject: [PATCH 6/9] Mark bot adverts, speed up initial advert, default
contacts auto-overwrite contacts auto-overwrite
Three coordination/discoverability fixes: Three coordination/discoverability fixes:

View File

@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: cj-vana <cj@depth23.online> From: cj-vana <cj@depth23.online>
Date: Sat, 16 May 2026 19:33:04 -0600 Date: Sat, 16 May 2026 19:33:04 -0600
Subject: [PATCH 7/8] Prefix bot responses with request token for inter-bot Subject: [PATCH 7/9] Prefix bot responses with request token for inter-bot
suppression suppression
Adds a 4-hex request token (low 16 bits of the request fingerprint) as a Adds a 4-hex request token (low 16 bits of the request fingerprint) as a

View File

@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: cj-vana <cj@depth23.online> From: cj-vana <cj@depth23.online>
Date: Sat, 16 May 2026 19:55:36 -0600 Date: Sat, 16 May 2026 19:55:36 -0600
Subject: [PATCH 8/8] Drop [MCBOT] advert suffix and auto-learn known-bot path Subject: [PATCH 8/9] Drop [MCBOT] advert suffix and auto-learn known-bot path
Removes BOT_ADVERT_MARKER / writeBotAdvertName / isBotAdvertName from Removes BOT_ADVERT_MARKER / writeBotAdvertName / isBotAdvertName from
FirmwareBot, autoLearnKnownBotAdvert and getAdvertNodeName from MyMesh, FirmwareBot, autoLearnKnownBotAdvert and getAdvertNodeName from MyMesh,

View File

@@ -0,0 +1,92 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: cj-vana <cj@depth23.online>
Date: Sat, 16 May 2026 20:05:19 -0600
Subject: [PATCH 9/9] Widen hop-step + drop "ack " prefix from test response
Two changes:
1. Coordination timing: bump BOT_HOP_STEP_MILLIS_DEFAULT 1500 -> 2500,
BOT_HOP_BIAS_MAX_MILLIS 8000 -> 12000, BOT_RESPONSE_PENDING_TTL_MILLIS
45000 -> 60000. Bumps BOT_PREFS_VERSION 3 -> 4 so existing bots
re-derive defaults instead of carrying the old 1500 ms hop step.
Why: a far bot (4 hops from request) was firing at ~7-10 s while a
near bot (1 hop) fired at ~3-6 s. Across 4-5 mesh hops, the near
bot's response took ~5-10 s of airtime+queueing to reach the far
bot, frequently arriving AFTER the far bot's scheduled fire time.
With 2500 ms/hop, the far bot now schedules at ~12 s, giving ~5-8 s
of margin for the near bot's response to arrive and trigger
token-based suppression.
2. Test command response: drop the literal "ack " prefix from
writeAckResponse and BotCommands::executeTest. Responses now start
directly with "@[sender] ..." which keeps the user mention and
metadata but matches user preference for less noise.
---
examples/companion_radio/BotCommands.cpp | 4 ++--
examples/companion_radio/BotTypes.h | 8 ++++----
examples/companion_radio/FirmwareBot.cpp | 2 +-
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/examples/companion_radio/BotCommands.cpp b/examples/companion_radio/BotCommands.cpp
index 44357a99..1aa4406d 100644
--- a/examples/companion_radio/BotCommands.cpp
+++ b/examples/companion_radio/BotCommands.cpp
@@ -536,9 +536,9 @@ BotCommandResult executeTest(const BotCommand& command, const BotCommandContext&
char received_at[9];
formatSecondsHms(context.uptime_seconds, received_at, sizeof(received_at));
if (command.args_len == 0) {
- return writeFormatted(output, output_len, "ack @[%s] local | recv %s", name, received_at);
+ return writeFormatted(output, output_len, "@[%s] local | recv %s", name, received_at);
}
- return writeFormatted(output, output_len, "ack @[%s] local | recv %s | %s", name, received_at, command.args);
+ return writeFormatted(output, output_len, "@[%s] local | recv %s | %s", name, received_at, command.args);
}
}
diff --git a/examples/companion_radio/BotTypes.h b/examples/companion_radio/BotTypes.h
index ad249300..5a953639 100644
--- a/examples/companion_radio/BotTypes.h
+++ b/examples/companion_radio/BotTypes.h
@@ -30,14 +30,14 @@
#define BOT_NEIGHBOR_RECENT_MILLIS (60UL * 60UL * 1000UL)
#define BOT_RESPONSE_DELAY_BASE_MILLIS 1200UL
#define BOT_RESPONSE_DELAY_JITTER_MILLIS 1800UL
-#define BOT_RESPONSE_PENDING_TTL_MILLIS 45000UL
+#define BOT_RESPONSE_PENDING_TTL_MILLIS 60000UL
#define BOT_RESPONSE_RECENT_TTL_MILLIS 30000UL
#define BOT_KNOWN_BOT_FLAG_SUPPRESS_NORMAL 0x01
#define BOT_SENDER_KEY_PREFIX_LEN 6
#define BOT_MIN_AUTH_SENDER_KEY_PREFIX_LEN 4
#define BOT_KNOWN_BOT_LABEL_LEN 12
#define BOT_PREFS_MAGIC 0x31504642UL
-#define BOT_PREFS_VERSION 3
+#define BOT_PREFS_VERSION 4
#define BOT_PREFS_DEFAULT_LOCAL_ADVERT_MILLIS (24UL * 60UL * 60UL * 1000UL)
#define BOT_PREFS_DEFAULT_FLOOD_ADVERT_MILLIS (24UL * 60UL * 60UL * 1000UL)
#define BOT_PREFS_INITIAL_LOCAL_ADVERT_MILLIS 60000UL
@@ -45,9 +45,9 @@
#define BOT_PREFS_MAX_DELAY_MILLIS 60000U
#define BOT_PREFS_MAX_ADVERT_MILLIS (7UL * 24UL * 60UL * 60UL * 1000UL)
#define BOT_PREFS_SERIALIZED_SIZE 296
-#define BOT_HOP_STEP_MILLIS_DEFAULT 1500U
+#define BOT_HOP_STEP_MILLIS_DEFAULT 2500U
#define BOT_HOP_STEP_MILLIS_MAX 30000U
-#define BOT_HOP_BIAS_MAX_MILLIS 8000UL
+#define BOT_HOP_BIAS_MAX_MILLIS 12000UL
enum BotChannelKind : uint8_t {
BOT_CHANNEL_DM = 0,
diff --git a/examples/companion_radio/FirmwareBot.cpp b/examples/companion_radio/FirmwareBot.cpp
index 3c310173..e228b7c8 100644
--- a/examples/companion_radio/FirmwareBot.cpp
+++ b/examples/companion_radio/FirmwareBot.cpp
@@ -322,7 +322,7 @@ BotWriteResult writeAckResponse(const BotMessage& message, const BotCommand& com
const char* connection = message.channel_kind == BOT_CHANNEL_DM
? "direct"
: (message.channel_name[0] ? message.channel_name : "channel");
- int n = snprintf(output, output_len, "ack @[%s] %s", sender, connection);
+ int n = snprintf(output, output_len, "@[%s] %s", sender, connection);
if (n < 0) {
output[0] = 0;
return BOT_WRITE_NO_SPACE;

View File

@@ -539,7 +539,7 @@ static void test_ack_response_format() {
char out[BOT_MAX_RESPONSE_LEN + 1]; char out[BOT_MAX_RESPONSE_LEN + 1];
size_t written = 0; size_t written = 0;
assert(FirmwareBot::writeAckResponse(message, command, out, sizeof(out), &written) == BOT_WRITE_OK); assert(FirmwareBot::writeAckResponse(message, command, out, sizeof(out), &written) == BOT_WRITE_OK);
assert(strcmp(out, "ack @[alice] #bot | 0h SNR 0.00 | recv 21:25:45 | hello") == 0); assert(strcmp(out, "@[alice] #bot | 0h SNR 0.00 | recv 21:25:45 | hello") == 0);
assert(written == strlen(out)); assert(written == strlen(out));
message.channel_kind = BOT_CHANNEL_DM; message.channel_kind = BOT_CHANNEL_DM;
@@ -547,7 +547,7 @@ static void test_ack_response_format() {
message.channel_name[0] = 0; message.channel_name[0] = 0;
assert(FirmwareBot::parseCommand("!t", 2, &command)); assert(FirmwareBot::parseCommand("!t", 2, &command));
assert(FirmwareBot::writeAckResponse(message, command, out, sizeof(out), &written) == BOT_WRITE_OK); assert(FirmwareBot::writeAckResponse(message, command, out, sizeof(out), &written) == BOT_WRITE_OK);
assert(strcmp(out, "ack @[unknown] direct | 0h SNR 0.00 | recv 21:25:45") == 0); assert(strcmp(out, "@[unknown] direct | 0h SNR 0.00 | recv 21:25:45") == 0);
uint8_t path[] = { 0x12, 0x34, 0xab, 0xcd }; uint8_t path[] = { 0x12, 0x34, 0xab, 0xcd };
message.channel_kind = BOT_CHANNEL_BOT; message.channel_kind = BOT_CHANNEL_BOT;
@@ -558,12 +558,12 @@ static void test_ack_response_format() {
message.path_hash_count = 2; message.path_hash_count = 2;
message.packet_snr_quarters = -5; message.packet_snr_quarters = -5;
assert(FirmwareBot::writeAckResponse(message, command, out, sizeof(out), &written) == BOT_WRITE_OK); assert(FirmwareBot::writeAckResponse(message, command, out, sizeof(out), &written) == BOT_WRITE_OK);
assert(strcmp(out, "ack @[bob] #bot | 2h@2B SNR -1.25 | recv 21:25:45") == 0); assert(strcmp(out, "@[bob] #bot | 2h@2B SNR -1.25 | recv 21:25:45") == 0);
assert(strstr(out, "Bot test OK") == NULL); assert(strstr(out, "Bot test OK") == NULL);
char small[16]; char small[16];
assert(FirmwareBot::writeAckResponse(message, command, small, sizeof(small), &written) == BOT_WRITE_TRUNCATED); assert(FirmwareBot::writeAckResponse(message, command, small, sizeof(small), &written) == BOT_WRITE_TRUNCATED);
assert(strncmp(small, "ack @[bob]", 10) == 0); assert(strncmp(small, "@[bob]", 6) == 0);
} }
static BotMessage make_message(const char* channel, const char* text) { static BotMessage make_message(const char* channel, const char* text) {
@@ -628,7 +628,7 @@ static void test_command_outputs() {
result = run_command("!test", out, sizeof(out)); result = run_command("!test", out, sizeof(out));
assert(result.code == BOT_COMMAND_RESULT_OK); assert(result.code == BOT_COMMAND_RESULT_OK);
assert_starts_with(out, "ack @["); assert_starts_with(out, "@[");
assert_contains(out, "recv "); assert_contains(out, "recv ");
assert(strstr(out, "Bot test OK") == NULL); assert(strstr(out, "Bot test OK") == NULL);