Contents

SPONSOR VIEW SOURCE
SYMMETRIC P2P MESH ZTP / mDNS ZEROMQ H3 SPATIAL CORROBORATION PLUGGABLE COMPRESSION SPATIAL RELAYING DYNAMIC OTAA KEYEX SQLITE TIMESERIES KUBERNETES HELM CADDY TLS

Synapse Ingestion Engine

Synapse is a brokerless, edge-first IoT ingestion engine using a symmetric P2P mesh. Using ZeroMQ, SQLite timeseries database, and Uber H3 spatial analysis, it offers decentralized telemetry ingestion. Every node is identical with no central brokers, no monitors, and no single points of failure. Nodes discover each other automatically via Zero-Touch Provisioning (mDNS/Zeroconf), validate sensor readings locally through H3 spatial corroboration, compress payloads using pluggable strategies (zlib, lz4, zstd), and secure communication via CurveZMQ and Caddy TLS.

bash
$ git clone https://github.com/onyks-os/Synapse.git && cd Synapse
$ make start
[Synapse] Building image synapse-node:latest...
[Synapse] Starting node-1 ... done
[Synapse] Starting node-2 ... done
[Synapse] Starting node-3 ... done
[Synapse] Starting node-4 ... done
[node-1] CurveZMQ: secure keypair auto-generated (pub: Z85...)
[node-1] ZTP: discovered 3 peers via mDNS
[node-1] OTAA: dynamic enrollments handshake active (token: synapse-otaa-default)
[node-1] Ingest: local timeseries store active (SQLite: synapse.db)
[node-1] MeshNode bound PUB socket on tcp://0.0.0.0:5555 (compression: none)
[node-1] Dashboard → https://localhost:8441
Symmetric P2P Mesh

Every node is identical: runs main_node.py. No central broker. Fully decentralized ZeroMQ PUB/SUB with dynamic failover.

Zero-Touch Provisioning

True plug-and-play discovery via mDNS/Zeroconf (default), UDP Multicast Beacon, or static CSV peer lists. No hardcoded addresses.

Active Connection Management

Peering bounds via SYNAPSE_MAX_CONNECTIONS. Node maintains at most X active peers with reserve failover and self-peering filter.

Spatial Anomaly Detection

Real-time localized validation using Uber H3 and pluggable robust estimators (MAD default, Z-score, or AND-hybrid). Leave-one-out corroboration.

Pluggable Compression

Bandwidth reduction (up to 70%) via zlib, lz4, or zstd while keeping spatial H3 topic headers in clear text for native ZMQ filtering.

Spatial Multi-Hop Relaying

Telemetry propagation beyond direct range (k-ring 1). Intermediate nodes act as relays with vector loop prevention and duplicate suppression.

TLS & Dynamic OTAA

Caddy sidecar terminates HTTPS. ZMQ data channel secured by CurveZMQ with dynamic Over-The-Air key exchange and auto-generation.

Local Timeseries Store

Local database archiving of node readings in SQLite, exposing REST history query endpoints with age and size-based GC pruning.

Kubernetes Helm

Official Helm chart with DaemonSet topology ensures exactly one Synapse node per edge device. Caddy sidecar included. SQLite HostPath persistence.

EDGE-FIRST DESIGN PRINCIPLE
Synapse operates on the principle that geographic proximity is fundamental to validating edge sensor integrity. Data is corroborated locally against immediate geographic neighbors never forwarded to a remote cloud for analysis. The mesh is self-healing: if a peer drops, the active connection manager promotes a reserve candidate automatically.
0x02

Synapse Quickstart & Setup Guide

Prerequisites

  • Python 3.11+
  • Docker (or rootless Podman auto-detected by the Makefile)
  • Docker Compose v2

1. Start the P2P Mesh (Recommended)

The Makefile is the primary interface. make start builds and deploys a simulated local mesh of 4 identical nodes, each alongside its secure Caddy proxy:

bash
$ make start # build + deploy 4-node mesh
$ make logs # follow all container logs
$ make stop # tear down all containers

2. Accessing the Dashboard

Each node serves its own localized dashboard via HTTPS through the Caddy sidecar. Open your browser and navigate to the secure endpoint bypass the local development certificate warning once:

bash
# Node 1 dashboard (HTTPS via Caddy)
https://localhost:8441
# Node 2, 3, 4 dashboards
https://localhost:8442 https://localhost:8443 https://localhost:8444
  • Green Hexagons: All active sensors in the H3 cell are healthy and congruent.
  • Yellow/Orange Hexagons: One or more sensors are FAULTY or DEAD.
  • Red Hexagons: The majority of sensors in the cell have failed local corroboration.
  • Connected Peers sidebar: Navigate between the perspectives of all peers in the mesh without centralized aggregation.

