docs/qe-reports/05-quality-experience.md
Report ID: QX-2026-005 Date: 2026-04-05 Scope: Full-stack quality experience across API, CLI, Mobile, DX, and Hardware QX Score: 71/100 (C+)
The WiFi-DensePose system demonstrates strong architectural foundations with a well-structured FastAPI backend, a mature React Native mobile app, and a comprehensive CLI. However, the quality experience is uneven across touchpoints, with several gaps that impact different user personas in distinct ways.
Strengths:
archive/v1/src/middleware/error_handler.py)ui/mobile/src/services/ws.service.ts)archive/v1/src/api/routers/health.py)archive/v1/src/api/routers/pose.py)ui/mobile/src/stores/settingsStore.ts)ui/mobile/src/screens/SettingsScreen/ServerUrlInput.tsx)Critical Issues:
docs_url=None, redoc_url=None when is_production=True), leaving production API consumers without discoverability (in archive/v1/src/api/main.py line 146-148)archive/v1/src/api/routers/pose.py lines 320-361)Retry-After message body; the client receives a bare "Rate limit exceeded" string with retry information only in HTTP headers (archive/v1/src/middleware/rate_limit.py line 323)status command uses emoji/Unicode characters that break in terminals without UTF-8 support (archive/v1/src/commands/status.py lines 360-474)MainTabs.tsx passes an inline arrow function as the component prop to Tab.Screen (line 130), causing unnecessary re-renders on every parent render cycleTop 3 Recommendations:
/api-docs) with authentication, rather than removing docs entirely--no-emoji CLI flag or auto-detect terminal capabilities to avoid broken status output| Dimension | Score | Grade | Assessment |
|---|---|---|---|
| Overall QX | 71/100 | C+ | Functional but inconsistent across touchpoints |
| API Experience | 78/100 | B- | Well-structured endpoints, good error model, weak discoverability |
| CLI Experience | 65/100 | D+ | Adequate commands, poor terminal compatibility, limited help |
| Mobile UX | 80/100 | B | Strong connection handling, good fallbacks, minor render issues |
| Developer Experience | 68/100 | D+ | Steep learning curve, complex build, limited onboarding docs |
| Hardware UX | 62/100 | D | Complex provisioning, limited error recovery guidance |
| Accessibility | 45/100 | F | No ARIA consideration in mobile, no high-contrast support |
| Trust & Reliability | 76/100 | B- | Good health checks, rate limiting, auth framework in place |
| Cross-Codebase Consistency | 70/100 | C | Different error formats between API/CLI, naming inconsistencies |
Journey: Clone repo -> Set up environment -> Build -> Run tests -> Develop -> Submit PR
| Step | Success Rate | Pain Level | Bottleneck |
|---|---|---|---|
| Clone & orient | Moderate | MEDIUM | Multiple codebases (Python v1, Rust, firmware, mobile) with no single entry point guide |
| Environment setup | Low | HIGH | Requires Python + Rust toolchain + Node.js + ESP-IDF for full development |
| Build Python API | Moderate | MEDIUM | Dependency management not containerized for easy onboarding |
| Run Rust tests | High | LOW | cargo test --workspace --no-default-features works reliably (1,031+ tests) |
| Run Python tests | Moderate | MEDIUM | Requires database setup, Redis optional but affects behavior |
| Contribute to mobile | Moderate | MEDIUM | Expo/React Native setup is standard but undocumented within this repo |
Key Findings:
CLAUDE.md is comprehensive for AI agents but not optimized for human developers; it mixes agent configuration with build instructionsCONTRIBUTING.md file existspip, Rust uses cargo, mobile uses npm, firmware uses ESP-IDFnpm test, cargo test, and python -m pytest with no unified runnerCLAUDE.md has 12 items, which is thorough but creates friction for external contributorsJourney: Install -> Configure -> Start server -> Monitor -> Troubleshoot
| Step | Success Rate | Pain Level | Bottleneck |
|---|---|---|---|
| Install | Low | HIGH | No single installation script or Docker Compose for the full stack |
| Configure | Moderate | MEDIUM | Config file path must be specified; no --init to generate default config |
| Start server | Moderate | MEDIUM | wifi-densepose start works but database must be initialized first |
| Monitor status | High | LOW | wifi-densepose status --detailed provides comprehensive output |
| Stop server | High | LOW | Both graceful and force-stop options available |
| Troubleshoot | Low | HIGH | Error messages reference internal exceptions; no runbook or FAQ |
Key Findings:
start, stop, status, db init/migrate/rollback, config show/validate/failsafe, tasks run/status, and version -- a reasonable command setwifi-densepose init command to scaffold a working configuration from scratchconfig validate command checks database, Redis, and directory availability -- good for operatorsconfig failsafe command showing SQLite fallback status is a strong resilience featurewifi-densepose doctor self-diagnosis commandJourney: Open app -> Connect to server -> View live data -> Check vitals -> Manage zones -> Configure settings
| Step | Success Rate | Pain Level | Bottleneck |
|---|---|---|---|
| Open app | High | LOW | Clean initial load with loading spinners |
| Connect to server | Moderate | MEDIUM | Default URL is localhost:3000 which will not work on physical devices |
| View live data | High | LOW | Simulation fallback ensures something is always displayed |
| Check vitals | High | LOW | Gauges, sparklines, and classification render smoothly |
| Manage zones | Moderate | LOW | Heatmap visualization is functional |
| Configure settings | High | LOW | Server URL validation, test connection, save workflow is solid |
Key Findings:
serverUrl in settingsStore.ts is http://localhost:3000, which will fail on a physical device where the server runs on a different machine; a first-run setup wizard would improve thisLIVE STREAM, SIMULATED DATA, and DISCONNECTED via ConnectionBanner.tsxgenerateSimulatedData()) activates automatically when WebSocket connection fails, ensuring the app never shows a blank screenErrorBoundary provides crash recovery with a "Retry" button, but the error message is the raw JavaScript error (error.message) without user-friendly contextThe API follows RESTful conventions with clear resource paths:
GET /health/health - System health
GET /health/ready - Readiness probe
GET /health/live - Liveness probe
GET /health/metrics - System metrics (auth required for detailed)
GET /health/version - Version info
GET /api/v1/pose/current - Current pose estimation
POST /api/v1/pose/analyze - Custom analysis (auth required)
GET /api/v1/pose/zones/{zone_id}/occupancy - Zone occupancy
GET /api/v1/pose/zones/summary - All zones summary
POST /api/v1/pose/historical - Historical data (auth required)
GET /api/v1/pose/activities - Recent activities
POST /api/v1/pose/calibrate - Start calibration (auth required)
GET /api/v1/pose/calibration/status - Calibration status
GET /api/v1/pose/stats - Statistics
WS /api/v1/stream/pose - Real-time pose stream
WS /api/v1/stream/events - Event stream
Issues Found:
GET /health/health is redundant path nesting; the health router is mounted at /health prefix, making the full path /health/health. This should be /health (root of the health router) or the prefix should be / for the health routerPOST /api/v1/pose/historical uses POST for a read operation. While this is common for complex queries, it violates REST conventions. A GET with query parameters or a POST /api/v1/pose/query would be clearerGET /) exposes feature flags (authentication, rate_limiting) which could leak security posture informationThe ErrorHandler class in archive/v1/src/middleware/error_handler.py is well-designed:
Strengths:
{ "error": { "code": "...", "message": "...", "timestamp": "...", "request_id": "..." } }X-Request-ID header for debuggingBusinessLogicError, ResourceNotFoundError, ConflictError, ServiceUnavailableError) with domain contextIssues Found:
ErrorHandlingMiddleware class exists but is commented out (line 432-434 in error_handler.py), meaning errors are handled by setup_error_handling() exception handlers instead. The middleware class and the exception handlers use different ErrorHandler instances, creating potential inconsistency if one is changed without the other_is_database_error() check uses string matching on module names (line 355-373), which is fragile. "ConnectionError" will match aiohttp.ConnectionError (an external service error), not just database connection errorsdocumentation_url field that could guide users to relevant docsStrengths:
X-RateLimit-* headers on all responsesRetry-After header on 429 responsesIssues Found:
"Rate limit exceeded" (a plain string). No structured error response with the ErrorResponse format is used. The rate limit middleware raises HTTPException directly rather than using CustomHTTPException or ErrorResponseRateLimitConfig presets (development, production, api, strict) are defined but there is no CLI command or API endpoint to switch between themStrengths:
type field (ping, update_config, get_status)update_config messageIssues Found:
websocket.accept() (line 80-93 in stream.py), meaning unauthenticated clients briefly hold a connection before being closed. This wastes resources and leaks the existence of the endpointhandle_websocket_message function handles unknown message types with an error, but does not suggest valid message types: "Unknown message type: foo" should list valid optionsIssues Found:
/docs) and ReDoc (/redoc) are disabled in production (line 146-148 of main.py): docs_url=settings.docs_url if not settings.is_production else NoneGET / root endpoint and GET /api/v1/info endpoint provide feature information but no link to documentationField(description=...) annotations, which would generate useful OpenAPI docs -- but only visible in developmentversion fieldThe CLI uses Click with a nested group structure:
wifi-densepose [--config FILE] [--verbose] [--debug]
start [--host] [--port] [--workers] [--reload] [--daemon]
stop [--force] [--timeout]
status [--format text|json] [--detailed]
db
init [--url]
migrate [--revision]
rollback [--steps]
tasks
run [--task cleanup|monitoring|backup]
status
config
show
validate
failsafe [--format text|json]
version
Strengths:
--config, --verbose, --debug available on all commands--daemon mode with PID file management and stale PID detectionstatus and failsafe for scriptingIssues Found:
init or setup command to generate a default configuration filelogs command to tail or search server logstasks status subcommand shadows the parent status command in Click's namespace (line 347-348 in cli.py defines def status(ctx): under the tasks group), which works but creates confusion--quiet option for scripting (opposite of --verbose)logger.error() which depends on logging configuration; if logging is misconfigured, errors are silently lostIssues Found:
start command show the raw exception: "Failed to start server: {e}" where {e} is the Python exception stringstart, the error is "Database connection failed: [psycopg2 error]" with no guidance like "Check your DATABASE_URL setting" or "Run 'wifi-densepose db init' first"config validate command outputs check-style messages ("X Database connection: FAILED - {e}") which is helpful, but the X and checkmark characters use Unicode that may not render in all terminalsstop command handles "Server is not running" gracefully, which is goodStrengths:
Issues Found:
epilog pattern used in provision.py is good practice but is not used in the Click CLI--help examples showing common workflows like "Start a development server", "Deploy to production", or "Initialize a fresh installation""Start the WiFi-DensePose API server" does not mention prerequisitesStrengths:
config show displays the full configuration without secretsconfig validate checks database, Redis, and directory accessconfig failsafe shows SQLite fallback and Redis degradation status--config flagIssues Found:
config init to generate a template configuration fileconfig set KEY VALUE to modify individual settingsconfig show output dumps JSON but does not annotate which values are defaults vs user-configuredThe app uses a bottom tab navigator with five screens:
Live (wifi icon) -> Vitals (heart) -> Zones (grid) -> MAT (shield) -> Settings (gear)
Strengths:
React.lazy and suspense fallbacks showing loading indicator with screen name"{label} screen not implemented yet" with a "Placeholder shell" subtitleIssues Found:
MainTabs.tsx line 130: component={() => <Suspended component={component} />} creates a new function reference on every render. This should be refactored to a stable component reference to prevent unnecessary tab re-rendersfontFamily: 'Courier New' which may not be available on all devices, with no fallback font specifiedThe WebSocket connection strategy in ws.service.ts is well-designed:
Strengths:
usePoseStream hookIssues Found:
buildWsUrl() hardcodes the path /ws/sensing, but the API server expects /api/v1/stream/pose. This path mismatch (WS_PATH = '/api/v1/stream/pose' in constants/websocket.ts vs /ws/sensing in ws.service.ts) is a potential connection failure pointStrengths:
LoadingSpinner component with smooth rotation animation using react-native-reanimatedErrorBoundary wraps the LiveScreen with crash recoveryviewerKey to force component remountConnectionBanner provides three distinct visual states with semantic colors (green/amber/red)Issues Found:
ErrorBoundary shows error.message directly, which may be a technical JavaScript error string like "Cannot read property 'x' of undefined". A user-friendly message mapping would improve the experienceonReady, the loading spinner displays indefinitelyN/A for features when no data is available, but the gauges (BreathingGauge, HeartRateGauge) behavior at zero/null values is not guarded in the screen codeStrengths:
poseStore (real-time data), settingsStore (configuration), matStore (MAT data)settingsStore uses persist middleware with AsyncStorage for cross-session persistenceposeStore uses a RingBuffer for RSSI history, capping at 60 entries to prevent memory growthreset() method on poseStore to clear all stateIssues Found:
poseStore is not persisted, so all historical data is lost on app restart. For a monitoring application, this is a significant gaphandleFrame method updates 6 state properties atomically in one set() call, which is correct, but the rssiHistory is computed from a module-level RingBuffer that exists outside the store, creating a potential synchronization issue during hot reloadsettingsStore -- if the schema changes between app versions, persisted state may cause errorsThe ServerUrlInput component in the Settings screen provides:
Strengths:
validateServerUrl() showing error messages inlineIssues Found:
http://localhost:3000 will never work on a physical device. The first-run experience should prompt for the server address or attempt auto-discovery via mDNS/BonjourIssues Found:
pip/poetry), Rust (cargo), Node.js (npm), and ESP-IDF for firmwareMakefile, Taskfile, or just file to abstract build commandsCLAUDE.md lists build commands but they are mixed with AI agent configurationdocker-compose.yml for local development was foundStrengths:
cargo test --workspace --no-default-featurespython archive/v1/data/proof/verify.py with SHA-256 hash checkingVERIFY.sh providing 7/7 pass/fail attestationIssues Found:
python -m pytest tests/ -x -q) requires proper environment setup firstjest, React Native testing libraries)Strengths:
docs/adr/docs/ddd/docs/user-guide.mdIssues Found:
CLAUDE.md is 500+ lines but is primarily an AI agent configuration file, not a developer guideStrengths:
wifi-densepose-core)Issues Found:
f"Pose estimation failed: {str(e)}". These are user-facing but contain internal detailsStrengths:
Settings class with environment variable support--config CLI flagIssues Found:
.env.example or .env.template file to guide environment variable setupconfig show command redacts secrets but does not explain where secrets should be configuredThe provision.py script in firmware/esp32-csi-node/ handles WiFi credential and mesh configuration:
Strengths:
--help text with usage examples in the argparse epilog--dry-run option to generate binary without flashing"WiFi Password: ****"Issues Found:
--port is required, but users may not know which port their ESP32 is on. A --port auto option using serial.tools.list_ports would helpesptool or nvs_partition_gen is not installed is a raw Python exception. A friendlier message like "Required tool 'esptool' not found. Install with: pip install esptool" would be betterprovision.py but it is invoked as python firmware/esp32-csi-node/provision.py, which is a long path. A CLI subcommand like wifi-densepose hw provision would integrate better--profile basic, --profile mesh, --profile edge) would simplify common use casesIssues Found:
python -m serial.tools.miniterm COM7 115200, which is a raw tool with no structured log parsingIssues Found:
idf.py flash which requires the full ESP-IDF toolchainota_data_initial.bin is listed in the release process but OTA update instructions are not providedsdkconfig.defaults files with manual copying| Touchpoint | Error Format | User Guidance | Recovery Path |
|---|---|---|---|
| API REST | Structured JSON with code, message, request_id | No documentation links | Retry logic needed by client |
| API WebSocket | JSON { type: "error", message: "..." } | Lists valid message types: No | Reconnect |
| CLI | Logger output to stderr | No remediation suggestions | Exit code 1 |
| Mobile | ErrorBoundary with retry, ConnectionBanner | Raw error messages | Retry button, reconnect |
| Provisioning | Python exceptions | Fallback CSV on failure | Manual flash instructions |
Key Gap: Error message styles differ between API (structured JSON) and CLI (logger strings). A unified error taxonomy would improve consistency.
| Action | Feedback Mechanism | Timeliness | Quality |
|---|---|---|---|
| API request | HTTP status + response body | Immediate | Good |
| WebSocket connect | connection_established message | Immediate | Good |
| CLI start | Log messages to stdout | Real-time | Adequate |
| CLI stop | "Server stopped gracefully" | After completion | Good |
| Calibration start | Returns calibration_id and estimated_duration_minutes | Immediate | Incomplete (no progress stream) |
| Mobile connect | Banner color change | ~1s delay | Good |
| Firmware flash | print() statements | Real-time | Adequate |
| Settings save | No confirmation | Silent | Poor |
| Failure Scenario | Recovery Path | Automated? | Documentation |
|---|---|---|---|
| Database connection fails | SQLite failsafe fallback | Yes | config failsafe command |
| Redis unavailable | Continues without Redis, logs warning | Yes | Mentioned in startup output |
| WebSocket disconnects | Exponential backoff reconnection, simulation fallback | Yes | Not documented |
| Stale PID file | Detected and cleaned up on start/stop | Yes | Not documented |
| API server crash | No automatic restart | No | No systemd/supervisor config |
| Mobile app crash | ErrorBoundary with retry | Partial | Not documented |
| Firmware flash fails | Fallback CSV with manual instructions | Partial | Inline help |
| Calibration fails | No documented recovery | No | Not documented |
Issues Found:
'#0F141E', '#0F6B2A', '#8A1E2A') with no high-contrast mode supportaccessibilityLabel or accessibilityRole props on interactive components in the mobile appConnectionBanner relies on color alone to distinguish states (green/amber/red). The text labels (LIVE STREAM, SIMULATED DATA, DISCONNECTED) help, but there is no screen reader announcement on state changeType: User Need vs Business Need Conflict
docs_url=None when is_production=True) leaves production API consumers without any discoverability mechanismFailure Modes:
Resolution Options:
| Option | User Score | Security Score | Recommendation |
|---|---|---|---|
| Keep docs disabled | 20 | 95 | Current state |
| Auth-gated docs endpoint | 85 | 80 | Recommended |
| Separate docs site from OpenAPI spec export | 90 | 90 | Best but more effort |
| Rate-limited docs with no auth | 70 | 60 | Compromise |
Type: User Experience vs Data Accuracy Conflict
Failure Modes:
Resolution Options:
| Option | UX Score | Safety Score | Recommendation |
|---|---|---|---|
| Current: auto-simulate with banner | 80 | 50 | Risky for safety-critical screens |
| Disable simulation on MAT/Vitals screens | 60 | 85 | Recommended |
| Prominent modal overlay for simulated mode | 70 | 80 | Good compromise |
| Require user confirmation to enter simulation | 55 | 90 | Safest |
Type: Missing Information / Implementation Inconsistency
ws.service.ts constructs the WebSocket URL as /ws/sensing (line 104), while constants/websocket.ts defines WS_PATH = '/api/v1/stream/pose'. The API server serves WebSocket on /api/v1/stream/pose (stream router). These paths do not match./ws/sensing), but the inconsistency creates confusion and potential silent connection failures| # | Recommendation | Effort | Impact | Persona |
|---|---|---|---|---|
| 1.1 | Add auth-gated API documentation endpoint for production | Low | High | Developer, Operator |
| 1.2 | Resolve WebSocket path mismatch between ws.service.ts and constants/websocket.ts | Low | High | End-User |
| 1.3 | Disable automatic simulation fallback on MAT screen (safety-critical) | Low | High | End-User, Operator |
| 1.4 | Fix MainTabs.tsx inline arrow function causing unnecessary re-renders (line 130) | Low | Medium | End-User |
| 1.5 | Include structured error body in 429 rate limit responses using ErrorResponse format | Low | Medium | Developer |
| # | Recommendation | Effort | Impact | Persona |
|---|---|---|---|---|
| 2.1 | Add wifi-densepose init command to scaffold default configuration | Medium | High | Operator |
| 2.2 | Change default mobile serverUrl from localhost:3000 to empty string with first-run setup prompt | Medium | High | End-User |
| 2.3 | Add terminal capability detection to CLI for emoji/unicode fallback | Medium | Medium | Operator |
| 2.4 | Add calibration progress WebSocket stream or polling endpoint with step-by-step updates | Medium | Medium | Operator, Developer |
| 2.5 | Create a CONTRIBUTING.md with quickstart for each codebase | Medium | High | Developer |
| 2.6 | Map ErrorBoundary error messages to user-friendly strings | Low | Medium | End-User |
| 2.7 | Add loading timeout to LiveScreen WebView initialization | Low | Medium | End-User |
| # | Recommendation | Effort | Impact | Persona |
|---|---|---|---|---|
| 3.1 | Create unified Makefile or Taskfile for cross-codebase builds and tests | High | High | Developer |
| 3.2 | Add --port auto to provisioning script with serial port auto-detection | Medium | Medium | Operator |
| 3.3 | Add accessibility labels to mobile app interactive components | Medium | Medium | End-User |
| 3.4 | Create architecture diagram showing component interactions | Medium | High | Developer |
| 3.5 | Add .env.example file documenting all environment variables | Low | Medium | Developer, Operator |
| 3.6 | Implement wifi-densepose doctor for self-diagnosis | High | Medium | Operator |
| 3.7 | Add wifi-densepose logs command with filtering and formatting | Medium | Medium | Operator |
| 3.8 | Persist poseStore RSSI history for post-restart analysis | Medium | Low | End-User |
| 3.9 | Add provisioning parameter presets (--profile basic/mesh/edge) | Medium | Medium | Operator |
| 3.10 | Authenticate WebSocket before websocket.accept() | Low | Low | Developer |
| Heuristic | Score | Finding |
|---|---|---|
| H1.1: Understand the Problem | 75/100 | The system addresses WiFi-based pose estimation well but the quality experience varies significantly across touchpoints. The core problem (sensing and display) is well-solved; the surrounding experience (setup, configuration, debugging) needs work. |
| H1.2: Identify Stakeholders | 70/100 | Three personas (developer, operator, end-user) are implicitly served but not explicitly designed for. The mobile app targets end-users well; the CLI targets operators adequately; developer experience is the weakest. |
| H1.3: Define Quality Criteria | 65/100 | Health checks define "healthy/degraded/unhealthy" but no SLA or quality thresholds are documented. Rate limits are configurable but default values are not justified. |
| H1.4: Map Failure Modes | 72/100 | Database failsafe, Redis degradation, and WebSocket reconnection cover major failure modes. Missing: calibration failure recovery, firmware flash failure recovery, mobile app state corruption. |
| Heuristic | Score | Finding |
|---|---|---|
| H2.1: Task Completion | 78/100 | Core tasks (view live data, check vitals, manage zones) are completable. Setup tasks (install, configure, provision) have friction. |
| H2.2: Error Recovery | 68/100 | Some automated recovery (database failsafe, WebSocket reconnect). Missing recovery paths for calibration failure and firmware issues. |
| H2.3: Learning Curve | 60/100 | Steep onboarding across four codebases. No quickstart guide. Mobile app is the most intuitive touchpoint. |
| H2.4: Feedback Clarity | 72/100 | API provides structured feedback. CLI provides log-style feedback. Mobile provides visual feedback. Calibration progress is the biggest gap. |
| H2.5: Consistency | 70/100 | Error formats differ between API (JSON) and CLI (logger). Mobile is internally consistent. Naming conventions mostly aligned. |
| Heuristic | Score | Finding |
|---|---|---|
| H3.1: Reliability | 76/100 | Health checks, failsafes, and reconnection strategies demonstrate reliability focus. No documented SLAs or uptime targets. |
| H3.2: Security Posture | 72/100 | Authentication framework exists but JWT validation is not implemented. Rate limiting is configurable. Production docs are hidden. Secrets redacted in config output. |
| H3.3: Scalability | 68/100 | Multi-worker support, WebSocket connection management, per-endpoint rate limiting. No load testing results or capacity planning documented. |
| H3.4: Maintainability | 74/100 | Well-separated crates, clear module boundaries, typed interfaces. Pre-merge checklist ensures documentation updates. ADR process is mature. |
| Heuristic | Score | Finding |
|---|---|---|
| H4.1: UX vs Security | 65/100 | Production API docs disabled for security, but no alternative provided. Authentication errors are informative without leaking implementation details. |
| H4.2: Simplicity vs Capability | 68/100 | Provisioning script has 22 parameters. CLI has good grouping but missing convenience features. API has comprehensive endpoints. |
| H4.3: Consistency vs Flexibility | 72/100 | Error handling is structured but not uniform across touchpoints. Settings are flexible (env vars + config file + CLI flags). |
| Heuristic | Score | Finding |
|---|---|---|
| H5.1: Visible Impact (GUI/UX) | 76/100 | Mobile app provides clear visual states. CLI status output is detailed. API responses are informative. |
| H5.2: Invisible Impact (Performance) | 70/100 | cpu_percent(interval=1) in health check blocks for 1 second per request. Rate limiting uses async locks correctly. RingBuffer prevents memory growth. |
| H5.3: Safety Impact | 62/100 | MAT screen auto-simulation is a safety concern. Simulated vitals data could mislead operators. No data provenance indicator beyond the connection banner. |
| H5.4: Data Integrity | 72/100 | Pydantic validation on all inputs. Zone ID existence checks. Time range validation on historical queries. Deterministic proof verification for core pipeline. |
| Heuristic | Score | Finding |
|---|---|---|
| H6.1: Novel Testing Approaches | 68/100 | Witness bundle verification is creative. Deterministic proof with SHA-256 is strong. No mutation testing or property-based testing. |
| H6.2: Alternative Perspectives | 65/100 | The simulation fallback is creative but creates oracle problems. Database failsafe is a pragmatic solution. |
| H6.3: Cross-Domain Insights | 70/100 | WiFi CSI for pose estimation is inherently cross-domain (RF + computer vision + IoT). The mobile app's GaussianSplat visualization is innovative. |
This Quality Experience analysis was performed by examining source code across all touchpoints of the WiFi-DensePose system. Files analyzed include:
API Layer (9 files):
archive/v1/src/api/main.py -- FastAPI application setup, middleware configuration, exception handlersarchive/v1/src/api/routers/health.py -- Health check endpointsarchive/v1/src/api/routers/pose.py -- Pose estimation endpointsarchive/v1/src/api/routers/stream.py -- WebSocket streaming endpointsarchive/v1/src/api/websocket/connection_manager.py -- WebSocket connection lifecyclearchive/v1/src/api/dependencies.py -- Dependency injection, authentication, authorizationarchive/v1/src/middleware/error_handler.py -- Error handling middlewarearchive/v1/src/middleware/rate_limit.py -- Rate limiting middlewareCLI Layer (4 files):
archive/v1/src/cli.py -- Click CLI entry pointarchive/v1/src/commands/start.py -- Server start commandarchive/v1/src/commands/stop.py -- Server stop commandarchive/v1/src/commands/status.py -- Server status commandMobile Layer (15 files):
ui/mobile/src/screens/LiveScreen/index.tsx -- Live visualization screenui/mobile/src/screens/VitalsScreen/index.tsx -- Vitals monitoring screenui/mobile/src/screens/ZonesScreen/index.tsx -- Zone occupancy screenui/mobile/src/screens/MATScreen/index.tsx -- Mass casualty assessment screenui/mobile/src/screens/SettingsScreen/index.tsx -- Settings screenui/mobile/src/screens/SettingsScreen/ServerUrlInput.tsx -- Server URL configurationui/mobile/src/navigation/MainTabs.tsx -- Tab navigationui/mobile/src/components/ErrorBoundary.tsx -- Error boundaryui/mobile/src/components/ConnectionBanner.tsx -- Connection status bannerui/mobile/src/components/LoadingSpinner.tsx -- Loading indicatorui/mobile/src/services/ws.service.ts -- WebSocket serviceui/mobile/src/services/api.service.ts -- HTTP API serviceui/mobile/src/stores/poseStore.ts -- Real-time data storeui/mobile/src/stores/settingsStore.ts -- Persisted settings storeui/mobile/src/utils/urlValidator.ts -- URL validationui/mobile/src/hooks/usePoseStream.ts -- Pose data stream hookui/mobile/src/constants/websocket.ts -- WebSocket constantsHardware Layer (1 file):
firmware/esp32-csi-node/provision.py -- ESP32 provisioning scriptThe analysis applied 23 QX heuristics across 6 categories (Problem Analysis, User Needs, Business Needs, Balance, Impact, Creativity) and identified 3 oracle problems where quality criteria conflict across stakeholders.