diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index b511141d..f7dcf273 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -24,10 +24,13 @@ services: environment: - RUST_LOG=info # CSI_SOURCE controls the data source for the sensing server. - # Options: auto (default) — probe for ESP32 UDP then fall back to simulation + # Options: auto (default) — probe for ESP32 UDP then host WiFi; **fail + # hard with exit 78 if neither is detected**. + # Synthetic data is no longer a silent fallback + # (issue #937 fix) — operators must opt in. # esp32 — receive real CSI frames from an ESP32 on UDP port 5005 # wifi — use host Wi-Fi RSSI/scan data (Windows netsh) - # simulated — generate synthetic CSI data (no hardware required) + # simulated — explicitly generate synthetic CSI for demo mode - CSI_SOURCE=${CSI_SOURCE:-auto} # MODELS_DIR controls where the server scans for .rvf model files. # Mount a host directory and set this to make models visible: diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index 681ae69d..192746c5 100755 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -11,7 +11,16 @@ # docker run ruvnet/wifi-densepose:latest --model /app/models/my.rvf # # Environment variables: -# CSI_SOURCE — data source: auto (default), esp32, wifi, simulated +# CSI_SOURCE — data source. Valid values: +# auto — try ESP32 then Windows WiFi, **fail-loud if no +# real hardware is detected** (issue #937 fix: +# the server no longer silently falls back to +# synthetic data — that's now opt-in only). +# esp32 — listen for UDP CSI on the configured port. +# wifi — Windows-native WiFi capture. +# simulated — explicit demo mode with synthetic CSI. +# Default is `auto`. Set CSI_SOURCE=simulated when you want +# fake data tagged as such; never set it implicitly. # MODELS_DIR — directory to scan for .rvf model files (default: data/models) set -e diff --git a/v2/crates/wifi-densepose-desktop/src/commands/server.rs b/v2/crates/wifi-densepose-desktop/src/commands/server.rs index d240f888..4b53d731 100644 --- a/v2/crates/wifi-densepose-desktop/src/commands/server.rs +++ b/v2/crates/wifi-densepose-desktop/src/commands/server.rs @@ -108,8 +108,14 @@ pub async fn start_server( cmd.args(["--log-level", log_level]); } - // Set data source (default to "simulate" if not specified for demo mode) - let source = config.source.as_deref().unwrap_or("simulate"); + // Default to explicit "simulated" demo mode when the desktop user hasn't + // chosen a source — this is the *Tauri demo* app, not a production + // sensing endpoint, so the demo default is correct here. Critically, the + // value passed downstream is the **explicit** "simulated", not "auto", + // which means the sensing-server will tag the data as synthetic in its + // API responses rather than silently fall back (issue #937 fix in + // sensing-server's `auto` handler). + let source = config.source.as_deref().unwrap_or("simulated"); cmd.args(["--source", source]); // Redirect stdout/stderr to pipes for monitoring @@ -317,7 +323,7 @@ pub async fn restart_server( log_level: None, bind_address: None, server_path: None, - source: None, // Use default (simulate) + source: None, // Falls through to explicit "simulated" — Tauri demo default. } }; diff --git a/v2/crates/wifi-densepose-sensing-server/src/main.rs b/v2/crates/wifi-densepose-sensing-server/src/main.rs index ae59d797..2d954e2a 100644 --- a/v2/crates/wifi-densepose-sensing-server/src/main.rs +++ b/v2/crates/wifi-densepose-sensing-server/src/main.rs @@ -6421,7 +6421,17 @@ async fn main() { info!(" UI path: {}", args.ui_path.display()); info!(" Source: {}", args.source); - // Auto-detect data source + // Auto-detect data source. + // + // Issue #937 / sibling fix: previously `auto` silently fell back to the + // synthetic data source when no ESP32 or Windows WiFi was reachable, with + // only an `info!` log line as the signal. Downstream API consumers + // (`/api/v1/sensing/latest`, `/ws/sensing`) had no in-band way to know they + // were being served fake CSI tagged as production telemetry. That is the + // exact "where's the real data?" pattern external reviewers (#943, #934) + // cited as the most damaging evidence of the project misrepresenting its + // posture. Synthetic-data is now opt-in only — operators who want demo + // mode must explicitly set `--source simulated` or `CSI_SOURCE=simulated`. let source = match args.source.as_str() { "auto" => { info!("Auto-detecting data source..."); @@ -6432,10 +6442,23 @@ async fn main() { info!(" Windows WiFi detected"); "wifi" } else { - info!(" No hardware detected, using simulation"); - "simulate" + error!( + "No real CSI source detected. Auto-detection refuses to silently \ + fall back to synthetic data because that would expose downstream \ + consumers (/api/v1/sensing/latest, /ws/sensing) to fake telemetry \ + tagged as production. To run with synthetic data, set the source \ + explicitly: --source simulated (or CSI_SOURCE=simulated in Docker). \ + To use real hardware: provision an ESP32 to emit CSI on UDP :{} or \ + install the Windows WiFi capture driver. See \ + https://github.com/ruvnet/RuView/issues/937 for context.", + args.udp_port + ); + std::process::exit(78); // EX_CONFIG } } + // "simulate" is a synonym for "simulated" (back-compat alias kept so + // existing operators who already opted in don't get broken by this fix). + "simulate" => "simulated", other => other, };