Files
ukmesh/docs/node-identity.md
T

49 lines
1.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Canonical node identity
Why one physical device can appear as multiple nodes, and how the stack
merges them at the data layer (not in the UI).
## The problem
`nodes` is keyed by the exact 64-hex `node_id`. Two failure modes create
ghost rows / "repeater not showing data":
1. A device that re-keys (or advertises a one-nibble-corrupted key) becomes a
separate row — same name, near-identical keys (GNOME-MSG-RPT ×3,
2E0MTU RPT Hilperton ×2).
2. MQTT status rows carry the OBSERVER key while advert/position rows carry
the node's own key — one device's status and position live under
DIFFERENT rows.
Every flow (history, adverts, owner dashboard, links, aggregates) queries
exact IDs, so data appears split/stale and the owner dashboard lists
repeaters multiple times.
## The fix
- `backend/src/db/nodeIdentity.ts` + migrations **036/037**: evidence-based
canonical identity merging at the repository layer. Canonical views return
one row per device with `identity_source_ids` (the merged member keys).
- Perf: canonical views are wrapped in a materialized CTE (migration 037);
`/api/node-status/latest` resolves canonical members first, then reads per
member via the `(node_id, time)` index. A naive canonical projection over
the 5.6M-row telemetry view was >8s; the fixed path is ~1.5s.
- Owner dashboard: the owner API exposes `canonicalId` + `members` for
authorized keys; the UI collapses same-name identities into one entry with
the member key list.
## False-merge guard (hard-won)
- Active-to-active packet-pairing alone is NOT identity proof — colocated
families named `Dunston-1/2/3`, `NorthMesh RPT-1/2`, `Reach Yagi E/NWW`
must stay separate.
- Differing ordinal/directional suffixes = hard ambiguity, never merge.
- Metadata-only observer rows DO qualify for merging.
## Diagnose
```sql
SELECT name, public_key, last_seen, advert_count
FROM nodes WHERE name ILIKE '<name>';
```