forge: add patch 13 — quadratic hop delay growth

bias = hop * step + hop^2 * BOT_HOP_GROW_MILLIS

Bumps hop_step 3000->2000, adds BOT_HOP_GROW_MILLIS=400, raises cap
15000->50000 and TTL 75000->95000. Forces re-default of hop_step on
existing bots via BOT_PREFS_VERSION 5->6.

Gap between adjacent hops now grows with hop count (3200ms at hop 1
all the way to 8000ms at hop 8), so a far bot reliably has time to
hear a near bot's reply through the mesh before its own scheduled
fire time -- previous linear bias kept the gap constant at 3000ms,
which wasn't enough at 6+ hops where reply propagation takes ~5-10s.
This commit is contained in:
cj-vana
2026-05-16 22:18:18 -06:00
parent 949b761195
commit ee1b95cc9e
14 changed files with 116 additions and 16 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 01/12] Add companion radio firmware bot command parity Subject: [PATCH 01/13] 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 02/12] Harden firmware bot response coordination Subject: [PATCH 02/13] 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 03/12] Allow prefixless firmware bot DMs Subject: [PATCH 03/13] 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 04/12] Align firmware bot commands with upstream behavior Subject: [PATCH 04/13] 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 05/12] Add hop-aware bot coordination, utility commands, and Subject: [PATCH 05/13] 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 06/12] Mark bot adverts, speed up initial advert, default Subject: [PATCH 06/13] 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 07/12] Prefix bot responses with request token for inter-bot Subject: [PATCH 07/13] 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 08/12] Drop [MCBOT] advert suffix and auto-learn known-bot Subject: [PATCH 08/13] Drop [MCBOT] advert suffix and auto-learn known-bot
path path
Removes BOT_ADVERT_MARKER / writeBotAdvertName / isBotAdvertName from Removes BOT_ADVERT_MARKER / writeBotAdvertName / isBotAdvertName from

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 20:05:19 -0600 Date: Sat, 16 May 2026 20:05:19 -0600
Subject: [PATCH 09/12] Widen hop-step + drop "ack " prefix from test response Subject: [PATCH 09/13] Widen hop-step + drop "ack " prefix from test response
Two changes: Two changes:

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 20:31:12 -0600 Date: Sat, 16 May 2026 20:31:12 -0600
Subject: [PATCH 10/12] Widen coordinator delays a tiny bit more Subject: [PATCH 10/13] Widen coordinator delays a tiny bit more
~25% bump across the main coordination knobs: ~25% bump across the main coordination knobs:
- BOT_RESPONSE_DELAY_BASE_MILLIS 1200 -> 1500 - BOT_RESPONSE_DELAY_BASE_MILLIS 1200 -> 1500

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 20:49:51 -0600 Date: Sat, 16 May 2026 20:49:51 -0600
Subject: [PATCH 11/12] Auto-advert on startup (initial flood at 5s instead of Subject: [PATCH 11/13] Auto-advert on startup (initial flood at 5s instead of
120s) 120s)
BOT_PREFS_INITIAL_FLOOD_ADVERT_MILLIS 120000 -> 5000. The bot now sends BOT_PREFS_INITIAL_FLOOD_ADVERT_MILLIS 120000 -> 5000. The bot now sends

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 21:32:04 -0600 Date: Sat, 16 May 2026 21:32:04 -0600
Subject: [PATCH 12/12] Spell out hops/byte in test+path; drop channel name Subject: [PATCH 12/13] Spell out hops/byte in test+path; drop channel name
from test ack from test ack
Test response (writeAckResponse): Test response (writeAckResponse):

View File

