Files
ruvnet--ruview/docs/adr/ADR-055-integrated-sensing-server.md
wehub-resource-sync 9740bc64c9
Firmware QEMU Tests (ADR-061) / QEMU Test (edge-tier1) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / QEMU Test (full-adr060) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / QEMU Test (tdm-3node) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / Swarm Test (ADR-062) (push) Has been skipped
npm packages / tools/ruview-mcp (node 22) (push) Failing after 1s
nvsim-server → ghcr.io / build-and-publish (push) Failing after 1s
ruview-swarm CI guard / tests (full+train) (push) Failing after 2s
Bench Regression Guard / bench compile-verify (--no-run) (push) Failing after 0s
Bench Regression Guard / bench fast-run (informational, non-gating) (push) Has been skipped
Firmware CI / Verify version.txt matches release tag (push) Has been skipped
Dashboard a11y + cross-browser / a11y (push) Failing after 0s
nvsim Dashboard → GitHub Pages / build-and-deploy (push) Failing after 2s
Firmware CI / Build firmware (esp32s3 / 4mb) (push) Failing after 15s
Firmware QEMU Tests (ADR-061) / Build Espressif QEMU (push) Failing after 1s
Firmware QEMU Tests (ADR-061) / Fuzz Testing (ADR-061 Layer 6) (push) Failing after 1s
Continuous Deployment / Pre-deployment Checks (push) Has been skipped
Firmware CI / Build firmware (esp32c6 / c6-4mb) (push) Failing after 15s
Firmware CI / Build firmware (esp32s3 / 8mb) (push) Failing after 15s
Firmware QEMU Tests (ADR-061) / QEMU Test (boundary-max) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / QEMU Test (boundary-min) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / QEMU Test (default) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / QEMU Test (edge-tier0) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / NVS Matrix Generation (push) Failing after 1s
Security Scanning / Security Policy Compliance (push) Failing after 0s
Security Scanning / Dependency Vulnerability Scan (push) Failing after 0s
Security Scanning / Static Application Security Testing (push) Failing after 1s
Security Scanning / Infrastructure Security Scan (push) Failing after 1s
Security Scanning / Secret Scanning (push) Failing after 1s
npm packages / harness/ruview (node 22) (push) Failing after 17s
Security Scanning / License Compliance Scan (push) Failing after 1s
Security Scanning / Container Security Scan (push) Failing after 4s
three.js demos → GitHub Pages / build-and-deploy (push) Failing after 1s
Verify Pipeline Determinism / Verify Pipeline Determinism (3.11) (push) Failing after 1s
Fix-Marker Regression Guard / Verify fix markers (push) Failing after 1s
ADR-115 MQTT integration tests / mqtt-integration (push) Failing after 1s
npm packages / harness/ruview (node 20) (push) Failing after 1s
npm packages / tools/ruview-mcp (node 20) (push) Failing after 1s
npm packages / tools/ruview-cli (node 20) (push) Failing after 1s
npm packages / tools/ruview-cli (node 22) (push) Failing after 1s
BFLD MQTT Integration / cargo test --features mqtt (live mosquitto) (push) Failing after 29s
ruview-swarm CI guard / build train_marl bin (push) Failing after 2s
ruview-swarm CI guard / clippy (-D warnings, --no-deps) (push) Failing after 3s
ruview-swarm CI guard / tests (ruflo) (push) Failing after 1s
ruview-swarm CI guard / tests (train) (push) Failing after 2s
ruview-swarm CI guard / tests (default) (push) Failing after 2s
Point Cloud Viewer → GitHub Pages / build-and-deploy (push) Failing after 8s
ruview-swarm CI guard / ITAR / publish guard (push) Failing after 0s
wifi-densepose sensing-server → Docker Hub + ghcr.io / build · push · smoke-test (push) Failing after 1s
Continuous Deployment / Deploy to Production (push) Has been cancelled
Continuous Deployment / Rollback Deployment (push) Has been cancelled
Continuous Deployment / Post-deployment Monitoring (push) Has been cancelled
Continuous Deployment / Notify Deployment Status (push) Has been cancelled
Continuous Deployment / Deploy to Staging (push) Has been cancelled
Security Scanning / Security Report (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 11:59:54 +08:00

3.8 KiB

ADR-055: Integrated Sensing Server in Desktop App

Status

Accepted

Context

The RuView Desktop application (ADR-054) requires the WiFi sensing server to provide real-time CSI data, activity detection, and vital signs monitoring. Currently, the sensing server is a separate binary (wifi-densepose-sensing-server) that must be installed separately and found in the system PATH.

This creates several problems:

  1. Distribution complexity: Users must install two binaries
  2. Path issues: Binary may not be in PATH, causing "No such file or directory" errors
  3. Version mismatch: Server and desktop app versions may diverge
  4. Poor UX: Error messages about missing binaries confuse users

Decision

Bundle the sensing server binary inside the desktop application and provide intelligent binary discovery with clear fallback paths.

Binary Discovery Order

The desktop app searches for the sensing server in this order:

  1. Custom path from user settings (server_path)
  2. Bundled resources (Contents/Resources/bin/ on macOS)
  3. Next to executable (same directory as the app binary)
  4. System PATH (legacy fallback)

Implementation

fn find_server_binary(app: &AppHandle, custom_path: Option<&str>) -> Result<String, String> {
    // 1. Custom path from settings
    if let Some(path) = custom_path {
        if std::path::Path::new(path).exists() {
            return Ok(path.to_string());
        }
    }

    // 2. Bundled in resources
    if let Ok(resource_dir) = app.path().resource_dir() {
        let bundled = resource_dir.join("bin").join(DEFAULT_SERVER_BIN);
        if bundled.exists() {
            return Ok(bundled.to_string_lossy().to_string());
        }
    }

    // 3. Next to executable
    if let Ok(exe_path) = std::env::current_exe() {
        if let Some(exe_dir) = exe_path.parent() {
            let sibling = exe_dir.join(DEFAULT_SERVER_BIN);
            if sibling.exists() {
                return Ok(sibling.to_string_lossy().to_string());
            }
        }
    }

    // 4. System PATH
    // ... which lookup ...

    Err("Sensing server binary not found")
}

Bundle Configuration

In tauri.conf.json:

{
  "bundle": {
    "resources": [
      {
        "src": "../../target/release/wifi-densepose-sensing-server",
        "target": "bin/wifi-densepose-sensing-server"
      }
    ]
  }
}

Consequences

Positive

  • Single package distribution: Users download one DMG/MSI/EXE
  • Version alignment: Server and UI always match
  • Better UX: No PATH configuration required
  • Offline capable: Works without network access to download server

Negative

  • Larger bundle size: ~10-15MB additional for server binary
  • Build complexity: Must build server before bundling desktop
  • Platform-specific: Need separate server binaries per platform

Neutral

  • CI/CD workflow updated to build server before desktop
  • GitHub Actions builds all platforms (macOS arm64/x64, Windows x64)

WebSocket Integration

The Sensing page connects to the bundled server's WebSocket endpoint:

  • ws://127.0.0.1:{ws_port}/ws/sensing - Real-time CSI data stream
  • ws://127.0.0.1:{ws_port}/ws/pose - Pose estimation stream

Message format:

interface WsSensingUpdate {
  type: string;
  timestamp: number;
  source: string;
  tick: number;
  nodes: WsNodeInfo[];
  classification: { motion_level: string; presence: boolean; confidence: number };
  vital_signs?: { breathing_rate_hz?: number; heart_rate_bpm?: number };
}

Security Considerations

  • Server binary signed with same certificate as desktop app
  • Communication over localhost only (127.0.0.1)
  • No external network access by default
  • Process spawned as child of desktop app (inherits permissions)
  • ADR-054: Desktop Full Implementation
  • ADR-053: UI Design System
  • ADR-052: Tauri Desktop Frontend