A 1-byte path hash off an RX-logged relay chain often can't be widened: `3d`
opens both YUL-Cartierville (3d63…) and T MeshPocket (3d1f…), so coalesce_prefixes
refused to guess and left it standing as its own node. On the live graph that was
26 stubs — and they are not harmless labels. `3d` sat in the first ring beside
YUL-Cartierville at the same +13.5 dB with 885 of its own samples, claiming *more*
onward links than the real node. Worse, a stub pools the links of every node it
could be, so it acts as a phantom hub joining neighbourhoods that were never
adjacent, and every hop distance measured through it comes back short.
Prefix alone is a coin toss, but the graph is not out of evidence: the stub carries
the links of whichever node it really was, so the company it keeps names its owner.
Neighbours that can tell the candidates apart — ones linking to exactly one of them
— vote; neighbours both candidates share abstain, because two repeaters in the same
city have plenty of those and they would drown the signal in local density.
The bar is high, since a wrong merge does the very thing this routine exists to
prevent. A winner needs two discriminating votes and a 3× lead, so a genuinely
contested stub — one whose neighbours point both ways, i.e. one that really is two
nodes' traffic pooled under one hash — stays exactly where it was: under-named but
honest. The two passes interleave, certain-first, because every merge can resolve
the next ambiguity.
On the live graph: 244 nodes / 852 links → 229 / 731, ambiguous stubs 26 → 11, and
29 nodes land on a truer ring. Adds ~2% to a build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>