Closes#90, #91, #92.
#90 — Spurious topology links
Topology treated IP addresses and system identities as unique across the whole
fleet. They are unique only within a broadcast domain, so an installation with
physically separate segments that each reuse 10.2.0.0/24 saw devices in one
segment joined to devices in another.
The reporter pointed at shared-segment detection, and that is one of four sites
with the same flaw — but not the first. Step 2 resolves a neighbour IP to a
managed device from a global first-wins map, so a reused address silently
resolves to whichever device was loaded first; the union-find in step 6 then
merges on the resulting device id, a correct-looking key derived from bad data.
Fixing only step 6 would have left the reported link in place.
Addresses and identities are now scoped to the device that reported them
wherever they name a neighbour, so they still collapse one device's duplicate
sightings but can never join two devices. Resolution and LLDP-coverage
suppression additionally require the address to be unambiguous fleet-wide.
MAC addresses and resolved device ids are unaffected — they identify hardware,
and genuinely shared segments still merge on them.
Ambiguity detection deliberately ignores MAC divergence. A switch assigns a MAC
per port, so a device with two uplinks is reported under several MACs; an
earlier version of this fix treated that as a conflict and refused to resolve
ordinary multi-port hardware. Caught on a live fleet, where three sightings of
one CRS510 disagreed on MAC but agreed on identity. The signals used instead are
an address claimed by two managed devices, or sightings that disagree about the
neighbour's identity.
The graph builder is extracted from the route into a pure module with 16 tests,
including a fixture of the reporter's five-device, three-segment network. It had
no test coverage before, which is why a flaw this systemic went unnoticed.
Verified against a live fleet: graph output is identical before and after, and
the ambiguity list is empty when addressing is clean.
#91 — CPU load not rounded
The devices table rendered the raw value from a 5-minute Influx mean, so a
device idling between 1% and 2% displayed as 1.3333333333333333%. Rounded for
display; the sparkline keeps the unrounded series so its curve stays smooth.
#92 — Serial number in the device table
Serials were already collected, stored, returned by the API and matched by
global search, so this is presentation only: a sortable SERIAL column, and
serial added to the table's filter predicate.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>