Files
ruvnet--RuView/v2/crates/wifi-densepose-sensing-server/Cargo.toml
T
ruv 65648fe4c2 feat(adr-186): P5/P6 + acceptance verification — dashboard honesty, HTTP tests, Accepted
Completes ADR-186 phases P5 (dashboard honesty / fallback guarantee) and P6
(tests + witness) on top of the P1–P4 reconnection, and flips the ADR to Accepted.

P5 — dashboard honesty:
- Backend (training_api): a runtime enablement gate (`RUVIEW_DISABLE_SERVER_TRAINING`)
  makes the three start endpoints return a structured `{enabled:false, reason,
  cli:"wifi-densepose train-room"}` HTTP 409 (never a silent success) when server
  training is disabled; `/api/v1/train/status` now carries an `enabled` flag. A runtime
  flag (not a Cargo feature) so `--no-default-features` builds keep training ON (resolves
  §9.4). Handlers return `Response` to carry the 409.
- Frontend (TrainingPanel.js): reads `enabled` off the status payload and disables the
  Start/Pretrain/LoRA buttons with a CLI tooltip when server training is off; a rejected
  start tears down the optimistically-opened WS and refreshes. The enabled path was
  already fully wired (opens the WS before POST, renders live epoch/loss/ETA + terminal
  state) — verified.

P6 — tests & witness:
- New HTTP-level tests in a `#[cfg(test)] mod adr186_http_tests` built on a minimal
  `AppStateInner::minimal()` test-state helper: a live-socket test that completes a
  genuine 101 WebSocket handshake (tokio-tungstenite) and receives a real progress frame
  after a POST start; a 426-not-404 route-wired check; a full POST→poll-status→`.rvf`-exists
  round-trip; and the disabled-409 structured-response test. Added `tokio-tungstenite`
  dev-dep (version already in the workspace lock).
- CHANGELOG updated; ADR §6 ledger + §7 acceptance criteria checked off with evidence;
  Status → Accepted. README/CLAUDE have no training route table (no edit needed).

Fixed a test-only parallelism race found under `cargo test --workspace`: two
model-writing tests deleted `.rvf`s by directory-diff and could remove a file a third
test asserted existed. Each test now cleans only its own artifact (data/models is
gitignored).

Verified this session: `cargo test -p wifi-densepose-sensing-server -p wifi-densepose-train
--no-default-features` — sensing-server bin 217 passed / 0 failed, all train suites 0
failed. Full `--workspace` re-run in progress to reconfirm untouched crates.
2026-07-21 17:19:20 -07:00

130 lines
5.8 KiB
TOML

