fix(analysis-map): render cross-source neighbor links (union, not intersection) (#3792)#3801
Conversation
…ersection) (#3792) NeighborLinksLayer keyed its node-position lookup by `${sourceId}:${nodeNum}` and resolved BOTH endpoints of each edge with the edge's own sourceId. A neighbor edge carries the sourceId of the reporting node, but the other endpoint's position may only be recorded under a different selected source — so that lookup missed and the edge was silently dropped (line `if (!a || !b) continue`). With multiple sources selected this collapsed the intended union of links into an intersection (fewer links than either source alone). The API (getNeighbors, inArray over sourceIds) already returns the union; this is a frontend-only fix. Endpoint positions (and transport class) now prefer the source-scoped key but fall back to the node's position on any selected source. Added regression tests: a cross-source edge now renders, while an edge with an endpoint that has no position anywhere is still dropped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4
|
Claude finished @Yeraze's task —— View job PR Review: fix(analysis-map): render cross-source neighbor links (union, not intersection)
SummaryThe fix is correct, well-scoped, and the root cause diagnosis in the PR description is accurate. The implementation uses a sensible fallback pattern and the tests cover the critical scenarios. Code Review
Correctness ✅ The fallback pattern ( Minor observations:
Test coverage ✅ The two new test cases directly cover the fix:
The One gap to consider: There's no test asserting that when a node appears under both sources, the source-scoped position takes precedence over the cross-source fallback. This would confirm the "prefer own source" behavior. It's not a blocker — the implementation is clearly correct — but it would harden the intent. VerdictApprove. The fix is minimal, targeted, and correct. The root cause is clearly explained, the fallback is sound, and the regression test will catch this class of bug going forward. The minor observations above are all low-severity or pre-existing and don't warrant blocking the merge. |
Summary
On the Analysis Map, selecting multiple sources (e.g. LoRa + MQTT) showed fewer neighbor links than viewing either source alone — an intersection where a union was intended. The API already returns the union; the bug is entirely in frontend rendering. (Verified the reporter's root-cause analysis against the code — it's correct.)
Root cause
NeighborLinksLayerbuilds a position lookup keyed"${sourceId}:${nodeNum}", then resolves both endpoints of each edge using only the edge's ownsourceId:A neighbor edge carries the
sourceIdof the reporting node, but the other endpoint's position may only be recorded under a different selected source. That lookup misses → the edge is dropped. Only edges whose both endpoints are positioned under the same source as the reporting node survive ⇒ effective intersection.The API is correct:
analysis.tsgetNeighbors()usesinArray(neighbors.sourceId, args.sourceIds)and returns the full union.Changes
NeighborLinksLayer.tsx— addednodeNum-keyed fallback maps (positionByNode,transportByNode). Endpoint position and transport class now prefer the source-scoped key, then fall back to the node's value on any selected source. Updated theedgesmemo deps and the component doc comment.NeighborLinksLayer.test.tsx— regression tests: a cross-source edge (neighbor positioned only under a different source) now renders; an edge whose endpoint has no position on any source is still dropped.CHANGELOG.md— Fixed entry.Issues Resolved
Fixes #3792.
Documentation Updates
CHANGELOG.md— Fixed entry under [Unreleased]. No other docs affected (internal rendering fix).Testing
🤖 Generated with Claude Code