mirror of
https://github.com/ruvnet/RuView
synced 2026-07-24 17:43:20 +00:00
chore(repo): move v1/ → archive/v1/ + add archive/README.md (#430)
The Rust port at v2/ has been the primary codebase since the rename in #427. The Python implementation at v1/ is no longer the active target; the only load-bearing path is the deterministic proof bundle at v1/data/proof/ (per ADR-011 / ADR-028 witness verification). Move the whole Python tree into archive/v1/ and document the policy in archive/README.md: no new features, bug fixes only when they affect a still-load-bearing path (currently just the proof), CI continues to verify the proof on every push and PR. Path references updated in 26 files via path-pattern sed (only matches v1/<known-child> patterns, never bare v1 or API URLs like /api/v1/). Two double-prefix typos (archive/archive/v1/) caught and hand-fixed in verify-pipeline.yml and ADR-011. Validated: - Python proof verify.py imports cleanly at archive/v1/data/proof/ (numpy/scipy still required; CI installs requirements-lock.txt from archive/v1/ now) - cargo test --workspace --no-default-features → 1,539 passed, 0 failed, 8 ignored (unaffected by Python tree relocation) - ESP32-S3 on COM7 untouched (no firmware paths changed) After-merge: contributors should re-run any local `python v1/...` commands as `python archive/v1/...` (CLAUDE.md and CHANGELOG already updated).
This commit is contained in:
@@ -20,31 +20,31 @@ The following code paths produce fake data **in the default configuration** or a
|
||||
|
||||
| File | Line | Issue | Impact |
|
||||
|------|------|-------|--------|
|
||||
| `v1/src/core/csi_processor.py` | 390 | `doppler_shift = np.random.rand(10) # Placeholder` | **Real feature extractor returns random Doppler** - kills credibility of entire feature pipeline |
|
||||
| `v1/src/hardware/csi_extractor.py` | 83-84 | `amplitude = np.random.rand(...)` in CSI extraction fallback | Random data silently substituted when parsing fails |
|
||||
| `v1/src/hardware/csi_extractor.py` | 129-135 | `_parse_atheros()` returns `np.random.rand()` with comment "placeholder implementation" | Named as if it parses real data, actually random |
|
||||
| `v1/src/hardware/router_interface.py` | 211-212 | `np.random.rand(3, 56)` in fallback path | Silent random fallback |
|
||||
| `v1/src/services/pose_service.py` | 431 | `mock_csi = np.random.randn(64, 56, 3) # Mock CSI data` | Mock CSI in production code path |
|
||||
| `v1/src/services/pose_service.py` | 293-356 | `_generate_mock_poses()` with `random.randint` throughout | Entire mock pose generator in service layer |
|
||||
| `v1/src/services/pose_service.py` | 489-607 | Multiple `random.randint` for occupancy, historical data | Fake statistics that look real in API responses |
|
||||
| `v1/src/api/dependencies.py` | 82, 408 | "return a mock user for development" | Auth bypass in default path |
|
||||
| `archive/v1/src/core/csi_processor.py` | 390 | `doppler_shift = np.random.rand(10) # Placeholder` | **Real feature extractor returns random Doppler** - kills credibility of entire feature pipeline |
|
||||
| `archive/v1/src/hardware/csi_extractor.py` | 83-84 | `amplitude = np.random.rand(...)` in CSI extraction fallback | Random data silently substituted when parsing fails |
|
||||
| `archive/v1/src/hardware/csi_extractor.py` | 129-135 | `_parse_atheros()` returns `np.random.rand()` with comment "placeholder implementation" | Named as if it parses real data, actually random |
|
||||
| `archive/v1/src/hardware/router_interface.py` | 211-212 | `np.random.rand(3, 56)` in fallback path | Silent random fallback |
|
||||
| `archive/v1/src/services/pose_service.py` | 431 | `mock_csi = np.random.randn(64, 56, 3) # Mock CSI data` | Mock CSI in production code path |
|
||||
| `archive/v1/src/services/pose_service.py` | 293-356 | `_generate_mock_poses()` with `random.randint` throughout | Entire mock pose generator in service layer |
|
||||
| `archive/v1/src/services/pose_service.py` | 489-607 | Multiple `random.randint` for occupancy, historical data | Fake statistics that look real in API responses |
|
||||
| `archive/v1/src/api/dependencies.py` | 82, 408 | "return a mock user for development" | Auth bypass in default path |
|
||||
|
||||
#### Moderate Severity (mock gated behind flags but confusing)
|
||||
|
||||
| File | Line | Issue |
|
||||
|------|------|-------|
|
||||
| `v1/src/config/settings.py` | 144-145 | `mock_hardware=False`, `mock_pose_data=False` defaults - correct, but mock infrastructure exists |
|
||||
| `v1/src/core/router_interface.py` | 27-300 | 270+ lines of mock data generation infrastructure in production code |
|
||||
| `v1/src/services/pose_service.py` | 84-88 | Silent conditional: `if not self.settings.mock_pose_data` with no logging of real-mode |
|
||||
| `v1/src/services/hardware_service.py` | 72-375 | Interleaved mock/real paths throughout |
|
||||
| `archive/v1/src/config/settings.py` | 144-145 | `mock_hardware=False`, `mock_pose_data=False` defaults - correct, but mock infrastructure exists |
|
||||
| `archive/v1/src/core/router_interface.py` | 27-300 | 270+ lines of mock data generation infrastructure in production code |
|
||||
| `archive/v1/src/services/pose_service.py` | 84-88 | Silent conditional: `if not self.settings.mock_pose_data` with no logging of real-mode |
|
||||
| `archive/v1/src/services/hardware_service.py` | 72-375 | Interleaved mock/real paths throughout |
|
||||
|
||||
#### Low Severity (placeholders/TODOs)
|
||||
|
||||
| File | Line | Issue |
|
||||
|------|------|-------|
|
||||
| `v1/src/core/router_interface.py` | 198 | "Collect real CSI data from router (placeholder implementation)" |
|
||||
| `v1/src/api/routers/health.py` | 170-171 | `uptime_seconds = 0.0 # TODO` |
|
||||
| `v1/src/services/pose_service.py` | 739 | `"uptime_seconds": 0.0 # TODO` |
|
||||
| `archive/v1/src/core/router_interface.py` | 198 | "Collect real CSI data from router (placeholder implementation)" |
|
||||
| `archive/v1/src/api/routers/health.py` | 170-171 | `uptime_seconds = 0.0 # TODO` |
|
||||
| `archive/v1/src/services/pose_service.py` | 739 | `"uptime_seconds": 0.0 # TODO` |
|
||||
|
||||
### Root Cause Analysis
|
||||
|
||||
@@ -119,7 +119,7 @@ def _parse_atheros(self, raw_data: bytes) -> CSIData:
|
||||
**All mock code moves to a dedicated module. Default execution NEVER touches mock paths.**
|
||||
|
||||
```
|
||||
v1/src/
|
||||
archive/v1/src/
|
||||
├── core/
|
||||
│ ├── csi_processor.py # Real processing only
|
||||
│ └── router_interface.py # Real hardware interface only
|
||||
@@ -157,7 +157,7 @@ if MOCK_MODE:
|
||||
A small real CSI capture file + one-command verification pipeline:
|
||||
|
||||
```
|
||||
v1/data/proof/
|
||||
archive/v1/data/proof/
|
||||
├── README.md # How to verify
|
||||
├── sample_csi_capture.bin # Real CSI data (1 second, ~50 KB)
|
||||
├── sample_csi_capture_meta.json # Capture metadata (hardware, env)
|
||||
@@ -172,7 +172,7 @@ v1/data/proof/
|
||||
"""Verify WiFi-DensePose pipeline produces deterministic output from real CSI data.
|
||||
|
||||
Usage:
|
||||
python v1/data/proof/verify.py
|
||||
python archive/v1/data/proof/verify.py
|
||||
|
||||
Expected output:
|
||||
PASS: Pipeline output matches expected hash
|
||||
@@ -265,13 +265,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
WORKDIR /app
|
||||
|
||||
# Pinned requirements (not a reference to missing file)
|
||||
COPY v1/requirements-lock.txt ./requirements.txt
|
||||
COPY archive/v1/requirements-lock.txt ./requirements.txt
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY v1/ ./v1/
|
||||
COPY archive/v1/ ./v1/
|
||||
|
||||
# Proof of reality: verify pipeline on build
|
||||
RUN cd v1 && python data/proof/verify.py
|
||||
RUN cd archive/v1 && python data/proof/verify.py
|
||||
|
||||
EXPOSE 8000
|
||||
# Default: REAL mode (mock requires explicit opt-in)
|
||||
@@ -281,7 +281,7 @@ CMD ["uvicorn", "v1.src.api.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
|
||||
**Key change**: `RUN python data/proof/verify.py` **during build** means the Docker image cannot be created unless the pipeline produces correct output from real CSI data.
|
||||
|
||||
**Requirements lockfile** (`v1/requirements-lock.txt`):
|
||||
**Requirements lockfile** (`archive/v1/requirements-lock.txt`):
|
||||
```
|
||||
# Core (required)
|
||||
fastapi==0.115.6
|
||||
@@ -307,9 +307,9 @@ name: Verify Signal Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
paths: ['v1/src/**', 'v1/data/proof/**']
|
||||
paths: ['archive/v1/src/**', 'archive/v1/data/proof/**']
|
||||
pull_request:
|
||||
paths: ['v1/src/**']
|
||||
paths: ['archive/v1/src/**']
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
@@ -322,11 +322,11 @@ jobs:
|
||||
- name: Install minimal deps
|
||||
run: pip install numpy scipy pydantic pydantic-settings
|
||||
- name: Verify pipeline determinism
|
||||
run: python v1/data/proof/verify.py
|
||||
run: python archive/v1/data/proof/verify.py
|
||||
- name: Verify no random in production paths
|
||||
run: |
|
||||
# Fail if np.random appears in production code (not in testing/)
|
||||
! grep -r "np\.random\.\(rand\|randn\|randint\)" v1/src/ \
|
||||
! grep -r "np\.random\.\(rand\|randn\|randint\)" archive/v1/src/ \
|
||||
--include="*.py" \
|
||||
--exclude-dir=testing \
|
||||
|| (echo "FAIL: np.random found in production code" && exit 1)
|
||||
@@ -336,23 +336,23 @@ jobs:
|
||||
|
||||
| File | Action | Description |
|
||||
|------|--------|-------------|
|
||||
| `v1/src/core/csi_processor.py:390` | **Replace** | Real Doppler extraction from temporal CSI history |
|
||||
| `v1/src/hardware/csi_extractor.py:83-84` | **Replace** | Hard error with descriptive message when parsing fails |
|
||||
| `v1/src/hardware/csi_extractor.py:129-135` | **Replace** | Real Atheros CSI parser or hard error with hardware instructions |
|
||||
| `v1/src/hardware/router_interface.py:198-212` | **Replace** | Hard error for unimplemented hardware, or real `iwconfig` + CSI tool integration |
|
||||
| `v1/src/services/pose_service.py:293-356` | **Move** | Move `_generate_mock_poses()` to `v1/src/testing/mock_pose_generator.py` |
|
||||
| `v1/src/services/pose_service.py:430-431` | **Remove** | Remove mock CSI generation from production path |
|
||||
| `v1/src/services/pose_service.py:489-607` | **Replace** | Real statistics from database, or explicit "no data" response |
|
||||
| `v1/src/core/router_interface.py:60-300` | **Move** | Move mock generator to `v1/src/testing/mock_csi_generator.py` |
|
||||
| `v1/src/api/dependencies.py:82,408` | **Replace** | Real auth check or explicit dev-mode bypass with logging |
|
||||
| `v1/data/proof/` | **Create** | Proof bundle (sample capture + expected hash + verify script) |
|
||||
| `v1/requirements-lock.txt` | **Create** | Pinned minimal dependencies |
|
||||
| `archive/v1/src/core/csi_processor.py:390` | **Replace** | Real Doppler extraction from temporal CSI history |
|
||||
| `archive/v1/src/hardware/csi_extractor.py:83-84` | **Replace** | Hard error with descriptive message when parsing fails |
|
||||
| `archive/v1/src/hardware/csi_extractor.py:129-135` | **Replace** | Real Atheros CSI parser or hard error with hardware instructions |
|
||||
| `archive/v1/src/hardware/router_interface.py:198-212` | **Replace** | Hard error for unimplemented hardware, or real `iwconfig` + CSI tool integration |
|
||||
| `archive/v1/src/services/pose_service.py:293-356` | **Move** | Move `_generate_mock_poses()` to `archive/v1/src/testing/mock_pose_generator.py` |
|
||||
| `archive/v1/src/services/pose_service.py:430-431` | **Remove** | Remove mock CSI generation from production path |
|
||||
| `archive/v1/src/services/pose_service.py:489-607` | **Replace** | Real statistics from database, or explicit "no data" response |
|
||||
| `archive/v1/src/core/router_interface.py:60-300` | **Move** | Move mock generator to `archive/v1/src/testing/mock_csi_generator.py` |
|
||||
| `archive/v1/src/api/dependencies.py:82,408` | **Replace** | Real auth check or explicit dev-mode bypass with logging |
|
||||
| `archive/v1/data/proof/` | **Create** | Proof bundle (sample capture + expected hash + verify script) |
|
||||
| `archive/v1/requirements-lock.txt` | **Create** | Pinned minimal dependencies |
|
||||
| `.github/workflows/verify-pipeline.yml` | **Create** | CI verification |
|
||||
|
||||
### Hardware Documentation
|
||||
|
||||
```
|
||||
v1/docs/hardware-setup.md (to be created)
|
||||
archive/v1/docs/hardware-setup.md (to be created)
|
||||
|
||||
# Supported Hardware Matrix
|
||||
|
||||
@@ -368,17 +368,17 @@ v1/docs/hardware-setup.md (to be created)
|
||||
2. Capture 10 seconds of empty-room baseline
|
||||
3. Have one person walk through at normal pace
|
||||
4. Capture 10 seconds during walk-through
|
||||
5. Run calibration: `python v1/scripts/calibrate.py --baseline empty.dat --activity walk.dat`
|
||||
5. Run calibration: `python archive/v1/scripts/calibrate.py --baseline empty.dat --activity walk.dat`
|
||||
```
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
- **"Clone, build, verify" in one command**: `docker build . && docker run --rm wifi-densepose python v1/data/proof/verify.py` produces a deterministic PASS
|
||||
- **"Clone, build, verify" in one command**: `docker build . && docker run --rm wifi-densepose python archive/v1/data/proof/verify.py` produces a deterministic PASS
|
||||
- **No silent fakes**: Random data never appears in production output
|
||||
- **CI enforcement**: PRs that introduce `np.random` in production paths fail automatically
|
||||
- **Credibility anchor**: SHA-256 verified output from real CSI capture is unchallengeable proof
|
||||
- **Clear mock boundary**: Mock code exists only in `v1/src/testing/`, never imported by production modules
|
||||
- **Clear mock boundary**: Mock code exists only in `archive/v1/src/testing/`, never imported by production modules
|
||||
|
||||
### Negative
|
||||
- **Requires real CSI capture**: Someone must capture and commit a real CSI sample (one-time effort)
|
||||
@@ -390,7 +390,7 @@ v1/docs/hardware-setup.md (to be created)
|
||||
|
||||
A stranger can:
|
||||
1. `git clone` the repository
|
||||
2. Run ONE command (`docker build .` or `python v1/data/proof/verify.py`)
|
||||
2. Run ONE command (`docker build .` or `python archive/v1/data/proof/verify.py`)
|
||||
3. See `PASS: Pipeline output matches expected hash` with a specific SHA-256
|
||||
4. Confirm no `np.random` in any non-test file via CI badge
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# ADR-013: Feature-Level Sensing on Commodity Gear (Option 3)
|
||||
|
||||
## Status
|
||||
Accepted — Implemented (36/36 unit tests pass, see `v1/src/sensing/` and `v1/tests/unit/test_sensing.py`)
|
||||
Accepted — Implemented (36/36 unit tests pass, see `archive/v1/src/sensing/` and `archive/v1/tests/unit/test_sensing.py`)
|
||||
|
||||
## Date
|
||||
2026-02-28
|
||||
@@ -323,7 +323,7 @@ class PresenceClassifier:
|
||||
### Proof Bundle for Commodity Sensing
|
||||
|
||||
```
|
||||
v1/data/proof/commodity/
|
||||
archive/v1/data/proof/commodity/
|
||||
├── rssi_capture_30sec.json # 30 seconds of RSSI from 3 receivers
|
||||
├── rssi_capture_meta.json # Hardware: Intel AX200, Router: TP-Link AX1800
|
||||
├── scenario.txt # "Person walks through room at t=10s, sits at t=20s"
|
||||
@@ -375,7 +375,7 @@ class CommodityBackend(SensingBackend):
|
||||
|
||||
### Implementation Status
|
||||
|
||||
The full commodity sensing pipeline is implemented in `v1/src/sensing/`:
|
||||
The full commodity sensing pipeline is implemented in `archive/v1/src/sensing/`:
|
||||
|
||||
| Module | File | Description |
|
||||
|--------|------|-------------|
|
||||
@@ -384,7 +384,7 @@ The full commodity sensing pipeline is implemented in `v1/src/sensing/`:
|
||||
| Classifier | `classifier.py` | `PresenceClassifier` with ABSENT/PRESENT_STILL/ACTIVE levels, confidence scoring |
|
||||
| Backend | `backend.py` | `CommodityBackend` wiring collector → extractor → classifier, reports PRESENCE + MOTION capabilities |
|
||||
|
||||
**Test coverage**: 36 tests in `v1/tests/unit/test_sensing.py` — all passing:
|
||||
**Test coverage**: 36 tests in `archive/v1/tests/unit/test_sensing.py` — all passing:
|
||||
- `TestRingBuffer` (4), `TestSimulatedCollector` (5), `TestFeatureExtractor` (8), `TestCusum` (4), `TestPresenceClassifier` (7), `TestCommodityBackend` (6), `TestBandPower` (2)
|
||||
|
||||
**Dependencies**: `numpy`, `scipy` (for FFT and spectral analysis)
|
||||
|
||||
@@ -22,8 +22,8 @@ This ADR answers *how* to build it — the concrete development sequence, the sp
|
||||
| Frame types | `wifi-densepose-hardware/src/csi_frame.rs` | Complete — `CsiFrame`, `CsiMetadata`, `SubcarrierData`, `to_amplitude_phase()` |
|
||||
| Parse error types | `wifi-densepose-hardware/src/error.rs` | Complete — `ParseError` enum with 6 variants |
|
||||
| Signal processing pipeline | `wifi-densepose-signal` crate | Complete — Hampel, Fresnel, BVP, Doppler, spectrogram |
|
||||
| CSI extractor (Python) | `v1/src/hardware/csi_extractor.py` | Stub — `_read_raw_data()` raises `NotImplementedError` |
|
||||
| Router interface (Python) | `v1/src/hardware/router_interface.py` | Stub — `_parse_csi_response()` raises `RouterConnectionError` |
|
||||
| CSI extractor (Python) | `archive/v1/src/hardware/csi_extractor.py` | Stub — `_read_raw_data()` raises `NotImplementedError` |
|
||||
| Router interface (Python) | `archive/v1/src/hardware/router_interface.py` | Stub — `_parse_csi_response()` raises `RouterConnectionError` |
|
||||
|
||||
**Not yet implemented:**
|
||||
|
||||
@@ -211,10 +211,10 @@ The bridge test: parse a known binary frame, convert to `CsiData`, assert `ampli
|
||||
|
||||
### Layer 4 — Python `_read_raw_data()` Real Implementation
|
||||
|
||||
Replace the `NotImplementedError` stub in `v1/src/hardware/csi_extractor.py` with a UDP socket reader. This allows the Python pipeline to receive real CSI from the aggregator while the Rust pipeline is being integrated.
|
||||
Replace the `NotImplementedError` stub in `archive/v1/src/hardware/csi_extractor.py` with a UDP socket reader. This allows the Python pipeline to receive real CSI from the aggregator while the Rust pipeline is being integrated.
|
||||
|
||||
```python
|
||||
# v1/src/hardware/csi_extractor.py
|
||||
# archive/v1/src/hardware/csi_extractor.py
|
||||
# Replace _read_raw_data() stub:
|
||||
|
||||
import socket as _socket
|
||||
|
||||
@@ -34,7 +34,7 @@ Implement a **sensing-only UI mode** that:
|
||||
- Breathing ring modulation when breathing-band power detected
|
||||
- Side panel with RSSI sparkline, feature meters, and classification badge
|
||||
|
||||
4. **Python WebSocket bridge** (`v1/src/sensing/ws_server.py`) that:
|
||||
4. **Python WebSocket bridge** (`archive/v1/src/sensing/ws_server.py`) that:
|
||||
- Auto-detects ESP32 UDP CSI stream on port 5005 (ADR-018 binary frames)
|
||||
- Falls back to `WindowsWifiCollector` → `SimulatedCollector`
|
||||
- Runs `RssiFeatureExtractor` → `PresenceClassifier` pipeline
|
||||
@@ -80,7 +80,7 @@ Windows WiFi RSSI ───┘ │ │
|
||||
### Created
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `v1/src/sensing/ws_server.py` | Python asyncio WebSocket server with auto-detect collectors |
|
||||
| `archive/v1/src/sensing/ws_server.py` | Python asyncio WebSocket server with auto-detect collectors |
|
||||
| `ui/components/SensingTab.js` | Sensing tab UI with Three.js integration |
|
||||
| `ui/components/gaussian-splats.js` | Custom GLSL Gaussian splat renderer |
|
||||
| `ui/services/sensing.service.js` | WebSocket client with reconnect + simulation fallback |
|
||||
|
||||
@@ -40,8 +40,8 @@ Use the `wifi-densepose-nn` crate with `default-features = ["onnx"]` only. This
|
||||
|
||||
| Component | Rust Crate | Replaces Python |
|
||||
|-----------|-----------|-----------------|
|
||||
| CSI processing | `wifi-densepose-signal::csi_processor` | `v1/src/sensing/feature_extractor.py` |
|
||||
| Motion detection | `wifi-densepose-signal::motion` | `v1/src/sensing/classifier.py` |
|
||||
| CSI processing | `wifi-densepose-signal::csi_processor` | `archive/v1/src/sensing/feature_extractor.py` |
|
||||
| Motion detection | `wifi-densepose-signal::motion` | `archive/v1/src/sensing/classifier.py` |
|
||||
| BVP extraction | `wifi-densepose-signal::bvp` | N/A (new capability) |
|
||||
| Fresnel geometry | `wifi-densepose-signal::fresnel` | N/A (new capability) |
|
||||
| Subcarrier selection | `wifi-densepose-signal::subcarrier_selection` | N/A (new capability) |
|
||||
|
||||
@@ -232,10 +232,10 @@ python scripts/provision.py --port COM7 \
|
||||
|
||||
| Component | File | Purpose |
|
||||
|-----------|------|---------|
|
||||
| Reference signal | `v1/data/proof/sample_csi_data.json` | 1,000 synthetic CSI frames, seed=42 |
|
||||
| Generator | `v1/data/proof/generate_reference_signal.py` | Deterministic multipath model |
|
||||
| Verifier | `v1/data/proof/verify.py` | SHA-256 hash comparison |
|
||||
| Expected hash | `v1/data/proof/expected_features.sha256` | `0b82bd45...` |
|
||||
| Reference signal | `archive/v1/data/proof/sample_csi_data.json` | 1,000 synthetic CSI frames, seed=42 |
|
||||
| Generator | `archive/v1/data/proof/generate_reference_signal.py` | Deterministic multipath model |
|
||||
| Verifier | `archive/v1/data/proof/verify.py` | SHA-256 hash comparison |
|
||||
| Expected hash | `archive/v1/data/proof/expected_features.sha256` | `0b82bd45...` |
|
||||
|
||||
**Audit-time result:** PASS. Hash regenerated with numpy 2.4.2 + scipy 1.17.1. Pipeline hash: `8c0680d7d285739ea9597715e84959d9c356c87ee3ad35b5f1e69a4ca41151c6`.
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ Remove duplicated platform-detection logic from `ws_server.py` and `install.sh`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
1. Add `create_collector()` and `BaseCollector.is_available()` to `v1/src/sensing/rssi_collector.py`
|
||||
1. Add `create_collector()` and `BaseCollector.is_available()` to `archive/v1/src/sensing/rssi_collector.py`
|
||||
2. Refactor `ws_server.py` `_init_collector()` to call `create_collector()`
|
||||
3. Update `install.sh` `detect_wifi_hardware()` to use shared detection logic
|
||||
4. Add unit tests for each platform path (mock `/proc/net/wireless` presence/absence)
|
||||
|
||||
@@ -17,19 +17,19 @@ Address the 15 prioritized issues from the QE analysis in three waves: P0 (immed
|
||||
|
||||
### 1. Rate Limiter Bypass (Security HIGH)
|
||||
|
||||
- **Location:** `v1/src/middleware/rate_limit.py:200-206`
|
||||
- **Location:** `archive/v1/src/middleware/rate_limit.py:200-206`
|
||||
- **Problem:** Trusts `X-Forwarded-For` without validation. Any client bypasses rate limits via header spoofing.
|
||||
- **Fix:** Validate forwarded headers against trusted proxy list, or use connection IP directly.
|
||||
|
||||
### 2. Exception Details Leaked in Responses (Security HIGH)
|
||||
|
||||
- **Location:** `v1/src/api/routers/pose.py:140`, `stream.py:297`, +5 endpoints
|
||||
- **Location:** `archive/v1/src/api/routers/pose.py:140`, `stream.py:297`, +5 endpoints
|
||||
- **Problem:** Stack traces visible regardless of environment.
|
||||
- **Fix:** Wrap with generic error responses in production; log details server-side only.
|
||||
|
||||
### 3. WebSocket JWT in URL (Security HIGH, CWE-598)
|
||||
|
||||
- **Location:** `v1/src/api/routers/stream.py:74`, `v1/src/middleware/auth.py:243`
|
||||
- **Location:** `archive/v1/src/api/routers/stream.py:74`, `archive/v1/src/middleware/auth.py:243`
|
||||
- **Problem:** Tokens in query strings visible in logs/proxies/browser history.
|
||||
- **Fix:** Use WebSocket subprotocol or first-message auth pattern.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user