3. Manual Python Development Setup

To develop and run a single node directly in Python without Docker:

bash
$ python3 -m venv .venv && source .venv/bin/activate
$ pip install -e ".[dev]"
# Run as many nodes as desired (each in a separate terminal)
$ python src/main_node.py # terminal 1 → node A
$ python src/main_node.py # terminal 2 → node B (auto-discovers A via mDNS)
UNIFIED ENTRYPOINT
Unlike older versions that shipped separate main_sensor.py and main_monitor.py daemons, v0.6.0 consolidates everything into a single src/main_node.py entrypoint. Every instance is a peer: there is no privileged "monitor" role.
0x03

P2P Mesh Technical Architecture & System Design

Synapse v0.6.0 adopts a fully Symmetric P2P Mesh model. Unlike hub-and-spoke topologies that depend on a central broker or monitor daemon, every participant is an identical Node that simultaneously senses data, ingests peer telemetry, validates anomalies, and serves its own operator dashboard.

Feature Traditional Hub-and-Spoke Synapse v0.6.0 P2P Mesh
Topology Centralized broker / monitor Symmetric: every node is identical
Discovery Hardcoded broker address ZTP via mDNS / UDP Beacon / Static
Single Point of Failure Yes: broker cluster None: any node loss is transparent
Anomaly Detection Centralized cloud analytics Local spatial corroboration per node
Compression No / Centralized proxy Pluggable (zlib, lz4, zstd) with clear-text topic filter
Relaying Centralized routing Spatial multi-hop with loop prevention path vector
Key Management Manual TLS certificates Dynamic OTAA Curve key exchange / auto-generation
Dashboard Central web UI Localized per node, cross-mesh navigation
Local History Store N/A (Forwarded to cloud) SQLite local timeseries archiving post-corroboration
TLS Optional / external LB Caddy sidecar per node (automatic)
Connection Scaling Full-mesh (exponential sockets) Bounded peers + dynamic failover

Core Components

ENTRYPOINT main_node.py

Unified daemon that orchestrates all components. Resolves node identity (via NODE_ID env or hostname), computes geographic coordinates to H3 cell, then wires together the MeshNode, GarbageCollector, PeerProvider, and DashboardServer. Handles graceful shutdown on SIGINT/SIGTERM.

NETWORK LAYER MeshNode (zmq_mesh.py)

The async ZeroMQ backbone. Binds a PUB socket to broadcast telemetry using the hybrid binary frame format. Dynamically connects a SUB socket to discovered peers. Key responsibilities:

  • Active Connection Management: Maintains at most SYNAPSE_MAX_CONNECTIONS live ZMQ SUB connections. Excess peers enter a reserve queue with dynamic reconnect failover.
  • Self-Peering Filter: Automatically removes its own bind address from the peer list, preventing socket waste.
  • Pluggable Compression & Decryption: Handles frame parsing, decompressing payloads lazily and decrypting with CurveZMQ.
  • Spatial Multi-Hop Relaying: Rewrites payload path vectors, appends own ID, and republishes telemetry within hop limits.
  • P2P History Replication: Periodically requests historical logs from peers via HTTP to backfill local storage.
  • Rate Limiter: Token-bucket rate-limiting checks prior to registry ingestion.
COMPRESSION ENGINE compression.py

Pluggable compression strategies implementing a strict protocol. Supports `none` (default), `zlib` (built-in), and optional `lz4` / `zstd` backends. Compresses payload bytes while ZeroMQ clear-text H3 topic prefixes are preserved for routing.

SQLITE STORAGE registry_store.py

Direct connection interface to the SQLite store database. Manages registry mirroring across process restarts and records post-corroboration sensor data into a high-performance timeseries historical table.

PEER DISCOVERY PeerProvider (peer_discovery.py)

Pluggable discovery layer, selected by SYNAPSE_DISCOVERY env:

  • ZeroconfPeerProvider DEFAULT: Publishes and discovers peers via mDNS (Zeroconf/Bonjour). Zero configuration required on local networks.
  • BeaconPeerProvider: UDP Multicast beacons. Useful on networks where mDNS is blocked.
  • StaticPeerProvider: Comma-separated list of static peer addresses. Suitable for Kubernetes or fixed infrastructure.
STATE ENGINE NodeRegistry (node_registry.py)

