mirror of
https://github.com/ruvnet/RuView.git
synced 2026-04-28 05:59:32 +00:00
docs(adr): ADR-084 — RaBitQ similarity sensor for CSI/pose/memory (proposed) (#429)
Adopt RaBitQ-style binary sketches as a first-class cheap similarity sensor at four points in the RuView pipeline: AETHER re-ID hot-cache filter, per-room novelty / drift detection, mesh-exchange compression, and privacy-preserving event logs. Implementation home is ruvector-core::quantization::BinaryQuantized (already vendored, already SIMD-accelerated NEON+POPCNT, 32x compression, 1-bit sign quantization + hamming distance), re-exported through a thin RuView-flavored API in wifi-densepose-ruvector::sketch. Pattern at every site: dense embedding -> RaBitQ sketch -> hamming pre-filter to top-K -> full-precision refinement only on miss. Decision boundary unchanged; sketch is a sensor that gates *which* comparisons run, not *what* they decide. Acceptance test (per source proposal): - sketch compare cost reduction: 8x-30x vs full float - top-K candidate coverage: >= 90% agreement with full-float pass - end-to-end accuracy regression: < 1 percentage point Site-by-site rollback if any criterion fails at a given site; remaining sites continue. Five implementation passes, each independently testable: ruvector module wrap, AETHER re-ID pre-filter, cluster-Pi novelty sensor, mesh-exchange compression, privacy log. Sensor MCU unchanged; sketches happen at the cluster Pi (ADR-083). Validation requires acceptance numbers on >= 3 of 5 passes. Open question (out-of-scope until pass-1 benchmark): whether RuView embeddings need a Johnson-Lindenstrauss / RaBitQ-paper randomized rotation before sign-quantization, or whether pure 1-bit sign quantization (today's BinaryQuantized) is sufficient.
This commit is contained in:
parent
259939b7ec
commit
c19a33ee1c
1 changed files with 276 additions and 0 deletions
276
docs/adr/ADR-084-rabitq-similarity-sensor.md
Normal file
276
docs/adr/ADR-084-rabitq-similarity-sensor.md
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
# ADR-084: RaBitQ Similarity Sensor for CSI / Pose / Memory Routing
|
||||
|
||||
| Field | Value |
|
||||
|----------------|-----------------------------------------------------------------------------------------|
|
||||
| **Status** | Proposed |
|
||||
| **Date** | 2026-04-26 |
|
||||
| **Authors** | ruv |
|
||||
| **Refines** | ADR-024 (AETHER re-ID embeddings), ADR-027 (cross-environment domain generalization), ADR-076 (CSI spectrogram embeddings), ADR-081 (5-layer firmware kernel) |
|
||||
| **Companion** | ADR-083 (per-cluster Pi compute hop) |
|
||||
| **Implements** | `vendor/ruvector/crates/ruvector-core/src/quantization.rs::BinaryQuantized` |
|
||||
|
||||
## Context
|
||||
|
||||
RuView's signal pipeline already produces several **dense float
|
||||
embeddings** at different layers:
|
||||
|
||||
- AETHER 128-d re-ID embeddings on each `PoseTrack` (ADR-024)
|
||||
- 64–256-d CSI spectrogram embeddings (ADR-076)
|
||||
- per-room field-model eigenmode vectors (ADR-030)
|
||||
- per-frame multistatic fused vectors (ADR-029)
|
||||
|
||||
Every one of these eventually answers the same shape of question:
|
||||
**"have I seen something like this before?"** Today the answer is
|
||||
computed by full float dot-product / Mahalanobis comparisons against a
|
||||
candidate set. That cost grows linearly with stored vectors and
|
||||
quadratically when used inside dynamic-mincut graph maintenance,
|
||||
re-identification re-scoring, and cross-environment domain detection.
|
||||
|
||||
The vendored `ruvector-core` crate already ships a 1-bit quantization
|
||||
(`BinaryQuantized`, 32× compression, SIMD popcnt + hamming distance)
|
||||
that is functionally equivalent to the **RaBitQ** family of binary
|
||||
sketches: a vector is reduced to one bit per dimension, compared via
|
||||
hamming distance, and used as a coarse pre-filter before full
|
||||
precision refinement. The same module also exposes `ScalarQuantized`
|
||||
(int8, 4×) and `ProductQuantized` (PQ, 8–16×), so the tiered
|
||||
quantization story is already implemented; the *deployment pattern* is
|
||||
not.
|
||||
|
||||
The user observation that motivates this ADR: **RaBitQ-style sketches
|
||||
are not just a vector compression trick — they are a cheap similarity
|
||||
sensor.** Used as a sensor, they unlock:
|
||||
|
||||
- always-on novelty / anomaly gating that wakes heavy CNNs only on
|
||||
meaningful change
|
||||
- cluster-Pi memory routing (which shard / room / model to query first)
|
||||
- cross-node mesh exchange of compressed sketches instead of raw vectors
|
||||
- privacy-preserving event logs (sketches, not reconstructable signals)
|
||||
|
||||
This ADR formalizes the deployment pattern across the RuView stack and
|
||||
commits to `ruvector::quantization::BinaryQuantized` as the canonical
|
||||
implementation.
|
||||
|
||||
## Decision
|
||||
|
||||
Adopt **RaBitQ-style binary sketches as a first-class, cheap
|
||||
similarity sensor** at four points in the RuView pipeline:
|
||||
|
||||
1. **CSI / pose embedding hot-cache filter** at the cluster Pi.
|
||||
2. **Drift / novelty sensor** between live observation and a
|
||||
per-room normal-state bank.
|
||||
3. **Mesh-exchange compression** between sensor nodes when reporting
|
||||
cross-cluster events.
|
||||
4. **Privacy-preserving event log** at the cluster Pi and gateway.
|
||||
|
||||
The canonical pattern at every point is:
|
||||
|
||||
```text
|
||||
dense embedding ──► RaBitQ sketch ──► hamming/popcnt compare
|
||||
├──► candidate set (top-K)
|
||||
└──► novelty score (0..1)
|
||||
│
|
||||
▼
|
||||
┌── below threshold ──► emit summary, no escalation
|
||||
│
|
||||
└── above threshold ──► full-precision refinement
|
||||
├──► ruvector mincut / HNSW
|
||||
├──► AETHER re-ID rescoring
|
||||
└──► pose model / CNN wake
|
||||
```
|
||||
|
||||
### Implementation home
|
||||
|
||||
- **Sketch type and SIMD primitives**:
|
||||
`vendor/ruvector/crates/ruvector-core/src/quantization.rs::BinaryQuantized`
|
||||
— already implemented, already SIMD-accelerated (NEON on aarch64,
|
||||
POPCNT on x86_64). Re-export through a new
|
||||
`crates/wifi-densepose-ruvector/src/sketch.rs` module so consumers in
|
||||
`signal`, `train`, `mat`, and `sensing-server` see a stable
|
||||
RuView-flavored API and don't bind directly to the vendor crate.
|
||||
|
||||
- **Per-room normal-state bank**: lives at the cluster Pi (ADR-083),
|
||||
not on the sensor MCU. Sensor MCUs continue to emit dense embeddings
|
||||
in the existing `rv_feature_state_t` packet shape; sketching happens
|
||||
on the Pi where the candidate bank is.
|
||||
|
||||
- **Sketch versioning**: each sketch carries a 16-bit `sketch_version`
|
||||
field so the Pi can tell incompatible sketches apart when an
|
||||
embedding model upgrades. Bumped on every embedding-model change.
|
||||
|
||||
### Where the sensor sits in the pipeline
|
||||
|
||||
| Pipeline stage | Today (full float) | With RaBitQ similarity sensor |
|
||||
|---|---|---|
|
||||
| AETHER re-ID match | full 128-d cosine on every active track × candidate | hamming pre-filter to top-K, then full cosine on K |
|
||||
| Mincut subcarrier selection | full graph re-evaluation | sketch-flagged "likely-changed" boundary edges, full mincut on those |
|
||||
| CSI room fingerprint | trained classifier on full embedding | sketch hamming to per-room sketch, classifier on miss |
|
||||
| Field-model novelty (ADR-030) | residual-energy threshold | sketch novelty as second gate before SVD redo |
|
||||
| Mesh / inter-cluster sync | dense embedding broadcast | sketch broadcast; full vector only on miss |
|
||||
| Event log retention | full embedding stored | sketch + witness hash stored; raw embedding ephemeral |
|
||||
|
||||
In every row, the **decision boundary is unchanged** — full precision
|
||||
still owns the final answer. The sketch is a sensor that only gates
|
||||
which comparisons run, not what they decide.
|
||||
|
||||
### Acceptance criterion (per the source proposal)
|
||||
|
||||
The system-level acceptance test is:
|
||||
|
||||
> RaBitQ should reduce compare cost by **8× to 30×** while preserving
|
||||
> top-k decisions well enough that full refinement changes **fewer
|
||||
> than 10%** of final results.
|
||||
|
||||
Concretely, this means:
|
||||
|
||||
- Sketch compare must be measurably **8× cheaper** than the float
|
||||
comparison it replaces (criterion-bench in `signal/`).
|
||||
- Top-K candidate set chosen by sketch must contain ≥ 90% of the
|
||||
candidates the full-float pass would have picked (offline replay
|
||||
against recorded CSI).
|
||||
- End-to-end pose / re-ID accuracy must regress by **less than 1
|
||||
percentage point** vs the full-float baseline on the existing
|
||||
evaluation set.
|
||||
|
||||
If any of these three fail, the sensor is rolled back at that point in
|
||||
the pipeline and the failing site reverts to full float; the rest of
|
||||
the pipeline keeps using sketches. This is point-by-point, not
|
||||
all-or-nothing.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- **Cheaper hot path everywhere a "have I seen this" question lives.**
|
||||
AETHER re-ID, mincut maintenance, room fingerprinting, novelty
|
||||
detection, mesh sync, and event-log retention all run a 32×-smaller,
|
||||
popcnt-friendly comparison first.
|
||||
- **Always-on anomaly gating becomes affordable.** The CNN / pose
|
||||
model only wakes when sketch novelty crosses a threshold. Energy
|
||||
budget per node drops materially in steady-state quiet rooms.
|
||||
- **Privacy story improves.** Event logs and inter-cluster mesh
|
||||
traffic carry sketches and witness hashes, not reconstructable
|
||||
embeddings. The 1-bit quantization is *not* invertible to the
|
||||
original CSI.
|
||||
- **Composes cleanly with ADR-083.** The cluster Pi is the natural
|
||||
home for the sketch bank; sensor MCUs remain unchanged.
|
||||
- **No new dependency.** `BinaryQuantized` is already in the vendored
|
||||
`ruvector-core` and already SIMD-accelerated.
|
||||
|
||||
### Negative / risks
|
||||
|
||||
- **Sketch quality depends on embedding distribution.** Pure 1-bit
|
||||
sign quantization (which `BinaryQuantized` implements) works best
|
||||
when the embedding space is roughly zero-centered and isotropic.
|
||||
AETHER and CSI spectrogram embeddings need to be benchmarked for
|
||||
this assumption; if either fails, a randomized rotation
|
||||
(Johnson-Lindenstrauss / RaBitQ-paper-style) must be added before
|
||||
sketching. Out-of-scope for this ADR; tracked as a follow-up if
|
||||
the acceptance test fails.
|
||||
- **Top-K coverage degrades for small candidate sets.** With < 16
|
||||
candidates, the sketch compare can pick the wrong K. Site-by-site
|
||||
fallback to full float is part of the rollout plan.
|
||||
- **Sketch-version skew during model upgrades.** A model change
|
||||
invalidates all stored sketches; the cluster Pi must re-sketch the
|
||||
candidate bank when `sketch_version` bumps. Cost is bounded but
|
||||
non-zero.
|
||||
|
||||
### Neutral
|
||||
|
||||
- ADR-024, ADR-027, ADR-029, ADR-030, ADR-076 are unchanged in
|
||||
*what* they compute. They gain a sketch pre-filter at the comparison
|
||||
step.
|
||||
- ADR-082's confirmed-track output filter is upstream of the sketch
|
||||
layer; it stays correct.
|
||||
|
||||
## Implementation
|
||||
|
||||
The implementation lands in five passes, each independently testable.
|
||||
Every pass is gated by the acceptance criterion above; if any fail,
|
||||
that site rolls back and the rest continue.
|
||||
|
||||
1. **`wifi-densepose-ruvector::sketch` module.** Re-export
|
||||
`BinaryQuantized` plus a thin RuView-flavored API
|
||||
(`Sketch::from_embedding`, `Sketch::distance`, `SketchBank::topk`).
|
||||
Add `sketch_version: u16` and `embedding_dim: u16` fields to the
|
||||
public type. Criterion benches: sketch ↔ float compare-cost ratio.
|
||||
|
||||
2. **AETHER re-ID pre-filter.** In
|
||||
`wifi-densepose-signal/src/ruvsense/pose_tracker.rs`, before
|
||||
computing the full 128-d cosine across active tracks × candidates,
|
||||
sketch both sides and reduce to top-K via hamming. Bench: re-ID
|
||||
pass time per frame, ID-stability under cross-room transitions.
|
||||
|
||||
3. **Cluster-Pi novelty sensor.** In
|
||||
`wifi-densepose-sensing-server`, maintain a per-room
|
||||
`SketchBank` of "normal-state" sketches; on each incoming
|
||||
`rv_feature_state_t`, compute embedding sketch, score novelty
|
||||
against the bank, and emit `novelty_score` as a new field on the
|
||||
WebSocket update envelope. Heavy CNN wake gate uses this score.
|
||||
|
||||
4. **Mesh-exchange compression.** Inter-cluster broadcasts (the
|
||||
ADR-066 swarm-bridge channel) carry sketch + witness instead of
|
||||
the full embedding when novelty is low. Full embedding only
|
||||
exchanged when novelty crosses threshold.
|
||||
|
||||
5. **Privacy-preserving event log.** Event log table on the cluster
|
||||
Pi stores `(sketch_bytes, sketch_version, novelty_score,
|
||||
witness_sha256)` instead of raw embeddings. Existing log readers
|
||||
are unchanged in API; only the storage layer rewrites.
|
||||
|
||||
Each pass adds tests: a property test (sketch ↔ float top-K agreement
|
||||
≥ 90%), a criterion bench (≥ 8× compare cost reduction), and an
|
||||
end-to-end accuracy regression test (< 1 pp drop).
|
||||
|
||||
## Validation
|
||||
|
||||
This ADR is **proposed**, not accepted. Acceptance requires the three
|
||||
acceptance numbers above to hold on **at least three of the five
|
||||
implementation passes** (the sites where the bulk of the load sits:
|
||||
AETHER re-ID, cluster-Pi novelty, and event log). The mesh-exchange
|
||||
and mincut prefilter passes are nice-to-haves; they can ship
|
||||
afterward if their per-site numbers hold.
|
||||
|
||||
Validation runs against:
|
||||
|
||||
- the existing 1,539-test workspace suite (must stay green)
|
||||
- a new `tests/integration/rabitq_sketch_pipeline.rs` integration test
|
||||
driving recorded CSI through the full pipeline with and without
|
||||
sketches, comparing top-K decisions and end-to-end pose accuracy
|
||||
- ESP32-S3 on COM7 — sensor MCU unchanged; sketch happens at the
|
||||
cluster Pi, so this validation is a smoke test that the
|
||||
sensor → Pi UDP path still works after the cluster Pi gains the
|
||||
sketch bank
|
||||
|
||||
## Related
|
||||
|
||||
- **ADR-024** (Accepted) — AETHER re-ID embeddings. Primary consumer
|
||||
of the sketch pre-filter.
|
||||
- **ADR-027** (Accepted) — Cross-environment domain generalization
|
||||
(MERIDIAN). Per-room sketch bank is the natural data structure for
|
||||
domain detection.
|
||||
- **ADR-030** (Proposed) — RuvSense persistent field model. Sketch
|
||||
novelty is the cheap second gate before SVD recompute.
|
||||
- **ADR-066** — Swarm bridge to coordinator. Inter-cluster sketch
|
||||
exchange.
|
||||
- **ADR-076** (Accepted) — CSI spectrogram embeddings. Sketch
|
||||
consumer; embedding source.
|
||||
- **ADR-081** (Accepted) — 5-layer adaptive CSI mesh firmware kernel.
|
||||
Sensor MCU unchanged by this ADR; sketches happen at the cluster Pi.
|
||||
- **ADR-083** (Proposed) — Per-cluster Pi compute hop. Defines the
|
||||
device class that hosts the sketch bank.
|
||||
|
||||
## Open questions
|
||||
|
||||
- **Does `BinaryQuantized` need a randomized rotation pre-pass for
|
||||
RuView's embedding distributions?** Pure sign quantization assumes
|
||||
zero-centered, isotropic embeddings. If AETHER / spectrogram
|
||||
distributions are skewed (likely for spectrogram), add a
|
||||
`randomized_rotation` pre-pass following the original RaBitQ paper
|
||||
(Gao & Long, SIGMOD 2024). Decided after pass-1 benchmark.
|
||||
- **Sketch dimension target.** Default to the embedding's native
|
||||
dimension (128 for AETHER, 256 for spectrogram). Higher-dimensional
|
||||
sketches (Johnson-Lindenstrauss-projected to 512) trade compute for
|
||||
recall; benchmark before committing.
|
||||
- **Per-room vs per-deployment sketch banks.** Defaulting to per-room
|
||||
for novelty detection. Cross-room re-ID may want a shared bank;
|
||||
decide once cross-room AETHER traces are available.
|
||||
Loading…
Add table
Add a link
Reference in a new issue