Adds vendor/metaharness (github.com/ruvnet/metaharness, pinned at
87b6c51 on main) -- the real MetaHarness generator: repo-aware CLI,
Rust/WASM+NAPI-RS kernel, host adapters, @metaharness/router
(cost-optimal model routing) and @metaharness/darwin ("Darwin Mode",
self-evolving harness config). ADR-285's harness/homecore/ already
depends on the real @metaharness/kernel@0.1.2 npm package; this
vendors the source repo alongside the other vendor/* submodules
(rufield, rvcsi, ruvector, sublinear-time-solver, midstream) for local
inspection and building.
No wiring into any harness/ or crate yet -- follow-up work.
Picks up a cargo-fmt pass on the rufield MFS reference stack
(github.com/ruvnet/rufield): whitespace/line-wrap only, no logic
changes. 98 tests, 0 failed.
--convert-model rejected the published model.safetensors because its
JSON header is padded to an 8-byte boundary with trailing NUL bytes,
which a strict serde_json::from_slice parse treats as trailing
characters. Trim the padding before parsing, with a regression test
that reproduces the exact boundary-padded shape of the real HF file.
docs/huggingface/MODEL_CARD.md had drifted from the card actually
published on the Hub: every file in its "Files in this repo" table
(pretrained-encoder.onnx, pretrained-heads.onnx, pretrained.rvf,
room-profiles.json) does not exist in ruvnet/wifi-densepose-pretrained.
Replaced it with the content live on the Hub and added a section
documenting the --convert-model / --model RVF conversion path, which
neither card mentioned.
Pins maintained action revisions that execute on Node 24, moves the project runtime to Node 22, and adds regression coverage so the deprecated Node 20 action runtime cannot silently return.
Add a fail-closed nightly Cognitum research pipeline with frozen Darwin policy, an honest-null Flywheel canary, bounded issue/PR automation, and declarative offline prototypes.
Imports and hardens #1382 with opt-in OTLP logging, registry-validated semantic conventions, a published schema, TLS roots, digest-pinned demo images, and corrected first-CSI lifecycle reporting. Co-authored by Jens Holdgaard Pedersen.
websocket.service.js (used by the pose/event streams) opened a bare
`new WebSocket(url)` with no ADR-272 ticket exchange, unlike
sensing.service.js which already mints a ticket per connect. Since a
browser cannot set an Authorization header on a WebSocket upgrade, and
the server rejects a long-lived bearer passed as a query string
(CWE-598), the pose stream 401'd whenever auth was on — visible in the
Live Demo tab as "Failed to create WebSocket connection".
Fix: createWebSocketWithTimeout() now strips any `token` query param a
caller put on the URL (pose.service.js does this) and exchanges the
stored bearer for a single-use `?ticket=` via withWsTicket(), done at
this one choke point so every consumer (pose, events, training) and
every reconnect attempt gets a fresh ticket.
Second, smaller bug: pose-fusion/js/main.js auto-connected to a
hardcoded `ws://localhost:8765/ws/sensing`, but the Docker image serves
the sensing WebSocket on :3001 (the same 3000->3001 mapping
sensing.service.js already encodes) — the auto-connect dialed a port
nothing listens on. Reuses that port mapping and tickets both the
auto-connect and the manual "Connect" button.
Bumped the pose-fusion.html cache-buster (v=13 -> v=14) so browsers
actually fetch the updated main.js.
Adds ui/services/websocket.service.test.mjs (4 executed Node tests,
stubbed WebSocket/fetch/localStorage) covering: no-auth passthrough,
ticket exchange + bearer-never-in-URL, stray ?token= stripping, and the
pre-ADR-272 404 fallback. Wired into the CI "Run UI unit tests" step.
Reported with a verified fix in #1461 by wsc7r4zcj4-collab; this PR
implements the same fix against current main with an added regression
test.
Closes#1461
Closes the two documentation gaps from #1456 (follow-up to #1401):
- docs/calibration-guide.md: what calibrate/enroll/train-room actually
enforce, grounded in v2/crates/wifi-densepose-calibration and
wifi-densepose-cli source (not just ADR-135/151 aspirational prose).
Covers the hard 600-frame baseline minimum, per-anchor quality gate
thresholds, the unsolved pet/small-motion presence-detection gap, and
what the empty-room baseline capture actually needs (steady vs silent).
Flags that ADR-135's drift_score/BaselineDrift staleness system is not
implemented in code — only bank.rs's baseline_id STALE check is real.
- docs/trust-and-engine-errors.md: exact trigger conditions for
engine_error_count vs the separate, non-sticky `demoted` privacy-class
flag, where both are exposed (/health/ready and /api/v1/status share a
handler), the real diagnostic gap (no per-cause breakdown, log line is
the closest thing), the WDP_GUARD_INTERVAL_US recovery path for
persistent clock-drift demotion, and an honest "no code path found"
answer on whether a converted HuggingFace model explains engine errors.
Also adds both docs to the README documentation table. No code changes.
HAP accessory signing seed no longer reachable via derived Debug. /api/history/period and /api/logbook no longer break the default (unfiltered) call shape above 32 entities. fire_event's event_type validation relaxed to match real HA's contract. homecore-migrate gained a --force flag for re-running imports. Public v2051 release notes corrected. 110 tests across the 3 touched crates, 0 failed, clippy clean.
Fixes#1422, Fixes#1423. HeartRateExtractor no longer truncates subcarrier count on empty phases; BreathingExtractor resets immediately on first out-of-band rejection instead of passively draining a stale window (recovery 28.6s -> 6.0s). 64 tests passing, clippy clean, zero regressions workspace-wide.
Fixes the calibration-path bug in #1440. Disables the variance channel when occupied-anchor variance doesn't genuinely exceed the empty-room baseline, mirroring the existing mean-shift channel's fallback. 64 tests passing, zero regressions.
Fixes#1442. Extracted classify_vitals() so presence is always derived from the label, matching the convention already used elsewhere in the codebase. 4 new regression tests, 707 tests passing, zero regressions.
Published: wifi-densepose-core 0.3.2, -vitals 0.3.2, -wifiscan 0.3.2, -hardware 0.3.2, -signal 0.3.6, -nn 0.3.2, -ruvector 0.3.3, -train 0.3.3, -mat 0.3.2, -wasm 0.3.1.
Not published (blocked, needs a decision): wifi-densepose-sensing-server and wifi-densepose-cli both path-depend on ruview-auth, which is publish = false. Version bumps reserved (0.3.5, 0.3.2) but not published.
Native frame contract, universal RF encoder, RF-aware Gaussian spatial memory, physics-guided synthetic RF worlds, edge sensing control plane, BLE-CS + factorized pose. All 10 ADRs (273-282) fully implemented and tested (99 tests); ADR-278 (radar inverse rendering) honestly gated with zero code as a future research program.
Deep-reviewed and hardware-tested against a live ESP32-C6 CSI node before merge: fixed a reachable panic, a silent NaN-corruption path, a cross-entity Gaussian conflation bug, and a wrong-center-frequency bug in the WiFi adapter (confirmed live: was misreporting channel 4 as 2437 MHz, now correctly reports 2427 MHz matching the hardware parser exactly). Added a standing hardware-in-the-loop test (examples/esp32_live_hardware_test.rs). Also fixed unrelated pre-existing issues surfaced during validation (wifi-densepose-core clippy warnings, a ruview-auth Windows build break, a sensing-server test flake).
Full review: https://gist.github.com/ruvnet/89795f3c4b8ea166cff5ac35ae4c7651
Make deployment consume the exact published sensing-server image, publish the two Python packages in lock-step, and enforce the production witness gate.
Make deployment consume the exact published sensing-server image, publish the two Python packages in lock-step, and enforce the production witness gate.
bc0e8fd0 added `serde_json` to the aether crate's [dev-dependencies] for the
native golden-parity test, but v2/Cargo.lock was not regenerated then (that
worktree had no submodules, so the workspace could not build). CI passed only
because it does not use `--locked`; committing the lockfile keeps Cargo.toml and
Cargo.lock in sync and lets a `--locked`/`--frozen` build succeed.
Co-Authored-By: Ruflo & AQE
Closes the two findings from the adversarial review that were verified but left
unfixed. Both now have proper tests, each proven to fail against the old code.
1. PyO3 bindings panicked / over-allocated on caller input (aether.rs).
`EmbeddingExtractor(n_heads=0)` reached `d_model % n_heads` in the transformer
and panicked (surfacing to Python as an opaque PanicException); a non-divisor
head count tripped the native assert; and `AetherConfig(d_model=100_000)`
allocated multi-gigabyte weight matrices that abort the interpreter. The
binding did no validation.
Now both constructors return `PyResult` and validate at the boundary —
positive dims, `d_model % n_heads == 0`, and a generous MAX_DIM/MAX_LAYERS cap
— raising `ValueError`. Proven: `n_heads=0` -> "n_heads must be positive",
`d_model=100_000` -> a clean ValueError, both previously a
PanicException / abort. +10 pytest cases (test_aether.py); a valid config
still constructs and embeds.
2. The single-training-job guard was a TOCTOU race (training_api.rs).
`spawn_training_job` checked `is_active()` under a `state` READ lock, released
it, then set `active` later. A tokio RwLock read lock is SHARED, so two
concurrent `POST /train/start` could both hold it, both see the slot free, and
both spawn jobs — sharing/overwriting one status+cancel and orphaning a task
handle.
Extracted `claim_training_slot`, which does the check-and-set in ONE `status`
mutex scope — the atomicity lives on the status mutex, not the coarse state
lock — so concurrent starts serialise and exactly one wins. This also makes it
unit-testable without a full AppState.
Test: 32 threads hit a barrier and race to claim; asserts EXACTLY ONE wins.
Mutation-proven — reverting to the split check-then-set makes it fail
(`left: 3, right: 1`), and it returns to 1 with the fix.
Verified on aarch64/macOS: training_api 28 pass (26 existing + 2 new), full
python/tests suite 237 pass (227 + 10). The native module keeps its internal
assert as a defence-in-depth invariant; the binding now enforces it at the edge.
Co-Authored-By: Ruflo & AQE
A cross-vendor review of the parity rework (2febbb81) found three issues; all
verified and fixed here.
1. HIGH — the native≈golden half never ran in CI, so a binding marshalling bug
could pass. The golden vectors were regenerated through the Python binding,
and only pytest (binding vs that golden) runs in CI — the native reference
tests in `python/tests/aether_parity.rs` link against the PyO3 crate and no
workflow runs them. A stable PyO3 conversion defect present at regeneration
would therefore be baked into the golden and go undetected.
Fix: a real native parity test IN the `wifi-densepose-aether` crate
(`tests/golden_parity.rs`), which is std-only and a member of the v2
workspace, so it runs under the existing `cargo test --workspace`. It
recomputes the embedding with no PyO3/marshalling and asserts it matches the
SAME committed golden within tolerance. Now native≈golden AND binding≈golden
both run in CI ⇒ binding≈native, and a binding-specific artifact in the
golden surfaces here as a native mismatch. serde_json added as a
dev-dependency only (test-only; never linked into the lib or the wheel, so
the crate stays runtime-dependency-free).
Independently proven at this commit: native output equals the committed
golden BIT-FOR-BIT (128/128 exact bits, Δ=0) for both base and loaded — the
golden is native-faithful today; this test keeps it that way.
2. MEDIUM — the Python parity helper passed non-finite output. `abs(nan - b) >
tol` is False, so an all-NaN embedding slipped through. Now every element
must be `math.isfinite` first. Proven: an all-NaN vector is rejected
("element 0 is not finite (nan)"); the Rust helpers already caught it via
`<=`.
3. LOW — a coherent shift inside the per-element tolerance could move the whole
vector undetected. Added a whole-vector cosine-similarity bound (≥ 1 - 1e-6)
alongside the per-element check.
Verified on aarch64/macOS: `test_aether` 13, full `python/tests/` suite 227
passed against a `--features sota` build; the new native test passes
(2/2) run standalone (the in-worktree `cargo test -p` only failed on an
un-checked-out submodule; ci.yml checks out submodules recursively).
Co-Authored-By: Ruflo & AQE