Do some same name ambiguous + known sibling collapse

This commit is contained in:
Jack Kingsman
2026-03-12 13:10:57 -07:00
parent b81f6ef89e
commit 3ee4f9d7a2
8 changed files with 407 additions and 77 deletions
@@ -29,6 +29,9 @@ export function PacketVisualizer3D({
const [showAmbiguousPaths, setShowAmbiguousPaths] = useState(savedSettings.showAmbiguousPaths);
const [showAmbiguousNodes, setShowAmbiguousNodes] = useState(savedSettings.showAmbiguousNodes);
const [useAdvertPathHints, setUseAdvertPathHints] = useState(savedSettings.useAdvertPathHints);
const [collapseLikelyKnownSiblingRepeaters, setCollapseLikelyKnownSiblingRepeaters] = useState(
savedSettings.collapseLikelyKnownSiblingRepeaters
);
const [splitAmbiguousByTraffic, setSplitAmbiguousByTraffic] = useState(
savedSettings.splitAmbiguousByTraffic
);
@@ -52,6 +55,7 @@ export function PacketVisualizer3D({
showAmbiguousPaths,
showAmbiguousNodes,
useAdvertPathHints,
collapseLikelyKnownSiblingRepeaters,
splitAmbiguousByTraffic,
chargeStrength,
observationWindowSec,
@@ -66,6 +70,7 @@ export function PacketVisualizer3D({
showAmbiguousPaths,
showAmbiguousNodes,
useAdvertPathHints,
collapseLikelyKnownSiblingRepeaters,
splitAmbiguousByTraffic,
chargeStrength,
observationWindowSec,
@@ -108,6 +113,7 @@ export function PacketVisualizer3D({
showAmbiguousPaths,
showAmbiguousNodes,
useAdvertPathHints,
collapseLikelyKnownSiblingRepeaters,
splitAmbiguousByTraffic,
chargeStrength,
letEmDrift,
@@ -143,6 +149,8 @@ export function PacketVisualizer3D({
setShowAmbiguousNodes={setShowAmbiguousNodes}
useAdvertPathHints={useAdvertPathHints}
setUseAdvertPathHints={setUseAdvertPathHints}
collapseLikelyKnownSiblingRepeaters={collapseLikelyKnownSiblingRepeaters}
setCollapseLikelyKnownSiblingRepeaters={setCollapseLikelyKnownSiblingRepeaters}
splitAmbiguousByTraffic={splitAmbiguousByTraffic}
setSplitAmbiguousByTraffic={setSplitAmbiguousByTraffic}
observationWindowSec={observationWindowSec}
@@ -94,8 +94,9 @@ When a new packet arrives from the WebSocket:
```typescript
packets.forEach((packet) => {
if (processedRef.current.has(packet.id)) return; // Skip duplicates
processedRef.current.add(packet.id);
const observationKey = getRawPacketObservationKey(packet);
if (processedRef.current.has(observationKey)) return; // Skip duplicates
processedRef.current.add(observationKey);
const parsed = parsePacket(packet.data);
const key = generatePacketKey(parsed, packet);
@@ -215,6 +216,8 @@ When a winner is found, the ambiguous node gets a `probableIdentity` label (the
**Interaction with traffic splitting:** Advert-path hints run first. If a probable identity is found, the display name is set. Traffic splitting can still produce separate node IDs (`?XX:>YY`), but won't overwrite the advert-path display name.
**Sibling collapse projection:** When an ambiguous repeater has a high-confidence likely identity and that likely repeater also appears as a definitely-known sibling connecting to the same next hop, the projection layer can collapse the ambiguous node into the known repeater. This is projection-only: canonical observations and canonical neighbor truth remain unchanged.
**Toggle:** "Use repeater advert-path identity hints" checkbox (enabled by default, disabled when ambiguous repeaters are hidden).
### Traffic Pattern Splitting (Experimental)
@@ -331,21 +334,22 @@ function buildPath(parsed, packet, myPrefix): string[] {
## Configuration Options
| Option | Default | Description |
| -------------------------- | ------- | --------------------------------------------------------- |
| Ambiguous repeaters | On | Show nodes when only partial prefix known |
| Ambiguous sender/recipient | Off | Show placeholder nodes for unknown senders |
| Advert-path identity hints | On | Use stored advert paths to label ambiguous repeaters |
| Split by traffic pattern | Off | Split ambiguous repeaters by next-hop routing (see above) |
| Observation window | 15 sec | Wait time for duplicate packets before animating (1-60s) |
| Let 'em drift | On | Continuous layout optimization |
| Repulsion | 200 | Force strength (50-2500) |
| Packet speed | 2x | Particle animation speed multiplier (1x-5x) |
| Shuffle layout | - | Button to randomize node positions and reheat sim |
| Oooh Big Stretch! | - | Button to temporarily increase repulsion then relax |
| Clear & Reset | - | Button to clear all nodes, links, and packets |
| Hide UI | Off | Hide legends and most controls for cleaner view |
| Full screen | Off | Hide the packet feed panel (desktop only) |
| Option | Default | Description |
| -------------------------- | ------- | ----------------------------------------------------------- |
| Ambiguous repeaters | On | Show nodes when only partial prefix known |
| Ambiguous sender/recipient | Off | Show placeholder nodes for unknown senders |
| Advert-path identity hints | On | Use stored advert paths to label ambiguous repeaters |
| Collapse sibling repeaters | On | Merge likely ambiguous repeater with known sibling repeater |
| Split by traffic pattern | Off | Split ambiguous repeaters by next-hop routing (see above) |
| Observation window | 15 sec | Wait time for duplicate packets before animating (1-60s) |
| Let 'em drift | On | Continuous layout optimization |
| Repulsion | 200 | Force strength (50-2500) |
| Packet speed | 2x | Particle animation speed multiplier (1x-5x) |
| Shuffle layout | - | Button to randomize node positions and reheat sim |
| Oooh Big Stretch! | - | Button to temporarily increase repulsion then relax |
| Clear & Reset | - | Button to clear all nodes, links, and packets |
| Hide UI | Off | Hide legends and most controls for cleaner view |
| Full screen | Off | Hide the packet feed panel (desktop only) |
## File Structure
@@ -13,6 +13,8 @@ interface VisualizerControlsProps {
setShowAmbiguousNodes: (value: boolean) => void;
useAdvertPathHints: boolean;
setUseAdvertPathHints: (value: boolean) => void;
collapseLikelyKnownSiblingRepeaters: boolean;
setCollapseLikelyKnownSiblingRepeaters: (value: boolean) => void;
splitAmbiguousByTraffic: boolean;
setSplitAmbiguousByTraffic: (value: boolean) => void;
observationWindowSec: number;
@@ -46,6 +48,8 @@ export function VisualizerControls({
setShowAmbiguousNodes,
useAdvertPathHints,
setUseAdvertPathHints,
collapseLikelyKnownSiblingRepeaters,
setCollapseLikelyKnownSiblingRepeaters,
splitAmbiguousByTraffic,
setSplitAmbiguousByTraffic,
observationWindowSec,
@@ -149,55 +153,77 @@ export function VisualizerControls({
Show ambiguous sender/recipient
</span>
</label>
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
checked={useAdvertPathHints}
onCheckedChange={(c) => setUseAdvertPathHints(c === true)}
disabled={!showAmbiguousPaths}
/>
<span
title="Use stored repeater advert paths to assign likely identity labels for ambiguous repeater nodes"
className={!showAmbiguousPaths ? 'text-muted-foreground' : ''}
>
Use repeater advert-path identity hints
</span>
</label>
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
checked={splitAmbiguousByTraffic}
onCheckedChange={(c) => setSplitAmbiguousByTraffic(c === true)}
disabled={!showAmbiguousPaths}
/>
<span
title="Split ambiguous repeaters into separate nodes based on traffic patterns (prev→next). Helps identify colliding prefixes representing different physical nodes, but requires enough traffic to disambiguate."
className={!showAmbiguousPaths ? 'text-muted-foreground' : ''}
>
Heuristically group repeaters by traffic pattern
</span>
</label>
<div className="flex items-center gap-2">
<label
htmlFor="observation-window-3d"
className="text-muted-foreground"
title="How long to wait for duplicate packets via different paths before animating"
>
Ack/echo listen window:
</label>
<input
id="observation-window-3d"
type="number"
min="1"
max="60"
value={observationWindowSec}
onChange={(e) =>
setObservationWindowSec(
Math.max(1, Math.min(60, parseInt(e.target.value, 10) || 1))
)
}
className="w-12 px-1 py-0.5 bg-background border border-border rounded text-xs text-center"
/>
<span className="text-muted-foreground">sec</span>
</div>
<details className="rounded border border-border/60 px-2 py-1">
<summary className="cursor-pointer select-none text-muted-foreground">
Advanced
</summary>
<div className="mt-2 flex flex-col gap-2">
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
checked={useAdvertPathHints}
onCheckedChange={(c) => setUseAdvertPathHints(c === true)}
disabled={!showAmbiguousPaths}
/>
<span
title="Use stored repeater advert paths to assign likely identity labels for ambiguous repeater nodes."
className={!showAmbiguousPaths ? 'text-muted-foreground' : ''}
>
Use repeater advert-path identity hints
</span>
</label>
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
checked={collapseLikelyKnownSiblingRepeaters}
onCheckedChange={(c) => setCollapseLikelyKnownSiblingRepeaters(c === true)}
disabled={!showAmbiguousPaths || !useAdvertPathHints}
/>
<span
title="When an ambiguous repeater has a high-confidence likely-identity that matches a sibling definitely-known repeater, and they both connect to the same next hop, collapse them into the known repeater. This should resolve more ambiguity as the mesh navigates the 1.14 upgrade."
className={
!showAmbiguousPaths || !useAdvertPathHints ? 'text-muted-foreground' : ''
}
>
Collapse likely sibling repeaters
</span>
</label>
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
checked={splitAmbiguousByTraffic}
onCheckedChange={(c) => setSplitAmbiguousByTraffic(c === true)}
disabled={!showAmbiguousPaths}
/>
<span
title="Split ambiguous repeaters into separate nodes based on traffic patterns (prev→next). Helps identify colliding prefixes representing different physical nodes, but requires enough traffic to disambiguate."
className={!showAmbiguousPaths ? 'text-muted-foreground' : ''}
>
Heuristically group repeaters by traffic pattern
</span>
</label>
<div className="flex items-center gap-2">
<label
htmlFor="observation-window-3d"
className="text-muted-foreground"
title="How long to wait for duplicate packets via different paths before animating"
>
Ack/echo listen window:
</label>
<input
id="observation-window-3d"
type="number"
min="1"
max="60"
value={observationWindowSec}
onChange={(e) =>
setObservationWindowSec(
Math.max(1, Math.min(60, parseInt(e.target.value, 10) || 1))
)
}
className="w-12 px-1 py-0.5 bg-background border border-border rounded text-xs text-center"
/>
<span className="text-muted-foreground">sec</span>
</div>
</div>
</details>
<div className="border-t border-border pt-2 mt-1 flex flex-col gap-2">
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
@@ -49,6 +49,7 @@ export interface UseVisualizerData3DOptions {
showAmbiguousPaths: boolean;
showAmbiguousNodes: boolean;
useAdvertPathHints: boolean;
collapseLikelyKnownSiblingRepeaters: boolean;
splitAmbiguousByTraffic: boolean;
chargeStrength: number;
letEmDrift: boolean;
@@ -102,6 +103,7 @@ export function useVisualizerData3D({
showAmbiguousPaths,
showAmbiguousNodes,
useAdvertPathHints,
collapseLikelyKnownSiblingRepeaters,
splitAmbiguousByTraffic,
chargeStrength,
letEmDrift,
@@ -256,6 +258,7 @@ export function useVisualizerData3D({
const projection = projectPacketNetwork(networkStateRef.current, {
showAmbiguousNodes,
showAmbiguousPaths,
collapseLikelyKnownSiblingRepeaters,
});
const previousNodes = nodesRef.current;
const nextNodes = new Map<string, GraphNode>();
@@ -279,7 +282,13 @@ export function useVisualizerData3D({
nodesRef.current = nextNodes;
linksRef.current = nextLinks;
syncSimulation();
}, [showAmbiguousNodes, showAmbiguousPaths, syncSimulation, upsertRenderNode]);
}, [
collapseLikelyKnownSiblingRepeaters,
showAmbiguousNodes,
showAmbiguousPaths,
syncSimulation,
upsertRenderNode,
]);
useEffect(() => {
ensureSelfNode(networkStateRef.current, config?.name || 'Me');
@@ -366,6 +375,7 @@ export function useVisualizerData3D({
const projectedPath = projectCanonicalPath(networkStateRef.current, ingested.canonicalPath, {
showAmbiguousNodes,
showAmbiguousPaths,
collapseLikelyKnownSiblingRepeaters,
});
if (projectedPath.nodes.length < 2) continue;
@@ -429,6 +439,7 @@ export function useVisualizerData3D({
packets,
packetNetworkContext,
publishPacket,
collapseLikelyKnownSiblingRepeaters,
rebuildRenderProjection,
showAmbiguousNodes,
showAmbiguousPaths,