Thread-safe in-memory registry protected by threading.RLock. Groups nodes by H3 cell. All reads return deep copies for safe cross-thread use with Flask. Optionally persists node rows to SQLite (SYNAPSE_REGISTRY_DB) so state survives node restarts. Prometheus counters remain in-memory only.

HTTP / DASHBOARD DashboardServer (http_server.py)

Flask + Waitress serving the glassmorphic operator dashboard and versioned REST endpoints. Exposes `/api/v1/otaa/enroll` for dynamic public key exchange and `/api/v1/timeseries` for querying historical telemetry. Secures all dashboard endpoints with token authentication while bypassing health probes and enrollment handshakes.

LIFECYCLE GarbageCollector (garbage_collector.py)

Background loop driving timeout markdowns and evictions. Tick routines run check-timeouts (DEAD state transition after silence) and evict-dead-nodes (removal after TTL). Additionally schedules periodic execution of timeseries database pruning routines based on age and record counts.

Data Flow

1. Discovery Each Node broadcasts a UDP multicast / mDNS beacon announcing its node_id, H3 cell, and ports. Peers receive beacons and build a local peer map.
2. Subscription Upon discovering a peer, MeshNode connects its ZMQ SUB socket (respecting SYNAPSE_MAX_CONNECTIONS limit) and subscribes to spatial topics of interest.
3. Publication The node publishes a JSON PING payload on its PUB socket every PING_INTERVAL seconds, prefixed with its h3_cell as the ZMQ topic.
4. Ingest & Validate The receive loop reads messages, passes them through the rate limiter and schema validator, updates the NodeRegistry, then triggers check_corroboration on the cell.
5. Visualization The local DashboardServer serves real-time node state via the REST API. The user can navigate between node dashboards via the Connected Peers sidebar.
0x04

Spatial Validation Mathematical Formalism

1. Geospatial Mesh via H3 Grid

Geographic coordinates are transformed into a single 64-bit integer H3 cell representing a hexagonal region. The default resolution of 7 covers an average area of 4.3 km² with an edge length of approximately 1.2 km. Peers are defined strictly as nodes occupying the same cell. Subscriptions extend to the k-ring 1 neighborhood (the 7 immediately adjacent cells) for cross-cell validation.

2. Node State Machine

Each node in the registry can be in exactly one of three states:

State Condition Role in corroboration
ALIVE Received ping within DEATH_TIMEOUT Participates as a peer in LOO set
FAULTY Fails spatial corroboration check Excluded from peer LOO set
DEAD Silent beyond DEATH_TIMEOUT Excluded; evicted after EVICTION_TTL

Any state → ALIVE on next valid ping (recovery is instantaneous).

3. Pluggable Outlier Detection (Leave-One-Out Corroboration)

When a sensor publishes telemetry, the node triggers a Leave-One-Out (LOO) test. For node n reporting value x_n inside cell C, the peer comparison set is:

P_n = { x_i | i ∈ C, i ≠ n, status(i) == ALIVE }

Corroboration only runs if |P_n| ≥ CORROBORATION_MIN_PEERS (default 3). The decision rule is pluggable via CORROBORATION_METHOD.

Method: zscore Classic Z-Score

Uses sample mean (μ) and sample standard deviation (σ) over the peer set P_n:

Z = |x_n − μ| / σ

Caveat: μ and σ are non-robust. A single high-variance faulty peer in P_n can skew the baseline and mask real outliers. Prefer mad for small cells.

Method: mad Modified Z-Score via Median Absolute Deviation DEFAULT

Uses the median (m) and the Median Absolute Deviation (MAD) of the peer set, providing a robust estimator unaffected by up to 50% compromised peers:

MAD = median( { |p − m| for p ∈ P_n } )
Modified Z = 0.6745 × |x_n − m| / MAD

The constant 0.6745 scales the denominator to be equivalent to standard Z-scores under normality. If the modified Z exceeds ANOMALY_ZSCORE_THRESHOLD (default 2.0), the node status changes to FAULTY.

Method: both AND-Hybrid

A node is marked FAULTY only if both the zscore and mad methods independently flag it at the same threshold. Maximizes precision at the cost of recall highly conservative.

WORKED EXAMPLE
H3 cell with 5 temperature sensors: min_peers=4, threshold=2.0. Values: s1=20.1, s2=20.0, s3=20.2, s4=19.9, s5=35.0.
For s5, peers = {20.1, 20.0, 20.2, 19.9} → median≈20.05, MAD≈0.10 → Modified Z ≈ 100.3 → FAULTY.

4. ZeroMQ Hybrid Binary Framing

ZeroMQ subscriptions perform spatial topic filtering in clear-text using the H3 cell prefix. The payload is separated by a pipe character and compressed using the selected strategy:

Frame = [H3_Cell_ASCII] + b"|" + Strategy(Payload_JSON)

This layout enables edge nodes to leverage ZeroMQ native subscription matching at the socket level without decompressing headers, drastically reducing CPU cycles for unrelated traffic.

5. Spatial Multi-Hop Relaying & Loop Prevention

To extend telemetry propagation beyond direct range (k-ring 1), nodes act as spatial relays by republishing messages under their local topic prefix while keeping coordinates and sender IDs unchanged. To prevent infinite forwarding loops and broadcast storms, the message schema introduces a path vector:

relayed_by = [node_1, node_2, ..., node_k]

When a node n receives a relayed packet, the loop prevention rule is enforced:

If n ∈ relayed_by: Discard packet
Else if len(relayed_by) ≥ SYNAPSE_RELAY_MAX_HOPS: Discard packet
Else: relayed_by_new = relayed_by + [n] → Republish

6. Historical Duplicate Suppression

To avoid parsing or storing redundant messages propagated from multiple relay paths, the ingestion layer compares incoming timestamps against the node registry historical cache. A packet is discarded immediately at the ingest boundary if:
timestamp_incoming ≤ timestamp_registry_last_seen

0x05

Flask REST API Endpoint Reference

Each node exposes a versioned JSON REST API at http://<node-host>:8080/api/v1/ (or HTTPS via Caddy on port 8441–844N). The API is read-only and reflects the local node's perspective of the network not a centralized view.

