mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-09-25 20:03:36 +00:00
Follow-up to #2057, which is correct in what it does and overclaims in one sentence. ## The sentence When no observer heard the node directly, the card said: > No observer is within radio range of this node. #2057's own rule cannot establish that: - every **direct route** is discarded, because the firmware removes the sender from the path before retransmitting (`Mesh.cpp`, `removeSelfFromPath`), so the packet cannot say who transmitted it. #2057 measured these at **38% of transmissions over 7 days**. - **28.8% of flood observations with a path** are dropped because the last hop resolves to more than one candidate, and the rule under-attributes rather than guesses. So an empty direct list is missing evidence, not evidence of missing coverage. ## Why it matters in practice Sampled 40 repeaters on a production instance after #2057 shipped: | | | |---|---| | at least one direct observer | 24 | | empty card, "no observer is within radio range" | **16** | | of those 16, with a non-zero `relayObserverCount` | **16** | Every node showing "nobody is in radio range" also showed "Seen via relay by N observers" two lines below. An operator reading that about a working repeater concludes they have a coverage problem they do not have. ## The change Wording only, in both copies of the card (full page and side pane): > No observation proves a direct reception here, which is not the same as being out of range. with the reason in a `title`, so the card stays one line: > Only flood-routed transmissions identify who was heard: a direct route removes the sender from the path before retransmitting (firmware `Mesh.cpp`, `removeSelfFromPath`), and an ambiguous relay hop is left unattributed rather than guessed. So an empty list is missing evidence, not proof of missing coverage. No API change. #2057's rule, shape and performance work are untouched — I verified its firmware derivation against the clone at `0679dbef` before writing this: `Packet.h:83`, the forwarder appending with `packet->getPathHashSize()` at `Mesh.cpp:349`, and `removeSelfFromPath` on the direct path at `Mesh.cpp:89-105` all read as described. ## Test `tests/unit/test-direct-rf-heard-by.js` slices this template out of `public/nodes.js`, so it pins the shipped markup. It now asserts the old sentence is gone and the qualifier is present. Worth recording how that assertion was reached: my first version banned the phrase "out of range" from the card, and it failed — on the new line, which contains that phrase precisely in order to deny it. A word ban was the wrong instrument. Matching the old sentence and requiring the new qualifier is the assertion that actually distinguishes the two states. 8 of 8 in that suite, eslint clean. ## Not in this PR The **Regions** line and **Region** column on the same card read `o.iata`, which `HealthObserverRow` does not emit, so both have always been dead. #2057 named this and left it; it is now **#2062** with the file and line references, rather than a remark inside a merged description. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>