diff --git a/data/mesh_ingestor/CONTRACTS.md b/data/mesh_ingestor/CONTRACTS.md index 91fd8245..f0092e79 100644 --- a/data/mesh_ingestor/CONTRACTS.md +++ b/data/mesh_ingestor/CONTRACTS.md @@ -8,7 +8,7 @@ This repo’s ingestion pipeline is split into: - Python collector (`data/mesh_ingestor/*`) which normalizes packets/events and POSTs JSON to the web app. - Sinatra web app (`web/`) which accepts those payloads on `POST /api/*` ingest routes and persists them into SQLite tables defined under `data/*.sql`. -This document records the contracts that future protocols must preserve. The intent is to enable adding new protocols (MeshCore, Reticulum, …) without changing the Ruby/DB/UI read-side. +This document records the contracts that future protocols must preserve. New protocols (MeshCore, Reticulum, …) reuse the shared read side (`nodes`, `/api/nodes`, the stats scopes, the federation record) and extend it only additively. A read-side addition for one protocol needs its own SPEC decision and leaves the other protocols' shapes unchanged, as Reticulum's `destinations` table and `GET /api/destinations` do (SPEC Invariant IV). ### Canonical node identity diff --git a/tests/test_reticulum_unit.py b/tests/test_reticulum_unit.py index 7f23767e..5aefbf45 100644 --- a/tests/test_reticulum_unit.py +++ b/tests/test_reticulum_unit.py @@ -32,6 +32,7 @@ if str(REPO_ROOT) not in sys.path: from RNS.vendor import umsgpack # noqa: E402 - path setup import data.mesh_ingestor.config as config # noqa: E402 - path setup +import data.mesh_ingestor.node_identity as node_identity # noqa: E402 - path setup import data.mesh_ingestor.protocols.reticulum as _mod # noqa: E402 - path setup from data.mesh_ingestor.protocols.reticulum import ( # noqa: E402 - path setup ReticulumProvider, @@ -492,11 +493,11 @@ def test_host_node_id_uses_the_reticulum_mapping_not_the_meshtastic_one(): registering ``!86c39940`` while its own peer row was ``!27716218``. """ identity_hash = "27716218762cfd2864141ef286c39940" - assert ReticulumProvider().extract_host_node_id(None) is None or True - with_env = ReticulumProvider() + # The shared helper keeps the low 32 bits: the id the field run registered. + assert node_identity.canonical_node_id(identity_hash) == "!86c39940" assert _mod._reticulum_node_id(bytes.fromhex(identity_hash)) == "!27716218" # The provider must canonicalise a raw identity hash the same way. - assert with_env._canonical_host_node_id(identity_hash) == "!27716218" + assert ReticulumProvider()._canonical_host_node_id(identity_hash) == "!27716218" def test_derived_host_node_id_is_none_when_no_identity_exists(monkeypatch):