@@ -0,0 +1,94 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: cj-vana <cj@depth23.online>
Date: Sat, 16 May 2026 22:18:02 -0600
Subject: [PATCH 13/13] =?UTF-8?q?Hop=20delay=20grows=20quadratically=20?=
=?UTF-8?q?=E2=80=94=20wider=20gaps=20at=20higher=20hop=20counts?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
New formula: bias = hop * step + hop^2 * BOT_HOP_GROW_MILLIS
Constants:
BOT_HOP_STEP_MILLIS_DEFAULT 3000 -> 2000
BOT_HOP_GROW_MILLIS NEW = 400
BOT_HOP_BIAS_MAX_MILLIS 15000 -> 50000
BOT_RESPONSE_PENDING_TTL_MILLIS 75000 -> 95000
BOT_PREFS_VERSION 5 -> 6
Hop -> bias / gap from previous:
1 -> 2400ms / --
2 -> 5600ms / +3200
3 -> 9600ms / +4000
4 -> 14400ms / +4800
5 -> 20000ms / +5600
6 -> 26400ms / +6400
7 -> 33600ms / +7200
8 -> 41600ms / +8000
9+-> 50000ms (cap)
Previous linear bias gave the same gap between every adjacent hop. At
higher hop counts that wasn't enough: a 7-hop bot's scheduled delay was
only one step longer than the 6-hop bot's, but the 6-hop bot's reply
needed ~5-10s of mesh airtime to propagate one extra hop to the 7-hop
bot. Result: the further bot fired before the closer bot's reply
arrived -> token suppression never triggered.
Now an N-hop bot has roughly 2*N*400ms more spacing than an (N-1)-hop
bot, which keeps growing as the mesh gets deeper.
---
examples/companion_radio/BotTypes.h | 9 +++++----
examples/companion_radio/ResponseCoordinator.cpp | 6 +++++-
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/examples/companion_radio/BotTypes.h b/examples/companion_radio/BotTypes.h
index 08fe8bc7..f3afa21f 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 1500UL
#define BOT_RESPONSE_DELAY_JITTER_MILLIS 2200UL
-#define BOT_RESPONSE_PENDING_TTL_MILLIS 75000UL
+#define BOT_RESPONSE_PENDING_TTL_MILLIS 95000UL
#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 5
+#define BOT_PREFS_VERSION 6
#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,10 @@
#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 3000U
+#define BOT_HOP_STEP_MILLIS_DEFAULT 2000U
#define BOT_HOP_STEP_MILLIS_MAX 30000U
-#define BOT_HOP_BIAS_MAX_MILLIS 15000UL
+#define BOT_HOP_GROW_MILLIS 400UL
+#define BOT_HOP_BIAS_MAX_MILLIS 50000UL
enum BotChannelKind : uint8_t {
BOT_CHANNEL_DM = 0,
diff --git a/examples/companion_radio/ResponseCoordinator.cpp b/examples/companion_radio/ResponseCoordinator.cpp
index 3640f8b6..837b3f12 100644
--- a/examples/companion_radio/ResponseCoordinator.cpp
+++ b/examples/companion_radio/ResponseCoordinator.cpp
@@ -23,7 +23,11 @@ uint32_t channelDelayBias(BotChannelKind kind) {
uint32_t hopDelayBias(BotChannelKind kind, uint8_t path_hash_count, uint16_t hop_step_millis) {
if (kind == BOT_CHANNEL_DM) return 0;
- uint32_t bias = (uint32_t)path_hash_count * (uint32_t)hop_step_millis;
+ // Linear + quadratic growth: gap between consecutive hops widens with hop
+ // count, so a far bot always has more slack than a near bot to receive
+ // the near bot's reply before its own scheduled fire time.
+ uint32_t hop = (uint32_t)path_hash_count;
+ uint32_t bias = hop * (uint32_t)hop_step_millis + hop * hop * BOT_HOP_GROW_MILLIS;
if (bias > BOT_HOP_BIAS_MAX_MILLIS) bias = BOT_HOP_BIAS_MAX_MILLIS;
return bias;
}

View File

@@ -1533,8 +1533,13 @@ static void test_response_coordinator_hop_count_ranking() {
base_delay, jitter, hop_step); base_delay, jitter, hop_step);
uint32_t d2 = ResponseCoordinator::responseDelayMillis(two_hop, BOT_COMMAND_PING, request, 0x01020304UL, 0, 0, uint32_t d2 = ResponseCoordinator::responseDelayMillis(two_hop, BOT_COMMAND_PING, request, 0x01020304UL, 0, 0,
base_delay, jitter, hop_step); base_delay, jitter, hop_step);
assert(d1 == d0 + hop_step); // Linear + quadratic growth: bias(h) = h*step + h*h*grow
assert(d2 == d0 + (uint32_t)hop_step * 2); assert(d1 == d0 + (uint32_t)hop_step + BOT_HOP_GROW_MILLIS);
assert(d2 == d0 + (uint32_t)hop_step * 2 + 4 * BOT_HOP_GROW_MILLIS);
// Gap between hops widens as hop count rises:
uint32_t gap_0_to_1 = d1 - d0;
uint32_t gap_1_to_2 = d2 - d1;
assert(gap_1_to_2 > gap_0_to_1);
uint32_t alt_step = 2000; uint32_t alt_step = 2000;
uint32_t d0_alt = ResponseCoordinator::responseDelayMillis(near, BOT_COMMAND_PING, request, 0x01020304UL, 0, 0, uint32_t d0_alt = ResponseCoordinator::responseDelayMillis(near, BOT_COMMAND_PING, request, 0x01020304UL, 0, 0,
@@ -1542,7 +1547,7 @@ static void test_response_coordinator_hop_count_ranking() {
uint32_t d1_alt = ResponseCoordinator::responseDelayMillis(one_hop, BOT_COMMAND_PING, request, 0x01020304UL, 0, 0, uint32_t d1_alt = ResponseCoordinator::responseDelayMillis(one_hop, BOT_COMMAND_PING, request, 0x01020304UL, 0, 0,
base_delay, jitter, alt_step); base_delay, jitter, alt_step);
assert(d0_alt == d0); assert(d0_alt == d0);
assert(d1_alt == d0 + alt_step); assert(d1_alt == d0 + alt_step + BOT_HOP_GROW_MILLIS);
BotMessage dm = make_message("dm", "!ping"); BotMessage dm = make_message("dm", "!ping");
dm.channel_kind = BOT_CHANNEL_DM; dm.channel_kind = BOT_CHANNEL_DM;
@@ -1570,7 +1575,8 @@ static void test_response_coordinator_hop_bias_cap() {
uint32_t dmany = ResponseCoordinator::responseDelayMillis(many_hops, BOT_COMMAND_PING, request, 0x01020304UL, 0, 0, uint32_t dmany = ResponseCoordinator::responseDelayMillis(many_hops, BOT_COMMAND_PING, request, 0x01020304UL, 0, 0,
base_delay, jitter, hop_step); base_delay, jitter, hop_step);
assert(dmany == d0 + BOT_HOP_BIAS_MAX_MILLIS); assert(dmany == d0 + BOT_HOP_BIAS_MAX_MILLIS);
assert((uint32_t)many_hops.path_hash_count * hop_step > BOT_HOP_BIAS_MAX_MILLIS); uint32_t hop_u32 = (uint32_t)many_hops.path_hash_count;
assert(hop_u32 * (uint32_t)hop_step + hop_u32 * hop_u32 * BOT_HOP_GROW_MILLIS > BOT_HOP_BIAS_MAX_MILLIS);
assert(dmany + BOT_RESPONSE_DELAY_JITTER_MILLIS < BOT_RESPONSE_PENDING_TTL_MILLIS); assert(dmany + BOT_RESPONSE_DELAY_JITTER_MILLIS < BOT_RESPONSE_PENDING_TTL_MILLIS);
} }