docs/adr/ADR-083-per-cluster-pi-compute-hop.md
| Field | Value |
|---|---|
| Status | Proposed — pending field evidence on three-tier proposal scope |
| Date | 2026-04-26 |
| Authors | ruv |
| Supersedes | — |
| Refines | ADR-028 (capability audit), ADR-081 (5-layer kernel), ADR-066 (swarm bridge) |
| Companion | docs/research/architecture/three-tier-rust-node.md, docs/research/architecture/decision-tree.md, docs/research/sota/2026-Q2-rf-sensing-and-edge-rust.md |
ADR-028 established the per-node BOM at ~$9 (ESP32-S3 8MB) — ~$15 with a mmWave sensor — and ADR-081 framed the firmware as a 5-layer adaptive kernel running entirely on a single ESP32-S3 die. Both decisions are correct for the per-node dimension; deployments that fit the "sensor talks UDP to a server somewhere" shape work fine on this stack.
The three-tier-node research exploration
(docs/research/architecture/three-tier-rust-node.md) raised a separate
question: what changes when a deployment scales past one or two rooms,
and where should the heavy compute live? The exploration's answer
("dual ESP32-S3 + Pi Zero 2W per node") is one shape, but the
companion decision-tree (decision-tree.md §1, §3 L3, §5) identifies a
materially cheaper path: keep today's single-S3 sensor node unchanged
and add one Pi per cluster of 3–6 sensor nodes. The 2026-Q2 SOTA
survey (sota/2026-Q2-rf-sensing-and-edge-rust.md) confirms that the
load this path needs to carry — model inference, QUIC backhaul, and a
real secure-boot story — fits comfortably on a Pi-class SoC, while the
load it doesn't need to carry — CSI capture, ISR-precise wake control —
is exactly what the ESP32-S3 already does well.
The three things this ADR is about, all of which the current single-S3 deployment shape pushes onto the cloud or onto every individual node:
quinn + rustls is mature on Linux but does
not run on ESP32-class hardware in any production-grade form
(SOTA §5). A Pi terminating QUIC for a cluster gives every sensor
node QUIC's loss/handoff/multiplex properties without porting QUIC
to the MCU.The cluster-Pi shape does not require any change to ADR-028 or ADR-081. The sensor node continues to be a single-MCU ESP32-S3 running the 5-layer kernel. Everything new lives at the cluster boundary.
Adopt a per-cluster Pi hop as the canonical RuView mid-scale deployment shape. A "cluster" is 3–6 ESP32-S3 sensor nodes within WiFi mesh range of one Pi.
Specifically:
rv_feature_state_t
packets (60 byte, ~5 Hz, ~300 B/s) over UDP, and connect via
ESP-WIFI-MESH or direct WiFi to the cluster Pi.wifi-densepose-ruvector crate).wifi-densepose-sensing-server, no Pi required. The cluster Pi
becomes the recommended shape for fleets ≥ 3 sensor nodes.The cluster Pi exposes two interfaces:
| Interface | Direction | Schema |
|---|---|---|
UDP rv_feature_state_t ingest | sensor → Pi | Existing 60-byte packed struct from ADR-081 (magic 0xC5110006) |
| QUIC mTLS uplink | Pi → gateway/cloud | New: cluster-level event envelope (CBOR), batched, ~10 KB/min upper bound |
Sensor → Pi is the same wire as today's sensor → server. Cluster Pi
uplink is new and is what the existing wifi-densepose-sensing-server
becomes — relocated from the user's laptop / container to the cluster
node. Concretely: the sensing server already exists in
crates/wifi-densepose-sensing-server; it cross-compiles to ARMv7 /
AArch64 today via cargo build --target aarch64-unknown-linux-gnu. The
relocation is a deployment change, not a re-implementation.
This ADR's cluster-Pi shape is the L3-hybrid path in
decision-tree.md §2 — not the full three-tier (dual-MCU + per-node
Pi) shape. It captures most of the value (ML, QUIC, secure-boot anchor)
at minimal BOM impact. The full three-tier shape remains the long-term
exploration target, blocked behind L4 (no_std CSI maturity) and L2
(per-node ISR-jitter evidence).
quinn + rustls runs on the
Pi as it does on a server (SOTA §5). The sensor MCU keeps UDP — the
cheapest, highest-tested wire it already speaks.The implementation is intentionally light because most of the pieces already exist; the ADR is largely about formalizing where they live.
rust-port/wifi-densepose-rs/.cargo/config.toml (or the equivalent
per-crate target spec) an aarch64-unknown-linux-gnu target so
wifi-densepose-sensing-server builds for Pi 4 / 5 / CM4 by
default. Also retain armv7-unknown-linux-gnueabihf for Pi Zero 2W
compatibility while the Pi-SoC decision (ADR-085 sketch) is open.firmware/cluster-pi/ (new directory) that runs
wifi-densepose-sensing-server with the cluster's UDP/QUIC ports
and drops privileges. Buildroot integration is a separate ADR if
the SoC choice goes to Pi Zero 2W (where there's no RPi-OS path).wifi-densepose-sensing-server a
feature-gated quic-uplink module using quinn + rustls. The
feature is off by default in the home-lab shape and on for the
cluster Pi.decision-tree.md §4. The cluster Pi's role is to hold
the manifest store, not to define the manifest format. Use the
existing ADR-066 swarm bridge channel for OTA staging.This ADR is proposed, not accepted. Acceptance requires:
wifi-densepose-sensing-server cross-compiles
cleanly on aarch64-unknown-linux-gnu and armv7-unknown-linux-gnueabihf
targets with the existing workspace tests passing.When the above pass, this ADR moves from Proposed → Accepted and the README + CLAUDE.md are updated to reflect cluster-Pi as the recommended fleet-shape.
decision-tree.md L4) — no_std CSI
capture maturity benchmark. Gates the dual-MCU shape; not required
for the cluster-Pi shape proposed here.decision-tree.md L6) — Cluster-Pi SoC
choice (Pi Zero 2W vs CM4 vs Pi 5). Pure secure-boot decision.