mirror of
https://github.com/ruvnet/RuView
synced 2026-07-17 16:33:18 +00:00
9d52d49c0b7e58aa1ff4cd926c2dfadf3d21d05a
948 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9d52d49c0b |
fix(homecore-api): close WS auth bypass + reply-theater, harden dev bin (ADR-161 A1/A2/A8)
A1 (CRITICAL): the /api/websocket handshake accepted any non-empty token, ignoring the LongLivedTokenStore whitelist the REST path enforces — a full WS auth bypass. Now validates via state.tokens().is_valid() before auth_ok; wrong tokens get auth_invalid + close. A2 (HIGH): WS command replies were pushed into an mpsc whose only consumer logged and discarded them — no result/pong/event reached the client. Split the socket with futures StreamExt::split; a dedicated writer task drains the response channel onto the wire. A8 (HIGH): the homecore-api dev bin bound 0.0.0.0 with unconditional allow-any auth and no env path. Wired the HOMECORE_TOKENS env path (dev fallback warn-logged when unset) and defaulted the bind to 127.0.0.1 (HOMECORE_BIND to opt into LAN). Tests (fail on old source): - ws_handshake::wrong_token_is_rejected (old → auth_ok) - ws_handshake::result_reply_is_received / ping_pong_reply_is_received (old → timeout) - server_bin_auth::provisioned_bin_rejects_wrong_bearer / from_env_path_enforces_whitelist Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
8487192d0f |
docs(proof): PROOF.md capstone + scripts/prove.sh reproduction harness
One-command harness: clone, run scripts/prove.sh, and every headline claim is either verified on your machine (re-runs the bug-catching tests) or printed as 'CLAIMED — not reproduced here' with the exact prerequisite. Hard gate = workspace tests + deterministic Python proof; section 3 re-runs 7 anti-slop assertion tests (each fails on pre-fix code); gated claims (GPU/dataset/hardware/ trained-checkpoint/named-identity) are honestly listed, never faked. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
d120cc2278 |
test(sensing-server): unique per-process temp dirs (deterministic under concurrent runs)
checkpoint_round_trip / rvf_test / rvf_pipeline_test shared fixed temp_dir paths and remove_dir at teardown, so two concurrent/repeated test runs raced (one's teardown wiped the other's file -> NotFound). Make each dir process-unique. Test-only; no public API change. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
8ad0d0f91c |
test+docs(wasm-edge): honest-labeling presence tests + ADR-160 (ADR-159 backlog now TRUE)
- tests/honest_labeling.rs: 10 source-presence tests asserting the A1-A5 claim invariants (disclaimers present, uncited stat removed, WEAPON_ALERT no longer exported, med_* feature-gated, no static-mut event buffers). Each is designed to FAIL on the pre-fix source (ADR-159 A5 manifest-roundtrip style). - ADR-160: records the headline (0 stubs/0 theater, all real DSP -> claim-surface honesty debt), the graded A1-A5 fixes, NO-ACTION positives, per-prefix classification, and the DATA-GATED deferred backlog (criterion benches, per-skill accuracy validation, wasm32 static_mut_refs CI confirmation). - ADR-159: its deferred-backlog line "wasm-edge ... honestly labelled, not claimed" is now actually TRUE. Validation (all 0 failed, host --features std): DEFAULT 615 | MEDICAL (+medical-experimental) 653 | NO-DEFAULT 615; 0 warnings. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
36af09a4a8 |
feat(wasm-edge): honest labeling + static-mut soundness for edge skills (ADR-160)
The wasm-edge skill library runs real DSP with 0 stubs / 0 theater; the exposure is an over-confident claim surface on unvalidated skills plus a latent static-mut soundness issue. Make the labels TRUE (do not pretend to validate the capability) and fix the soundness mechanically: - A1 (HIGH): med_seizure/cardiac/respiratory/sleep_apnea/gait -- add mandatory "EXPERIMENTAL / NOT VALIDATED AGAINST CLINICAL DATA / NOT A MEDICAL DEVICE" disclaimers, soften assertive verbs to "flags candidate <X>-like signatures", and gate all 5 behind a NON-default medical-experimental cargo feature so they cannot be silently shipped. DSP kept. - A2 (HIGH): exo_happiness_score/exo_emotion_detect -- delete the uncited "~12% faster" stat, add "speculative, unvalidated affect heuristic; outputs are NOT measurements of emotion" disclaimers, reframe HAPPINESS_SCORE as a gait-energy proxy. Math kept. - A3 (MEDIUM): sec_weapon_detect -- rename EVENT_WEAPON_ALERT -> EVENT_HIGH_METAL_REFLECTIVITY and WEAPON_RATIO_THRESH -> HIGH_REFLECTIVITY_THRESH (a variance ratio measures reflectivity, not weapons). Registry updated. - A4 (MEDIUM): exo_dream_stage/exo_gesture_language -- add experimental disclaimers, promote the Exotic/Research tag into the header. - A5 (MEDIUM, soundness): replace ~61 `static mut EVENTS`/EV/TE/EMPTY per-call scratch buffers (60 modules) with owned per-instance `events` fields returned as `&self.events[..n]`. Public signature unchanged; behavior preserved. Only the two legitimate single-threaded WASM module singletons (lib.rs STATE, ghost_hunter DETECTOR) remain as static mut. Removes the static_mut_refs source. NO-ACTION positives (cited, labels untouched): qnt_* (quantum-/Grover-inspired, disclosed), exo_time_crystal, exo_ghost_hunter, sig_*/lrn_* algorithm-named skills. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
772ece4568 |
docs(adr): ADR-159 Cognitum appliance beyond-SOTA sweep
Records the anti-AI-slop sweep over cog-person-count, cog-pose-estimation, cog-ha-matter, ruview-swarm. HEADLINE: the "never identified anyone" accusation is REFUTED (real SHA-pinned Ed25519-signed trained Candle models, honest 34%/3% accuracy in manifests). Documents claim-surface fixes A1-A5 (MEASURED), NO-ACTION positives (witness chain, fusion, PPO + randn audit), graded SOTA landscape (counting/pose DATA-GATED, swarm MARL untrained-at-runtime by design), and the deferred backlog (benches, Location/Vector, Matter v0.8, wasm-edge accuracy). Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
48b002fa7e |
docs(cog-ha-matter): stop claiming Matter until it exists (ADR-159 A5)
Matter commissioning is deferred to v0.8 (TlsConfig::Off, LAN-only, per tls_defaults_to_off_for_v1_lan_only). Soften the Cargo.toml description from "Home Assistant + Matter integration" to "Home Assistant (MQTT) integration ... Matter Bridge commissioning is deferred to v0.8 and not yet implemented" (honest-absence, ADR-158 pattern). No code change. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
8d9c5994db |
fix(ruview-swarm): honest NED metres in Remote ID, not WGS84 (ADR-159 A3)
RemoteIdBroadcast::update stored NED metres (state.position.x/.y) into
drone_lat/drone_lon, so the ASTM F3411 broadcast would carry physically
-impossible coordinates ("latitude = 37.5 m"). The module doc claimed a
Location/Vector message but only encode_basic_id() exists.
- Rename drone_lat/drone_lon -> drone_north_m/drone_east_m (NED metres
relative to the operator/takeoff datum), documented as non-geodetic.
operator_lat/lon stay true WGS84.
- Correct the module doc to claim Basic ID only; Location/Vector encoding
is deferred until a datum-anchored NED->WGS84 transform lands.
Never broadcast physically-impossible coordinates.
Failing-on-old test:
security::remote_id::tests::test_ned_offset_stored_as_metres_not_latlon.
Co-Authored-By: claude-flow <ruv@ruv.net>
|
||
|
|
6b5fd3cf25 |
fix(cog-person-count): emit real signed manifest from CLI (ADR-159 A4)
cmd_manifest emitted a null skeleton (binary_sha256: null) while the real signed manifest existed on disk at cog/artifacts/manifests/<arch>/manifest.json. - New manifest module include_str!-embeds the real signed manifests (x86_64 + arm), selected by build target arch. - cmd_manifest parses-then-emits the embedded signed manifest, mirroring cog-pose-estimation manifest_roundtrips. CLI now reports the real binary_sha256, weights_sha256, Ed25519 signature, and honest build_metadata (training_class1_accuracy = 0.343). Failing-on-old test: manifest::tests::embedded_manifest_has_non_null_binary_sha256 (+ embedded_manifest_is_signed, embedded_manifest_id_matches_cog). Verified end-to-end: cog-person-count manifest -> non-null sha256. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
2400216920 |
fix(cog-person-count): flag untrained-class counts low_confidence (ADR-159 A2)
The count head has 8 classes but count_train_results.json only has support for classes 0/1 (presence, not multi-occupant counting). An argmax on classes 2..=7 is out-of-distribution, yet the cog emitted it as a confident headcount and the crate billed itself a "multi-person counter". - Add MAX_TRAINED_CLASS=1, CountPrediction::is_low_confidence() and clamped_count(). - person.count events now carry low_confidence + raw_count, downgrade to level "warn" when OOD, and clamp the reported count to the trained range (no fabricated headcount). - run.started discloses count_max_trained_class / count_classes. - Cargo.toml description: "multi-person counter" -> "presence detector + (data-gated) person count". Multi-occupant accuracy stays DATA-GATED (not fabricated). Failing-on-old test: untrained_class_argmax_is_flagged_low_confidence. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
98bf8c4726 |
fix(cog-pose-estimation): emit frames under default config (ADR-159 A1)
pose_v1 has no confidence head, so infer() emits a constant 0.185 per frame. The config default_min_confidence was 0.3 and the runtime gates on confidence >= min_confidence, so a default install silently emitted ZERO pose.frame events while health reported healthy. - Add inference::MODEL_TYPICAL_CONFIDENCE (0.185, the validation PCK@50) as the single published per-frame confidence. - Pin default_min_confidence() to MODEL_TYPICAL_CONFIDENCE so a default install clears its own gate and emits. - Warn at run.started when min_confidence exceeds the model typical confidence (disclosed, not silent); document the trade-off in the config field, the JSON schema, and inference.rs. Failing-on-old test: default_config_emits_frames_with_real_model (with old 0.3 it panics: "default install would emit zero pose.frame events"). Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
2e4461d64d |
release: bump 9 crates changed in the beyond-SOTA sweep for crates.io
vitals/wifiscan/hardware/nn 0.3.0->0.3.1, ruvector 0.3.1->0.3.2, signal 0.3.2->0.3.3, train 0.3.1->0.3.2, mat 0.3.0->0.3.1, sensing-server 0.3.1->0.3.2. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
97fae198d1 |
docs(changelog): beyond-SOTA sweep ADR-154–158 + stub-implementation push
Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
156323564a |
docs(readme): correct person-identification claims to measured reality (#1021)
An external audit correctly found the person-ID/Soul-Signature capability was spec-only with a no-op oracle. The §3.6 matcher is now real (wifi-densepose-bfld) but WiFi-only channels are MEASURED not-separable (cardiac+respiratory gap ~0.0005); named identity is data-gated on enrollment with the decisive AETHER/body-resonance channel. README now frames person re-id as experimental research, not a shipped feature. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
d79c22e03a |
fix(homecore-assist): exact in-memory cosine k-NN, drop fragile :memory: HNSW
The semantic recognizer built a ruvector-core VectorDB at ":memory:"; under full-workspace feature unification the file-storage backend is enabled and ":memory:" is an invalid Windows filename (os error 123), panicking via .expect(). Replace the external index with an exact in-memory cosine k-NN over the enrolled exemplars (embeddings are L2-normalised, so cosine = dot product). For HOMECORE's small intent vocabularies this is faster, fully deterministic, and removes the storage backend + cross-crate feature coupling entirely. ruvector-core dropped from the crate (only used here). Workspace 3122 passed/0 failed. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
3d96789475 |
docs(adr): ADR-158 MAT/world-model beyond-SOTA sweep (graded, MEASURED)
Records the cluster sweep: §1 triage unification, §2 real RSSI + dedup, §3 real ESP32/UDP/PCAP ingest with honest typed errors, §4 parabolic interpolation, §5 real GDOP, §6 occworld-prior fail-safe (mat consumes none). Graded SOTA table (RF-through-rubble DATA-GATED; worldgraph NO-ACTION already-SOTA; worldmodel clamp-proven; pointcloud cited), confirmed negative results, deferred backlog (nothing dropped), and reproduction commands. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
e1dc6e05ab |
feat(mat): wire real ESP32/UDP/PCAP CSI ingest; honest typed errors for gated adapters (ADR-158 §3)
hardware_adapter read_esp32_csi/read_udp_csi/read_pcap_csi returned 'not yet implemented'. Wired them to the real CsiParser/PcapCsiReader that already live in csi_receiver: - UDP: bind + recv + parse (auto-detect) -> CsiReadings. End-to-end test sends a real JSON datagram on the wire and parses it. - PCAP: load + read_next + parse. End-to-end test writes a real little-endian .pcap with one record and reads it back. - ESP32: parse CSI_DATA CSV via the real parser; live serial byte I/O behind an optional feature (native serialport gated off the default/appliance build) — without it, live reads return a typed UnsupportedAdapter while the byte parser still works (tested). Intel5300/Atheros/PicoScenes now return typed HardwareUnavailable/UnsupportedAdapter (no device/driver/validatable-format here) instead of fake CSI — added AdapterError::HardwareUnavailable and ::UnsupportedAdapter. Test asserts the gated adapters error honestly. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
982994ca3c |
fix(mat): real dimensionless GDOP = sqrt(trace((HtH)^-1)), not ad-hoc angle factor (ADR-158 §5)
estimate_gdop returned an average-pair-angle factor merely labelled GDOP (the same class of defect ADR-156 §2.3 fixed). Replaced with the genuine Geometric Dilution of Precision computed from the range-measurement Jacobian H (unit target->sensor bearings): GDOP = sqrt(trace((HtH)^-1)), dimensionless, returning None for singular (collinear) geometry which the caller treats as factor 1.0. Tests assert a well-spread array yields lower GDOP than a near-collinear one, cross-check the closed form, and confirm singular geometry returns None. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
c9a8ca758a |
feat(mat): real 3-point parabolic peak interpolation in find_dominant_frequency (ADR-158 §4)
The comment claimed interpolation but the function returned the bin center, capping breathing-rate resolution at +/-half a bin. Implemented quadratic (3-point parabolic) peak interpolation: delta = 0.5*(yL-yR)/(yL-2y0+yR), clamped to [-0.5,0.5], with an edge fallback to bin center. For a parabola-shaped peak the recovery is exact (delta=0.4 for a true peak at bin 10.4). Test asserts the result lands within half a bin of truth and strictly beats the old bin-center estimate. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
650e2b5c52 |
fix(mat): real RSSI localization + vitals-signature dedup, kill count inflation (ADR-158 §2)
simulate_rssi_measurements always returned vec![], so every survivor got location: None, which disabled spatial dedup — one person re-detected across N scan cycles became N survivors, fabricating a mass-casualty event. Two fixes: 1. Real RSSI source: SensorPosition gains an optional last_rssi (populated by the hardware layer from actual signal-strength readings). collect_rssi_measurements reads only real per-sensor RSSI and feeds the existing triangulator; it NEVER fabricates a value. <min_sensors real readings -> None location (honest). 2. Zone + vitals-signature dedup: when no usable location exists, record_detection matches an existing active, un-located survivor in the same zone whose latest vital signature (breathing presence + START rate band, heartbeat presence, movement class) is compatible — collapsing repeat detections of one person while keeping genuinely distinct survivors (different rate bands) separate. Tests (fail on old code): 3x identical-vitals/None-location -> 1 survivor (was 3); distinct vitals stay 2; real-RSSI path yields a position; no-RSSI path yields None. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
78821f1657 |
fix(mat): unify divergent triage engines to single canonical source (ADR-158 §1)
The ensemble gate (EnsembleClassifier::determine_triage) and the survivor record (Survivor::new -> TriageCalculator::calculate) used two different START-protocol approximations with different rate bands and movement handling. The pipeline gated on the ensemble triage then discarded it and recomputed via TriageCalculator, so a survivor could be admitted as one priority and recorded as another (e.g. 28 bpm + Tremor: gate said Delayed, record said Immediate). In a mass-casualty tool that divergence is a life-safety defect. determine_triage now delegates to TriageCalculator (the single source of truth), retaining only the ensemble confidence gate (low confidence -> Unknown, except Immediate which is never suppressed). Updated unit + integration tests to the canonical expectations and added a divergent-boundary regression asserting gate triage == survivor-record triage. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
67dd539e68 |
bench(pointcloud): sweep points-per-cell density for splats bench
Realistic depth backprojection is dense (many points per 8 cm voxel). Sweep
points-per-cell {4,16,64,256} at n=50k instead of point-count, so the
measurement reflects where the 9-pass→2-pass reduction actually applies.
Parity guard (old≡new, bit-for-bit) holds at every density.
Co-Authored-By: claude-flow <ruv@ruv.net>
|
||
|
|
2754af804e |
feat(occworld): real conv encoder/decoder forward pass + honesty flag
Replace the `Tensor::randn` stubs in occworld-candle's VQVAE encoder (`encode_occupancy`) and decoder (`decode_to_logits`) with a real, deterministic, input-dependent convolutional forward pass. Previously `predict()` emitted trajectory waypoints + confidence that were a function of RANDOM NOISE, independent of the input and silently presented as model output — the exact "AI slop" the project must eliminate. occworld-candle: - New `cnn.rs`: `Encoder2D` (3× Conv2d + GELU, interpolate2d to pin the token grid) and `Decoder2D` (upsample_nearest2d + Conv2d + 1×1 head). Both are deterministic functions of the input — same input → identical output; different input → different output. No randn in any forward path. - Deterministic weight init (`det_fill`, seeded xorshift64*) across all `dummy()` constructors (encoder/decoder, VQ codebook, quant-convs, transformer), so untrained engines are bit-for-bit reproducible. - `InferenceOutput.weights_trained: bool` — honest disclosure flag. `false` for `dummy()` (real but untrained net), `true` only after `load()` reads a real checkpoint. Priors are always from the real forward pass, never faked. - VQ codebook + quant/post-quant convs kept and wired encoder→VQ→decoder. - Centerpiece tests in `tests/predict_honesty.rs` (input-dependence, run-to-run + cross-engine determinism, untrained flag). All three FAIL on the old randn stub (verified by temporarily reinstating randn). pointcloud: - Optimize `to_gaussian_splats` hot path: 9 separate `.iter().sum()` passes per voxel → 2 fused accumulation passes. Bit-identical output. - `benches/splats_bench.rs` (criterion) measures old 9-pass vs new 2-pass with a parity guard. ~1.3× faster on representative cloud sizes. - Confirmed: no `randn`/placeholder in any claimed production path. The remaining synthetic generators (`send_test_frames`, `demo_depth_cloud`) and honestly-flagged heuristics (`heuristic_pose_from_amplitude`, luminance pseudo-depth fallback) are explicitly disclosed, not faked output. DATA-GATED: a trained checkpoint. An untrained-but-real net is the honest deliverable; accuracy is flagged via `weights_trained`, never claimed. Tests: occworld 16 unit + 3 integration + 2 doc, pointcloud 18 — all pass (CPU `Device::Cpu`; CUDA feature is GPU-gated and untouched). Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
7c80711454 |
feat(homecore-assist,homecore-recorder): replace stubs with real impls (ADR-132/133)
Implements the three placeholder paths with real, tested behaviour and an honest typed result wherever a capability is genuinely data-gated. homecore-assist: - runner.rs: add LocalRunner — runs the real IntentRecognizer pipeline and returns a fully-formed RufloResponse (resolved intent + speech). NoopRunner is now honest: typed NotStarted before spawn, explicit empty after (never a silent fabricated response). A live ruflo-agent.js subprocess remains the data-gated future path. - recognizer.rs / semantic_recognizer.rs: real SemanticIntentRecognizer — embeds the utterance (deterministic feature-hash embedding, new embedding.rs) and runs ruvector-core HNSW nearest-neighbour search over enrolled exemplars, accepting matches above a configurable cosine-similarity threshold (default 0.75) and falling back to regex below it. Measured: paraphrase "turn on the kitchen light" vs exemplar "turn on the light" -> sim 0.855 (match); "schedule a dentist appointment" -> sim 0.106 (no-match). `semantic` feature on by default. homecore-recorder: - db.rs: search_states_by_text — real SQL LIKE query over entity_id/state/attrs returning real rows (newest-first, k-capped, LIKE-escaped). search_semantic now falls back to it when the vector index yields no hits, so it is no longer always-empty under the default NullSemanticIndex. Tests (real behaviour; each fails on the old always-empty stub, verified): - homecore-assist: 39 passed / 0 failed - homecore-recorder (P1, no features): 19 passed / 0 failed - homecore-recorder (P2, --features ruvector): 25 passed / 0 failed All files < 500 lines; homecore-server consumer still builds. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
a0e72eef50 |
feat(wifiscan,sensing): native wlanapi.dll FFI + real Matter manual code
wifiscan (Tier 2 wlanapi adapter ONLY): - Real native wlanapi.dll BSS-list FFI (new adapter/wlanapi_native.rs): WlanOpenHandle -> WlanEnumInterfaces -> WlanGetNetworkBssList -> WlanFreeMemory/WlanCloseHandle via windows-sys 0.59 (already in lock tree). Per-BSSID RSSI(dBm)/channel/band/radio-type/SSID + CSI-capable filter. #[cfg(windows)] real path; #[cfg(not(windows))] returns typed WifiScanError::Unsupported (honest, never fabricated). - wlanapi_scanner now native-first with documented netsh fallback, native_scans metric, scan_native()/scan_native_csi_capable(), and a benchmark() that MEASURES real Hz (no hardcoded "10x" claim). - MEASURED 9.74 Hz native on ruvzen (30 iters, Native backend) vs netsh ~2 Hz baseline. Live measurement kept as an #[ignore] test. - Cargo.toml: unsafe_code forbid->deny so only the audited wlan_ffi module opts into unsafe; all unsafe confined + null-checked + freed. sensing-server (Matter commissioning): - Replaced the lossy modulo placeholder in matter/commissioning.rs with the real Matter Core Spec 1.3 §5.1.4.1.1 field-packing. Canonical vector (20202021, 3840) now encodes to the published 34970112332. - Added ManualPairingCode::decode + DecodedManualCode proving the code is real/lossless (passcode round-trips bit-for-bit; short discriminator = top 4 bits) with Verhoeff integrity, incl. proptest. Tests: wifi-densepose-wifiscan 145 passed (real FFI exercised on Windows); wifi-densepose-sensing-server 614 passed. 0 failed. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
b0ee2a4aaf |
docs(soul): mark §3.6 matching algorithm as implemented + data-gated
Update specification.md §3.6 ONLY with an honest implementation-status note: the matching algorithm is now implemented and tested in v2/crates/wifi-densepose-bfld/, weights remain unvalidated design intent, and named-identity locking is data-gated (cardiac+respiratory alone are not separable — measured gap ~0.0005). The broader Soul Signature system remains Pre-Implementation. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
e2864bbd52 |
test(bfld): measured §3.6 separability + audit's cardiac-alone negative result
Deterministic synthetic-data tests producing reproducible, honestly-labeled numbers (MEASURED-on-synthetic, explicitly NOT real-person identification): - same_person_scores_higher_than_cross_person: self-match ≈1.0000, cross-person ≈0.8088 (full channels) — a real but modest ~0.19 margin. - cardiac_alone_cannot_separate_identity_matches_audit (centerpiece): with the decisive channels (AETHER 0.35, subcarrier 0.20) absent, cardiac (0.15) + respiratory (0.10) alone give same=1.0000 cross=0.9995, gap=0.0005 — no threshold fits, so the matcher correctly refuses to lock identity. Proves the audit's claim 'your heartbeat alone overlaps too much' with real numbers. - Graceful degradation, zero-norm/NaN safety, insufficient-channels typed result, empty-enrolled-set, threshold boundary, min-channels gate. 13 new tests; full crate suite 364 passed / 0 failed. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
b08e49e47c |
feat(bfld): implement §3.6 Soul Signature matcher + real SoulMatchOracle
First running implementation of the spec's §3.6 per-channel weighted-cosine matcher (docs/research/soul/specification.md). Replaces reliance on NullOracle (which always returns NotEnrolled) with a real EnrolledMatcher oracle. - soul_channels.rs: 8-channel SoulChannels container (AETHER reuses IdentityEmbedding, preserving invariant I2 — no Clone/Serialize, zeroized on Drop), MatchWeights with the §3.6 default table (unvalidated design intent), heapless FeatureVector. no_std-compatible. - soul_match.rs: match_score() implementing the exact formula Σ w·cos / Σ w·availability, with graceful degradation, zero-norm/NaN safety, and a typed 'insufficient channels' result (never a default-high score). EnrolledMatcher (std) satisfies the existing SoulMatchOracle trait, gated on a score threshold AND a minimum shared-channel count (so a single low-weight channel can never lock identity). NullOracle retained as the disabled default. Named-identity locking remains data-gated: it requires real AETHER enrollment + body-resonance data, which has not been provided. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
66ebf798e5 |
docs(adr): ADR-157 Hardware/Sensing beyond-SOTA sweep — Milestone 3
Documents Milestone 3 across the four acquisition crates (vitals, hardware, wifiscan, calibration). Honest headline: this layer was already well-hardened, so the real work is small. - §A1 (perf, MEASURED): Vec::remove(0) O(n^2) sliding windows -> VecDeque. End-to-end win is NULL within noise at realistic window sizes (DSP dominates); the win is the algorithmic O(n^2)->O(n) shown in isolation. Claimed nothing more -- the committed bench proves the null. - §A2 (correctness): breathing partial-weights scale-mixing -> normalized by Sigma(effective weights). Pinned by two fail-on-old tests. - §A3 (stability): IIR resonator divergence. Corrected the research report's physically-inaccurate trigger (divergence needs |r|>=1, i.e. bw>=4, not "r negative"); clamp + finite-guard. Pinned by two fail-on-old tests. - §B1 hardening on an unreachable (already-gated) truncation path -- disclosed. - §B4 (constant-time HMAC compare) DEFERRED: not worth a new direct `subtle` dependency for an 8-byte LAN sync-beacon tag. - MEASURED negative-results section (the centerpiece): esp32_parser length gate, sync_packet infallible slices, the whole ieee80211bf validate-on-deserialize / no-panic-FSM / single-role / SBP-single-evaluate model, secure_tdm HMAC+replay, netsh_scanner fixed-argv + Option parse, geometry_embedding MAX_COORD_M -- each cited file:line, all NO-ACTION. - SOTA landscape: deep-CSI vitals (DATA-GATED), 802.11bf conformance (CLAIMED, non-public suite), per-room calibration (CLAIMED on numbers), native wlanapi FFI multi-BSSID (CLAIMED-unmeasured -- explicitly NOT claiming the 10x). Mostly NO-ACTION / ACCEPTED-FUTURE. - Deferred backlog (§8): nothing silently dropped. Validation: cargo test --workspace --no-default-features = 3054 passed / 0 failed; python verify.py = VERDICT PASS (hash unchanged, Rust-only changes). Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
0b78eb6e03 |
fix(hardware): drop-instead-of-truncate subcarrier count in 802.11bf bridge (ADR-157 §B1)
OpportunisticCsiBridge::ingest built CsiReportPayload.n_subcarriers via `self.amp_accum.len() as u16`, which would silently wrap a count above 65_535. Replace with `u16::try_from(...).ok()?` (drop-instead-of-truncate). Disclosed honestly as defense-in-depth on an UNREACHABLE path: ingest already gates subcarrier_count > MAX_REPORT_SUBCARRIERS (484) at entry and report.validate() rejects oversized counts downstream, so the cast can never wrap in practice. Correct-by-construction rather than gate-dependent; no behavior change, no new test (the gate prevents the input that would exercise it). Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
8fb6ef6547 |
fix(vitals): renormalize partial-weight fusion + clamp IIR resonator (ADR-157 §A2/§A3)
§A2 (correctness): BreathingExtractor weighted fusion was an un-normalized sum.
When `weights` was supplied shorter than n, supplied entries were used raw while
the missing tail defaulted to uniform 1/n -- two scales summed with no
renormalization, silently mis-scaling the breathing signal by a factor of
weights.len(). Extract to fuse_weighted_residuals() and normalize by
Sigma(effective weights), mirroring heartrate::compute_phase_coherence_signal.
Tests: partial_weights_are_renormalized_not_scale_mixed,
partial_weights_fusion_is_weighted_average (both fail on old code).
§A3 (stability): the IIR resonator pole radius r = 1 - bw/2 diverges when the
pole MAGNITUDE |r| >= 1 (i.e. bw >= 4: a very low fs relative to band width) --
NOT merely when r is negative, as the research report stated (a negative r with
|r| < 1 is still stable; the comments/tests are corrected accordingly). On
divergence the filter overflows to +/-inf within ~600 frames, NaN-poisons acf0,
and the extractor stalls permanently. Clamp r to [0, 0.9999] AND finite-guard
the filter output before the history push (defense-in-depth, mirrors ADR-154 §3).
Applied to both heartrate.rs and breathing.rs. Tests:
{heartrate,breathing}::low_sample_rate_filter_stays_finite (fs=0.5, 0.1-0.9 Hz
band, 600-frame unit step -> all-finite; both panic on old code).
These files also carry the §A1 VecDeque window conversion (bit-identical).
Co-Authored-By: claude-flow <ruv@ruv.net>
|
||
|
|
a7f7adfabc |
perf(vitals,wifiscan): O(1) VecDeque sliding windows + vitals bench (ADR-157 §A1/§D1)
Replace Vec::remove(0) (O(n) per-sample buffer shift -> O(n^2) full-window sweep) with VecDeque push_back/pop_front (O(1) eviction) in the fixed-length sliding/ring buffers of the vital-sign and wifiscan extractors. Where the autocorrelation / zero-crossing / Pearson loop needs a contiguous slice, make_contiguous() is called once per extract(), matching the idiom already used in wifiscan/pipeline/orchestrator.rs. Output is bit-identical. Sites: anomaly.rs (rr/hr history), store.rs (readings ring; history() now takes &mut self to hand back a contiguous slice, no external callers), wifiscan breathing_extractor.rs (filtered history), wifiscan correlator.rs (per-BSSID histories -> Vec<VecDeque<f32>>). (heartrate.rs/breathing.rs windows land with the §A2/§A3 fixes in a separate commit.) New criterion bench crates/wifi-densepose-vitals/benches/vitals_bench.rs drives each extractor over a full-window fill. Honest MEASURED result: end-to-end win is NULL within noise at realistic ESP32 window sizes (1500-3000) because the per-frame DSP dominates the eviction (heartrate 42.8ms->44.4ms, breathing 7.95ms->7.86ms, overlapping CIs). In isolation the eviction collapses O(n^2) -> O(n) (34.6x at window=3000, 3158x at window=100000); A1 lands as the correct data structure removing a latent O(n^2), NOT a claimed hot-path speedup. Reproduce: cargo bench -p wifi-densepose-vitals --bench vitals_bench Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
0ce2ac6440 |
docs(adr): ADR-156 RuVector/Fusion beyond-SOTA sweep — Milestone 2
Documents Milestone 2 of the beyond-SOTA sweep on the cross-viewpoint fusion path: four correctness/integrity/security fixes (each pinned by a bug-catching test), one MEASURED hot-path perf win, and the ANN/fusion SOTA landscape graded MEASURED/CLAIMED/data-gated. - Integrity: honest dimensionless GDOP (was RMSE mislabelled); canonical wrapped angular distance (disclosed numeric no-op under cos kernel — landed for contract/single-source-of-truth, not claimed as a behaviour change). - Security: crafted-index/zero-bin DoS panics closed on the multistatic path. - Perf: fuse() double-clone eliminated, ~2.17x on marshalling (MEASURED). - SOTA landscape: SymphonyQG (#1, CLAIMED — reproduction deferred) + multi-bit/Extended RaBitQ (#2, accepted near-term, the sketch.rs Pass-2); GraphPose-Fi learned fusion head documented ACCEPTED-FUTURE, data-gated per ADR-152 (b); CRB/sensor-placement investigated, no action (already SOTA). - Deferred backlog (§8): nothing silently dropped. Validation: cargo test --workspace --no-default-features = 3050 passed / 0 failed; python verify.py = VERDICT PASS. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
a92b043143 |
perf(ruvector): eliminate fuse() double-clone (~2.17x marshalling) + bench (ADR-156 §2.4, §4)
MultistaticArray::fuse / fuse_ungated cloned every viewpoint embedding twice per fusion (once into `extracted`, again when building the attention input). Now the embeddings are MOVED out of `extracted` (one clone per viewpoint instead of two), capturing geometry/ids by Copy in the same pass. Correctness-neutral — all 100 viewpoint/mat lib tests pass unchanged. MEASURED (new benches/fusion_bench.rs, embedding_extract A/B, 8 vp x 128-d): before_double_clone 1.0029 us -> after_single_clone 461.6 ns (~2.17x) End-to-end fusion_pipeline (8 vp): 202 us — marshalling is <1% of fusion (n*n attention dominates), so end-to-end win is modest; the A/B isolates the clone elimination. Reproduce: cargo bench -p wifi-densepose-ruvector --bench fusion_bench Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
a2daa2e443 |
fix(ruvector): crafted-input DoS — no panic on out-of-range indices (ADR-156 §2.2)
Security fix: two functions on a fusion/localisation path that can carry network-sourced multistatic frames panicked on crafted input (remote DoS). - triangulation::solve_triangulation indexed ap_positions[0] (empty table) and ap_positions[i]/[j] (crafted out-of-range AP index in a TDoA tuple). Now uses .first()? / .get(i)? / .get(j)? — returns None, never panics. - heartbeat::band_power computed n_freq_bins-1 (usize underflow on a zero-bin spectrogram) and did not clamp low_bin. Now guards n_freq_bins==0 and clamps both bounds into [0,last]; returns 0.0 for empty/inverted ranges. Tests (each panics on old code, verified by revert): triangulation_out_of_range_index_returns_none_no_panic, triangulation_empty_ap_positions_returns_none_no_panic, heartbeat_band_power_zero_bins_no_panic, heartbeat_band_power_out_of_range_bounds_no_panic. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
5b3e337c6d |
fix(ruvector): honest GDOP + canonical wrapped angular distance (ADR-156 §2.1, §2.3)
Two correctness/integrity fixes on the cross-viewpoint fusion geometry path, each pinned by a regression test that fails on the old code. - GDOP mislabel (§2.3): CramerRaoBound.gdop was `sqrt(crb_x+crb_y)` — identical to rmse_lower_bound (metres, noise-dependent), NOT a dimensionless GDOP. Now computes true GDOP = sqrt(trace(G^-1)) on the unit-variance bearing geometry, in both estimate() and estimate_regularised(); INFINITY (not NaN) for degenerate collinear geometry. Test gdop_is_dimensionless_and_noise_independent asserts GDOP is unchanged under 10x noise while RMSE scales 10x (old code failed: it scaled with noise, proving it was RMSE). - Angular wrap (§2.1): GeometricBias::build_matrix used raw |delta-azimuth| (can exceed pi, mis-states the 0/2pi seam) instead of the wrapped distance. angular_distance made pub and reused as the single canonical helper. HONEST: under the current cos() kernel this is a NUMERIC NO-OP (cos is even/periodic, cos(raw)==cos(wrapped)); landed for contract correctness + single-source-of- truth + future non-even kernels, not as a behaviour change. Tests pin the contract (wrapped value in [0,pi], seam symmetry). ruvector lib tests: 100 passed / 0 failed (+ new tests). Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
ea5ead7fb7 |
docs(adr): ADR-155 NN/training beyond-SOTA sweep — Milestone 1
Records the integrity-critical fixes (unified canonical metric, leak-free subject-disjoint split + synthetic-val disclosure, rapid_adapt real gradients, proof margin + committed-hash rigor), the Tier-2 correctness/security fixes, the measured Tier-3 perf win, the NN SOTA landscape graded MEASURED/CLAIMED/ THEORETICAL (GraphPose-Fi as top ACCEPTED-future candidate; INT4; CSI-JEPA-vs-MAE with the honest "no JEPA/MAE-on-WiFi-pose yet" caveat; "Mamba-CSI-pose does not exist"), and the ~45-finding deferred backlog. Discloses the libtorch/tch-gating limitation and that the Rust proof is honestly in SKIP until a baseline is committed. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
5cacb5fe0a |
perf(nn): zero-copy ORT input (~1.48x) + dynamic-dim guard + concurrency bench (ADR-155 §Tier-3)
- onnx.rs ORT input: arr.as_slice() single-memcpy fast path with iterator fallback for strided views. MEASURED [1,256,64,64]: 1.972ms -> 1.336ms (~1.48x). Repro: cargo bench -p wifi-densepose-nn --no-default-features --features onnx --bench onnx_bench -- onnx_input_copy - onnx.rs checked_output_dims: reject ONNX dim <= 0 (incl. unresolved -1) before allocation (config-OOM class) + test. - onnx_concurrency bench: empirically proves the per-inference write lock serializes (throughput drops with more threads). The intended read-lock win is NOT landable on ort 2.0.0-rc.11 (safe Session::run is &mut self, verified) and is deferred to the backlog with the upgrade path documented in-code. New committed fixture tests/fixtures/tiny_conv.onnx (666 B, not gitignored). Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
aa3a6725a6 |
fix(train,nn): Tier-2 correctness/security — metric scale, OOM bounds, panics (ADR-155 §Tier-2)
Each fix ships a test that would have caught the bug: - ruview_metrics OKS: derive scale from GT extent (no s=1.0 fake-Gold), reject s<=0, bound the loop to array extents (no panic on short/adversarial input). - config.validate(): UPPER bounds on window_frames/subcarriers/backbone_channels/ heatmap_size/keypoints/body_parts/batch_size + reject negative gpu_device_id (closes the config-OOM class); defaults+presets still validate. - subcarrier.rs: graceful fallback instead of panic on non-contiguous input. - ablation.rs latency_percentiles: total_cmp + NaN guard (no partial_cmp unwrap). - tensor.rs softmax(axis): normalize per-lane along the given axis (was whole- tensor), out-of-range axis -> NnError; fixes densepose per-pixel probs. - translator.rs apply_attention: real scaled-dot-product attention (was a uniform 1/seq_len stub that made any "with attention" ablation == without); mis-shaped checkpoint projections rejected. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
84e2c920fd |
fix(train): proof margin + committed-hash requirement (ADR-155 §Tier-1.4)
The deterministic proof self-certified: PASS on any loss decrease (incl. 1e-9 noise) and a missing expected hash defaulted to PASS. - MIN_LOSS_DECREASE=1e-4: a run counts as learning only above float noise; a noise-only pipeline now FAILS. - is_pass() requires hash_matches==Some(true); no-hash -> SKIP (exit 2), never PASS. verify-training fails fast on a sub-margin loss before the hash compare, so a missing baseline cannot mask a non-learning pipeline. Documented honestly: the proof certifies reproducibility/determinism on a synthetic dataset, NOT that real data produced the weights nor that any accuracy claim is met. Tests: no_committed_hash_is_skip_not_pass, submargin_loss_change_fails_even_without_hash, committed_matching_hash_with_real_decrease_passes. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
7fb3e33557 |
fix(train): rapid_adapt real finite-difference gradients, not a fake step (ADR-155 §Tier-1.3)
contrastive_step/entropy_step wrote a fake gradient (grad += v*0.01) unrelated to the stated objective, so any "TTA improves the metric" was unsupported. The *_loss functions are now pure evaluators of the real objective; adapt() descends them with a central finite-difference gradient of that exact loss, so "the adaptation loss decreases" is now a real, reproducible measurement. Honest scope caveat (documented): this minimizes a self-supervised proxy over a LoRA bottleneck on raw CSI; it is NOT wired to the pose model and there is NO measured end-to-end PCK gain on WiFi pose from this path. Tests: contrastive_loss_decreases, entropy_loss_decreases (real gradient steps don't increase the loss), reported_loss_is_the_real_objective_not_a_placeholder. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
2a2a2c5b06 |
fix(train): leak-free subject-disjoint split + synthetic-val disclosure (ADR-155 §Tier-1.2)
MM-Fi windows are stride-1 (~99% overlap), so an index-level split leaks; and
bin/train.rs validated real training against a SYNTHETIC val set, making any
printed PCK meaningless on two counts.
- MmFiDataset::subject_disjoint_split partitions whole subjects -> the two views
share no subject and no window (leak-free by construction, deterministic per
seed). assert_split_leak_free verifies subject- AND window-disjointness and is
called inside the split so a leaky split is never handed out.
- bin/train.rs now prefers the real split; the synthetic path is a labelled
run_smoke_test ("[SMOKE-TEST] DO NOT REPORT") reachable only as a fallback.
- New DatasetError::InvalidSplit.
Tests prove disjointness, determinism, single-subject/bad-fraction rejection,
and that the validator catches an injected subject leak.
Co-Authored-By: claude-flow <ruv@ruv.net>
|
||
|
|
50b657459f |
fix(train): unify 7 divergent PCK/OKS into one canonical metric (ADR-155 §Tier-1.1)
Collapse the four PCK and three OKS implementations into a single source of
truth — pck_canonical (torso hip↔hip, COCO/ADR-152 convention validated at
~96% PCK@20 in benchmarks/wiflow-std) and oks_canonical (scale from GT pose
extent). MetricsAccumulator, compute_pck/_per_joint/_oks, aggregate_metrics and
the deprecated *_v2 path all route through them, so Trainer::evaluate() and the
bench definition agree.
Fixes two claim-inflating bugs, each pinned by a regression test:
- zero-visible-joint PCK was 1.0 (false-perfect) -> now 0.0
- OKS s=1.0 on normalized coords made OKS~=1.0 for any pose ("fake Gold tier")
-> scale now derived from the pose; a 3x-torso-wrong pose yields OKS<0.2
Divergent local kernels (training_bench raw-threshold, sensing-server
torso-height) annotated "DO NOT USE for reported metrics". Legitimately changed
test expectations (all-coincident "perfect" fixtures are correctly unscoreable;
all-invisible -> 0.0) updated with comments citing the finding.
Co-Authored-By: claude-flow <ruv@ruv.net>
|
||
|
|
6511ca90fb |
docs(adr): ADR-154 signal/DSP beyond-SOTA sweep — Milestone 0
Records Milestone-0 of the signal/DSP beyond-SOTA sweep with full PROOF discipline (MEASURED vs CLAIMED vs THEORETICAL grading throughout): - §2 discloses the headline anti-slop finding: the ADR-134 CIR coherence gate was DEAD in production (canonical-56 frames -> SubcarrierMismatch -> silent freq-domain fallback for every frame). Documents the canonical56() fix + the 4 committed proof tests. - §3 NaN/inf adversarial bypass; §4 divide-by-(n-1) window trio. - §5 the two MEASURED perf wins with before/after medians + reproduce commands. - §6 per-module SOTA landscape, evidence-graded: deep-unfolded ISTA/LISTA for CSI->CIR (~3 dB NMSE, MEASURED, arXiv 2211.15440 + 2502.05952), diffusion CIR prior (public weights, MEASURED), Wi-Spoof adversarial eval (MEASURED, arXiv 2511.20456), Bayesian multi-AP fusion (CLAIMED, no code, 2512.02462), coherence gating + RF intention-lead (THEORETICAL). - §7 roadmap: LISTA-for-CIR as the top ACCEPTED-future item (M effort; the ISTA + Phi already exist in cir.rs) — proposed, NOT implemented this milestone — plus the explicit deferred-findings backlog (the ~45 review findings not fixed here, graded P1/P2/P3) so nothing is silently dropped, with a horizon-ledger DONE-vs-DEFERRED one-liner. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
4d384cb884 |
perf(signal): cache PSD FFT planner (2.0–3.1x) + honor DTW band (2.4–4.1x) (ADR-154 M0)
Two measured, bit-equivalent perf wins. Each ships a criterion bench
(benches/features_bench.rs, new) with before/after numbers and a committed
bit-identity test — no perf claim without a measured before/after.
PSD FFT-planner caching (features.rs)
PowerSpectralDensity::from_csi_data re-planned a FftPlanner on EVERY frame,
and FeatureExtractor::extract calls it per frame on the hot path. New
from_csi_data_with_fft(csi, n, &Arc<dyn Fft>) reuses a plan cached in
FeatureExtractor (built once in new()). Bit-identical output
(psd_cached_fft_bit_identical_to_fresh, f64::to_bits over 6 sizes).
MEASURED (median ns/frame, criterion):
fft=64 5.84µs -> 1.89µs (3.09x)
fft=128 9.31µs -> 3.61µs (2.58x)
fft=256 13.77µs -> 6.73µs (2.04x)
DTW Sakoe-Chiba band (gesture.rs)
dtw_distance computed j_start/j_end but iterated the FULL 1..=m row,
continue-ing out-of-band — band constrained the path, not the work (O(n*m)).
Now iterates j_start..=j_end (O(n*band)), resetting only the two boundary
guard cells the recurrence reads, with endpoint reachability (|n-m|<=band)
at the return. Bit-identical across 12 shapes x 8 bands
(dtw_banded_bit_identical_to_fullrow).
MEASURED (median, criterion):
n=m=100 band=5 33.45µs -> 13.77µs (2.43x)
n=m=200 band=5 122.32µs -> 29.55µs (4.14x)
n=m=200 band=10 159.98µs -> 60.19µs (2.66x)
Reproduce:
cd v2 && cargo bench -p wifi-densepose-signal --no-default-features \
--bench features_bench
Co-Authored-By: claude-flow <ruv@ruv.net>
|
||
|
|
be068748b3 |
fix(signal): revive dead CIR coherence gate + NaN bypass + window div0 (ADR-154 M0)
Milestone-0 correctness/security fixes for the beyond-SOTA signal/DSP sweep.
Every fix ships with a committed regression test (proof, not adjectives).
CRITICAL — ADR-134 CIR coherence gate was DEAD in production
MultistaticFuser fuses canonical-56 frames (hardware_norm.rs resamples every
chipset onto a 56-tone grid), but the gate was wired to CirConfig::ht20()
which expects 64/52. Every estimate() returned SubcarrierMismatch and
cir_gate_coherence silently fell back to freq-domain coherence — use_cir_gate
was indistinguishable from false. Fixes:
- new CirConfig::canonical56() (64-bin HT20 framing, 56 active tones, 168 taps)
- new MultistaticFuser::with_cir_canonical56() (correct default); ht20 kept,
now doc-warned
- active_indices() handles (64,56) + length-matched fallback (no silent
fall-through to the 52-index slice)
- SubcarrierMismatch in the gate now debug_assert!s loudly (config error can
no longer hide as a graceful degrade)
- cir_estimate_first() exposes the Ok/Err verdict for tests
PROOF (ruvsense::multistatic::tests): ht20 → 8/8 Err (dead); canonical56 →
8/8 Ok (alive); coherence(gate on) != coherence(gate off).
CRITICAL — adversarial.rs NaN/inf detector bypass
One non-finite link energy bypassed the whole detector (every `e>thresh`
false on NaN; score clamp returns NaN). A non-finite input is itself the
strongest spoof — now short-circuits to a definite anomaly (score 1.0,
affected link reported) and does not poison the temporal-continuity state.
PROOF: nan_link_energy_flags_anomaly, inf_link_energy_flags_anomaly.
CORRECTNESS — divide-by-(n-1) window trio
csi_processor hamming_window (n=0 usize underflow, n=1 div0), bvp Hann,
spectrogram make_window all guarded for n<=1 (empty / constant-1.0 window).
Python deterministic proof still PASS, same pipeline hash (reference uses n>=2).
PROOF: *_degenerate_sizes / *_size_one_is_finite / make_window_size_0_and_1.
CLARITY — calibration.rs subtract_in_place
Removed the vacuous `if active_input {ki} else {ki}` branch that implied a
full-FFT->bin remap that never existed; documented the sequential
active-index convention (matches sibling extract_first_stream). No behavior
change.
Tests: cargo test -p wifi-densepose-signal --no-default-features (+--features cir)
green; full workspace green; verify.py VERDICT: PASS.
Co-Authored-By: claude-flow <ruv@ruv.net>
|
||
|
|
07b6bf8084 |
chore: extract ruv-neural to ruvnet/ruv-neural, wire as submodule (#1019)
The 12-crate brain-topology analysis ecosystem (v2/crates/ruv-neural) was a self-contained nested workspace with no inbound deps from the v2 workspace (verified: zero path references outside its own tree). Published standalone at github.com/ruvnet/ruv-neural and re-attached here as a submodule at the same path, so the build layout is unchanged while the project gets its own repo/CI/release cadence.v1677 |
||
|
|
d22616c488 |
docs(research): WiFlow-STD audit writeup (published as public gist + upstream issue)
Gist: https://gist.github.com/ruvnet/47d4369c0bd251ed233bbc450d50f6e6 Upstream report: DY2434/WiFlow...issues/3 Co-Authored-By: claude-flow <ruv@ruv.net>v1674 v1675 |
||
|
|
17471e93ff |
ADR-152: WiFi-Pose SOTA 2026 intake — WiFlow-STD benchmark, Rust integrations, ADR-153 802.11bf layer, efficiency frontier (#1008)
* feat(calibration): NodeGeometry transceiver-geometry recording (ADR-152 §2.1.1) PerceptAlign-motivated geometry capture at enrollment: per-node optional records (position, antenna orientation, inter-node distances, acquisition method) — recorded when known, never required. Event-sourced via EnrollmentEvent::GeometryRecorded (latest recording wins); persisted on SpecialistBank with serde defaults so pre-ADR-152 bank JSON loads cleanly (fixture-proven, and geometry-free banks serialize byte-shape-identical to the old schema); threaded through MultiNodeMixture as data only — the learned geometry embeddings and algorithmic fusion use are §2.1.2, deliberately deferred until the ADR-151 P6 LoRA heads exist. Geometry recorded from now on means banks captured today remain usable for layout-conditioned training later — you can't retroactively add geometry to data you didn't record. 8 new tests (3 geometry, 2 anchor, 2 bank, 1 multistatic) + full-loop extension (2-node geometry, one tape-measured + one unknown, surviving the bank JSON round-trip the runtime loads from). 50/50 calibration (both feature configs) + 23 CLI tests green. Co-Authored-By: RuFlo <ruv@ruv.net> * feat(training): two-checkerboard camera↔room calibration for ADR-079 labels (ADR-152 §2.1.3) Defends the camera-supervised pipeline against PerceptAlign's "coordinate overfitting": MediaPipe keypoints were emitted in raw camera coordinates with no shared frame and no transceiver-geometry metadata — the exact label shape that memorizes deployment layout and collapses cross-layout. - scripts/calibrate-camera-room.py + calibration_lib.py: OpenCV two-checkerboard calibration → versioned bundle JSON (intrinsics, camera→room extrinsics, checkerboard spec, transceiver geometry, sha256 calibration_id). Intrinsics resolve from file > cache > multi-view computation > loud-warning 2-view fallback. - collect-ground-truth.py --calibration <bundle>: every sample gains keypoints_room (unit bearing rays from the camera center in the room frame — documented projective alignment; raw image coords preserved so training chooses), camera_origin_room, calibration_id, and the transceiver geometry stamp. Without the flag, output is byte-identical to before (tested) + a one-line ADR-152 warning. Design finding (recorded for ADR-152): a single planar checkerboard's corner grid is centrosymmetric — the reversed corner ordering fits a ghost camera pose with IDENTICAL reprojection error, so per-board flip disambiguation is mathematically ill-posed. solve_two_board_extrinsics solves the joint wall+floor set over all 4 flip combinations, where the minimum is unique — an independent reason the TWO-checkerboard method is required, beyond what PerceptAlign states. 15 headless pytest tests green (synthetic corners: extrinsics recovery incl. ghost resolution, bundle round-trip + hash stability, ray transforms w/ distortion + cross-resolution, no-calibration byte identity). Co-Authored-By: RuFlo <ruv@ruv.net> * feat(benchmarks): WiFlow-STD reproduction harness + measurement (a) results (ADR-152 §2.2) Shipped checkpoint REFUTED (0.08% PCK@20, wrong keypoint normalization); 6 reproducibility defects documented (broken imports, corrupted dataset tail with float32-max garbage that NaN-poisons fp16 BatchNorm, unreachable test phase). After repairs, retraining with upstream defaults reproduces 96.09% PCK@20 full-test / 96.61% corruption-free (published 97.25%) on RTX 5080. Claims graded MEASURED-EQUIVALENT; 2.23M params + ~0.055 GFLOPs verified. Third-party code/weights/data stay out of tree (gitignored). Co-Authored-By: claude-flow <ruv@ruv.net> * feat: ADR-152 Rust integrations + ADR-153 802.11bf protocol model - calibration: GeometryEmbedding — 32-slot permutation-invariant NodeGeometry featurization for future LoRA-head conditioning (ADR-152 §2.1.2); derived SpecialistBank::geometry_embedding() accessor; 59 tests - train: MaePretrainConfig + patchify/random-mask with UNSW measured recipe (80% masking, (30,3) patches; ADR-152 §2.3, arXiv 2511.18792); strict no-truncate/no-NaN policy; proptest properties - train: WiFlowStdModel — tch-gated port of the verified ~96%-PCK@20 WiFlow-STD architecture (ADR-152 §2.2 beyond-SOTA); ungated param formula pinned to 2,225,042; 15/17-keypoint support; 239 crate tests - hardware: ieee80211bf forward-compatibility protocol model (ADR-153): SpecProfile gates, SensingCapabilities negotiation, required ConsentMode, session FSM, SensingTransport + SimTransport + OpportunisticCsiBridge; full acceptance checklist covered; 156+4 tests - deps: ruvector bumps per ADR-152 §2.6 survey (mincut/solver 2.0.6, attention 2.1.0, gnn 2.2.0); vendor/ruvector synced to a083bd77f - docs: ADR-153 accepted; ADR-152 §2.2 status, §2.4 amendment, §2.6 added Workspace: 162 test suites green (--no-default-features); Python proof PASS. Known pre-existing flake: homecore-api env_empty_falls_back_to_defaults (unserialized env-var mutation) — untouched, follow-up. Co-Authored-By: claude-flow <ruv@ruv.net> * docs: CHANGELOG + CLAUDE.md entries for ADR-152 integrations and ADR-153 Co-Authored-By: claude-flow <ruv@ruv.net> * fix(train): repair tch-backend bit-rot — gated path compiles and tests run again Mechanical API refresh against current tch: Vec::from(Tensor) -> try_from (+ explicit flatten), numel() usize cast, Rem/div ops -> remainder() / divide_scalar_mode(floor) — the latter fixed a silent true-division bug in heatmap argmax decoding; clamp(1.0, f64::MAX) -> clamp_min (torch 2.x scalar overflow panic); petgraph EdgeRef import; missing EvalMetrics and verify_checkpoint_dir APIs that tests documented. wiflow_std roundtrip test uses safetensors (.pt _save_parameters roundtrip broken in torch 2.11 Windows). Gated: 349 passed (incl. all 20 wiflow_std); ungated: unchanged. Known pre-existing: gaussian-heatmap convention mismatch (2 tests), proof seed race under parallel threads — documented, deliberate follow-ups. Co-Authored-By: claude-flow <ruv@ruv.net> * feat(train): WiFlow-STD PyTorch->tch weight import + numerical parity proof export_to_safetensors.py maps the retrained checkpoint (295 tensors -> 248 mapped, param sum exactly 2,225,042; num_batches_tracked dropped) into a tch-loadable safetensors plus a deterministic parity fixture. Gated #[ignore] integration test loads it strictly and asserts forward-pass agreement: max abs diff 1.192e-7 on the seed-42 fixture. dump_variable_names test makes the tch name layout authoritative. Zero architecture discrepancies found. Co-Authored-By: claude-flow <ruv@ruv.net> * fix: workflow-review findings — BN gamma init, ThresholdParams serde, init docs Concurrent validation workflow (2 review lanes + adversarial verification, 13 agents): 5 confirmed findings, 3 refuted. Fixes: - wiflow_std: pin BatchNorm gamma to 1.0 (tch default draws Uniform(0,1) — silently halves activations in from-scratch training; loaded checkpoints unaffected, parity re-verified after the change) - wiflow_std: document the conv-init divergences vs the reference's effective kaiming_normal(fan_out) re-init (from-scratch dynamics only) - ieee80211bf: ThresholdParams deserialization validates via try_from so the <=100 invariant holds for untrusted payloads (+ rejection test) Benchmarks (release, ruvzen): GeometryEmbedding 1.84us/call (542k/s), MAE tokenization 7.38us/window (135k/s), 802.11bf FSM 8.9M events/s — nothing suspicious. Co-Authored-By: claude-flow <ruv@ruv.net> * docs(adr): ADR-152 §2.1.4 gate resolved — PerceptAlign repo MIT, dataset on HF Co-Authored-By: claude-flow <ruv@ruv.net> * feat(benchmarks): edge optimization measured + measurement (b) blocked + 92.9% retraction Edge optimization (ADR-152 optimize track): ONNX Runtime fp32 is the CPU latency win (3.2 ms/window, ~3.4x faster than torch, parity 2.4e-7); ORT dynamic int8 reaches 2.44 MB (paper's ~2.2 MB claim plausible only via conv-capable toolchains; -0.16pt PCK@20, +18% MPJPE, 2x slower); torch dynamic quant converts 0% of this conv-only model; fp16 halves storage free but is slower on CPU. Measurement (b) BLOCKED-ON-DATA: only 1,077 paired ESP32 windows exist (stop rule <2k). Forensic recheck of the surviving April holdout RETRACTS the ADR-079 '92.9% PCK@20' figure: constant-output model, absolute (not torso) threshold, 69 near-static frames — mean predictor scores 100% under that protocol; torso-PCK@20 is 19.1%. Corroborates PR #535. Stale citations removed from user-guide, readme-details, ADR-152 §2.1.3; no-citation rule extended to ADR-079 accuracy claims. Unblock: >=2k-window multi-pose paired session + torso-PCK re-baseline. Co-Authored-By: claude-flow <ruv@ruv.net> * docs(user-guide): corrected camera-supervised collection tutorial Step 0 CSI-rate check + session-length math (window yield = frames/20 — the May session's 8x under-delivery was a ~12 Hz CSI rate, not an aligner bug); two-checkerboard calibration step (ADR-152 §2.1.3); pose-variety and confidence guidance; torso-normalized PCK + temporal-split + pred-variance eval protocol (lessons from the 92.9% retraction); scale presets re-keyed to realistic window counts. Co-Authored-By: claude-flow <ruv@ruv.net> * feat(benchmarks): static PTQ int8 (calibrated) results + overnight capture script Conv-only static QDQ beats dynamic int8 on accuracy (PCK@20 96.61-96.63% vs 96.52%, MPJPE +10% vs +18% over fp32) at ~equal size/latency; all-ops QDQ strictly worse (int8 activations through attention glue). Entropy calibration verified bit-identical to MinMax on this data. Deployment: ONNX fp32 for speed (3.2ms), static conv-only QDQ for smallest (2.53MB). Also: scripts/overnight-empty-capture.py — segmented UDP CSI recorder for empty-room baselines (no glob collisions, detach-safe). Co-Authored-By: claude-flow <ruv@ruv.net> * feat(benchmarks): measurement (b) MEASURED — optimization transfer only, mean-pose baseline wins WiFlow-STD fine-tuned on 2,046 fresh single-room ESP32 paired windows (temporal 70/15/15, 70->540 adapter, K=17): pretrained-init 65% PCK@20 vs scratch 0% (optimization transfer) but frozen-trunk ~0% (no feature transfer), and NOTHING beats the mean-pose baseline (95.9% PCK@20 — single subject, near-static normalized coords). Honesty gates held: pred std 0.0113 (non-constant model) but mean-baseline dominance means no citable CSI->pose capability from this data. ADR-152 open question 1 answered partially; definitive answer needs multi-subject/position data. Two new aligner findings: heterogeneous csi_shape with silent zero-padding (~20%), and extractCsiMatrix's transposed shape label (frame-major data, [nSc, nFrames] label) — fixes pending. Co-Authored-By: claude-flow <ruv@ruv.net> * feat(benchmarks): efficiency sweep MEASURED — half model dominates full reference Compact WiFlow-STD variants on the same data/split/protocol: half (843,834 params, 0.38x) strictly dominates the 2.23M reference (PCK@20 96.62 vs 96.61, PCK@50 99.47 vs 99.11, MPJPE 0.00898 vs 0.0094) — the published architecture is over-parameterized for its own benchmark. quarter (338k) 96.05%; tiny (56,290 params, 1/39.5) holds 94.11% — a ~220KB fp32 edge candidate. In-domain caveats recorded; cross-domain untested. Co-Authored-By: claude-flow <ruv@ruv.net> * feat(train): compact WiFlow-STD presets in Rust + tiny edge artifact (ADR-152) WiFlowStdConfig gains half()/quarter()/tiny() mirroring the overnight sweep exactly: TcnGroupsMode (Fixed/Gcd/Depthwise), input_pw_groups, derived stride schedule and decoder-mid (all default to upstream behavior; legacy serde JSON unaffected). Param formulas pin to trained ground truth first try: 843,834 / 338,600 / 56,290; default 2,225,042 pin and 1.192e-7 parity unchanged. 248 tests green. Tiny edge artifact (tiny_edge_bench.py): ONNX fp32 = 295 KB, 0.66 ms/win (~1,500/s CPU), 94.11% PCK@20 (matches sweep clean-test exactly; parity 1.49e-7). Static int8 is a bad trade at this scale (-1.43pt, +19% MPJPE, -16% size, slower) — recorded as negative result. Export note: width-16 breaks AdaptiveAvgPool((15,1)) TorchScript export; replaced by exact mean+matmul equivalent, proven by parity. Co-Authored-By: claude-flow <ruv@ruv.net> * fix: resolve all 10 confirmed code-review findings (7-angle review, 20/20 verified) wiflow_std: min_feature_width (default 15) replaces the keypoints->stride coupling — for_keypoints(17) now provably builds the trained [2,2,2,2] graph and pools 15->17, matching the validated Python protocol (pinned by tests); param_count() total on invalid configs; random_mask returns Result and rejects non-finite/out-of-range ratios; trainer checkpoints switched to safetensors (.pt VarStore roundtrip broken on Windows torch 2.11). ieee80211bf: SBP proxy now re-triggers instances and relays reports via Action::RelaySbpReport -> SensingFrame::SbpReport (clients consume via their existing path); missed_instances reset on success = consecutive semantics; SessionTable gains a guarded SBP entry point + unknown-id drop counter; initiator-role sessions reject inbound setup/SBP requests (RejectedNotSupported) closing the idle hijack; StartSetup/StartSbp outside Idle return InvalidStateForCommand; SBP validation unified through evaluate_setup with a 1:1 SetupStatus->SbpStatus mapping. events.rs split out to honor the 500-line cap. calibration/cli: enrollment geometry now actually reaches trained banks — both production call sites attach .with_geometry; --geometry flag on train-room and POST /enroll/geometry + train-body geometry on calibrate-serve give production a recording surface; geometry-free banks log the ADR-152 §2.1.2 note. benchmarks: corruption masks committed as ground truth (unregenerable after in-place cleaning; verified bit-identical regeneration from the pristine copy) + generate_corruption_masks.py producer; _bench_common.py dedups the 5x-copied shim/evaluate/seed/remap (post-refactor PCK@20 re-verified equal to the last digit); remote scripts get the mmap patch; tiny_edge --calib validated multiple-of-64; onnx_bench --help no longer executes (and overwrote) the export — artifact restored byte-exact. Workspace: 2,963 tests passed, 0 failed; Python proof PASS. Co-Authored-By: claude-flow <ruv@ruv.net> * ci: build workspace tests without debuginfo — runner disk exhaustion The combined 38-crate debug target exceeds the GitHub runner's disk ('final link failed: No space left on device'); the same tree measured 151GB locally with full debuginfo. CARGO_PROFILE_{DEV,TEST}_DEBUG=0 shrinks the target ~5-10x; debuginfo serves no purpose in CI test runs. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
29de574e63 |
Beyond-SOTA engine/signal/train improvements: mesh partition guard, FFT CIR solver, canonical frame decoder, falsifiable occupancy benchmark, governed streaming, adapter provenance (#1018)
* 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>v1669 |