Skip to content

docs(adr): ADR-086 — edge novelty gate (proposed)#434

Merged
ruvnet merged 1 commit intomainfrom
feat/adr-086-edge-novelty-gate
Apr 26, 2026
Merged

docs(adr): ADR-086 — edge novelty gate (proposed)#434
ruvnet merged 1 commit intomainfrom
feat/adr-086-edge-novelty-gate

Conversation

@ruvnet
Copy link
Copy Markdown
Owner

@ruvnet ruvnet commented Apr 26, 2026

Summary

Pushes the ADR-084 novelty sensor down into the ESP32 sensor MCU's Layer 4 (On-device Feature Extraction) of ADR-081's 5-layer kernel. When novelty falls below the gate threshold, the firmware suppresses the UDP send — saving bandwidth, RF airtime, and TX energy in steady-state quiet rooms.

What this changes (and what it does NOT)

Layer Change
Sensor MCU firmware New rv_sketch.{h,c} (no_std 1-bit sketch + 32-slot IRAM ring bank), three Kconfig flags, rv_feature_state_t magic bumps to 0xC5110007
Wire format 0xC5110007 adds suppressed_since_last: u16 + gate_version: u8 without growing payload (narrows existing 16-bit quality_flags to 8-bit; only 8 bits were ever defined). v6 receivers fall back gracefully.
Cluster-Pi receiver Reconciliation: when suppressed_since_last > 0, treat the gap as low-novelty contribution to the bank rather than missing data
ADR-084 server work Unchanged. ADR-086 is the firmware twin of the cluster-Pi novelty gate.

Decision summary

  • Gating policy: suppress UDP send when novelty < CONFIG_RV_EDGE_NOVELTY_THRESHOLD (basis-point integer, default 500 = 0.05).
  • Stuck-gate self-heal: never suppress more than CONFIG_RV_EDGE_MAX_CONSEC_SUPPRESS (default 50 frames ≈ 10 s at 5 Hz).
  • Default-off Kconfig (CONFIG_RV_EDGE_NOVELTY_GATE_ENABLE=n) so existing deployments behave identically until opted in.
  • Computation budget: ≤ 200 µs sketch insert+score per frame on Xtensa LX7 at 240 MHz.

Validation commitments

Metric Target
Sketch insert + score on Xtensa LX7 ≤ 200 µs
UDP TX-energy reduction (steady-state quiet rooms) ≥ 30%
Cluster-Pi novelty top-K coverage drop vs unsuppressed ≤ 5 pp
Bandwidth reduction (stable-room scenarios) ≥ 50%
Stuck-gate self-heal exercised by unit test, ≤ 10 s suppression cap

Six-pass implementation plan

  1. rv_sketch.{h,c} no_std primitive — 1-bit sign quantization, packed-byte storage, 8-bit-table popcount for hamming. QEMU validation first.
  2. IRAM ring bankRV_EDGE_BANK_SIZE × RV_EDGE_VECTOR_DIM_BYTES bytes. FIFO eviction.
  3. Kconfig flags — three, all default-off / safe.
  4. rv_feature_state_t v7 wire format — magic + new fields, v6 fallback on receiver.
  5. Cluster-Pi reconciliationsuppressed_since_last interpolation in the novelty bank.
  6. QEMU + COM7 hardware-in-loop validation — measure suppression rate on stable-room CSI; assert acceptance numbers.

Open questions explicitly flagged

  1. Xtensa LX7 POPCNT — claim "no hardware POPCNT" is conjecture (no primary-source check yet). Pass 2 bench is the falsifier.
  2. PSRAM-backed bank when the board has it (8 MB on the Waveshare AMOLED).
  3. gate_version: u8 provenance — Kconfig-pinned, NVS-stored, or per-firmware-release embedded?
  4. (Likeliest weak point) Interaction with ADR-082 Tentative→Active gate — the edge gate may suppress legitimate first-detection frames the cluster-Pi tracker needs for promotion. Mitigations are speculative.

Reserved follow-up ADR slots (pointer stubs in §"Related ADR slots")

  • ADR-087 (prospective) — Pass-4 mesh-exchange scope clarification: locks ADR-084 Pass 4's cluster↔cluster reading; reserves the slot for sensor→Pi UDP compression if scope shifts.
  • ADR-088 (prospective) — Firmware-release coordination policy: when does a server-side change require a firmware release vs not.

Why this lands as its own ADR (not folded into ADR-084)

ADR-084 explicitly states "Sensor MCU is unchanged by this ADR; sketches happen at the cluster Pi." Pushing the gate down to the MCU is a different engineering decision with its own cost/benefit, its own threat model (firmware Secure-Boot V2 + signed images per ADR-028), and its own release cycle. Keeping it separate makes the cluster-Pi work shippable independently of the firmware release cycle.

Test plan

  • ADR text references existing ADRs correctly (ADR-018, ADR-028, ADR-066, ADR-081, ADR-082, ADR-083, ADR-084, ADR-085)
  • All path references on v2/ and archive/v1/ (post-rename)
  • Cites primary sources where claims are real; marks conjecture explicitly where they're not
  • Six-pass plan is independently shippable per pass
  • Reviewer accepts the v7 wire format (magic 0xC5110007, narrowed quality_flags, two new fields)
  • Reviewer accepts the conjecture flag on Xtensa LX7 POPCNT (Pass 2 bench will resolve)

🤖 Generated with claude-flow

