mirror of
https://github.com/ruvnet/RuView.git
synced 2026-10-22 06:32:35 -05:00
5a97ebe09e111fe9112d87e5577633ce48400c82
113
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5a97ebe09e | Add frozen predictive transfer experiment and record failed utility gate | ||
|
|
acddd777a7 |
Add gated active evidence loop, KGE proposals and predictive CSI experiments
Record ADRs 421 to 423, actual dependency integration, bounded input and evidence authority, duration evaluation, security regressions and measured receipts. Preserve negative predictive and caching results; no model promotion. |
||
|
|
e2cff64cb3 | feat(inference): validate explicit native ACF reduction runtime | ||
|
|
ab25f5466d | feat(inference): add validated optional mixed classifier runtime | ||
|
|
e652359c5c | perf(inference): accelerate retained ACF runtime with verified direct reductions | ||
|
|
46895cc603 | test(inference): preserve buffered ACF prototype and failed speed gate | ||
|
|
b39a0b2a2c | feat(training): compact retained ACF model and record spatial ablation | ||
|
|
4ec8a86f5d |
Audit activity labels and evaluate native CSI resolution
Preserve native source precision and exact pooled controls under the original training and development split. Add an 18-configuration resolution ablation, input provenance and artifact tests, and measured results retaining the existing ACF model. Document unresolved semantic labels and confirmation limits. |
||
|
|
56e5ae1a6d |
Explore RuField and WorldGraph with bounded CSI context experiments
Retain the stronger ACF model after an 18-configuration temporal ablation regresses on development data. Add a pinned actual-library integrity probe, strict bounded replay inspection, measured synthetic overhead, and CI tests. Preserve source hashes and separate software integrity from sensing accuracy. |
||
|
|
6e5c72fc93 | Retain motion ACF research candidate with worst-room selection and measured gates | ||
|
|
b7b76de1f3 | feat(csi): freeze source-backed motion ablation and record rejected mean-score candidate | ||
|
|
b3937732e5 | perf(csi): add verified buffered inference runtime and parity benchmark | ||
|
|
d8c4ff9032 | perf(training): halve seeded RFF model state with verified float32 inference | ||
|
|
1f3039ef26 | perf(training): encode fixed RFF maps by seed and record rejected blend | ||
|
|
dd9b74af3a | Add frozen nonlinear CSI search and audited SOTA evidence | ||
|
|
1a52823c82 | feat(training): improve development macro F1 with isolated spectral model search | ||
|
|
648d180e19 | feat(training): public CSI activity optimization with leakage guards and measured inference folding | ||
|
|
2d8d88a1ef | feat(training): add reproducible CSI encoder harness and evidence contracts | ||
|
|
2c1222789d | Merge remote-tracking branch 'origin/main' into codex/toolkit-release-20261012 | ||
|
|
3620abff12 |
fix(toolkit): integrate capture and device corrections for 0.9.2
Integrate reviewed source PRs #2201-#2223, #2225-#2231, #2235-#2240, #2242 and #2243 (firmware README hunks remain in #2247). Regenerate one package manifest after integration, validate native Windows test execution, bound MTK listener startup, support official C6 release bundles, and retain stronger release metadata gates. |
||
|
|
8a140c1906 | fix(docs): harden README visual XML and path validation | ||
|
|
4696804b23 | docs: add Cognitum-style animated RuView visual system | ||
|
|
a72174c571 |
fix: review findings and cross-PR integration fixes for aepod release set
- mediatek: cap per-device maps at 64 with oldest-first eviction; clamp --csi-ring - training: mark live-buffer fallback runs degraded (data_source/degraded) instead of plain "completed" - multistatic: skip CIR blend when any frame in the cohort has a placeholder phase - groundtruth: median count baseline; radar labels carry evidence=CLAIMED - spatial-evidence: default proof CODE; MEASURED requires a reproducer - scripts: collect-ground-truth guards non-JSON replies and unreadable token files - docker: entrypoint accepts 1/true/yes/on for RUVIEW_UDP_INSECURE_LAN - adaptive model: untrack v2/data/adaptive_model.json (#2135) - docs: ADR-379 evidence tags, RUNBOOK/README OTA wording, NOTICE for vendored MediaTek patch - tests: fresh timestamps for privacy tests (#2119 staleness), plan_source Result handling, drop obsolete qualcomm-binds-nothing test (#2126), ignore slow live-binary test (#2157) Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
9f0821cf69 | Merge PR #2104 (aepod) into release integration | ||
|
|
b6c2fb5b7d | Merge PR #2116 (aepod) into release integration | ||
|
|
b3d31510ee | Merge PR #2130 (aepod) into release integration | ||
|
|
7af5477f04 |
fix(scripts): parse the ADR-018 header layout in the UDP capture scripts
Both capture scripts decoded a header layout the firmware does not send. csi_collector.c and esp32_parser.rs use: magic u32 @0, node_id @4, n_antennas @5, n_subcarriers u16 @6, freq_mhz u32 @8, sequence u32 @12, rssi i8 @16, noise_floor i8 @17, ppdu_type @18, flags @19, then n_antennas * n_subcarriers int8 I/Q pairs from @20. - collect-training-data.py read a 16-byte header and int16 I/Q, so its length check rejected every real single-antenna frame. It now reads the 20-byte header and int8 pairs, records freq/channel/seq/ppdu/flags, and lets the recorder stamp receive time (the header has no timestamp). - record-csi-udp.py read rssi from byte 6 and channel from byte 7 (the n_subcarriers bytes) and treated bytes 8-19 as I/Q, so a 64-subcarrier frame came out as 70 subcarriers with header bytes in the first six amplitudes. It now checks the magic, reads the real fields, and writes only the I/Q block to iq_hex. - Add scripts/tests/test_capture_adr018.py, which builds frames with the esp32_parser.rs test layout and checks the decoded fields. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
84f5e19e9d |
fix(scripts): run the proof with python3 and report INCOMPLETE when a gate is skipped
prove.sh looked only for `python`, so on macOS (python3 only) it skipped the deterministic proof and still printed RESULT: PASS with exit 0. - Pick $PYTHON, then python3, then python. - Check numpy/scipy import before running verify.py and print the lockfile install command when they are missing; warn when installed versions differ from archive/v1/requirements-lock.txt. - Run verify.py single-threaded, as CI does. - Hard gates that cannot run (no cargo, no Python, missing deps) are reported as [NOT RUN] and the run ends INCOMPLETE with exit 2. Data/hardware-gated claims are unchanged. - Tell people to stop any local server on UDP 5005 first (#2086). Fixes #2095 Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
ea6da967d2 |
docs(mediatek): OpenWrt WN586X3 CSI patch set, router CSI guide, ADR-266 amendment
- firmware/openwrt-wn586x3/: the patch set that made a Wavlink WL-WN586X3 Rev A (MT7981B + MT7976C) emit CSI on OpenWrt 24.10.8. It contains: MediaTek's mt7915 CSI driver patch rebased onto the mt76 revision 24.10.8 pins (BSD-3-Clause-Clear, MediaTek author line kept); the Rev A board patch (GPL-2.0); a buffer-overrun fix for `mt76-vendor dump csi`; and an attribute-enum fix for MtkCSIdump. Each patch keeps the licence of the code it modifies. There are no images, firmware blobs, or captures. - docs/mediatek-router-csi.md: an operator guide covering supported silicon, the image build route that was tested, arming CSI, the bridge, `--source mediatek`, endpoints and provenance labels, what the data is not, evidence, and troubleshooting. Every claim is tagged MEASURED, CODE-DERIVED, CLAIMED, or SYNTHETIC. - scripts/mediatek-csi-phase-stability.py: a read-only reproducer for the one MEASURED offline result. On one MT7976C radio, the cross-chain phase arg(H0*conj(H1)) moves 0.014-0.039 rad (p50) between adjacent frames for well-sampled transmitters, against about 1.56 rad for raw per-chain phase, which is what random phase gives. It never prints a transmitter address. The captures it was run on are not in the tree. - ADR-266 Amendment 1: vendor CSI exists on MT7981 through MediaTek's public feed patch, demonstrated on one board model, and still `mediatek:physical-unvalidated`. The hardware gates remain open. - user-guide.md and the bridge README link to the guide. Developed in whitsentry, a RuView-based project. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
43f5f99108 |
fix(scripts): send the API token from collect-ground-truth and check the reply
With authentication enabled, collect-ground-truth.py could not start a CSI
recording: it sent no bearer token. It also treated any HTTP 200 as success,
but the recording endpoints answer 200 with {"success": false, "error": ...}
for refusals such as "recording already in progress". Either way it went on
capturing camera keypoints with no paired CSI and only printed a warning.
- Read the token from --token-file, else RUVIEW_API_TOKEN, and send it as
Authorization: Bearer on start and stop.
- post_json() returns False when the body says success: false.
- Name the CSI recording gt_<timestamp> so it pairs with
keypoints_<timestamp>.jsonl.
- Exit with an error when the recording cannot start, unless
--allow-no-csi is given.
Tests: py_compile; scripts/tests (15 passed); a local smoke test against a
stub HTTP server checked the bearer header, the request id, the
success:false refusal, and token precedence (file, then env).
Co-Authored-By: claude-flow <ruv@ruv.net>
|
||
|
|
8cd8742d2b | Add bounded RTL8721Dx RAC1 CSI ingest to current RuView main | ||
|
|
2c3a924231 |
fix(training): export the real contrastive lossHistory/duration, not a no-op baseline pass
scripts/train-ruvllm.js ran two separate computations during contrastive pretraining: ContrastiveTrainer.train() (a baseline pass that computes loss but never updates the encoder) and a hand-written loop that actually applies gradient updates to encoder.w2. The exported training-metrics.json took lossHistory and contrastive.durationMs from the first (no-op) pass instead of the second (real) one, so the published curve was flat/meaningless (~0.1352 for all 20 epochs) and the duration was ~30x too short. This did not affect finalLoss/improvement or the held-out temporal-triplet accuracy metric published for this model on HuggingFace (ruvnet/wifi-densepose-pretrained) -- those already came from the real loop. It only affected the diagnostic curve/duration anyone auditing convergence from the published JSON would see. Also: config.json's training.steps field (epochs * triplets, technically consistent but reads like an optimizer-step count) is now reported as separate epochs/tripletUpdatesPerEpoch fields, and the exported version bumped 1.0.0 -> 2.0.1 to match the "v2" naming already used elsewhere for this file set. Verified by re-running against the real capture (data/recordings/overnight-1775217646.csi.jsonl): lossHistory now shows a genuine decreasing curve (0.1037 -> 0.0654 across 20 epochs, matching the already-published finalLoss exactly), durationMs reports the real ~40s gradient-loop time instead of ~12s. Model card updated with the same disclosure (docs/huggingface/MODEL_CARD.md) plus a real, previously-undisclosed EWC forgetting-rate figure (32.97%, present in training-metrics.json but not surfaced in the human-readable card) and a corrected repro-script pointer. |
||
|
|
de099c1f2d |
feat: train real fal.ai synthetic visual teacher LoRA (ADR-353)
feat: train real fal.ai synthetic visual teacher LoRA (ADR-353) |
||
|
|
5c50fa8588 |
feat: train real fal.ai synthetic visual teacher LoRA (ADR-353)
Trains a real fal.ai LoRA fine-tune (fal-ai/flux-lora-fast-training) on frames extracted from the real fal.ai-generated room-visualization MP4s already captured this session, so display-layer generation has a specific trained style target instead of prompt engineering against a stock model. Architecture boundary: this model only ever produces supplementary synthetic visual/pixel output. It has no path into measured/derived RF, pose, vitals, identity, or confidence values, which remain local and authoritative. Real run: request 01a060b2-c940-7972-abf9-ea48847eb2ae, 1000 steps, 27 training images, ~$2.04 spend, validated with a real inference call against the trained LoRA (assets/fal-visual-teacher-sample.png). |
||
|
|
f19938a7b6 |
docs(ruforecast): real zero-shot pretrained-checkpoint comparison beats naive baselines
Chronos-Bolt (base/small), Chronos-T5-small, and TimesFM-2.5-200M run zero-shot (no fine-tuning) on the same BIDMC cross-entity test windows, baselines, and WQL/MAE metrics as the prior from-scratch RuForecast BIDMC result. Unlike every from-scratch RuForecast configuration tried this session, all four pretrained checkpoints beat both last-value and seasonal-naive baselines on WQL, on both independent patient-partition judges (12-42% margin), consistent with the massive-pretraining-corpus hypothesis from the prior literature pass. |
||
|
|
e5bf0d4892 |
feat(forecast): add independent Rust multivariate training stack (#1766)
* feat(forecast): add independent Rust training stack Signed-off-by: Codex <codex@openai.com> * docs(forecast): record informal HPO exploration note (unaccepted) Records an exploratory Darwin Mode numeric-genome hyperparameter search against the tiny_ci synthetic accuracy protocol: WQL improved 0.257 -> 0.161 -> 0.153 over two search rounds, staying ahead of both baselines throughout. Explicitly scoped as informal/exploratory (not a frozen leakage-free report, not eligible for the evidence ledger, not validated for large_linux or any real dataset) per this doc's own evidence-tagging discipline. * feat(forecast-core): add per-horizon weighted quantile loss weighted_quantile_loss collapses the whole horizon into one aggregate number, hiding whether error grows with lead time. Add a sibling function using the identical per-cell pinball formula and domain checks, just reduced per horizon step instead of globally. A unit test reconstructs the aggregate from the per-step numerators/ denominators to prove the two functions agree exactly, not just approximately. * feat(forecast-model): add evaluation-only local activation Adds activate_for_evaluation and build_eval_input, gated behind the cpu feature. activate_for_evaluation self-signs an unsigned candidate with a fixed, publicly-known, non-secret Ed25519 key so a CLI operator can run inference against their own just-trained candidate without a real release signature -- explicitly never a production trust path, documented as such in the module doc comment. The schema-digest check in ArtifactActivationPolicy still applies in full; only signing is relaxed. build_eval_input constructs a single-window ModelInput for CPU inference from raw context-major values/mask arrays, matching the training batch builders exact time-feature/descriptor encoding. Six unit tests cover: malformed-candidate rejection, digest-mismatch rejection (proving the schema check has teeth even on this relaxed path), getting past the policy gate with a matching digest, and eval-input shape validation. * feat(forecast-train): add evaluate and prepare-synthetic-dataset CLI Turns this sessions throwaway HPO scripts into real, tested CLI surfaces, replacing two example binaries that bypassed the CLI/TOML training path entirely. prepare-synthetic-dataset generates a larger, configurable synthetic training shard (default 24 windows) plus a matching train-local.toml with the given OptimizerSpec hyperparameters baked in, and a separate held-out test.jsonl -- the same synthetic-only, local-validation-only posture as prepare-local-example, just bigger and configurable. evaluate scores a trained (unsigned) candidate against held-out windows and the LastValue/SeasonalNaive baselines: overall weighted quantile loss, a per-horizon breakdown, 80% interval coverage, and missingness, for the model and both baselines. Explicitly lists what docs/benchmarks/ruforecast.mds full accuracy protocol additionally asks for that this does not cover (abstention coverage, selective risk, site/device slices, interference regime, RuVector-retrieval ablation) rather than silently omitting them -- each needs infrastructure a single-entity synthetic fixture does not have. Together the three real commands (prepare-synthetic-dataset, train-local, evaluate) reproduce the exact WQL numbers the old library-bypassing example scripts produced for the same hyperparameters, confirmed by re-running the harness/ruview HPO dry-run end to end against the new CLI path. New integration test trains a real candidate via smoke, evaluates it against held-out synthetic windows, and asserts the full report shape and an empty-input rejection. * feat(forecast-train): add prepare-synthetic-dataset --seed + Autogenous bridge --seed (default 0, backward compatible) makes prepare-synthetic-dataset's generator deterministic per offset: same seed -> byte-identical corpus across runs (needed to train two genomes on the SAME corpus for a fair comparison); different seeds -> genuinely independent corpora (needed for honest multi-seed/multi-judge evaluation upstream, both in harness/ruview/flywheel/ruforecast/gate.mjs's fitness function and in the new v2/crates/ruforecast-autogenous-bridge crate added here). ruforecast-autogenous-bridge is a LOCAL-DEV-ONLY (excluded from the v2 workspace, publish = false) bridge from this crate's real evaluate CLI into ruvnet/autogenous's new regression-candidate promotion path (separate, unpushed branch feat/regression-candidate-kind): runs N independent train+evaluate judges on genuinely distinct synthetic corpora, signs receipts, and gets a real cryptographically-verified PROMOTE/REJECT decision -- defense in depth on top of, not a replacement for, Darwin's own promotion gate. Path-depends on a sibling autogenous checkout that does not exist in CI; build/run directly via `cargo build --manifest-path crates/ruforecast-autogenous-bridge/Cargo.toml`. cargo test -p ruview-forecast-train --no-default-features --features cpu,cli: all green (unaffected existing tests + this backward-compatible addition). * docs(forecast): retract round-2 HPO result, record honest multi-seed finding The earlier "Informal HPO exploration note" claimed a real improvement (WQL 0.257 -> 0.153) from a 3-round hyperparameter search. That search evaluated every candidate against one fixed synthetic corpus (seed 0) for every round -- textbook overfitting. Independent verification against two fresh corpora (via the new ruforecast-autogenous-bridge crate) showed the "winner" losing to the baseline on both. Fixed the root cause in harness/ruview/flywheel/ruforecast/gate.mjs: candidates are now scored against three independent corpora, worst-case across them, not one fixed corpus. Re-ran the search under the fix. It found a new winner that genuinely beat baseline on all three of its own search seeds -- and that winner ALSO lost independent verification on fresh seeds. Two independent search rounds, pre- and post-fix, both produced an illusory "winner." The honest reading: at this dataset scale (24 synthetic windows) held-out WQL varies enormously by which corpus is drawn, regardless of hyperparameters -- confirmed directly by the baseline genome's own primary swinging from 0.83 to a full regression across the three fixed search seeds with unchanged hyperparameters. No RuForecast hyperparameter configuration has been shown to reliably beat the trivial baselines out-of-sample at this scale. Also fixes a real design inconsistency surfaced by this exploration: the Autogenous regression-candidate promotion verifier (envelope::regression::verify_regression_promotion, separate unpushed ruvnet/autogenous branch feat/regression-candidate-kind) required all judges to share one corpus_id, which conflicts with this kind's intentional cross-corpus judge design. Corrected there (commit bfa4c48); did not change either REJECT verdict, which were already driven by the real NotBetterThanParent signal on their own. Append-only: the original round-2 row is kept, read together with this new amendment section, per this doc's own evidence-ledger discipline. * refactor(forecast): extract RuForecast to ruvnet/RuForecast submodule Mirrors the v2/crates/worldgraph pattern: RuForecast becomes its own independent public repo/workspace (ruforecast-core/model/train), mounted at v2/crates/ruforecast as a git submodule, with v2/Cargo.toml path-depping into its sub-crates and excluding the submodule from the v2 workspace. Full v2 --workspace check passes; the ruforecast CLI builds and runs correctly from its new location. Real git history for the extracted crates (7 commits) was preserved via git-filter-repo, not squashed. * feat(autogenous-bridge): real-data independent verification tool real_data_verify.rs: signs two real, temporally-independent judge measurements (different train/test split boundaries on the same real household vitals corpus, not synthetic seeds) through the real Autogenous regression-candidate promotion path, and gets a genuine cryptographically-checked PROMOTE/REJECT verdict. Result recorded (see docs/benchmarks/ruforecast.md): REJECT. One judge nominally beat the trivial baseline but by less than the 0.01 non-inferiority margin; the other judge lost outright. Consistent with every synthetic-data search this session -- no configuration has yet been shown to reliably beat trivial baselines out-of-sample, now including a real 6390-sample household corpus. Bumps the ruforecast submodule to pick up the evaluate real-gap fix. * docs(forecast): record real-household-data result (REJECT, signed) 6390 real vital-signs samples, two independent temporal splits, independently verified via the real Autogenous regression-candidate promotion path. Signed verdict: REJECT -- neither split cleared the non-inferiority margin. Same conclusion as every synthetic search this session, now confirmed with real data too: more real data is the credible next lever, not further search on this scale of fixture. * chore(forecast): point ruforecast submodule at published main (post gap-tolerance fix) * ci(forecast): fix ruforecast-ci.yml for the new v2/crates/ruforecast submodule layout The RuForecast crates were extracted into a standalone submodule (v2/crates/ruforecast, mirroring the existing v2/crates/worldgraph pattern) and are no longer members of the v2 workspace. The CI workflow still referenced the old in-tree package names/paths (ruview-forecast-core/model/train under v2/), which broke every forecast job with "cannot specify features for packages outside of workspace". Fixed every job to target the submodule: working-directory -> v2/crates/ruforecast, -p ruview-forecast-* -> -p ruforecast-*, all hardcoded Cargo.toml/source paths in the Python assertion and clean-room-scan blocks, the Swatinem/rust-cache workspaces input, the artifact-tree output paths, and the two levels of relative path (../ -> ../../) in the informational-benchmark steps whose working directory moved one level deeper. Also collapsed the paths: trigger filters internal-crate globs (v2/crates/ruview-forecast-*/**) down to the single v2/crates/ruforecast path, since GitHub Actions path filters only ever see a submodule gitlink change as one entry in the parent tree, never its internal file paths -- the old globs could never have matched anything. Includes a real cargo fmt fix (submodule commit d9902f9) for formatting drift left over from the earlier real-data gap-tolerance fix, which the contract job's fmt --check step would otherwise have failed on. All four forecast CI jobs' real commands verified locally before push: cargo test/check for CPU, CUDA/WGPU compile-check, the contract job's Python assertion block, the hosted-boundaries clean-room scan, and cargo fmt --check. * docs(forecast): record real BIDMC cross-entity holdout result (REJECT) Two independent real-patient partitions (34/16 and 24/26 splits, 53 total ICU patients from PhysioNet BIDMC, Open Data Commons Attribution License v1.0) both show the model losing to trivial baselines by a decisive margin (+69% and +601% worse WQL). First genuine cross-entity real-data test this project has run; same conclusion as every prior synthetic and single-household test. Full Autogenous signed verification was not run for this entry - flagged explicitly in the note. * chore(forecast): point ruforecast submodule at published main (example feature-gate fix) * chore(forecast): point ruforecast submodule at published main (clippy fix) --------- Signed-off-by: Codex <codex@openai.com> |
||
|
|
0370d49e4a | feat: add physics-constrained pose refinement | ||
|
|
ba978041ae |
Merge remote-tracking branch 'origin/main' into resolve-1579-conflict
# Conflicts: # docs/adr/README.md |
||
|
|
34c9804002 |
feat: implement ADR-292/293/294/295/296 — provenance, UDP hardening, multi-node, model gates, CSI policy
ADR-292 (sensing-server): SourceState enum + pure transition (provenance.rs); auth-error/unknown can never resolve to LiveVerified; synthetic exports watermarked. Pose-fusion simulator starts SYNTHETIC and only shows LIVE on a real decoded frame (#1557); sensing client no longer labels an unauthorized status endpoint as live (#1526). ADR-294 (sensing-server): NodeInference distinct from RoomInference (inference.rs); deterministic freshness-weighted fuse_room; RateLimiter re-keyed to (NodeId,EntityKind) so nodes do not starve each other (#1541); stale nodes go unavailable not frozen-online (#1555). ADR-293 (sensing-server): --udp-bind (default 127.0.0.1) + --udp-allow allowlist + fail-closed refusal of routable bind without allowlist unless --udp-insecure-lan (udp_bind.rs); crate SECURITY.md documents the threat model and the deferred per-device-auth step two. ADR-295 (train): model_gates.rs — constant-output, unreachable-boundary (the issue-1521 degenerate presence head), class-balance, baseline, and metric-name-provenance gates. ADR-296 (ci): scripts/csi-data-policy-check.sh (+ allowlist) and a workflow that fails on tracked CSI-format/oversized-JSONL files; 6/6 self-tests pass. Per-crate suites reported green by the swarm; CSI policy self-test 6/6 and JS syntax verified here. Full workspace re-verification deferred until the concurrent phase-1 spine build frees the target dir (disk pressure). Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_015TcKegTS7QqhWPC2L2SzaS |
||
|
|
5780c239e4 | security: repair scanning and close stale alert sources | ||
|
|
6fd185f8ce |
ci(python): gate python/ package in main CI + add fix-marker guards for filename-collision and wheel-budget regressions
The python/ PyO3+maturin wheel (wifi-densepose, ADR-117/185) had ZERO
per-PR CI coverage: pip-release.yml only fires on release triggers, so a
PR could break the wheel build, a native-Rust parity test, or the wheel
budget and nothing in the gating CI would catch it until release day.
New .github/workflows/python-ci.yml (path-scoped to python/** + the
backing crates, following the repo convention cf. firmware-ci.yml --
GitHub has no per-job paths filter and no workflow here uses a
change-detection action, so a dedicated path-scoped workflow is the
idiomatic, no-new-dependency choice):
* parity-tests: cargo build of the aether/mat/train backing crates
(fast-fail attribution), then `maturin develop --features sota` +
`pytest python/tests/ -q`. sota builds the aether/meridian/mat
compiled submodules so their SHA-256 parity tests against native
Rust actually run (those test modules import the submodules at
collection time -- without the features they error, not skip).
* wheel-size-budget: builds the DEFAULT (no-features) wheel and fails
if it exceeds the ADR-117 5.4 5 MiB budget -- the real numeric
enforcement a string fix-marker cannot provide.
Two fix-marker guards (scripts/fix-markers.json):
* RuView#1387-rvf-filename-collision: training_api.rs next_model_id()
must keep the microsecond timestamp (%6f) + AtomicU64 counter; the
forbid uses a negative lookahead so it fires only on a bare
second-resolution format lacking the disambiguator. Guards the
CI-caught collision fixed on this branch in
|
||
|
|
c0d3d7c792 |
chore(firmware): add release guard against stale-sdkconfig partition mismatch (#1194)
While cutting v0.8.3-esp32, an incremental 8MB build reused a leftover generated `sdkconfig` and silently linked the 4MB dual-OTA partition layout (no spiffs, ota_1 @ 0x1F0000) — the would-be released `partition-table.bin` did not match the 8MB `partitions_display.csv` it claimed. scripts/firmware-release-guard.sh regenerates the expected partition table from the CSV the named flash-size variant must use and byte-compares it to the built `partition-table.bin`, and cross-checks flash size in flasher_args.json. Fails closed so a release pipeline can't ship a mismatched table. Usage: scripts/firmware-release-guard.sh <8mb|4mb> <build-dir> Claude-Session: https://claude.ai/code/session_01AgpTcBLRJ32hUsKWxDXf36 |
||
|
|
15a983b555 |
fix(paired-data): 4 bugs corrupting/blocking camera-supervised training data (#1007)
1. record-csi-udp.py stamped LOCAL time with a 'Z' (UTC) suffix → camera/CSI disagreed by the UTC offset → 0 aligned pairs. Now writes true UTC via datetime.now(timezone.utc). 2. align-ground-truth.js kept empty-keypoint (non-detection) records at confidence 0, collapsing window avgConf below threshold → all windows rejected. Now skipped at load. 3. extractCsiMatrix silently zero-padded/truncated mixed-subcarrier frames. Now frames are filtered to the session's modal subcarrier count before windowing — never padded. 4. CSI/feature matrices are filled frame-major but were labeled shape [nSc, nFrames] — transposed. Labels corrected to [nFrames, nSc] / [nFrames, dim]. Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
1a17cc5b06 |
docs(ADR-163): edge-latency RESULTS + PROOF/prove.sh wiring (T3)
Adds benchmarks/edge-latency/RESULTS.md (wiflow-std RESULTS style: each measured number with reproduce command, machine, MEASURED-on-host grade, and the honest host-vs-ESP32 / steady-state-vs-cold-start caveats) and ADR-163 (HEADLINE: CLAIMED latency budgets -> MEASURED-on-host, closing M5/M6 measurement debt; ESP32-on-hardware still pending). - ADR-160 deferred 'criterion benches for process_frame budget claims' line updated to DONE (host) with the ESP32-pending note. - PROOF.md performance table gains the two edge-latency reproduce rows; provenance ADR range extended to ADR-163. - prove.sh gated section gains the edge-latency bench note (host proxy only; not asserted, never claims the ESP32 figure). Benches/docs only; no crate republishes. 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> |
||
|
|
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> |
||
|
|
2a307138f2 |
feat: per-room calibration system (ADR-151) + cognitum-v0 appliance integration spec (#989)
* docs(adr): ADR-151 — Per-Room Calibration & Specialized Model Training Room-first calibration -> bank of small specialised ruVector models (breathing, heartbeat, restlessness, posture, presence, anomaly) distilled from the frozen Hugging-Face-published RF Foundation Encoder (ADR-150). Four-stage local-first pipeline: baseline (ADR-135 environmental fingerprint) -> guided enrollment (NEW EnrollmentProtocol, clean anchors not hours) -> feature extraction (reuse signal_features + ruvsense) -> specialist bank training (rapid_adapt LoRA heads, RVF storage, HNSW prototypes). Invariants: specialisation over scale; local heads over a shared public base; honest STALE degradation on baseline drift. Indexes ADR-149/150/151. Co-Authored-By: claude-flow <ruv@ruv.net> * feat(cli): calibration HTTP API for UI-driven baseline capture (ADR-135/151) Adds `wifi-densepose calibrate-serve` — an Axum HTTP API that wraps the ADR-135 CalibrationRecorder so a UI (or any client) can drive an empty-room baseline capture remotely. Stage 1 ("teach the room") of the ADR-151 room calibration & training pipeline. A single background task owns the UDP socket (ESP32 0xC511_0001 frames) and the optional active recorder; HTTP handlers talk to it over an mpsc command channel and read a shared status snapshot, keeping the &mut recorder lock-free. CORS permissive so a browser UI can call it. Endpoints (/api/v1/calibration/*): GET /health liveness + UDP ingest stats (frames_seen, streaming) POST /start { tier?, duration_s?, room_id?, min_frames? } GET /status live progress (state, frames, progress, z, eta) — poll for UI POST /stop finalize the current session early GET /result finalized baseline summary (amp/phase-dispersion averages) GET /baselines list persisted baseline .bin files Reuses the existing calibrate.rs ESP32 wire parser (made pub(crate)); honest abort when <10 frames arrive in the window (e.g. ESP32 not streaming). Verified end-to-end over loopback: start -> 300 replayed HT20 frames -> state=complete, 52-subcarrier baseline, phase_dispersion_avg=0.00096 (concentrated/valid), persisted to disk; all 6 endpoints exercised. CLI: 19 tests pass; crate builds clean. Co-Authored-By: claude-flow <ruv@ruv.net> * test(cli): firewall-free CSI UDP relay for local Windows ESP32 testing Windows Defender blocks inbound LAN UDP to a freshly-built binary without an admin allow-rule; python.exe is already allowed. This relay binds the public CSI port and forwards each datagram verbatim to a loopback port where `calibrate-serve --udp-bind 127.0.0.1 --udp-port 5006` listens (loopback is firewall-exempt). No admin required. Validated: ESP32-format 0xC5110001 frames -> :5005 -> relay -> :5006 -> calibrate-serve -> state=complete, 52-subcarrier baseline, phase_dispersion_avg=0.00098 (clean). Completes the no-admin live-test path. Co-Authored-By: claude-flow <ruv@ruv.net> * docs(changelog): record ADR-151 calibration API (calibrate-serve) Co-Authored-By: claude-flow <ruv@ruv.net> * feat(calibration): ADR-151 Stages 2–5 — enrollment, extraction, specialist bank, runtime New crate wifi-densepose-calibration implementing the per-room pipeline beyond Stage-1 baseline: - anchor.rs: guided-anchor sequence + event-sourced EnrollmentSession (Stage 2) - enrollment.rs: AnchorQualityGate + AnchorRecorder — gates anchors against the ADR-135 baseline deviation (presence/motion), re-prompts bad captures - extract.rs: Features + AnchorFeature — autocorrelation periodicity (breathing/ HR bands), variance/motion (Stage 3) - specialist.rs: 6 small room-calibrated models — presence (learned threshold), posture (nearest-prototype), breathing/heartbeat (band periodicity), restlessness (calm/active normalization), anomaly (novelty vs anchors) (Stage 4) - bank.rs: SpecialistBank — train/persist + baseline-drift STALE invalidation - runtime.rs: MixtureOfSpecialists — presence short-circuit + anomaly veto + stale flagging (Stage 5) Statistical heads make the pipeline runnable/validatable today; the ADR-150 HF RF Foundation Encoder backbone is the documented upgrade path. 29 unit tests pass. Co-Authored-By: claude-flow <ruv@ruv.net> * feat(cli): wire ADR-151 enroll / train-room / room-status / room-watch Integrates the wifi-densepose-calibration crate into the CLI as four subcommands driving the full Stage 2–5 pipeline against a live ESP32 raw-CSI stream (edge_tier=0): - enroll: walks the guided anchor sequence, gates each capture against the ADR-135 baseline deviation (re-prompts bad anchors), writes labelled features - train-room: fits the SpecialistBank from the enrollment, persists JSON - room-status: prints a trained bank's summary - room-watch: live mixture-of-specialists readout (presence/posture/breathing/ heart/restless) over a rolling window, with anomaly veto + STALE flagging Per-frame scalar is the mean CSI amplitude (carries presence/motion + breathing modulation). Validated end-to-end on the live ESP32 (COM8, edge_tier=0): the real parser → feature extraction → runtime detected breathing (~16–31 BPM) on hardware. Full multi-anchor enrollment accuracy requires the operator to perform the poses; phase-based breathing extraction is a noted refinement. 48 tests pass (29 calibration + 19 CLI). Co-Authored-By: claude-flow <ruv@ruv.net> * docs(adr-151): mark Stages 1–5 implemented; expand CHANGELOG Co-Authored-By: claude-flow <ruv@ruv.net> * fix(cli): keep proven mean-amplitude carrier for room features The max-variance-subcarrier carrier locked onto motion artifacts (not breathing) and also had an out-of-bounds bug on variable CSI subcarrier counts. Reverted to the mean-amplitude carrier, which is validated live to detect breathing. Phase-based extraction on a stable subcarrier remains the proper higher-SNR refinement (ADR-151 §4). Co-Authored-By: claude-flow <ruv@ruv.net> * feat(calibration): multistatic fusion of co-located nodes (ADR-029/151) MultiNodeMixture fuses several co-located nodes (each with its own room-calibrated SpecialistBank) into one RoomState: - presence: OR across nodes (any node seeing a person wins) - posture/breathing/heartbeat: highest-confidence node (best viewpoint) - restlessness/anomaly: max across nodes - veto: any node's physically-implausible signal vetoes the room's vitals (anti-hallucination, same as single-node runtime) + presence short-circuit - stale: any node's STALE flag propagates Same-room multistatic only; cross-room is federation (ADR-105), not fusion. 6 unit tests (presence OR, best-confidence breathing, single-node veto, staleness). 35 calibration tests pass. Co-Authored-By: claude-flow <ruv@ruv.net> * feat(cli): multistatic room-watch — fuse co-located nodes (ADR-029/151) `room-watch --node-bank N:path` (repeatable) groups live CSI frames by node_id and fuses per-node banks via MultiNodeMixture. Validated live on COM8 (node 9, edge_tier=0): frames grouped + fused end-to-end. True 2-node fusion is covered by unit tests; a second raw-CSI node is the hardware blocker. 54 tests pass. Co-Authored-By: claude-flow <ruv@ruv.net> * docs(integration): calibration → cognitum-v0 appliance integration overview Detailed cross-repo integration spec for cognitum-one/v0-appliance: data contracts (CSI wire format, ADR-135 baseline binary, enrollment/bank/RoomState JSON schemas), calibrate-serve HTTP API, public crate API, Pi5+Hailo tiering, and a 5-step appliance integration plan. Grounded in the verified cognitum-v0 inventory (aarch64, cargo 1.96, HAILO10H, ruview-vitals-worker:50054). Co-Authored-By: claude-flow <ruv@ruv.net> * fix(calibration): address PR review — aarch64 decouple, API auth, path traversal, throttle Resolves the review on #989: - **Cross-compile (the appliance blocker):** make wifi-densepose-mat optional and feature-gate it (`mat`), so `cargo build -p wifi-densepose-cli --no-default-features` excludes the mat→nn→ort(ONNX)→openssl-sys chain. Verified: `cargo tree --no-default-features` shows 0 ort/openssl deps → calibration cross-compiles clean for the Pi. - **Security (must-fix before LAN):** - `--token` / CALIBRATE_TOKEN bearer-auth middleware on every route; warns if bound non-loopback without a token. - sanitize client-supplied `room_id` to [A-Za-z0-9_-] (≤64) before it reaches the baseline write path — kills the `../` file-write primitive. + test. - **Perf:** stop locking shared status + cloning SessionStatus on every UDP frame — counters/snapshot flush on the 200 ms tick instead (no CPU starvation under flood). finalize write moved to async `tokio::fs::write`. - **Docs:** ADR-151 STALE wording matches the impl (baseline-id change; drift-threshold = P6 refinement); integration doc gets the `--no-default-features` build + auth/sanitize notes. 35 calibration + 15 CLI tests (no-default) / 20 CLI (default) pass. Co-Authored-By: claude-flow <ruv@ruv.net> * docs(worldgraph,worldmodel): add crates.io READMEs Plain-language overviews + feature lists, comparison tables (symbolic graph vs predictive occupancy; graph vs grid vs event-log), usage, and technical details. Adds readme = "README.md" to both manifests so they render on crates.io on the next release. Co-Authored-By: claude-flow <ruv@ruv.net> * release: worldgraph & worldmodel 0.3.1 (READMEs on crates.io) Co-Authored-By: claude-flow <ruv@ruv.net> * docs: precise calibration validation scope (capture+API+auth proven; clean enroll→train→infer not yet on-target) Aligns ADR-151 §7 + the appliance integration doc with the PR #989 scope clarification: nothing has run a clean baseline → enroll → train → infer on live CSI; the live breathing read used the stateless head, not a trained bank. Adds --source-format adr018v6 to the backlog. Co-Authored-By: claude-flow <ruv@ruv.net> * feat(calibrate-serve): live GET /room/state endpoint (mixture over CSI window) Adds a live RoomState readout over HTTP — the appliance UI's main need. The ingest task maintains a rolling per-frame scalar window (flushed on the 200 ms tick, no per-frame lock); the handler loads a bank (resolved as a sanitized name under output_dir — same path-traversal defense as room_id), runs the MixtureOfSpecialists over the window, returns RoomState JSON. Validated live (ESP32-S3 via relay): breathing 14-19 BPM over HTTP; a bank=../../etc/passwd query is neutralized to 'etcpasswd' (no traversal). Co-Authored-By: claude-flow <ruv@ruv.net> * feat(calibrate-serve): POST /room/train + fix AnchorLabel JSON to snake_case - POST /api/v1/room/train: { room_id, baseline_id, anchors[] } → trains a SpecialistBank and persists it as <output_dir>/<room_id>.json (path-sanitized), readable via /room/state?bank=<room_id>. Completes the HTTP train→infer loop. - Fix data-contract bug: AnchorLabel serialized as PascalCase variant names (serde default) while as_str() + the integration doc used snake_case. Added #[serde(rename_all = "snake_case")] so the JSON wire format matches the documented contract (empty/stand_still/…). Locked with a roundtrip test. Validated live (ESP32-S3): POST train (4 anchors → 6 specialists, persisted) → GET /room/state returns RoomState with the trained presence/restlessness; the synthetic-vs-real scale mismatch correctly triggers the anomaly veto. 36 calibration tests pass. Co-Authored-By: claude-flow <ruv@ruv.net> * feat(calibrate-serve): live enroll-over-HTTP (POST /enroll/anchor + /enroll/status) Closes the last HTTP gap — the appliance can now drive the ENTIRE calibration pipeline over HTTP without the CLI: baseline (start/stop) -> enroll/anchor x8 -> room/train -> room/state - POST /enroll/anchor { room_id, baseline, label, duration_s? }: the ingest task loads the baseline (sanitized name under output_dir), captures the anchor for the duration against it (AnchorRecorder + per-frame series), runs the quality gate, and on completion replies with the verdict + accumulates the AnchorFeature in an in-server enrollment map keyed by room_id. Re-prompts on rejection. - GET /enroll/status?room=<id>: accepted anchors, next, complete. - POST /room/train now falls back to the in-server enrollment when anchors[] is omitted. Validated live (ESP32-S3): capture baseline -> enroll stand_still (271 frames, 6s) -> gate correctly rejects "no person detected (presence_z 0.90 < 1.50)" relative to a same-occupancy baseline (a clean empty-room baseline is the documented on-target prerequisite). Builds clean; CLI tests pass. Co-Authored-By: claude-flow <ruv@ruv.net> * test(calibrate-serve): HTTP integration tests for the room/enroll endpoints Factor the router into build_router() (shared by execute + tests) and add tower-oneshot integration tests (no network/ingest needed): - health + descriptor → 200 - POST /room/train persists the bank; GET /room/state → 200; train with no anchors/enrollment → 400 - path-traversal: /room/state?bank=../../etc/passwd → 404 (sanitized, never reads outside output_dir) - enroll/status empty; /enroll/anchor with an unknown label → 400 CI regression coverage for the endpoints added this session. 18 CLI tests pass. Co-Authored-By: claude-flow <ruv@ruv.net> * fix(mat): make serde non-optional — unblocks `cargo test --workspace --no-default-features` Making wifi-densepose-mat optional in the CLI (for the aarch64/ort decouple) exposed a latent feature bug: mat's `api` module compiles unconditionally and uses serde, but `serde` was an optional dep enabled only via the `api`/`serde` features. Previously the CLI's *unconditional* mat dependency enabled those features transitively, so `--workspace --no-default-features` still got serde; once mat became optional+gated, the workspace build lost it → `error[E0432]: unresolved import serde` across mat's api/* (CI red). mat already pulls serde_json + axum unconditionally, so making `serde` non-optional has no real cost and restores the workspace build. Does NOT affect the aarch64 CLI build (mat isn't built there at all): verified `cargo tree -p wifi-densepose-cli --no-default-features` still shows 0 ort/openssl deps, and `cargo test --workspace --no-default-features` compiles clean. Co-Authored-By: claude-flow <ruv@ruv.net> * docs(claude.md): add wifi-densepose-calibration to crate table (pre-merge) Co-Authored-By: claude-flow <ruv@ruv.net> * docs(adr): ADR-152 — WiFi-pose SOTA 2026 intake (geometry-conditioned calibration, external benchmarks, encoder recipe) Records the 2026-06-10 deep-research run (22 sources, 110 claims, 25 adversarially verified: 24 confirmed / 1 refuted) and the decisions it implies: - §2.1 ACCEPTED: geometry-condition the ADR-151 calibration system — NodeGeometry at enrollment, geometry embeddings for future LoRA heads, PerceptAlign-style two-checkerboard camera↔WiFi alignment for the ADR-079 supervised path. PerceptAlign (MobiCom'26) names the failure mode ("coordinate overfitting") that matches our own ADR-150 cross- subject collapse. - §2.2 ACCEPTED: benchmark protocol vs external "WiFlow-STD (DY2434)" (claimed 97.25% PCK@20, Apache-2.0 weights+dataset) with a no-citation rule until measured on our 17-keypoint ESP32 eval set. Name collision with our internal WiFlow is disambiguated. - §2.3 ACCEPTED: amend ADR-150 training recipe per UNSW MAE study — 80% masking, (30,3) patches, data-over-capacity priority (log-linear, unsaturated at 1.3M samples). - §2.4 watch items: IEEE 802.11bf-2025 published 2025-09-26; esp_wifi_sensing as external presence baseline (drop-in claim REFUTED 0-3); ZTECSITool 160MHz/512-subcarrier anchor node (procurement-gated). - §2.5 NOT adopted: non-WiFi "foundation model" papers; DensePose-UV (no 2025-2026 work does UV regression from commodity WiFi). Every number is evidence-graded CLAIMED vs MEASURED in the source register. Re-check horizon 2026-12. Co-Authored-By: RuFlo <ruv@ruv.net> * test(calibration): full-loop integration test — baseline→enroll→train→infer proven in-process (ADR-151 §7 gap, software half) Closes the software half of PR #989's headline validation gap: the complete calibration loop had never run end-to-end anywhere, even in-process. tests/full_loop.rs (412 lines, deterministic xorshift32 room simulator, HT20/52-subcarrier/20Hz, same fingerprint family as the ADR-135 roundtrip test) now drives the CLI's exact stage order through the public API: 1. baseline — 600 static frames, zero motion flags post-warmup, calibration_uuid() exactly as the CLI derives it 2. enroll — all 8 AnchorLabel::SEQUENCE anchors through AnchorQualityGate::default(), session is_complete() 3. extract — AnchorFeature::from_series recovers injected 0.25Hz and 0.125Hz breathing within ±0.04Hz 4. train — SpecialistBank::train fits all 6 specialists; JSON round-trip and the runtime consumes the RELOADED bank 5. infer — positive: never-enrolled 0.30Hz subject reads present, 18±2 BPM; negative: empty window reads absent; degradation: foreign baseline_id flags STALE Seed-robust (5 seeds), passes with and without default features: 36 unit + 1 integration green. Validation docs updated (ADR-151 §7 + integration doc §7 matrix): what remains is strictly the on-target hardware session (real CSI, physically empty room, operator performing the guided anchors). Three behavioral findings from building the test are recorded for pre-session triage: z-band squeeze between baseline motion flagging (z>2.0) and the still- anchor gate (presence_z≥1.5) — likeliest on-hardware enroll failure; variance-only PresenceSpecialist missing motionless-person mean shift; ungated breathing_hz/heart_hz in noise-window embeddings. Co-Authored-By: RuFlo <ruv@ruv.net> * fix(calibration): close all four ADR-152 behavioral findings pre-hardware-session The full-loop integration test surfaced three findings; fixing the third exposed a fourth. All four are fixed and regression-guarded: 1. z-band squeeze (enrollment.rs) — anchor motion is now measured from frame-to-frame deltas of the deviation series (|Δz| > Z_DELTA_MOTION 0.5 ∨ |Δφ| > π/6), not from the absolute motion_flagged, which fires at amplitude_z_median > 2.0 vs the EMPTY baseline and so conflated presence strength with motion. A strongly-reflecting still person (z = 3.0 — every frame flagged by the old heuristic) now enrolls. The old unit tests mocked (z=3.0, motion=false), a combination the real deviation() can never emit — which is exactly how the squeeze hid; tests now derive the flag from z the way the producer does. 2. variance-only presence (specialist.rs) — PresenceSpecialist gains a mean-shift channel: present when variance > threshold OR |mean − empty_mean| > mean_dist_threshold (trained at half the empty→occupied mean distance, None when the means don't separate). Detects the motionless person whose body raises the scalar mean but not its variance. Old persisted banks deserialize with the channel inert (serde default None) — variance-only behavior preserved, proven by a fixture test against pre-change JSON. 3. ungated hz embedding (extract.rs) — Features::embedding() zeroes breathing_hz/heart_hz below EMBED_MIN_SCORE (0.25), keeping the random in-band peaks of noise windows out of the posture/anomaly prototype space. Raw fields stay ungated (specialists have their own stricter gates). 4. heart-band lag-floor leakage (extract.rs, found while fixing 3) — a pure 0.30 Hz breathing signal scored 0.67 in the heart band at 3.33 Hz: out-of-band rhythm leaks as a monotonic slope whose max sits at the band's lag floor, so score gating alone cannot stop it. autocorr_dominant now requires the winning lag to be an interior local maximum; band-edge "peaks" are rejected, true in-band peaks (interior by definition) are preserved. full_loop.rs strengthened to drive the fixes end-to-end: the StandStill anchor is now a z=3.0 strong reflector (unenrollable pre-fix), and a new motionless-person runtime case proves mean-channel detection at empty- level variance. Validation: 41 calibration unit + 1 full-loop integration + 23 CLI tests green; cargo test --workspace --no-default-features exit 0. Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
0d3d835bf8 |
feat(swarm): add ruview-swarm crate — drone swarm control system (ADR-148) (#862)
* feat(swarm): add wifi-densepose-swarm crate implementing ADR-148 drone swarm control system
New crate `wifi-densepose-swarm` with hierarchical-mesh swarm topology,
Raft consensus, MAPPO MARL, CSI sensing integration, and ITAR-gated
coordination features. Closes 3 of 7 milestones (M1, M2, M5) with 5/5
ADR-148 SOTA performance targets met.
## Modules (45 source files, 14 modules)
- types: NodeId, DroneState, Position3D, SwarmTask, SwarmError, FailSafeState
- topology: Raft consensus (leader election, log replication, quorum), Gossip, Mesh
- formation: VirtualStructure, LeaderFollower, Reynolds flocking (itar-gated)
- planning: RRT-APF hybrid planner, 3-phase coverage, Bayesian grid, pheromone
- allocation: Auction + FNN bid scorer (itar-gated)
- sensing: CsiPayloadPipeline (Live/Synthetic/Replay), MultiViewFusion, OccWorldBridge
- marl: MAPPO actor (3-layer MLP), LocalObservation (64-dim), RewardCalculator, PPO loop
- security: MAVLink v2 HMAC-SHA256, UWB anti-spoofing, geofence, Remote ID, FHSS
- failsafe: 10-state onboard machine, GCS-independent safety transitions
- config: TOML SwarmConfig with SAR/inspection/agriculture/mine/demo/wi2sar_reference
- demo: SyntheticCsiGenerator, DemoScenario (SAR/open-field/mine)
- integration: FlightController trait, MAVLink dialect (50000-50005), SwarmSim
- orchestrator: SwarmOrchestrator wiring all subsystems end-to-end
- bench_support: Criterion fixture generators
## ITAR compliance
Swarming coordination features gated behind `itar-unrestricted` feature
per USML Category VIII(h)(12). Default build compiles clean stubs.
## Benchmark results (criterion, release mode)
- MARL actor inference: 3.3 µs (target ≤ 5 ms — 1,516× headroom)
- RRT-APF planning (100 iter): 0.043 ms (target < 300 ms — 6,946× headroom)
- MultiView CSI fusion (3 UAVs): 58.5 ns (target < 10 ms — 171,000× headroom)
- 3-view localization: 1.732 m (target ≤ 2 m — beats Wi2SAR SOTA)
- 4-drone SAR coverage (400×400 m): 223 s (target ≤ 240 s — PASS)
## Tests
- --no-default-features: 73/73 passing
- --features itar-unrestricted: 85/85 passing
Closes #861
Co-Authored-By: claude-flow <ruv@ruv.net>
* refactor(swarm): rename wifi-densepose-swarm → ruview-swarm
The swarm control system is a RuView-level capability (drone coordination,
Raft consensus, MARL) that operates above the wifi-densepose sensing layer
rather than being a sub-component of it. Rename aligns with the project
identity and separates coordination infrastructure from sensing modules.
Co-Authored-By: claude-flow <ruv@ruv.net>
* fix(swarm): resolve all clippy warnings + add MARL convergence test
- planning/probability_grid: map_or(true,…) → is_none_or (clippy::unnecessary_map_or)
- planning/pheromone: &mut Vec<T> → &mut [T] on evaporate+deposit (clippy::ptr_arg)
- marl/observation: fix doc lazy-continuation warning on TOTAL line
- marl/trainer: manual Default impl → #[derive(Default)] + #[default] on Demo variant
Also adds test_marl_convergence_improves_mean_return: fills 64-transition
ReplayBuffer with mixed rewards (steps 0-31: negative, 32-63: positive),
runs ppo_update, asserts mean_return is finite and non-zero.
Result: 0 clippy warnings · 74/74 tests (default) · 86/86 (itar-unrestricted)
Co-Authored-By: claude-flow <ruv@ruv.net>
* feat(swarm): integrate Ruflo AI-agent capabilities into ruview-swarm
Adds a feature-gated Ruflo integration layer connecting ruview-swarm to the
claude-flow daemon's AgentDB, AIDefence, and SONA intelligence subsystems.
Default build is unaffected (all paths behind `Option<Box<dyn RufloBackend>>`).
## New module: src/ruflo/
- backend.rs: RufloBackend trait (9 async methods) + RufloError, MissionMemoryEntry,
PatternEntry, MavlinkScanResult types (always compiled)
- mock_backend.rs: MockRufloBackend in-memory impl for testing (always compiled, 5 tests)
- http_backend.rs: HttpRufloBackend — JSON-RPC 2.0 → claude-flow daemon localhost:3000
(gated behind `ruflo` feature, requires reqwest)
- mission_summary.rs: MissionSummary serializer with pattern description + confidence
scoring from victim recall, coverage %, collision penalty (always compiled, 3 tests)
## 4 capability areas
1. MissionMemory → memory_store / memory_search (cross-mission victim memory)
2. PatternLearner → agentdb_pattern-store / -search (HNSW SONA trajectory patterns)
3. MavlinkDefence → aidefence_is_safe / aidefence_scan (scan MAVLink before accepting)
4. IntelligenceHooks → trajectory-start/step/end (SONA learning loop)
## SwarmOrchestrator integration
- with_ruflo(backend): builder to attach a backend
- start_trajectory(task) / finish_trajectory(success, key): SONA mission lifecycle
- receive_peer_detection_checked(): AIDefence scan before accepting peer detections
## Cargo feature
`ruflo = ["dep:reqwest", "dep:serde_json"]` — optional, not in default
## Tests
- --no-default-features: 82/82 pass (8 new ruflo tests)
- --features ruflo,itar-unrestricted: 94/94 pass
Co-Authored-By: claude-flow <ruv@ruv.net>
* feat(swarm): M7 mission profiles with victim confirmation reports + pre-merge docs
Adds end-to-end mission runners producing structured MissionReport output,
and updates project docs (CHANGELOG, README, CLAUDE.md) per pre-merge checklist.
## M7 Mission Profiles (integration/mission_report.rs + swarm_sim.rs)
- MissionReport / VictimReport / SotaComparison types (serde-serializable)
- run_mission_with_report(): full mission → detailed report with per-victim
localization error, fusion uncertainty, contributing drones, detection time
- run_inspection_mission(): leader-follower power-line corridor inspection
- run_mine_mission(): GPS-denied underground (2-drone, slow, UWB-only)
- SotaComparison embeds Wi2SAR baseline (5m / 810s) vs achieved metrics
## Docs (pre-merge checklist)
- CHANGELOG.md: ruview-swarm + Ruflo integration + performance entries
- README.md: ruview-swarm row
- CLAUDE.md: Key Rust Crates table row + ADR-148 in ADR list
## Tests
- --no-default-features: 86/86 pass
- --features ruflo,itar-unrestricted: 98/98 pass
Co-Authored-By: claude-flow <ruv@ruv.net>
* fix(swarm): convergence-assist for victim fusion + 5s Ruflo HTTP timeout
Follow-up to
|
||
|
|
9ad550d95f |
feat(worldmodel): Candle Rust port + GCP GPU scripts (ADR-147 Phase 4+6)
Candle native port — wifi-densepose-occworld-candle v0.3.0: - config.rs: OccWorldConfig (14 params matching occworld.py) - vqvae.rs: ClassEmbedding(18→64), VQCodebook(512×512, squared-L2), QuantConv/PostQuantConv(1×1 Conv2d), fold_3d_to_2d helpers ResNet encoder/decoder are documented stubs (Phase 5 checkpoint pending) - transformer.rs: full Candle MHA transformer (2 layers, temporal+spatial cross-attention, FFN, pre-norm residuals) - inference.rs: OccWorldCandle::dummy() + ::load() + predict() InferenceOutput: sem_pred(1,15,200,200,16) + trajectory_priors - 14/14 tests pass (12 lib + 2 doctests) GCP GPU scripts — scripts/gcp/: - provision_training.sh: a2-highgpu-8g (8×A100 40GB) for Phase 5 retraining - run_training.sh: rsync + torchrun 8-GPU train + checkpoint download - provision_cosmos.sh: a2-ultragpu-1g (A100 80GB) for Cosmos evaluation - cosmos_eval.sh: run Cosmos-Transfer2.5 inference, download results - teardown.sh: safe checkpoint download + instance delete Co-Authored-By: claude-flow <ruv@ruv.net> |
||
|
|
cd1c391afc |
feat(worldmodel): ADR-147 Phase 3+5 — RuViewOccDataset domain adapter + retraining pipeline
Phase 3 — scripts/ruview_occ_dataset.py: - RuViewOccDataset: WorldGraph JSON snapshots → OccWorld (F,H,W,D) tensors - Indoor class remapping: person→7, floor→9, wall→11, furniture→16, free→17 - Zero ego-poses (fixed indoor sensor, no ego-motion) - record_snapshot() helper for training data accumulation - Validated: 5 windows, (16,200,200,16) tensor, person+floor voxels confirmed Phase 5 — scripts/occworld_retrain.py: - record: stream WorldGraph snapshots from sensing server REST API - vqvae: fine-tune VQVAE tokenizer on RuView occupancy (200 epochs, AdamW) - transformer: fine-tune autoregressive transformer with frozen VQVAE wifi-densepose-worldmodel v0.3.0 published to crates.io Co-Authored-By: claude-flow <ruv@ruv.net> |