Simulated multi-hop MeshCore fabric for scale-testing the bearer - #168
Merged
Conversation
Two adjacent bench radios can't exercise the design centre - sparse DAPPS nodes with long strings of relays between them. The firmware is a verified fixed input (64-hop cap, 160-entry dedup ring, transport-code scope drop), so what needs scale-testing is OUR logic on top of it. This adds an in-process mesh that runs the REAL bearer over arbitrary multi-hop topologies. - Extract IMeshCoreLink (SendDataAsync/DrainAsync/MessageWaiting/PacketHeard/State) from MeshCoreLink; MeshCoreCompanionBackhaul + MeshCoreInbound take the interface (behaviour-preserving - MeshCoreLink implements it, all 744 tests still pass). - dapps.meshcore.sim: MeshFabric models Leaf (DAPPS companion) / Relay (repeater) nodes on lossy undirected edges and floods a datagram hop-by-hop with per-node dedup (the ring), the hop cap, and flood-scope containment (a scoped flood is re-flooded only by relays sharing the scope). SimulatedMeshCoreLink : IMeshCoreLink drops in for the serial link; MeshDappsNode runs the real backhaul + inbound + reliability + discovery on a leaf. - Tests: MeshFabricTests (multi-hop delivery, dedup across paths, ring terminates, leaf-doesn't-relay, scope containment + controls, real transport carried/decoded once over 3 relay hops) and MeshFabricScenarioTests (the full bearer stack over a 4-relay backbone bidirectionally + a 5-sender fan-in, each message delivered exactly once, peers discovered multi-hop). This is the tier-1 test strategy from the #24 discussion: it validates multi-hop, dedup-across-paths, and model-B containment deterministically, in CI, with no RF. A real Repeater board + attenuators remains the way to validate the firmware boundary itself. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KLbwvhE2cKCe8WPZNg8k17
The adversarial review caught a real (low) modelling bug: the flood re-flooded through at most 63 relays, but MeshCore's cap is MAX_PATH_SIZE=64 forwarders (a relay forwards while the path_len it received is < 64). The bug came from carrying a 1-based "hop" and enqueuing the transmitter's hop rather than the path_len the receiver sees. Track path_len exactly as the firmware does: the origin transmits with path_len=0; a relay that received path_len P forwards iff P < 64 and its transmission carries P+1. So relays R1..R64 forward and R65 (which would receive 64) is dropped - one relay further than before, matching the firmware boundary the harness exists to exercise. Test: HopCap_DeliversAtExactly64Relays_DropsBeyond (delivered at 64 relays, not at 65) - the long-chain edge no prior test reached. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KLbwvhE2cKCe8WPZNg8k17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
An in-process multi-hop MeshCore mesh that runs the real bearer classes over topologies the two bench radios (one hop, direct) can't reach — multi-hop flood, dedup across paths, flood-scope containment, reliability + discovery over several hops — with no RF, deterministically, in CI. This is the tier-1 strategy from the #24 test-strategy discussion.
Why
The firmware is a source-verified fixed input (64-hop cap, 160-entry no-expiry dedup ring, transport-code scope drop). What actually needs scale-testing is our logic running on top of that behaviour — so reproduce the behaviour and run the unchanged bearer over it.
How
IMeshCoreLinkextracted fromMeshCoreLink(SendDataAsync/DrainAsync/MessageWaiting/PacketHeard/State);MeshCoreCompanionBackhaul+MeshCoreInboundtake the interface. Behaviour-preserving —MeshCoreLinkimplements it and all 744 tests still pass.dapps.meshcore.sim—MeshFabricmodelsLeaf(DAPPS companion) /Relay(repeater) nodes on lossy undirected edges;Floodpropagates hop-by-hop with per-node dedup (the ring), the hop cap, and flood-scope containment (a scoped flood re-floods only through relays sharing the scope).SimulatedMeshCoreLink : IMeshCoreLinkdrops in for the serial link;MeshDappsNoderuns the real backhaul + inbound + reliability + discovery on a leaf.Tests
MeshFabricTests— multi-hop delivery, dedup across two paths, ring-terminates (no infinite flood), leaf-doesn't-relay, scope containment + controls, and the real transport carried + decoded exactly once over 3 relay hops (single- and multi-fragment).MeshFabricScenarioTests— the full bearer stack (transport + reliability ACK + idempotent inbound + passive discovery) over a 4-relay backbone bidirectionally, and a 5-sender fan-in — every message delivered exactly once, peers discovered multi-hop.Scope
Models the channel, not serial-link liveness. No-loss runs are deterministic/fast; loss-recovery (multi-second reliability resends) is left to a longer harness run. Propagation is instantaneous — correctness (delivery/dedup/containment) is faithful; fine-grained timing isn't. Validating the firmware boundary itself still wants a real Repeater board + attenuators.
🤖 Generated with Claude Code