Pushes the ADR-084 novelty sensor down into the ESP32 sensor MCU's
Layer 4 (On-device Feature Extraction) of ADR-081's 5-layer kernel:
sketch + 32-slot ring bank in IRAM, suppress UDP send when novelty
< CONFIG_RV_EDGE_NOVELTY_THRESHOLD (default 0.05).

Wire format bumps to magic 0xC5110007 with two new fields
(suppressed_since_last: u16, gate_version: u8) packed in by narrowing
the existing 16-bit quality_flags to 8-bit (only 8 bits were ever
defined). Frame size stays at 60 bytes; v6 receivers fall back
gracefully.

Stuck-gate self-heal at CONFIG_RV_EDGE_MAX_CONSEC_SUPPRESS (default
50 frames ≈ 10 s) so a wedged threshold can't silently disappear a
node. Default-off Kconfig so existing deployments are unaffected.

Validation commitments:
- ≤ 200 µs sketch insert+score on Xtensa LX7
- ≥ 30% UDP TX-energy reduction in steady-state quiet rooms
- ≤ 5 pp drop on cluster-Pi novelty top-K coverage vs unsuppressed
- ≥ 50% bandwidth reduction in stable-room scenarios

Six-pass implementation plan, default-off Kconfig, QEMU + COM7
hardware-in-loop validation. Honest gaps flagged: Xtensa LX7 POPCNT
absence is conjecture (Pass 2 bench is the falsifier); interaction
with ADR-082's Tentative→Active gate is the likeliest weak point
(Open Q4).

ADR-087 / ADR-088 reserved as pointer stubs at end:
- ADR-087: Pass-4 mesh-exchange scope (cluster↔cluster vs sensor→Pi)
- ADR-088: Firmware-release coordination policy

Status: Proposed. SOTA review by goal-planner agent.

Co-Authored-By: claude-flow <ruv@ruv.net>
@ruvnet
Copy link
Copy Markdown
Owner Author

ruvnet commented Apr 26, 2026

Why this matters, in plain language

This enables edge reflexes.

Instead of sending every sensor frame upward and asking the bigger system "is this interesting?", each small device can decide locally:

"This looks familiar. Don't waste radio, power, or compute."

or:

"This looks different. Send it now."

That is the practical shift.

Before

Every node sends feature packets constantly:

sensor → cluster Pi → novelty check → maybe ignore

The current firmware emits one rv_feature_state_t packet every 100 to 1000 ms, defaulting around 5 Hz, even when the room is quiet and nothing meaningful has changed. Across 12 nodes that creates a steady stream the Pi mostly classifies as familiar.

After

The sensor MCU does a tiny RaBitQ-style sketch locally:

sensor → sketch → compare to recent sketches → send only if novel

So the node suppresses boring frames and only transmits when the signal changes enough to matter. It still reports how many frames it suppressed, so the system knows silence was intentional, not failure.

What this gives you

Benefit Simple meaning
Lower power Fewer WiFi transmissions
Less mesh traffic Cleaner airtime for important messages
Lower Pi load Pi processes fewer boring packets
Faster anomaly response Novel frames stand out immediately
Better logs Suppression count becomes a signal
Safer rollout Feature is default-off behind Kconfig

Why the numbers matter

Radio transmission is expensive on tiny devices. At 50% suppression a node drops from ~5 packets/sec to ~2.5 packets/sec; at 90% suppression it drops to ~0.5 packets/sec. The ADR's validation targets are at least 30% UDP TX-energy reduction in quiet rooms and 50% bandwidth reduction per node.

The real product meaning

This turns the sensor node from a dumb streamer into a local decision point.

Not full intelligence.

A reflex.

normal     → stay quiet
different  → transmit
stuck silent → force-send within 10 seconds

That last part matters. The suppression cap prevents the device from going silent forever. The ADR sets the default CONFIG_RV_EDGE_MAX_CONSEC_SUPPRESS = 50, which at 5 Hz forces a send within ~10 seconds.

Bottom line

This enables a mesh of devices that is mostly quiet, low power, and low noise until something changes.

That is exactly how an always-on sensing system should behave. It does not process everything deeply. It watches cheaply, escalates selectively, and proves when it stayed silent.

@ruvnet ruvnet merged commit d71ef9a into main Apr 26, 2026
15 of 36 checks passed
@ruvnet ruvnet deleted the feat/adr-086-edge-novelty-gate branch April 26, 2026 06:21
ruvnet added a commit that referenced this pull request Apr 26, 2026
All five implementation passes plus four security-review hardenings
shipped in PR #435 (squash-merged as d71ef9a). Acceptance numbers
measured on synthetic AETHER-shape data:

- Compare-cost reduction: 8x-30x floor → 43-51x pair-wise (d=512),
  12.4x top-K (d=128 n=1024 k=8), 7.6x full pipeline (d=128 n=4096 k=8).
- Top-K coverage: ≥90% floor → 90%+ at prefilter_factor=8 (78.9%
  at factor=4 documented as fail; codified in
  test_search_prefilter_topk_coverage_meets_adr_084).
- Wire envelope: 28-byte AETHER 128-d (vs 512-byte raw float; 18x
  compression).

The third acceptance criterion (`< 1 pp end-to-end accuracy regression`)
needs a real-CSI soak test against a multi-day AETHER trace; that's
post-merge follow-up rather than a merge-blocker. Synthetic-data
acceptance was sufficient evidence to ship.

PR #434 (ADR-086 firmware-side gate) merged separately as 17509a2.

Co-Authored-By: claude-flow <ruv@ruv.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant