From 448b1d0104c554e4a7e736753a7ff3b3e892eb68 Mon Sep 17 00:00:00 2001 From: Joey Stanford Date: Wed, 19 Aug 2026 17:27:24 -0600 Subject: [PATCH 1/3] fix(reticulum): regenerate rsReticulum overlays for b4c0358 Rebase path-medium-slots and announce-rebroadcast-exclude-rf patches onto floated rsReticulum origin/main so clone-ratspeak-stack succeeds in Build and Flatpak CI. --- reticulum-sidecar/patches/README.md | 2 +- ...ulum-announce-rebroadcast-exclude-rf.patch | 20 ++--- .../rsReticulum-path-medium-slots.patch | 87 ++++++++++++------- 3 files changed, 64 insertions(+), 45 deletions(-) diff --git a/reticulum-sidecar/patches/README.md b/reticulum-sidecar/patches/README.md index d18e69f67..8bc669dee 100644 --- a/reticulum-sidecar/patches/README.md +++ b/reticulum-sidecar/patches/README.md @@ -464,7 +464,7 @@ Ranked multi-path slots (up to 3 per destination) plus global / per-peer RF-vs-n | Field | Value | | ----- | ----- | -| **Base commit** | `70b7399` (+ prior mesh-client overlays) | +| **Base commit** | `b4c0358` (+ prior mesh-client overlays) | | **Upstream PR** | none yet (mesh-client-local) | **Touches:** `constants.rs`, `path_table.rs`, `messages.rs`, `actor/{inbound,mod,rpc,outbound,persistence}.rs` diff --git a/reticulum-sidecar/patches/rsReticulum-announce-rebroadcast-exclude-rf.patch b/reticulum-sidecar/patches/rsReticulum-announce-rebroadcast-exclude-rf.patch index 310a2535d..dcbfde6d9 100644 --- a/reticulum-sidecar/patches/rsReticulum-announce-rebroadcast-exclude-rf.patch +++ b/reticulum-sidecar/patches/rsReticulum-announce-rebroadcast-exclude-rf.patch @@ -1,16 +1,8 @@ -From: mesh-client -Subject: Exclude RF sinks from announce rebroadcast enqueue - -With enable_transport, rebroadcasted mesh announces were enqueued onto every -eligible OUT iface including flow-controlled BLE RNodes. Host TX mpsc filled -while FC drained slowly. Local announces still use -broadcast_local_announce_on_interfaces (unchanged). Inlines iface_is_rf_sink -(RNode name or bitrate < 100 kbps). - diff --git a/crates/rns-transport/src/actor/mod.rs b/crates/rns-transport/src/actor/mod.rs +index e8f1d61..6bfa911 100644 --- a/crates/rns-transport/src/actor/mod.rs +++ b/crates/rns-transport/src/actor/mod.rs -@@ -39,6 +39,16 @@ mod rpc; +@@ -40,6 +40,16 @@ mod rpc; const LOCAL_LINK_INITIATOR_INTERFACE: InterfaceId = InterfaceId::MAX; const LOCAL_LINK_RESPONDER_INTERFACE: InterfaceId = InterfaceId::MAX - 1; @@ -27,10 +19,10 @@ diff --git a/crates/rns-transport/src/actor/mod.rs b/crates/rns-transport/src/ac #[derive(Clone)] struct LocalLinkRoute { initiator_tx: mpsc::Sender, -@@ -1700,6 +1710,11 @@ impl TransportActor { - /// optionally one). Eligibility mirrors Python's AP/roaming/boundary mode +@@ -1833,6 +1843,11 @@ impl TransportActor { /// gates. Enqueueing lets `process_announce_queues` apply ANNOUNCE_CAP - /// spacing and hop priority. + /// spacing and hop priority. Python retains at most one queued entry per + /// destination, replacing it only when a newer announce is emitted. + /// + /// Flow-controlled RF sinks (RNode / low-bitrate) are skipped for + /// *rebroadcast* — transport-enabled leaves otherwise enqueue every mesh @@ -39,7 +31,7 @@ diff --git a/crates/rns-transport/src/actor/mod.rs b/crates/rns-transport/src/ac fn broadcast_announce_on_interfaces(&mut self, raw: &[u8], except: Option) { let destination_hash = rns_wire::header::PacketHeader::unpack(raw) .ok() -@@ -1711,10 +1726,20 @@ impl TransportActor { +@@ -1845,10 +1860,20 @@ impl TransportActor { // shared Arc for free. let shared = Bytes::copy_from_slice(raw); diff --git a/reticulum-sidecar/patches/rsReticulum-path-medium-slots.patch b/reticulum-sidecar/patches/rsReticulum-path-medium-slots.patch index 0ec2eeaac..db804b2ae 100644 --- a/reticulum-sidecar/patches/rsReticulum-path-medium-slots.patch +++ b/reticulum-sidecar/patches/rsReticulum-path-medium-slots.patch @@ -1,5 +1,5 @@ diff --git a/crates/rns-transport/src/actor/inbound.rs b/crates/rns-transport/src/actor/inbound.rs -index e63666c..830cfb2 100644 +index 9ec6306..acb2edd 100644 --- a/crates/rns-transport/src/actor/inbound.rs +++ b/crates/rns-transport/src/actor/inbound.rs @@ -375,24 +375,51 @@ impl TransportActor { @@ -142,7 +142,7 @@ index e63666c..830cfb2 100644 return; } diff --git a/crates/rns-transport/src/actor/mod.rs b/crates/rns-transport/src/actor/mod.rs -index 9670424..34b4128 100644 +index dd53467..e8f1d61 100644 --- a/crates/rns-transport/src/actor/mod.rs +++ b/crates/rns-transport/src/actor/mod.rs @@ -19,6 +19,7 @@ use crate::messages::{ @@ -153,7 +153,7 @@ index 9670424..34b4128 100644 use crate::rate_limit::RateTable; use crate::reverse_table::ReverseTable; use crate::traffic::TrafficCounter; -@@ -99,6 +100,11 @@ pub struct TransportActor { +@@ -125,6 +126,11 @@ pub struct TransportActor { /// Used when a Direct LinkRequest timed out on one route, so the next /// path request can discover alternates instead of instantly reusing it. pub path_interface_suppressions: HashMap<([u8; 16], InterfaceId), f64>, @@ -165,7 +165,7 @@ index 9670424..34b4128 100644 last_discovery_pr_tx: f64, /// External interface waiting for a path response from a local shared client. /// Python calls this `pending_local_path_requests`. -@@ -334,6 +340,8 @@ impl TransportActor { +@@ -371,6 +377,8 @@ impl TransportActor { discovery_pr_tags: HashMap::new(), pending_discovery_prs: VecDeque::new(), path_interface_suppressions: HashMap::new(), @@ -174,7 +174,7 @@ index 9670424..34b4128 100644 last_discovery_pr_tx: 0.0, pending_local_path_requests: HashMap::new(), path_states: HashMap::new(), -@@ -1269,15 +1277,92 @@ impl TransportActor { +@@ -1408,15 +1416,92 @@ impl TransportActor { let until = now_f64() + duration; self.path_interface_suppressions .insert((dest, interface_id), until); @@ -267,7 +267,7 @@ index 9670424..34b4128 100644 fn is_path_interface_suppressed( &mut self, dest: [u8; 16], -@@ -1731,16 +1816,6 @@ fn interface_marked_offline(entry: &InterfaceEntry) -> bool { +@@ -1928,12 +2013,6 @@ fn interface_marked_offline(entry: &InterfaceEntry) -> bool { .unwrap_or(false) } @@ -277,6 +277,13 @@ index 9670424..34b4128 100644 - u64::from_be_bytes(emitted) -} - + fn announce_emitted_from_raw(raw: &[u8]) -> Option { + let (header, data_offset) = rns_wire::header::PacketHeader::unpack(raw).ok()?; + if header.flags.packet_type != rns_wire::flags::PacketType::Announce || data_offset >= raw.len() +@@ -1948,10 +2027,6 @@ fn announce_emitted_from_raw(raw: &[u8]) -> Option { + Some(announce_timebase(&announce.random_hash)) + } + -fn path_timebase_from_random_blobs<'a>(random_blobs: impl Iterator) -> u64 { - random_blobs.map(announce_timebase).max().unwrap_or(0) -} @@ -284,7 +291,7 @@ index 9670424..34b4128 100644 /// Random jitter in `[0, PATHFINDER_RW)` for announce rebroadcast timing. /// The jitter avoids synchronized retransmits when many nodes learn the /// same announce in the same tick. -@@ -2043,6 +2118,14 @@ mod tests { +@@ -2271,6 +2346,14 @@ mod tests { (entry, rx) } @@ -299,7 +306,7 @@ index 9670424..34b4128 100644 #[test] fn test_actor_creation() { let (actor, _tx) = TransportActor::new(); -@@ -4383,6 +4466,9 @@ mod tests { +@@ -5465,6 +5548,9 @@ mod tests { assert!(actor.state_dirty); } @@ -309,7 +316,7 @@ index 9670424..34b4128 100644 #[test] fn test_replayed_announce_random_blob_does_not_replace_path() { let (mut actor, _tx) = TransportActor::new(); -@@ -4395,9 +4481,9 @@ mod tests { +@@ -5477,9 +5563,9 @@ mod tests { let identity = rns_identity::identity::Identity::new(); let blob = random_blob(0xA1, 100); let (raw_first, dest_hash) = @@ -321,7 +328,7 @@ index 9670424..34b4128 100644 let (htx, mut hrx) = mpsc::channel(8); actor.announce_handlers.push(AnnounceHandlerRegistration { id: crate::messages::AnnounceHandlerId(0), -@@ -4415,7 +4501,7 @@ mod tests { +@@ -5498,7 +5584,7 @@ mod tests { q: None, }); let first_event = hrx.try_recv().expect("fresh announce should dispatch"); @@ -330,7 +337,7 @@ index 9670424..34b4128 100644 actor.on_inbound(InboundPacket { raw: raw_replay, -@@ -4426,13 +4512,19 @@ mod tests { +@@ -5509,13 +5595,19 @@ mod tests { }); let path = actor.path_table.get(&dest_hash).unwrap(); @@ -352,7 +359,7 @@ index 9670424..34b4128 100644 "replayed announces must not refresh recent announce state" ); assert!( -@@ -4450,6 +4542,334 @@ mod tests { +@@ -5533,6 +5625,334 @@ mod tests { ); } @@ -687,7 +694,7 @@ index 9670424..34b4128 100644 #[test] fn test_newer_equal_or_higher_hop_announce_replaces_path() { let (mut actor, _tx) = TransportActor::new(); -@@ -7377,6 +7797,7 @@ mod tests { +@@ -8508,6 +8928,7 @@ mod tests { expires: now - 1.0, random_blobs: Default::default(), interface_id: 7, @@ -696,10 +703,10 @@ index 9670424..34b4128 100644 }, ); diff --git a/crates/rns-transport/src/actor/outbound.rs b/crates/rns-transport/src/actor/outbound.rs -index 4fd8692..82470e8 100644 +index da06af8..276d72a 100644 --- a/crates/rns-transport/src/actor/outbound.rs +++ b/crates/rns-transport/src/actor/outbound.rs -@@ -925,6 +925,12 @@ impl TransportActor { +@@ -939,6 +939,12 @@ impl TransportActor { expires: tunnel_path.expires, random_blobs: tunnel_path.random_blobs.iter().copied().collect(), interface_id, @@ -713,10 +720,10 @@ index 4fd8692..82470e8 100644 }; self.path_table.insert(*dest_hash, entry); diff --git a/crates/rns-transport/src/actor/persistence.rs b/crates/rns-transport/src/actor/persistence.rs -index cfeb09d..ee7b3c2 100644 +index 7327d22..dc92509 100644 --- a/crates/rns-transport/src/actor/persistence.rs +++ b/crates/rns-transport/src/actor/persistence.rs -@@ -1061,6 +1061,14 @@ impl TransportActor { +@@ -1064,6 +1064,14 @@ impl TransportActor { /// just-registered interface. Bound to `RegisterInterface` so each entry /// rebinds to whatever `interface_id` the runtime allocated this boot. pub(super) fn drain_pending_for_interface(&mut self, id: InterfaceId, name: &str) { @@ -731,7 +738,7 @@ index cfeb09d..ee7b3c2 100644 if !self.pending_path_entries.is_empty() { let mut promoted = 0usize; self.pending_path_entries.retain(|pe| { -@@ -1104,6 +1112,7 @@ impl TransportActor { +@@ -1107,6 +1115,7 @@ impl TransportActor { }) .collect(), interface_id: id, @@ -739,7 +746,7 @@ index cfeb09d..ee7b3c2 100644 packet_hash: pe.packet_hash.as_ref().and_then(|h| { if h.len() == 32 { let mut arr = [0u8; 32]; -@@ -1316,6 +1325,7 @@ mod announce_sweep_actor_tests { +@@ -1319,6 +1328,7 @@ mod announce_sweep_actor_tests { expires: crate::now_f64() + 600.0, random_blobs: std::collections::VecDeque::new(), interface_id: 7, @@ -747,7 +754,7 @@ index cfeb09d..ee7b3c2 100644 packet_hash: Some(path_hash), }, ); -@@ -1471,6 +1481,7 @@ mod async_save_tests { +@@ -1474,6 +1484,7 @@ mod async_save_tests { expires: crate::now_f64() + 600.0, random_blobs: std::collections::VecDeque::new(), interface_id: 7, @@ -755,7 +762,7 @@ index cfeb09d..ee7b3c2 100644 packet_hash: Some([0x33; 32]), }, ); -@@ -1587,6 +1598,7 @@ mod async_save_tests { +@@ -1590,6 +1601,7 @@ mod async_save_tests { expires: crate::now_f64() + 600.0, random_blobs: std::collections::VecDeque::new(), interface_id: 7, @@ -764,10 +771,19 @@ index cfeb09d..ee7b3c2 100644 }, ); diff --git a/crates/rns-transport/src/actor/rpc.rs b/crates/rns-transport/src/actor/rpc.rs -index 07f3b52..2ec775d 100644 +index 07f3b52..1d900a0 100644 --- a/crates/rns-transport/src/actor/rpc.rs +++ b/crates/rns-transport/src/actor/rpc.rs -@@ -262,6 +262,41 @@ impl TransportActor { +@@ -120,6 +120,8 @@ impl TransportActor { + announce_cap: entry.announce_cap, + ifac_size: entry.ifac_size, + tx_drops: entry.tx_drops.load(std::sync::atomic::Ordering::Relaxed), ++ tx_queue_used: (entry.tx.max_capacity() - entry.tx.capacity()) as u64, ++ tx_queue_max: entry.tx.max_capacity() as u64, + } + }) + .collect(); +@@ -262,6 +264,41 @@ impl TransportActor { self.suppress_path_interface(dest, interface_id, duration) })) } @@ -810,10 +826,10 @@ index 07f3b52..2ec775d 100644 for entry in self.interfaces.values_mut() { entry.announce_queue.clear(); diff --git a/crates/rns-transport/src/constants.rs b/crates/rns-transport/src/constants.rs -index 879a965..350ee3e 100644 +index 1747689..a6d48a1 100644 --- a/crates/rns-transport/src/constants.rs +++ b/crates/rns-transport/src/constants.rs -@@ -47,6 +47,12 @@ pub const MAX_RANDOM_BLOBS: usize = 64; +@@ -52,6 +52,12 @@ pub const MAX_RANDOM_BLOBS: usize = 64; /// Max local rebroadcasts before stopping. pub const LOCAL_REBROADCASTS_MAX: u32 = 2; @@ -826,7 +842,7 @@ index 879a965..350ee3e 100644 /// Path request timeout (seconds). pub const PATH_REQUEST_TIMEOUT: f64 = 15.0; -@@ -274,6 +280,72 @@ pub enum PathState { +@@ -279,6 +285,72 @@ pub enum PathState { Responsive = 0x02, } @@ -900,10 +916,10 @@ index 879a965..350ee3e 100644 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum InterfaceMode { diff --git a/crates/rns-transport/src/messages.rs b/crates/rns-transport/src/messages.rs -index 1229814..486ee33 100644 +index a96aae4..fff523f 100644 --- a/crates/rns-transport/src/messages.rs +++ b/crates/rns-transport/src/messages.rs -@@ -668,6 +668,23 @@ pub enum TransportQuery { +@@ -809,6 +809,23 @@ pub enum TransportQuery { dest: [u8; 16], duration: f64, }, @@ -927,7 +943,7 @@ index 1229814..486ee33 100644 DropAnnounceQueues, GetBlackholedIdentities, BlackholeIdentity { -@@ -776,6 +793,7 @@ pub enum TransportQuery { +@@ -917,6 +934,7 @@ pub enum TransportQuery { #[derive(Debug)] pub enum TransportQueryResponse { PathTable(Vec), @@ -935,7 +951,7 @@ index 1229814..486ee33 100644 InterfaceStats(Vec), RateTable(Vec), Announces(Vec), -@@ -809,6 +827,32 @@ pub struct PathTableRpcEntry { +@@ -950,6 +968,32 @@ pub struct PathTableRpcEntry { pub interface_role: InterfaceRole, } @@ -968,6 +984,17 @@ index 1229814..486ee33 100644 #[derive(Debug, Clone)] pub struct InterfaceStatRpcEntry { pub id: InterfaceId, +@@ -981,6 +1025,10 @@ pub struct InterfaceStatRpcEntry { + pub announce_cap: f64, + pub ifac_size: usize, + pub tx_drops: u64, ++ /// Host outbound TX mpsc fill (`max_capacity - capacity`). ++ pub tx_queue_used: u64, ++ /// Host outbound TX mpsc `max_capacity`. ++ pub tx_queue_max: u64, + } + + #[derive(Debug, Clone)] diff --git a/crates/rns-transport/src/path_table.rs b/crates/rns-transport/src/path_table.rs index e051675..23a7728 100644 --- a/crates/rns-transport/src/path_table.rs From 6f9af53d4c15469f83117610c9d9b1da82d77681 Mon Sep 17 00:00:00 2001 From: Joey Stanford Date: Wed, 19 Aug 2026 17:36:30 -0600 Subject: [PATCH 2/3] fix(reticulum): keep tx-queue overlay separate from path-medium patch Regenerate path-medium-slots without accidentally embedding interface-tx-queue-stats hunks, then rebaseline the tx-queue patch on top so rns-stack builds compile. --- ...rsReticulum-interface-tx-queue-stats.patch | 35 +++++++++---------- .../rsReticulum-path-medium-slots.patch | 26 ++------------ 2 files changed, 20 insertions(+), 41 deletions(-) diff --git a/reticulum-sidecar/patches/rsReticulum-interface-tx-queue-stats.patch b/reticulum-sidecar/patches/rsReticulum-interface-tx-queue-stats.patch index 23435313e..199b975b3 100644 --- a/reticulum-sidecar/patches/rsReticulum-interface-tx-queue-stats.patch +++ b/reticulum-sidecar/patches/rsReticulum-interface-tx-queue-stats.patch @@ -1,14 +1,8 @@ -From: mesh-client -Subject: Expose host TX mpsc fill on GetInterfaceStats - -Add tx_queue_used / tx_queue_max to InterfaceStatRpcEntry so mesh-client -can show live RNode outbound queue depth (and early buffering) without -scraping PACKET DROPPED logs. - diff --git a/crates/rns-runtime/src/remote_management.rs b/crates/rns-runtime/src/remote_management.rs +index ea0b8ba..e3b0479 100644 --- a/crates/rns-runtime/src/remote_management.rs +++ b/crates/rns-runtime/src/remote_management.rs -@@ -551,6 +551,8 @@ +@@ -551,6 +551,8 @@ mod tests { announce_cap: 0.02, ifac_size: 0, tx_drops: 0, @@ -18,9 +12,10 @@ diff --git a/crates/rns-runtime/src/remote_management.rs b/crates/rns-runtime/sr TransportQueryResponse::InterfaceStats(stats) } diff --git a/crates/rns-runtime/src/reticulum.rs b/crates/rns-runtime/src/reticulum.rs +index e83762b..03bc46d 100644 --- a/crates/rns-runtime/src/reticulum.rs +++ b/crates/rns-runtime/src/reticulum.rs -@@ -2089,6 +2089,8 @@ +@@ -2090,6 +2090,8 @@ fn rpc_response_to_transport_response( announce_cap: entry.announce_cap, ifac_size: entry.ifac_size, tx_drops: entry.tx_drops, @@ -29,7 +24,7 @@ diff --git a/crates/rns-runtime/src/reticulum.rs b/crates/rns-runtime/src/reticu }) .collect(); TransportQueryResponse::InterfaceStats(entries) -@@ -10268,6 +10270,8 @@ +@@ -10318,6 +10320,8 @@ loglevel = 7 announce_cap: 0.02, ifac_size: 0, tx_drops: 0, @@ -38,7 +33,7 @@ diff --git a/crates/rns-runtime/src/reticulum.rs b/crates/rns-runtime/src/reticu }; let mut second = first.clone(); second.id = 2; -@@ -10413,6 +10417,8 @@ +@@ -10463,6 +10467,8 @@ loglevel = 7 announce_cap: 0.02, ifac_size: 0, tx_drops: 0, @@ -48,9 +43,10 @@ diff --git a/crates/rns-runtime/src/reticulum.rs b/crates/rns-runtime/src/reticu let mut missing_mtu_interface = master_interface.clone(); missing_mtu_interface.id = 82; diff --git a/crates/rns-runtime/src/rpc.rs b/crates/rns-runtime/src/rpc.rs +index c8bf0e4..e333fca 100644 --- a/crates/rns-runtime/src/rpc.rs +++ b/crates/rns-runtime/src/rpc.rs -@@ -179,6 +179,10 @@ +@@ -179,6 +179,10 @@ pub struct InterfaceStatEntry { pub announce_cap: f64, pub ifac_size: usize, pub tx_drops: u64, @@ -61,7 +57,7 @@ diff --git a/crates/rns-runtime/src/rpc.rs b/crates/rns-runtime/src/rpc.rs } #[derive(Debug, Clone, Serialize, Deserialize)] -@@ -566,6 +570,8 @@ +@@ -566,6 +570,8 @@ fn response_to_py_value(resp: &RpcResponse) -> PyValue { .unwrap_or(PyValue::None), ), ("tx_drops", PyValue::Int(i128::from(e.tx_drops))), @@ -70,7 +66,7 @@ diff --git a/crates/rns-runtime/src/rpc.rs b/crates/rns-runtime/src/rpc.rs ]; if let Some(blocked_ips) = e.blocked_ips { fields.push(("blocked_ips", PyValue::Int(i128::from(blocked_ips)))); -@@ -859,6 +865,8 @@ +@@ -859,6 +865,8 @@ fn parse_interface_stats(value: &PyValue) -> Result, Rpc .map(|v| v as usize) .unwrap_or(0), tx_drops: dict_get(m, "tx_drops").and_then(py_u64).unwrap_or(0), @@ -79,7 +75,7 @@ diff --git a/crates/rns-runtime/src/rpc.rs b/crates/rns-runtime/src/rpc.rs }) }) .collect() -@@ -1786,6 +1794,8 @@ +@@ -1786,6 +1794,8 @@ mod tests { announce_cap: 0.02, ifac_size: 0, tx_drops: 1, @@ -89,9 +85,10 @@ diff --git a/crates/rns-runtime/src/rpc.rs b/crates/rns-runtime/src/rpc.rs } diff --git a/crates/rns-runtime/src/rpc_server.rs b/crates/rns-runtime/src/rpc_server.rs +index f7d945e..efa9a8f 100644 --- a/crates/rns-runtime/src/rpc_server.rs +++ b/crates/rns-runtime/src/rpc_server.rs -@@ -404,6 +404,8 @@ +@@ -404,6 +404,8 @@ async fn process_rpc_request( announce_cap: e.announce_cap, ifac_size: e.ifac_size, tx_drops: e.tx_drops, @@ -101,9 +98,10 @@ diff --git a/crates/rns-runtime/src/rpc_server.rs b/crates/rns-runtime/src/rpc_s .collect(); RpcResponse::InterfaceStats(rpc_entries) diff --git a/crates/rns-transport/src/actor/rpc.rs b/crates/rns-transport/src/actor/rpc.rs +index 2ec775d..1d900a0 100644 --- a/crates/rns-transport/src/actor/rpc.rs +++ b/crates/rns-transport/src/actor/rpc.rs -@@ -120,6 +120,8 @@ +@@ -120,6 +120,8 @@ impl TransportActor { announce_cap: entry.announce_cap, ifac_size: entry.ifac_size, tx_drops: entry.tx_drops.load(std::sync::atomic::Ordering::Relaxed), @@ -113,9 +111,10 @@ diff --git a/crates/rns-transport/src/actor/rpc.rs b/crates/rns-transport/src/ac }) .collect(); diff --git a/crates/rns-transport/src/messages.rs b/crates/rns-transport/src/messages.rs +index 8d810ae..fff523f 100644 --- a/crates/rns-transport/src/messages.rs +++ b/crates/rns-transport/src/messages.rs -@@ -884,6 +884,10 @@ +@@ -1025,6 +1025,10 @@ pub struct InterfaceStatRpcEntry { pub announce_cap: f64, pub ifac_size: usize, pub tx_drops: u64, diff --git a/reticulum-sidecar/patches/rsReticulum-path-medium-slots.patch b/reticulum-sidecar/patches/rsReticulum-path-medium-slots.patch index db804b2ae..df1756a0d 100644 --- a/reticulum-sidecar/patches/rsReticulum-path-medium-slots.patch +++ b/reticulum-sidecar/patches/rsReticulum-path-medium-slots.patch @@ -771,19 +771,10 @@ index 7327d22..dc92509 100644 }, ); diff --git a/crates/rns-transport/src/actor/rpc.rs b/crates/rns-transport/src/actor/rpc.rs -index 07f3b52..1d900a0 100644 +index 07f3b52..2ec775d 100644 --- a/crates/rns-transport/src/actor/rpc.rs +++ b/crates/rns-transport/src/actor/rpc.rs -@@ -120,6 +120,8 @@ impl TransportActor { - announce_cap: entry.announce_cap, - ifac_size: entry.ifac_size, - tx_drops: entry.tx_drops.load(std::sync::atomic::Ordering::Relaxed), -+ tx_queue_used: (entry.tx.max_capacity() - entry.tx.capacity()) as u64, -+ tx_queue_max: entry.tx.max_capacity() as u64, - } - }) - .collect(); -@@ -262,6 +264,41 @@ impl TransportActor { +@@ -262,6 +262,41 @@ impl TransportActor { self.suppress_path_interface(dest, interface_id, duration) })) } @@ -916,7 +907,7 @@ index 1747689..a6d48a1 100644 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum InterfaceMode { diff --git a/crates/rns-transport/src/messages.rs b/crates/rns-transport/src/messages.rs -index a96aae4..fff523f 100644 +index a96aae4..8d810ae 100644 --- a/crates/rns-transport/src/messages.rs +++ b/crates/rns-transport/src/messages.rs @@ -809,6 +809,23 @@ pub enum TransportQuery { @@ -984,17 +975,6 @@ index a96aae4..fff523f 100644 #[derive(Debug, Clone)] pub struct InterfaceStatRpcEntry { pub id: InterfaceId, -@@ -981,6 +1025,10 @@ pub struct InterfaceStatRpcEntry { - pub announce_cap: f64, - pub ifac_size: usize, - pub tx_drops: u64, -+ /// Host outbound TX mpsc fill (`max_capacity - capacity`). -+ pub tx_queue_used: u64, -+ /// Host outbound TX mpsc `max_capacity`. -+ pub tx_queue_max: u64, - } - - #[derive(Debug, Clone)] diff --git a/crates/rns-transport/src/path_table.rs b/crates/rns-transport/src/path_table.rs index e051675..23a7728 100644 --- a/crates/rns-transport/src/path_table.rs From 035be53938bbdf250cca039251eb60276fa899e9 Mon Sep 17 00:00:00 2001 From: Joey Stanford Date: Wed, 19 Aug 2026 17:49:21 -0600 Subject: [PATCH 3/3] test(reticulum): update announce-rebroadcast fixture for b4c0358 context Match regenerated patch doc/context so apply script tests reflect floated rsReticulum main. --- ...apply-rsReticulum-announce-rebroadcast-exclude-rf.test.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/apply-rsReticulum-announce-rebroadcast-exclude-rf.test.mjs b/scripts/apply-rsReticulum-announce-rebroadcast-exclude-rf.test.mjs index 8caf43423..8fe4a35d4 100644 --- a/scripts/apply-rsReticulum-announce-rebroadcast-exclude-rf.test.mjs +++ b/scripts/apply-rsReticulum-announce-rebroadcast-exclude-rf.test.mjs @@ -68,13 +68,15 @@ impl TransportActor { /// Enqueue an announce on every eligible outbound interface (except /// optionally one). Eligibility mirrors Python's AP/roaming/boundary mode /// gates. Enqueueing lets \`process_announce_queues\` apply ANNOUNCE_CAP - /// spacing and hop priority. + /// spacing and hop priority. Python retains at most one queued entry per + /// destination, replacing it only when a newer announce is emitted. fn broadcast_announce_on_interfaces(&mut self, raw: &[u8], except: Option) { let destination_hash = rns_wire::header::PacketHeader::unpack(raw) .ok() .map(|(h, _)| h.destination_hash) .unwrap_or([0u8; 16]); let hops = raw.get(1).copied().unwrap_or(0); + let emitted = announce_emitted_from_raw(raw); let now = now_f64(); // One copy at the boundary; per-interface queue entries clone the // shared Arc for free.