OPTIONAL AUTH
When SYNAPSE_DASHBOARD_API_KEY is set, requests to /api/v1/* and /metrics require an X-Api-Key header. The UI will prompt for the key client-side when needed.
Endpoint Method Response Description
/api/v1/nodes GET Array of NodeEntry All registered nodes with coordinates, last value, and status. Legacy alias: /api/nodes.
/api/v1/cells GET Dict of Cell Summaries Per-H3-cell aggregation with alive/faulty/dead counts and centroid. Legacy alias: /api/cells.
/api/v1/otaa/enroll POST JSON Status Object Symmetrically exchange and authorize ZMQ CURVE public keys upon discovery. Excluded from dashboard token auth.
/api/v1/timeseries GET Array of historical readings Query historical telemetry database. Parameters: node_id, h3_cell, start_time, end_time, limit. Legacy alias: /api/timeseries.
/metrics GET Prometheus text/plain Scrapable metrics: message rates, invalid payloads, rate-limited counts, node state gauges.
/live GET {"status":"ok"} Kubernetes liveness probe.
/ready GET JSON Status Object Readiness probe with nodes_total and nodes_alive counts.

NodeEntry Schema

Field Type Description
node_id string Unique node identifier.
type string Sensor type (e.g., "mock", "chaos").
status string ALIVE, FAULTY, or DEAD.
last_seen float Unix timestamp of last received ping.
h3_cell string H3 index (resolution 7) of the node's location.
lat / lon float Last known geographic coordinates.
last_value float Last telemetry reading (shown in °C on dashboard).

Prometheus Metrics

Metric Type Description
Synapse_messages_total Counter Total valid PING messages processed.
Synapse_invalid_payload_total Counter Messages dropped due to schema validation failure.
Synapse_rate_limited_total Counter Messages dropped by the token-bucket rate limiter.
Synapse_corroboration_faulty_total Counter Total FAULTY transitions triggered by corroboration.
Synapse_nodes_alive Gauge Current count of ALIVE nodes.
Synapse_nodes_faulty Gauge Current count of FAULTY nodes.
Synapse_nodes_dead Gauge Current count of DEAD nodes.

Example: GET /api/v1/nodes

JSON
[
  {
    "node_id": "node-a1b2",
    "type": "mock",
    "status": "ALIVE",
    "last_seen": 1748389082.5,
    "h3_cell": "871fb4670ffffff",
    "lat": 45.4642,
    "lon": 9.1895,
    "last_value": 24.5
  },
  {
    "node_id": "node-c3d4",
    "type": "mock",
    "status": "FAULTY",
    "last_seen": 1748389079.1,
    "h3_cell": "871fb4670ffffff",
    "lat": 45.4640,
    "lon": 9.1890,
    "last_value": 999.0
  }
]

Example: POST /api/v1/otaa/enroll

Send enrollment requests with a node identifier and public key Z85 string to configure peer authentication dynamically.

JSON Request
{
  "node_id": "node-c3d4",
  "public_key": "t7.d&F-gV=m]W5hR#c(P/y?Xq+eL*Z@wK8oNU2iv"
}

Example: GET /api/v1/timeseries

Query historical node telemetry readings archived in the local store. Filters: node_id, h3_cell, start_time, end_time, and limit.

JSON Response
[
  {
    "timestamp": 1748389082.5,
    "node_id": "node-a1b2",
    "h3_cell": "871fb4670ffffff",
    "lat": 45.4642,
    "lon": 9.1895,
    "value": 24.5,
    "status": "ALIVE"
  },
  {
    "timestamp": 1748389079.1,
    "node_id": "node-a1b2",
    "h3_cell": "871fb4670ffffff",
    "lat": 45.4642,
    "lon": 9.1895,
    "value": 24.1,
    "status": "ALIVE"
  }
]
0x06

Mesh Messaging Protocol & Spatial Relaying

ZeroMQ transmits structured telemetry using lightweight JSON framing. Each message is prefixed with the sender's h3_cell as the ZMQ topic, allowing subscribers to filter spatially with zero overhead.

PING Payload Schema

JSON Schema
{
  "schema_version": 1,          // forward-compat version; listener accepts missing as v1
  "node_id": "node-a1b2",         // resolved from NODE_ID env or hostname
  "type": "mock",
  "timestamp": 1748389082.12,
  "status": "PING",
  "h3_cell": "871fb4670ffffff",      // also used as ZMQ topic prefix
  "relayed_by": ["node-x9y0"],  // list of node IDs that relayed this message
  "payload": {
    "value": 22.45,             // required: used in corroboration
    "lat": 45.4642,
    "lon": 9.1895
  }
}
SCHEMA VALIDATION
The receive loop runs rapid schema validation. PING packets lacking mandatory fields (node_id, h3_cell, payload.value) are silently dropped at the ingest boundary. Dropped payloads increment the Synapse_invalid_payload_total Prometheus counter.

Environment Configuration

Variable Default Description
SYNAPSE_ZMQ_PORT 5555 Port the PUB socket binds to.
PING_INTERVAL 1.0 Seconds between PING publications.
H3_RESOLUTION 7 H3 spatial resolution (4.3 km² per cell).
SYNAPSE_MAX_CONNECTIONS 0 (unlimited) Max active ZMQ SUB connections. Set 8–12 for 50+ node meshes.
SYNAPSE_DISCOVERY zeroconf Peer discovery mode: zeroconf, beacon, static.
DEATH_TIMEOUT 3.0 Seconds of silence before node → DEAD.
EVICTION_TTL 10.0 Seconds after DEAD before permanent eviction.
CORROBORATION_METHOD mad Outlier method: mad, zscore, both.
ANOMALY_ZSCORE_THRESHOLD 2.0 Score above which a node is flagged FAULTY.
CORROBORATION_MIN_PEERS 3 Min ALIVE peers required before corroboration runs.
RATE_LIMIT_MSG_PER_SEC 100 Token-bucket replenish rate per node.
RATE_LIMIT_BURST 20 Token-bucket burst capacity.
SYNAPSE_COMPRESSION none Compression strategies: none, zlib, lz4, zstd.
SYNAPSE_RELAY_MAX_HOPS 0 Hop limit for spatial multi-hop relaying (0 disables relaying).
SYNAPSE_OTAA_ENABLED true Enable dynamic Over-The-Air Activation key exchange.
SYNAPSE_OTAA_TOKEN synapse-otaa-default Secret key used to authorize REST key exchange handshakes.
SYNAPSE_TIMESERIES_ENABLED true Enable local database archiving of node readings in SQLite.
SYNAPSE_TIMESERIES_RETENTION_PERIOD 86400 History retention window in seconds (defaults to 24 hours).
SYNAPSE_TIMESERIES_RETENTION_LIMIT 1000 History retention count limit per node.
SYNAPSE_REPLICATION_INTERVAL 30.0 Seconds between periodic query pull backfills from discovered peers.
SYNAPSE_REGISTRY_DB (none) SQLite path for node row persistence across restarts.
NODE_ID hostname Override node identity string.
SENSOR_LAT / SENSOR_LON random (Italy) Fixed geographic coordinates for the node.
SYNAPSE_LOG_FORMAT text Log format: text or json (structured).
0x07

CurveZMQ Security & Caddy TLS Sidecar

Synapse v0.6.0 implements a layered security model: Caddy TLS at the HTTP/dashboard layer, CurveZMQ (Curve25519) with ZAP authentication at the ZMQ data channel layer, and Dynamic OTAA key enrollment.

Layer 1: Caddy TLS Reverse Proxy Sidecar

Every Synapse node in the Docker Compose and Helm deployments is paired with a Caddy proxy sidecar container within the same pod/service. Caddy automatically generates and rotates a self-signed certificate for local development, and can be configured for ACME/Let's Encrypt certificates in production.

bash
# Each node's dashboard is available over HTTPS via the Caddy sidecar
https://localhost:8441 # node-1 (bypass dev cert warning once)
https://localhost:8442 # node-2
# Caddy proxies HTTPS → http://127.0.0.1:8080 internally

Layer 2: CurveZMQ Elliptic Curve Transport Encryption

The ZMQ data channel can be encrypted and authenticated with CurveZMQ (Elliptic Curve Cryptography based on Curve25519). Generate keys and container-specific environment configurations automatically:

bash
$ python tools/generate_curve_setup.py --count 5 --out-dir .curve-setup
[Curve] Generating Curve25519 key pairs...
[Curve] Created .curve-setup/server.env (server public + secret keys)
[Curve] Created .curve-setup/allowed_client_publickeys.txt (5 authorized keys)
[Curve] Created .curve-setup/sensor-envs/sensor_0000.env ... sensor_0004.env
ZAP AUTHENTICATION (ZERO ACCESS PROTOCOL)
When CurveZMQ is enabled, ZeroMQ's ZAP handler is active on the node's SUB socket. Any client whose public key is not present in the allowed list is rejected at the TCP handshake phase: before any payload is processed.

Layer 4: Dynamic Over-The-Air Activation (OTAA)

To bypass manual keypair pre-distribution, nodes run symmetrically authorized REST handshakes via POST /api/v1/otaa/enroll upon discovery. Public Curve keys are automatically registered on the target node, allowing handshake validation at the ZeroMQ ZAP authentication phase.

SECURE BY DEFAULT CONFIGURATION
Encryption (ZMQ CURVE) and dynamic enrollment (OTAA) are enabled by default. Fallback configurations utilize predefined default values (synapse-admin for HTTP credentials and synapse-otaa-default for enrollment tokens) ensuring deployments are secure out-of-the-box.

Layer 3: Rate Limiting via Token-Bucket

To mitigate DoS attempts by faulty or flooded nodes, the registry enforces a per-node token-bucket rate limiter:

  • Burst Capacity: Maximum burst allowance (RATE_LIMIT_BURST, default 20 tokens).
  • Replenish Rate: Token restoration per second (RATE_LIMIT_MSG_PER_SEC, default 100).
  • Action: Packets depleting the bucket are dropped and counted in Synapse_rate_limited_total.
0x08

Mesh Node Development & Test Framework

Synapse follows strict TDD practices. The full verification suite ruff auto-fix, pytest, mypy, Helm lint, and chaos smoke integration runs as a single make verify command.

97
Unit & Integration Tests
100%
Passing
0
Mypy Errors
0
Ruff Issues

Running the Full Verification Suite

bash
$ make verify
=> Linting Helm charts...
=> Helm charts are valid.
=> Applying automatic linting fixes and formatting (ruff)...
=> Running tests (pytest)...
tests/integration/test_compressed_mesh.py PASSED
tests/integration/test_otaa_flow.py PASSED
tests/integration/test_relay_flow.py PASSED
tests/integration/test_timeseries_api.py PASSED
tests/unit/test_timeseries.py PASSED
tests/unit/test_compression.py PASSED
tests/unit/test_corroboration.py PASSED
tests/unit/test_node_registry.py PASSED
... (89 more)
========================== 97 passed in 8.99 seconds ===========================
=> Running type checking (mypy)...
Success: no issues found in 21 source files.
=> Running chaos smoke test integration...
=> Verification complete. The codebase is ready for release.

Test Suite Overview

Test Module Coverage
test_corroboration.py MAD, Z-score, AND-hybrid, edge cases (zero spread, insufficient peers)
test_node_registry.py State transitions, thread safety, RLock semantics, deep copy returns
test_rate_limiter.py Token bucket drain, replenish, burst enforcement
test_zmq_mesh_limits.py Active connection limits, reserve failover, self-peering filter
test_zeroconf_discovery.py mDNS service registration and peer list resolution
test_zmq_curve.py Curve25519 key generation, ZAP allowlist enforcement
test_http_server.py API endpoint responses, Prometheus metrics, liveness/readiness
test_garbage_collector.py Timeout detection, eviction scheduling
test_registry_sqlite.py SQLite persistence, restart recovery
test_peer_discovery.py Static, beacon, and zeroconf provider interfaces
test_event_logger.py Structured event logging, JSON format output
test_main_node.py Identity resolution, coordinate fallbacks, env parsing
test_timeseries.py SQLite historical logs archiving, filters, SQL-based age/count pruning
test_compression.py Pluggable compression strategies initialization (zlib, lz4, zstd, none)
test_compressed_mesh.py End-to-end ZeroMQ mesh publishing with active compression and decompression
test_otaa_flow.py REST dynamic key exchange handshake and token validation flows
test_relay_flow.py Spatial multi-hop relay topologies, loop prevention, and TTL hop limits
test_timeseries_api.py REST timeseries GET endpoints, filtering parameters, and data retrieval

Linter & Type Checking

bash
$ ruff check --fix src tests tools && ruff format src tests tools
All checks passed.
$ mypy src
Success: no issues found in 21 source files.
0x09

Mesh Ingestion Benchmarking & Performance

Synapse includes a native, container-overhead-free benchmark tool (tools/benchmark.py) that orchestrates up to 50 in-process simulated nodes via subprocess.Popen with static peer discovery. It measures mesh convergence time and aggregate message throughput under intense stress tests.

Key Performance Metrics (N=50 nodes)

2.9s
Full-Mesh Convergence (N=50, O(N²) topology)
~2470 msg/sec throughput
2.39s
Bounded-Mesh Convergence (X=8 limit)
~400 msg/sec · 84% fewer TCP sockets
SCALING INSIGHT
With SYNAPSE_MAX_CONNECTIONS=8, the bounded mesh converges 17% faster than a full-mesh at 50 nodes, while using 84% fewer TCP sockets. The mesh remains fully connected and resilient to failures the reserve failover mechanism guarantees dynamic re-peering.

Running Benchmarks

bash
# Incremental stress test: scales from 5 to 50 simulated nodes
$ make benchmark
# Fixed scale benchmark (e.g. 10 nodes)
$ make benchmark NODES=10
[Benchmark] Spawning 10 nodes with static discovery...
[Benchmark] Convergence time: 0.72s
[Benchmark] Total throughput: 487 msg/sec
[Benchmark] All nodes ALIVE. Mesh is fully connected.
0x0A

Chaos Engineering & Mesh Resilience Testing

Synapse ships two complementary chaos tools: the Chaos Monkey (tools/chaos_monkey.py) for application-level failure injection, and Pumba for kernel-level network degradation via tc/netem.

Chaos Monkey Application-Level Failure Injection

KILL MODE

Randomly terminates running Docker sensor containers via SIGKILL. Validates that the mesh marks them DEAD after DEATH_TIMEOUT and that the reserve failover reconnects surviving peers.

ANOMALY MODE

Broadcasts well-formed PING messages with deliberately extreme values (e.g., 999.0 °C). Tests whether the H3 spatial corroboration immediately flags rogue nodes as FAULTY.

FLOOD MODE

Floods the ingestion port with malformed payloads and high-velocity packet bursts. Tests schema validation isolation, rate limiter enforcement, and parser stability under storm conditions.

bash
# Install chaos dependencies first
$ pip install ".[chaos]"
# Aggressively test corroboration: high-amplitude anomalies every 5s
$ python tools/chaos_monkey.py --mode anomaly --intensity high --interval 5
[Chaos] Attacking network with mode: anomaly (intensity: high)
[Chaos] Target selected: node-c3d4 in cell 871fb4670ffffff
[Chaos] Overriding node-c3d4 telemetry to 999.00 (Outlier injected)
# Or use the Makefile shortcut (runs via Docker Compose)
$ make chaos
# Full stress test (all modes, 120 seconds)
$ python tools/chaos_monkey.py --mode both --intensity medium --duration 120

Pumba Network-Level Chaos (Latency & Packet Loss)

Pumba intercepts the network stack of node containers and injects degradation via the Linux kernel's tc/netem subsystem. This validates the ZeroMQ P2P mesh's resilience to physical network impairment.

Parameter Default
Target containers All matching docker-node-*
Network latency 200ms ± 50ms jitter
Packet loss 15%
Degradation blocks 1 min degraded / 2 min normal (cyclic)
bash
# Start network latency + packet loss injection
$ make chaos-network
# Stop Pumba and immediately restore clean network
$ make chaos-network-stop
0x0B

Edge Deployment & Kubernetes Helm Charts

Option 1: Docker Compose (Local / Development)

The Makefile wraps all Docker Compose operations and auto-detects rootless Podman sockets. A 4-node mesh with Caddy sidecars starts in seconds:

bash
$ make start # build + launch 4 nodes + 4 Caddy sidecars
$ make logs # follow logs
$ make stop # teardown + remove orphans

Option 2: Kubernetes via Helm (Edge Production)

For production deployment on physical edge clusters (K3s, MicroK8s), Synapse provides an official Helm chart implementing a DaemonSet topology guaranteeing exactly one Synapse instance per physical node:

DaemonSet Topology

Exactly one Synapse pod per physical edge device. Complements the decentralized P2P architecture perfectly each device runs an independent mesh participant.

Caddy Sidecar Container

Each pod includes a Caddy reverse proxy sidecar for TLS termination. Caddy config injected via ConfigMap.

SQLite HostPath Persistence

Node registry persists to a local hostPath volume (default /var/lib/synapse/data). Survives pod restarts without a distributed database.

bash
# Install the Helm chart (DaemonSet)
$ helm install synapse-edge ./charts/synapse
# Override values at install time
$ helm install synapse-edge ./charts/synapse \
--set persistence.hostPath=/opt/synapse/data \
--set node.logFormat=json
# Lint and template-check the chart
$ make verify-helm

Helm Chart: Key Values (charts/synapse/values.yaml)

Key Default Description
image.repository ghcr.io/onyks-os/synapse-node Docker image for the Synapse node.
image.tag latest Image tag (pin to a release in production).
persistence.hostPath /var/lib/synapse/data Absolute path on the edge device for SQLite storage.
caddyfile (inline) Raw Caddy configuration string injected via ConfigMap.
node.logFormat text text or json structured logging.
0x0C

CI/CD Pipeline & Automated Testing

Synapse uses GitHub Actions for fully automated quality assurance and release publishing. No secrets are stored PyPI publishing uses OIDC Trusted Publishing.

CI .github/workflows/ci.yml every push & PR
  • Static analysis: mypy strict type checking + ruff linting
  • Unit testing: pytest (97 tests)
  • Helm chart linting: helm lint charts/synapse
  • Chaos smoke integration: spins up a full Docker Compose topology, runs tools/ci_chaos_smoke.py to inject ZMQ anomalies and verify the mesh survives the attack
CD .github/workflows/cd.yml every versioned tag
  • Multi-arch Docker images: Builds linux/amd64 + linux/arm64 via QEMU and pushes to GHCR (ghcr.io/onyks-os/synapse-node)
  • PyPI publication: Builds sdist + wheel and publishes via OIDC Trusted Publishing zero stored secrets
Published Artifact Registry Architectures
synapse-node Docker image ghcr.io/onyks-os/synapse-node linux/amd64, linux/arm64
synapse Python package PyPI (pypi.org/project/Synapse) any (pure Python)
OIDC TRUSTED PUBLISHING
PyPI publishing uses GitHub Actions OIDC tokens no API keys or secrets are stored in the repository. The identity of the release is cryptographically attested by the GitHub Actions workflow provenance.
0x0D

Synapse Project Roadmap & Future Development

Synapse is an evolving research project exploring edge ingestion paradigms.

V1 PROOF OF CONCEPT

COMPLETE

Core Python ingestion, ZeroMQ PUB/SUB binding, in-memory NodeRegistry, Z-score anomaly detection, primitive status updates, Docker Compose deployment.

V2 SYMMETRIC P2P MESH & SECURE RUNTIME

COMPLETE (v0.2.0)

Symmetric P2P mesh with ZTP (mDNS/Zeroconf), Active Connection Management with dynamic reserve failover, self-peering filter, MAD robust outlier detection, CurveZMQ mutual authentication, token-bucket rate limiting, Caddy TLS sidecar, glassmorphic operator dashboard (Leaflet, radial gauge, Chaos console), Kubernetes Helm DaemonSet chart, SQLite registry persistence, 80-test suite, GitHub Actions CD (multi-arch GHCR + PyPI OIDC), native benchmark suite, Pumba network chaos.

V3 COMPRESSION, RELAYING & TIMESERIES

COMPLETE (v0.6.0)

Pluggable payload compression strategies (zlib, lz4, zstd), spatial multi-hop relaying with loop prevention path vectors, dynamic Over-The-Air Activation (OTAA) symmetrically enrolling keys via Flask, secure by default fallback modes, and local SQLite timeseries storage archiving post-corroboration readings with automated background garbage collection pruning.

V4 WASM PREDICTIVE RUNTIMES

IN DEVELOPMENT

Migrating outlier and anomaly models into WebAssembly (WASM) modules to enable sandboxed cryptographic computation directly on microcontroller layers. Payloads signed at the sensor core before transmission, enabling tamper-evident telemetry without a PKI server.