mirror of
https://github.com/ruvnet/RuView
synced 2026-06-24 12:43:18 +00:00
29de574e63
* docs(research): add RuView beyond-SOTA system review (00) First document of the beyond-SOTA research series: capability audit of the current RuView engine with role-to-crate maturity matrix, ruvsense module inventory, gap analysis, and risk register. https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * docs(research): add beyond-SOTA architecture design (02, in progress) https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * docs(research): finalize beyond-SOTA architecture (02) https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * docs(research): add benchmark/validation methodology snapshot (03) https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * docs(research): add beyond-SOTA series index with validation results; changelog README index ties the 5 research docs together with the session's measured validation evidence: 2,797 workspace tests / 0 failed, Python proof PASS (bit-exact), and paired pre/post criterion CIR benchmarks. https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * perf(signal): precompute CIR warm-start system; hoist tomography solver allocs Exact, determinism-safe optimizations (bit-identical float results): - cir.rs: diag(PhiH Phi)+lambda*I and its CSR matrix depend only on Phi and lambda (fixed at CirEstimator::new) but were rebuilt every frame (O(K*G) pass + CSR allocation). Now built once in new() via build_warm_start_system; summation order unchanged. - tomography.rs: ISTA gradient buffer hoisted out of the 100-iteration loop (fill(0.0) reset) and the Frobenius Lipschitz bound moved from per-reconstruct to construction. Verified: signal 456 tests green; engine 11/11 green including cycle_is_deterministic and witness-stability tests. Criterion paired pre/post: cir_estimate/he40 -3.9% (p<0.01), multiband -1.2/-1.4%. https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * fix(worldgraph): bound SemanticState growth with deterministic retention StreamingEngine::process_cycle appended one SemanticState belief per cycle with no eviction — ~1.7M nodes/day at 20 Hz (beyond-SOTA roadmap finding #6). Add WorldGraph::prune_semantic_states(max): deterministic eviction of the oldest beliefs by (valid_from_unix_ms, id); structural nodes (rooms, zones, sensors, anchors, tracks, events) are never eligible. Wire it into the engine after each belief append (DEFAULT_SEMANTIC_RETENTION = 7,200, ~6 min at 20 Hz; set_semantic_retention to tune). The WorldGraph holds current beliefs; durable history is the recorder's job, so no audit data is lost. 3 new tests: end-to-end bounded growth, oldest-only eviction, deterministic equal-timestamp tie-break. Workspace gate: 2,865 passed, 0 failed. https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * feat(sensing-server): route live frames through the governed StreamingEngine Closes the live-trust-path gap (ADR-136 section 8, beyond-SOTA system review): the running server fused live CSI with the bare MultistaticFuser, while the privacy/provenance/witness control plane (ADR-135..146) only ever ran on synthetic in-test frames. The privacy control plane was therefore bypassable on the real path. New engine_bridge module drives StreamingEngine::process_cycle from the server's live NodeState map, reusing the existing NodeState -> MultiBandCsiFrame conversion. It lazily wires each contributing node as a WorldGraph sensor (idempotent), bounds belief growth via the retention cap, and forwards explicit timestamps/calibration ids so the path stays deterministic and replayable. Wired additively into both live ESP32/WiFi fusion sites in main.rs via a split-borrow off the write guard, so person-count behavior is unchanged; the latest BLAKE3 witness is stored on AppState. Every published belief now carries evidence + model + calibration + privacy decision and a deterministic witness. Adds wifi-densepose-engine/-worldgraph/-bfld/-geo deps. 6 new bridge tests (witnessed belief with full provenance, cross-run determinism, idempotent node registration, retention bound, privacy-mode propagation). sensing-server suite 430+128 green; workspace gate 2,904 passed / 0 failed. https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * feat(train): falsifiable occupancy benchmark with anti-overfitting gate Makes the presence/person-count "beyond SOTA" claim falsifiable in code instead of aspirational (the unfalsifiability gap from the beyond-SOTA system review). occupancy_bench grades predictions vs ground truth and gates a SOTA claim behind one claim_allowed invariant requiring ALL of: - DataProvenance::Measured — synthetic/mock data is scorable for regression but never claimable (anti-mock-contamination; the CLAUDE.md Kconfig-bug lesson made structural). - A leak-free EvalSplit — validate() refuses any split where a subject OR environment id appears in both train and test (subject leakage / per-environment overfitting). - n_test >= min_test_samples (small-N guard). - Presence F1 whose bootstrap-CI lower bound (deterministic seeded splitmix64) clears the threshold — not the point estimate. - Count MAE within threshold. The claim string is unreadable except through the gate (NO_CLAIM otherwise), same discipline as the ruview-gamma acceptance gate. What remains is data, not method: a frozen, SHA-pinned, subject/environment-disjoint measured replay set turns the claim into a passing/failing test. Lives in wifi-densepose-train (the eval bounded context, alongside ablation/ eval/metrics). 10 tests cover each refusal path; warning-clean under the crate's missing_docs lint. Workspace gate 2,914 passed / 0 failed. Doc 03 updated. https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * feat(engine): per-room adapter provenance + drift-to-recalibration advisor Closes the trust-chain gap where an ~11 KB per-room LoRA adapter (ADR-150 section 3.4) could silently change inference without the witness noticing: provenance carried only "rfenc-v<N>" with no notion of adapter identity. - StreamingEngine::set_room_adapter(AdapterInfo): pins the adapter's content-derived id into provenance model_version ("rfenc-v1+adapter:<id>") — and therefore into the BLAKE3 witness — so swapping or clearing adapter weights always shifts the witness. Engine test proves base -> adapter -> other-adapter -> cleared all witness differently and cleared == base. - RecalibrationAdvisor: recommends re-running the ADR-135 empty-room baseline / refitting the room adapter on sustained low fusion coherence (streak threshold, default 60 cycles ~ 3 s at 20 Hz) or an ADR-142 change-point. Surfaced as TrustedOutput::recalibration_recommended, stored on the sensing-server AppState alongside the witness at both live fusion sites. - Bridge plumbing: EngineBridge::{set_room_adapter, clear_room_adapter} + live-path test that the adapter id flows into the live witness. Scope note (honest): this is the deployable provenance/trigger half of the "retrained model" roadmap item. Fitting the adapter itself runs in the existing external calibration service (aether-arena/calibration/); a trained RF-encoder checkpoint still does not exist in-tree. Engine 15 tests, bridge 7 tests. Workspace gate: 2,918 passed / 0 failed. https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * fix(mat): gate api module behind its feature — standalone no-default-features builds pub mod api was unconditional while its only dependency, serde, is optional behind the 'api' feature, so any build without default features failed with 101 unresolved-serde errors (masked in --workspace runs by feature unification). The api module and its create_router/AppState re-export are now cfg(feature = "api")-gated with docsrs annotations. All combos compile: bare --no-default-features (was 101 errors, now 0), --no-default-features --features api, and full default (177 tests pass). Workspace gate: 2,918 passed / 0 failed. https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * perf(signal): opt-in FFT operator for the CIR ISTA solver (8-14x measured) Phi is a sub-DFT, so each ISTA mat-vec can run as one length-G FFT (O(G log G)) instead of a dense O(K*G) product — the dominant-latency-hazard finding from the beyond-SOTA optimization roadmap. New CirConfig::fft_operator, default FALSE: the dense path stays the bit-exact witness default. The FFT evaluates the same sums in a different order, so enabling it shifts float results in the last bits and requires regenerating any pinned witness — strictly opt-in per deployment. FftOperator (rustfft, planned once at CirEstimator::new, scratch buffers reused across the ISTA loop) dispatches inside ista_solve: Phi x = scale * forward-FFT(x) sampled at bins (k_idx mod G) Phi^H v = scale * unnormalised inverse-FFT of v scattered into those bins Warm-start and Lipschitz estimation stay dense at construction. Measured (criterion, same run, same machine): ht20: 2.22 ms -> 265 us (8.4x) ht40: 10.26 ms -> 717 us (14.3x) The real HE40 grid (K=484, G=1452) scales further per the O(K*G)/O(G log G) ratio. 3 new tests: FFT<->dense matvec equivalence to float tolerance on ht20 and he40 grids; end-to-end dominant-tap agreement on a single-path frame; all default configs keep FFT off. New cir_estimate_fft bench group. Workspace gate: 2,921 passed / 0 failed (default path bit-exact, witnesses unchanged). https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * feat(core): canonical frame decoder — capture-to-claim replay (ADR-136) The encode half of the ADR-136 frame contract existed (ComplexSample, to_canonical_bytes, witness_hash) but there was no decoder: a captured canonical frame could be witnessed but never reconstructed, blocking replay-from-capture. CsiFrame::from_canonical_bytes is the exact inverse: same id, metadata, complex payload, and witness hash (tested as the round-trip law AC7 — the replayed frame re-encodes byte-identically). Amplitude/phase are recomputed from the payload (projections, not independent state). Every malformed-input class fails closed (AC8): header truncation -> Truncated, payload truncation -> PayloadMismatch, unknown discriminants, non-UTF-8 device id, trailing bytes. Nil calibration uuid decodes as None per the documented encoding. Core: 36 tests pass. Workspace gate: 2,937 passed / 0 failed. https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * feat(engine): dynamic min-cut mesh partition guard (ruvector-mincut) Maintains an exact min-cut over the live mesh coupling graph — nodes are sensing nodes, coupling is the product of fusion attention weights — and surfaces per cycle, as TrustedOutput::mesh: - cut value: the global "how close is the array to partitioning" number, a structural measure per-node heuristics miss; - weak side: which specific nodes would split off (failure/jamming triage, feeds ADR-032 posture); - at-risk flag: counts as a structural event for the drift->recalibration advisor (alongside ADR-142 change-points). Degenerate cases fail toward risk: a node with zero coupling is reported as already partitioned (cut 0, that node as the weak side). Measured cost policy (criterion, 12-node mesh — the honest part): - weights quantized (1/64) + change-gated: steady-state cycles do ZERO graph work and reuse the cached cut (~7.3 us, ~23x cheaper than building); - on any real change a full exact rebuild (~171 us) is used, because ONE DynamicMinCut delete+insert measured ~240 us — the subpolynomial machinery amortizes on much larger graphs, so rebuild-on-change is the measured optimum at mesh scale (one-edge case -28% after switching policy); - full process_cycle with the guard: ~33 us for 4 nodes vs the 50 ms budget. 9 mesh_guard tests (weak-node detection, steady-state zero updates, sub-quantum gating, join/drop rebuild, determinism, disconnection) + an engine-level wiring test (down-weighted node -> weak side -> recalibration). Engine 24 tests; workspace gate 2,946 passed / 0 failed. https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * feat(engine): mesh partition risk demotes privacy + enters the witness (ADR-032) Completes the mesh-guard integration: its at_risk signal was advisory-only (fed the recalibration advisor). It now also contributes to the ADR-141 privacy demotion alongside fusion- and array-level contradictions — a mesh close to partitioning makes the fused belief less trustworthy, so the cycle emits at a more restricted class (monotonic; information only removed). Because effective_class feeds the BLAKE3 witness, a fragmenting array now shifts the witness: partition risk is auditable, not just logged. The mesh computation moved ahead of the demotion step in process_cycle; mesh_guard_mut exposes risk-threshold tuning. Test: a forced-risk 3-node cycle demotes PrivateHome Anonymous->Restricted and shifts the witness vs a clean baseline. Engine 25 tests; workspace gate 2,947 passed / 0 failed. https://claude.ai/code/session_01MjBucx95K4BuUxZi8NWwRH * fix: public-PR review findings — privacy-path honesty, gate holes, mesh-guard cliff - sensing-server: engine errors logged+counted (no silent swallow), trust state exposed via status surface, privacy-demotion claims aligned with the actual parallel-audit-path behavior - occupancy_bench: vacuous-F1 hole closed (degenerate test sets fail with their own criterion); CI-lower-bound test made probative - mesh_guard: quantization scaled to observed coupling range — >=65-node balanced meshes no longer permanently at_risk (regression test) - engine: both wiring tests made probative (same-topology witness compare, deterministic risk-crossing fixture) - mat: axum/tokio optional behind api; real serde feature (api enables it) - core: canonical decoder strict (non-zero reserved bytes and nil UUID rejected — injective on accepted domain, forged-bytes tests) - CHANGELOG: un-spliced the FFT/adapter bullet mangle Co-Authored-By: claude-flow <ruv@ruv.net> * chore: strip private-track references for public PR Reword the occupancy-benchmark changelog bullet to drop a cross-reference to the private research track, and restore the WorldGraph retention bullet header that was glued onto the preceding MAT bullet. Co-Authored-By: claude-flow <ruv@ruv.net> * chore: lockfile refresh for cherry-picked feature set Co-Authored-By: claude-flow <ruv@ruv.net> --------- Co-authored-by: Claude <noreply@anthropic.com>
WiFi-DensePose Rust Crates
See through walls with WiFi. No cameras. No wearables. Just radio waves.
A modular Rust workspace for WiFi-based human pose estimation, vital sign monitoring, and disaster response using Channel State Information (CSI). Built on RuVector graph algorithms and the WiFi-DensePose research platform by rUv.
Performance
| Operation | Python v1 | Rust v2 | Speedup |
|---|---|---|---|
| CSI Preprocessing | ~5 ms | 5.19 us | ~1000x |
| Phase Sanitization | ~3 ms | 3.84 us | ~780x |
| Feature Extraction | ~8 ms | 9.03 us | ~890x |
| Motion Detection | ~1 ms | 186 ns | ~5400x |
| Full Pipeline | ~15 ms | 18.47 us | ~810x |
| Vital Signs | N/A | 86 us (11,665 fps) | -- |
Crate Overview
Core Foundation
| Crate | Description | crates.io |
|---|---|---|
wifi-densepose-core |
Types, traits, and utilities (CsiFrame, PoseEstimate, SignalProcessor) |
|
wifi-densepose-config |
Configuration management (env, TOML, YAML) | |
wifi-densepose-db |
Database persistence (PostgreSQL, SQLite, Redis) |
Signal Processing & Sensing
| Crate | Description | RuVector Integration | crates.io |
|---|---|---|---|
wifi-densepose-signal |
SOTA CSI signal processing (6 algorithms from SpotFi, FarSense, Widar 3.0) | ruvector-mincut, ruvector-attn-mincut, ruvector-attention, ruvector-solver |
|
wifi-densepose-vitals |
Vital sign extraction: breathing (6-30 BPM) and heart rate (40-120 BPM) | -- | |
wifi-densepose-wifiscan |
Multi-BSSID WiFi scanning for Windows-enhanced sensing | -- |
Neural Network & Training
| Crate | Description | RuVector Integration | crates.io |
|---|---|---|---|
wifi-densepose-nn |
Multi-backend inference (ONNX, PyTorch, Candle) with DensePose head (24 body parts) | -- | |
wifi-densepose-train |
Training pipeline with MM-Fi dataset, 114->56 subcarrier interpolation | All 5 crates |
Disaster Response
| Crate | Description | RuVector Integration | crates.io |
|---|---|---|---|
wifi-densepose-mat |
Mass Casualty Assessment Tool -- survivor detection, triage, multi-AP localization | ruvector-solver, ruvector-temporal-tensor |
Hardware & Deployment
| Crate | Description | crates.io |
|---|---|---|
wifi-densepose-hardware |
ESP32, Intel 5300, Atheros CSI sensor interfaces (pure Rust, no FFI) | |
wifi-densepose-wasm |
WebAssembly bindings for browser-based disaster dashboard | |
wifi-densepose-sensing-server |
Axum server: ESP32 UDP ingestion, WebSocket broadcast, sensing UI |
Applications
| Crate | Description | crates.io |
|---|---|---|
wifi-densepose-api |
REST + WebSocket API layer | |
wifi-densepose-cli |
Command-line tool for MAT disaster scanning |
Architecture
wifi-densepose-core
(types, traits, errors)
|
+-------------------+-------------------+
| | |
wifi-densepose-signal wifi-densepose-nn wifi-densepose-hardware
(CSI processing) (inference) (ESP32, Intel 5300)
+ ruvector-mincut + ONNX Runtime |
+ ruvector-attn-mincut + PyTorch (tch) wifi-densepose-vitals
+ ruvector-attention + Candle (breathing, heart rate)
+ ruvector-solver |
| | wifi-densepose-wifiscan
+--------+---------+ (BSSID scanning)
|
+------------+------------+
| |
wifi-densepose-train wifi-densepose-mat
(training pipeline) (disaster response)
+ ALL 5 ruvector + ruvector-solver
+ ruvector-temporal-tensor
|
+-----------------+-----------------+
| | |
wifi-densepose-api wifi-densepose-wasm wifi-densepose-cli
(REST/WS) (browser WASM) (CLI tool)
|
wifi-densepose-sensing-server
(Axum + WebSocket)
RuVector Integration
All RuVector crates at v2.0.4 from crates.io:
| RuVector Crate | Used In | Purpose |
|---|---|---|
ruvector-mincut |
signal, train | Dynamic min-cut for subcarrier selection & person matching |
ruvector-attn-mincut |
signal, train | Attention-weighted min-cut for antenna gating & spectrograms |
ruvector-temporal-tensor |
train, mat | Tiered temporal compression (4-10x memory reduction) |
ruvector-solver |
signal, train, mat | Sparse Neumann solver for interpolation & triangulation |
ruvector-attention |
signal, train | Scaled dot-product attention for spatial features & BVP |
Signal Processing Algorithms
Six state-of-the-art algorithms implemented in wifi-densepose-signal:
| Algorithm | Paper | Year | Module |
|---|---|---|---|
| Conjugate Multiplication | SpotFi (SIGCOMM) | 2015 | csi_ratio.rs |
| Hampel Filter | WiGest | 2015 | hampel.rs |
| Fresnel Zone Model | FarSense (MobiCom) | 2019 | fresnel.rs |
| CSI Spectrogram | Standard STFT | 2018+ | spectrogram.rs |
| Subcarrier Selection | WiDance (MobiCom) | 2017 | subcarrier_selection.rs |
| Body Velocity Profile | Widar 3.0 (MobiSys) | 2019 | bvp.rs |
Quick Start
As a Library
use wifi_densepose_core::{CsiFrame, CsiMetadata, SignalProcessor};
use wifi_densepose_signal::{CsiProcessor, CsiProcessorConfig};
// Configure the CSI processor
let config = CsiProcessorConfig::default();
let processor = CsiProcessor::new(config);
// Process a CSI frame
let frame = CsiFrame { /* ... */ };
let processed = processor.process(&frame)?;
Vital Sign Monitoring
use wifi_densepose_vitals::{
CsiVitalPreprocessor, BreathingExtractor, HeartRateExtractor,
VitalAnomalyDetector,
};
let mut preprocessor = CsiVitalPreprocessor::new(56); // 56 subcarriers
let mut breathing = BreathingExtractor::new(100.0); // 100 Hz sample rate
let mut heartrate = HeartRateExtractor::new(100.0);
// Feed CSI frames and extract vitals
for frame in csi_stream {
let residuals = preprocessor.update(&frame.amplitudes);
if let Some(bpm) = breathing.push_residuals(&residuals) {
println!("Breathing: {:.1} BPM", bpm);
}
}
Disaster Response (MAT)
use wifi_densepose_mat::{DisasterResponse, DisasterConfig, DisasterType};
let config = DisasterConfig {
disaster_type: DisasterType::Earthquake,
max_scan_zones: 16,
..Default::default()
};
let mut responder = DisasterResponse::new(config);
responder.add_scan_zone(zone)?;
responder.start_continuous_scan().await?;
Hardware (ESP32)
use wifi_densepose_hardware::{Esp32CsiParser, CsiFrame};
let parser = Esp32CsiParser::new();
let raw_bytes: &[u8] = /* UDP packet from ESP32 */;
let frame: CsiFrame = parser.parse(raw_bytes)?;
println!("RSSI: {} dBm, {} subcarriers", frame.metadata.rssi, frame.subcarriers.len());
Training
# Check training crate (no GPU needed)
cargo check -p wifi-densepose-train --no-default-features
# Run training with GPU (requires tch/libtorch)
cargo run -p wifi-densepose-train --features tch-backend --bin train -- \
--config training.toml --dataset /path/to/mmfi
# Verify deterministic training proof
cargo run -p wifi-densepose-train --features tch-backend --bin verify-training
Building
# Clone the repository
git clone https://github.com/ruvnet/wifi-densepose.git
cd wifi-densepose/v2
# Check workspace (no GPU dependencies)
cargo check --workspace --no-default-features
# Run all tests
cargo test --workspace --no-default-features
# Build release
cargo build --release --workspace
Feature Flags
| Crate | Feature | Description |
|---|---|---|
wifi-densepose-nn |
onnx (default) |
ONNX Runtime backend |
wifi-densepose-nn |
tch-backend |
PyTorch (libtorch) backend |
wifi-densepose-nn |
candle-backend |
Candle (pure Rust) backend |
wifi-densepose-nn |
cuda |
CUDA GPU acceleration |
wifi-densepose-train |
tch-backend |
Enable GPU training modules |
wifi-densepose-mat |
ruvector (default) |
RuVector graph algorithms |
wifi-densepose-mat |
api (default) |
REST + WebSocket API |
wifi-densepose-mat |
distributed |
Multi-node coordination |
wifi-densepose-mat |
drone |
Drone-mounted scanning |
wifi-densepose-hardware |
esp32 |
ESP32 protocol support |
wifi-densepose-hardware |
intel5300 |
Intel 5300 CSI Tool |
wifi-densepose-hardware |
linux-wifi |
Linux commodity WiFi |
wifi-densepose-wifiscan |
wlanapi |
Windows WLAN API async scanning |
wifi-densepose-core |
serde |
Serialization support |
wifi-densepose-core |
async |
Async trait support |
Testing
# Unit tests (all crates)
cargo test --workspace --no-default-features
# Signal processing benchmarks
cargo bench -p wifi-densepose-signal
# Training benchmarks
cargo bench -p wifi-densepose-train --no-default-features
# Detection benchmarks
cargo bench -p wifi-densepose-mat
Supported Hardware
| Hardware | Crate Feature | CSI Subcarriers | Cost |
|---|---|---|---|
| ESP32-S3 Mesh (3-6 nodes) | hardware/esp32 |
52-56 | ~$54 |
| Intel 5300 NIC | hardware/intel5300 |
30 | ~$50 |
| Atheros AR9580 | hardware/linux-wifi |
56 | ~$100 |
| Any WiFi (Windows/Linux) | wifiscan |
RSSI-only | $0 |
Architecture Decision Records
Key design decisions documented in docs/adr/:
| ADR | Title | Status |
|---|---|---|
| ADR-014 | SOTA Signal Processing | Accepted |
| ADR-015 | MM-Fi + Wi-Pose Training Datasets | Accepted |
| ADR-016 | RuVector Training Pipeline | Accepted (Complete) |
| ADR-017 | RuVector Signal + MAT Integration | Accepted |
| ADR-021 | Vital Sign Detection Pipeline | Accepted |
| ADR-022 | Windows WiFi Enhanced Sensing | Accepted |
| ADR-024 | Contrastive CSI Embedding Model | Accepted |
Related Projects
- WiFi-DensePose -- Main repository (Python v1 + Rust v2)
- RuVector -- Graph algorithms for neural networks (5 crates, v2.0.4)
- rUv -- Creator and maintainer
License
All crates are dual-licensed under MIT OR Apache-2.0.
Copyright (c) 2024 rUv