[package]
name = "wifi-densepose-sensing-server"
version = "0.3.4"
edition.workspace = true
description = "Lightweight Axum server for WiFi sensing UI with RuVector signal processing"
license.workspace = true
authors = ["rUv <ruv@ruv.net>", "WiFi-DensePose Contributors"]
repository.workspace = true
documentation = "https://docs.rs/wifi-densepose-sensing-server"
keywords = ["wifi", "sensing", "server", "websocket", "csi"]
categories = ["web-programming::http-server", "science"]
readme = "README.md"
[lib]
name = "wifi_densepose_sensing_server"
path = "src/lib.rs"
[[bin]]
name = "sensing-server"
path = "src/main.rs"
[dependencies]
# Web framework
axum = { workspace = true }
tower-http = { version = "0.6", features = ["fs", "cors", "set-header"] }
tokio = { workspace = true, features = ["full", "process"] }
futures-util = "0.3"
ruvector-mincut = { workspace = true }
# Serialization
serde = { workspace = true }
serde_json.workspace = true
# Logging
tracing.workspace = true
tracing-subscriber = { workspace = true }
# Time
chrono = { version = "0.4", features = ["serde"] }
# CLI
clap = { workspace = true }
# Multi-BSSID WiFi scanning pipeline (ADR-022 Phase 3)
wifi-densepose-wifiscan = { version = "0.3.0", path = "../wifi-densepose-wifiscan" }
# Signal processing with RuvSense pose tracker (accuracy sprint).
# default-features = false drops the optional ndarray-linalg/BLAS chain so that
# `--no-default-features` at the workspace root can produce a Windows-friendly
# build without vcpkg/openblas (issue #366, #415).
wifi-densepose-signal = { version = "0.3.1", path = "../wifi-densepose-signal", default-features = false }
# Hardware crate — SyncPacket decoder for ADR-110 §A0.12 mesh-aligned timestamps.
wifi-densepose-hardware = { version = "0.3.0", path = "../wifi-densepose-hardware" }
# Governed streaming engine (ADR-135..146): fusion + privacy demotion +
# WorldGraph belief + deterministic witness. The live server data runs through
# this as a governed path whose Restricted-class decision strips per-node raw
# amplitudes from the live publish; full output gating is a tracked follow-up —
# see engine_bridge.rs ("Honest scope of the live-path governance").
wifi-densepose-engine = { version = "0.3.0", path = "../wifi-densepose-engine" }
wifi-densepose-worldgraph = { version = "0.3.0", path = "../worldgraph/wifi-densepose-worldgraph" }
wifi-densepose-bfld = { version = "0.3.1", path = "../wifi-densepose-bfld", default-features = false }
wifi-densepose-geo = { version = "0.1.0", path = "../worldgraph/wifi-densepose-geo" }
# ADR-262 P3: live RuField surface. The thin anti-corruption bridge that turns
# this server's governed sensing cycle into signed RuField `FieldEvent`s on
# `/api/field` + `/ws/field`. It path-deps the standalone `vendor/rufield`
# submodule (it is the single coupling point — ADR-262 §5.4) and pulls in no
# RuView internal crate, so the dep surface added here is just the bridge.
wifi-densepose-rufield = { version = "0.3.0", path = "../wifi-densepose-rufield" }
# midstream — real-time introspection / low-latency tap (ADR-099 D1).
# Two crates only, on purpose: scheduler / neural-solver / strange-loop are
# explicitly out of scope of ADR-099 (D5).
midstreamer-temporal-compare = "0.2" # DTW / LCS / Edit-Distance pattern matching
midstreamer-attractor = "0.2" # Lyapunov + regime classification
# ADR-102: Edge Module Registry — fetch the canonical Cognitum cog catalog
# at `https://storage.googleapis.com/cognitum-apps/app-registry.json`,
# cache with TTL, surface via /api/v1/edge/registry. ureq is the smallest
# blocking HTTP client we can use without dragging a tokio HTTP stack in;
# rustls is enabled implicitly via the `tls` default feature.
ureq = { version = "2", default-features = false, features = ["tls", "json"] }
sha2 = "0.10"
thiserror = "1"
# ADR-115 §3.8 — MQTT publisher (HA-DISCO).
# Gated behind the `mqtt` feature so the default binary stays small for users
# who don't need Home Assistant integration. `rumqttc` is the chosen Rust MQTT
# client (ADR-115 §10 references). `rustls` is preferred over openssl on
# Windows to keep parity with the rest of the workspace (`ureq` above also
# uses rustls).
rumqttc = { version = "0.24", default-features = false, features = ["use-rustls"], optional = true }
[features]
default = []
# Enables the ADR-115 §2 MQTT auto-discovery publisher. Without this feature
# all `--mqtt-*` CLI flags still parse (cli.rs declares them unconditionally),
# but enabling `--mqtt` at runtime logs a `WARN` and the publisher is a no-op.
mqtt = ["dep:rumqttc"]
# ADR-115 §3.11 — Matter Bridge (HA-FABRIC). Same gating principle: flags
# parse unconditionally; the bridge is a no-op without this feature.
# matter-rs is added in P7; intentionally absent in P1 to keep the dep
# surface small until the SDK choice is validated.
matter = []
[dev-dependencies]
tempfile = "3.10"
# `tower::ServiceExt::oneshot` for in-process Router tests (bearer_auth).
tower = { workspace = true }
# ADR-186 P6 — real-socket WebSocket client for the `/ws/train/progress`
# 101-upgrade + live-progress-frame test. Pinned to the version already resolved
# in the workspace lock (via homecore-api) so this adds no new lock entry.
tokio-tungstenite = "0.24"
# ADR-115 P9 — micro-benchmarks for MQTT hot paths + semantic bus.
# Heavy dep tree (~80 transitive crates) so it's dev-only; benches live
# behind --features mqtt because they bench the mqtt module.
criterion = { version = "0.5", features = ["html_reports"] }
# ADR-115 P9 — property-based fuzzing for the wire-boundary security
# audit. Catches edge cases the example-based unit tests would miss
# (random Unicode, control chars, etc.). Pinned to a small version that
# doesn't pull in proptest-derive (we don't need it).
proptest = { version = "1.5", default-features = false, features = ["std"] }
[[bench]]
name = "mqtt_throughput"
harness = false
required-features = ["mqtt"]