Back to Ruview

Code Quality and Complexity Analysis Report

docs/qe-reports/01-code-quality-complexity.md

1.99.0-pip25.2 KB
Original Source

Code Quality and Complexity Analysis Report

Project: wifi-densepose (ruview) Date: 2026-04-05 Analyzer: QE Code Complexity Analyzer v3 Scope: Full codebase -- Rust, Python, C firmware, TypeScript/React Native


Executive Summary

This report analyzes code complexity across the entire wifi-densepose project -- 153,139 lines of Rust, 21,399 lines of Python, 7,987 lines of C firmware, and 7,457 lines of TypeScript/React Native. The analysis identified 231 Rust functions with cyclomatic complexity > 10, a single 4,846-line Rust file that constitutes the most critical hotspot in the entire codebase, and systematic code duplication patterns that inflate maintenance cost.

Key Findings

MetricRustPythonC FirmwareTypeScript
Source files379633271
Total lines153,13921,3997,9877,457
Functions analyzed6,64188814597
CC > 10231 (3.5%)16 (1.8%)22 (15.2%)3 (3.1%)
CC > 2074 (1.1%)05 (3.4%)1 (1.0%)
Functions > 50 lines282 (4.2%)49 (5.5%)26 (17.9%)3 (3.1%)
Functions > 100 lines81 (1.2%)6 (0.7%)6 (4.1%)1 (1.0%)
Files > 500 lines92 (24%)11 (17%)4 (25%)1 (1.4%)
Files > 1000 lines24 (6%)01 (6%)0
Max nesting > 4215 (3.2%)7 (0.8%)4 (2.8%)2 (2.1%)

Overall Quality Score: 62/100 (MODERATE)

The Python and TypeScript codebases are well-structured. The Rust codebase has pockets of extreme complexity concentrated in the sensing server, and the C firmware has proportionally the highest rate of complex functions.


1. Rust Codebase (153,139 lines, 17 crates)

1.1 Crate Size Breakdown

CrateFilesLinesAssessment
wifi-densepose-wasm-edge6828,888Largest; 68 vendor modules with repetitive process_frame
wifi-densepose-mat4319,572Mass casualty assessment; moderate complexity
wifi-densepose-sensing-server1817,825CRITICAL -- contains the worst hotspot
wifi-densepose-signal2816,194RuvSense multistatic modules; well-decomposed
wifi-densepose-train1810,562Training pipeline; moderate complexity
wifi-densepose-wifiscan235,779Multi-BSSID pipeline; clean architecture
wifi-densepose-ruvector164,629Cross-viewpoint fusion
wifi-densepose-hardware114,005ESP32 TDM protocol
wifi-densepose-desktop153,309Tauri desktop app
wifi-densepose-nn72,959Neural network inference
wifi-densepose-core52,596Core types and traits
Other (6 crates)144,987Small, well-sized
Total267121,306 (src only)

1.2 Top 20 Most Complex Rust Functions

RankCCLinesDepthFunctionFileLine
11217768mainsensing-server/src/main.rs4070
2664228udp_receiver_tasksensing-server/src/main.rs3504
3552785updatemat/src/tracking/tracker.rs171
4501848process_framewasm-edge/src/med_seizure_detect.rs157
5472326train_from_recordingssensing-server/src/adaptive_classifier.rs284
6423815detect_formatmat/src/integration/csi_receiver.rs815
741784deserialize_nvs_configdesktop/src/commands/provision.rs345
8411694process_framewasm-edge/src/sec_perimeter_breach.rs140
9404726real_training_loopsensing-server/src/training_api.rs825
10371536process_framewasm-edge/src/bld_lighting_zones.rs118
11371787process_framewasm-edge/src/ret_table_turnover.rs134
12361547process_framewasm-edge/src/lrn_dtw_gesture_learn.rs145
13341674process_framewasm-edge/src/exo_breathing_sync.rs197
14341704process_framewasm-edge/src/exo_ghost_hunter.rs198
15331345process_framewasm-edge/src/ind_structural_vibration.rs137
1633904process_framewasm-edge/src/ais_prompt_shield.rs65
17321445process_framewasm-edge/src/ret_shelf_engagement.rs163
18321745process_framewasm-edge/src/exo_plant_growth.rs170
19311296process_framewasm-edge/src/bld_meeting_room.rs98
20311255process_framewasm-edge/src/ret_dwell_heatmap.rs116

1.3 Critical Hotspot: sensing-server/src/main.rs (4,846 lines)

This is the single worst file in the entire codebase. At 4,846 lines, it is 9.7x the project's 500-line guideline and contains:

God Object: AppStateInner (lines 424-525)

  • 40+ fields spanning unrelated concerns: vital signs, recording state, training state, adaptive model, per-node state, field model calibration, model management
  • Violates Single Responsibility Principle -- mixes signal processing state, application lifecycle, network I/O, and persistence concerns

Monolithic main() function (lines 4070-4846)

  • CC=121, 776 lines, nesting depth 8
  • Handles CLI dispatch (benchmark, export, pretrain, embed, build-index, train, server startup) all in one function
  • Should be decomposed into at least 8 separate command handlers

udp_receiver_task() function (lines 3504-3926)

  • CC=66, 422 lines, nesting depth 8
  • Handles three different packet types (vitals 0xC511_0002, WASM 0xC511_0004, CSI 0xC511_0001) in a single monolithic match chain
  • Each branch duplicates the full sensing update construction and broadcast logic

Systematic Code Duplication (6 instances):

  • smooth_and_classify / smooth_and_classify_node -- identical logic, differs only in operating on AppStateInner vs NodeState (could use a trait)
  • smooth_vitals / smooth_vitals_node -- same pattern, identical algorithm duplicated for AppStateInner vs NodeState
  • SensingUpdate construction -- built identically in 6 different places (WiFi task, WiFi fallback, simulate task, ESP32 CSI handler, ESP32 vitals handler, broadcast tick)
  • Person count estimation -- repeated in WiFi, ESP32, and simulate paths

1.4 Code Smell: wasm-edge Vendor Modules

The wifi-densepose-wasm-edge crate contains 68 files (28,888 lines), with nearly every module implementing a process_frame function following the same pattern. At least 20 of these have CC > 25. This is a textbook case for:

  • Extracting a common process_frame trait with shared scaffolding
  • Using a generic signal pipeline builder

1.5 Oversized Rust Files (> 500 lines, violating project guideline)

92 Rust files exceed the 500-line guideline. The worst offenders:

LinesFile
4,846sensing-server/src/main.rs
1,946sensing-server/src/training_api.rs
1,673wasm/src/mat.rs
1,664train/src/metrics.rs
1,523signal/src/ruvsense/pose_tracker.rs
1,498sensing-server/src/embedding.rs
1,430ruvector/src/crv/mod.rs
1,401mat/src/integration/csi_receiver.rs
1,360mat/src/integration/hardware_adapter.rs
1,346signal/src/ruvsense/field_model.rs

1.6 Dependency Analysis

No circular dependencies detected. The dependency graph is clean and follows the documented crate publishing order. Maximum depth is 3 (CLI -> MAT -> core/signal/nn).


2. Python Codebase (21,399 lines, 63 files)

2.1 Overall Assessment: GOOD

The Python codebase is significantly better structured than the Rust codebase. Only 16 functions (1.8%) exceed CC=10, and no function exceeds CC=20. The code follows clean separation of concerns with distinct layers (api, services, core, hardware, middleware, sensing).

2.2 Top 10 Most Complex Python Functions

RankCCLinesDepthFunctionFileLine
119904estimate_posesservices/pose_service.py491
2181266_print_text_statuscommands/status.py350
315724websocket_events_streamapi/routers/stream.py156
4141003health_checkdatabase/connection.py349
514473get_overall_healthservices/health_check.py384
613523_authenticate_requestmiddleware/auth.py236
713644_handle_preflightmiddleware/cors.py89
813844websocket_pose_streamapi/routers/stream.py69
913654generate_signal_fieldsensing/ws_server.py236
1013746create_collectorsensing/rssi_collector.py770

2.3 Files Exceeding 500 Lines

LinesFileConcern
856services/pose_service.pyPose estimation service -- acceptable for a service class
843sensing/rssi_collector.pyRSSI collection with 3 collector implementations
772tasks/monitoring.pyBackground monitoring tasks
640database/connection.pyDatabase connection management
620cli.pyCLI command handler
610tasks/backup.pyBackup task logic
598tasks/cleanup.pyCleanup task logic
519sensing/ws_server.pyWebSocket server
515hardware/csi_extractor.pyCSI data extraction
510commands/status.pyStatus reporting
504middleware/error_handler.pyError handling middleware

2.4 Observations

  • Well-typed: Uses type hints consistently throughout
  • Clean separation: API routers, services, core, and middleware are distinct
  • Moderate nesting: Only 7 functions (0.8%) exceed nesting depth 4
  • Minor concern: _print_text_status (CC=18, 126 lines) in commands/status.py is essentially a large formatting function that could be split into per-component formatters

3. C Firmware (7,987 lines, 32 files)

3.1 Overall Assessment: MODERATE

The C firmware has the highest proportion of complex functions (15.2% with CC>10). This is partly expected for embedded C, but several functions warrant attention.

3.2 Top 10 Most Complex C Functions

RankCCLinesDepthFunctionFileLine
1593143nvs_config_loadnvs_config.c19
2401853process_frameedge_processing.c708
3251255display_ui_updatedisplay_ui.c259
422943mock_timer_cbmock_csi.c518
5221743app_mainmain.c127
6211363rvf_parservf_parser.c33
7191193wasm_runtime_loadwasm_runtime.c442
818843send_vitals_packetedge_processing.c554
917744update_multi_person_vitalsedge_processing.c474
1017343ld2410_feed_bytemmwave_sensor.c274

3.3 Critical Hotspot: nvs_config_load (CC=59, 314 lines)

This function in nvs_config.c has the highest complexity of any C function. It loads 30+ configuration parameters from NVS flash storage, each with its own error handling and default-value fallback. This is a classic case for:

  • Table-driven configuration loading with a descriptor array
  • Macro-based parameter definition to eliminate repetition

3.4 edge_processing.c (1,067 lines)

This is the only C file exceeding 1,000 lines. It implements the full dual-core CSI processing pipeline (11 processing stages). The process_frame function (CC=40, 185 lines) combines phase extraction, variance tracking, subcarrier selection, bandpass filtering, BPM estimation, presence detection, and fall detection in a single function.

3.5 Stack Safety Concern

The code documents that process_frame + update_multi_person_vitals combined used 6.5-7.5 KB of the 8 KB task stack, necessitating static scratch buffers. This indicates the functions are pushing resource limits and should be decomposed for safety margin.


4. TypeScript/React Native (7,457 lines, 71 files)

4.1 Overall Assessment: GOOD

The UI codebase is the cleanest in the project. Only 3 functions exceed CC=10, no file exceeds 1,000 lines, and the component architecture follows React best practices with proper separation of screens, components, stores, and services.

4.2 Critical Hotspot: GaussianSplatWebView.web.tsx (CC=70, 747 lines)

This is the only significant complexity hotspot in the TypeScript codebase. The GaussianSplatWebViewWeb component (CC=70, 467 lines) manages:

  • Three.js scene initialization and teardown
  • Multi-person skeleton rendering with DensePose-style body parts
  • Signal field visualization
  • Animation loop management
  • Frame data parsing and keypoint mapping

This component should be decomposed into:

  • A Three.js scene manager (initialization, camera, lighting, animation)
  • A skeleton renderer (body parts, keypoints, bones)
  • A signal field renderer (grid, heatmap)
  • A data adapter (frame parsing, person mapping)

4.3 Well-Structured Patterns

  • Zustand stores (poseStore.ts, matStore.ts, settingsStore.ts): Clean state management with proper typing
  • Custom hooks (useMatBridge, useOccupancyGrid, useGaussianBridge): Good separation of WebSocket logic from UI components
  • Component decomposition: Screens are split into sub-components (AlertCard, SurvivorCounter, MetricCard, etc.)

5. Top 20 Hotspots (Cross-Codebase, Risk-Ranked)

Hotspots are ranked by a composite score combining complexity, file size, nesting depth, and duplication density.

RankRiskCCLinesFileFunctionPrimary Issue
10.98121776sensing-server/main.rs:4070mainGod function; CLI dispatch
20.96--4,846sensing-server/main.rs(file)God file; 9.7x guideline
30.9466422sensing-server/main.rs:3504udp_receiver_task3 packet types monolithic
40.90--40+ fieldssensing-server/main.rs:424AppStateInnerGod object
50.8759314nvs_config.c:19nvs_config_loadNeeds table-driven approach
60.8555278mat/tracking/tracker.rs:171updateComplex tracking logic
70.8250184wasm-edge/med_seizure_detect.rs:157process_frameDeep nesting (8)
80.8070467GaussianSplatWebView.web.tsx:277GaussianSplatWebViewWebThree.js god component
90.7847232sensing-server/adaptive_classifier.rs:284train_from_recordingsComplex training logic
100.7642381mat/csi_receiver.rs:815detect_formatFormat detection chain
110.7540472sensing-server/training_api.rs:825real_training_loopLong training loop
120.7340185edge_processing.c:708process_frame11-stage DSP in one func
130.70--6xsensing-server/main.rsSensingUpdate buildsDuplicated 6 times
140.681990services/pose_service.py:491estimate_posesHighest Python CC
150.65--1,946sensing-server/training_api.rs(file)3.9x guideline
160.63--1,673wasm/mat.rs(file)3.3x guideline
170.61--1,664train/metrics.rs(file)3.3x guideline
180.59--1,523signal/ruvsense/pose_tracker.rs(file)3.0x guideline
190.5725125display_ui.c:259display_ui_updateDeep nesting (5)
200.5528106sensing-server/main.rs:2161estimate_persons_from_correlationComplex graph algorithm

6. Code Smell Catalog

6.1 God Class / God File

SmellLocationSeverity
God Filesensing-server/main.rs (4,846 lines)CRITICAL
God ObjectAppStateInner (40+ fields)CRITICAL
God Functionmain() (776 lines, CC=121)CRITICAL
God Functionudp_receiver_task() (422 lines, CC=66)HIGH

6.2 Duplicated Code

PatternInstancesLines DuplicatedSeverity
smooth_and_classify / smooth_and_classify_node2~50 per copyHIGH
smooth_vitals / smooth_vitals_node2~50 per copyHIGH
SensingUpdate {} construction6~40 per instanceHIGH
Person count estimation pattern3+~15 per instanceMEDIUM
frame_history capacity check6+~3 per instanceLOW
tracker_bridge::tracker_update call pattern5~5 per instanceMEDIUM

Estimated duplicated code in main.rs alone: ~450 lines (9.3% of file).

6.3 Deep Nesting (> 4 levels)

215 Rust functions exceed 4 levels of nesting. The worst cases:

  • main(): 8 levels (lines 4070-4846)
  • udp_receiver_task(): 8 levels (lines 3504-3926)
  • Multiple process_frame in wasm-edge: 7-8 levels

6.4 Long Parameter Lists (> 5 parameters)

43 Rust functions have more than 5 parameters. Notable:

  • process_frame variants in wasm-edge: 5-7 parameters each
  • extract_features_from_frame: 3 parameters but returns a 5-tuple

6.5 Repetitive Vendor Modules (wasm-edge)

The wifi-densepose-wasm-edge crate has 68 files following a near-identical pattern. At least 35 have a process_frame function with CC > 20. A trait-based or macro-based approach would reduce this to a fraction of the code.


7. Testability Assessment

ComponentScoreRatingKey Blockers
wifi-densepose-core85/100EASYPure types, no side effects
wifi-densepose-signal78/100EASYMostly pure computation
wifi-densepose-train72/100MODERATEExternal dataset dependencies
wifi-densepose-mat68/100MODERATEIntegration with core+signal+nn
wifi-densepose-wifiscan75/100EASYPlatform-specific but well-abstracted
wifi-densepose-sensing-server32/100VERY DIFFICULTGod object, coupled state, async
wifi-densepose-wasm-edge55/100MODERATERepetitive but self-contained
archive/v1/src (Python)70/100MODERATEGood DI, some tight coupling
firmware (C)40/100DIFFICULTHardware deps, global state
ui/mobile (TypeScript)72/100MODERATEComponent isolation is good

8. Refactoring Recommendations

Priority 1: CRITICAL -- sensing-server/main.rs Decomposition

Estimated effort: 3-5 days Impact: Reduces maintenance cost for the most-changed file in the project

  1. Extract AppStateInner into bounded contexts:

    • SensingState -- frame history, features, classification
    • VitalSignState -- HR/BR smoothing, detector, buffers
    • RecordingState -- recording lifecycle, file handles
    • TrainingState -- training status, config
    • ModelState -- loaded model, progressive loader, SONA profiles
    • NodeRegistry -- per-node states, pose tracker, multistatic fuser
  2. Extract command handlers from main():

    • run_benchmark() (lines 4082-4089)
    • run_export_rvf() (lines 4092-4142)
    • run_pretrain() (lines 4145-4247)
    • run_embed() (lines 4250-4312)
    • run_build_index() (lines 4315-4357)
    • run_train() (lines 4360-end)
    • run_server() -- the remaining server startup
  3. Extract SensingUpdate builder: Create a SensingUpdateBuilder that encapsulates the repeated 6-instance construction pattern.

  4. Unify node vs global variants via trait:

    rust
    trait SmoothingState {
        fn smoothed_motion(&self) -> f64;
        fn set_smoothed_motion(&mut self, v: f64);
        // ... etc
    }
    impl SmoothingState for AppStateInner { ... }
    impl SmoothingState for NodeState { ... }
    

    Then a single smooth_and_classify<S: SmoothingState>() replaces both copies.

  5. Extract udp_receiver_task into packet-type handlers:

    • handle_vitals_packet()
    • handle_wasm_packet()
    • handle_csi_frame()

Priority 2: HIGH -- C Firmware nvs_config_load Table-Driven Refactor

Estimated effort: 1 day Impact: Reduces CC from 59 to approximately 5

Replace the 314-line sequential NVS load with a descriptor table:

c
typedef struct {
    const char *key;
    nvs_type_t type;
    void *dest;
    size_t size;
    const void *default_val;
} nvs_param_desc_t;

static const nvs_param_desc_t params[] = {
    {"node_id", NVS_U8, &cfg->node_id, 1, &(uint8_t){1}},
    // ... 30+ entries
};

Priority 3: HIGH -- wasm-edge process_frame Trait Extraction

Estimated effort: 2-3 days Impact: Reduces 28,888 lines by an estimated 30-40%

Define a common trait:

rust
trait WasmEdgeModule {
    fn name(&self) -> &str;
    fn init(&mut self, config: &ModuleConfig);
    fn process_frame(&mut self, ctx: &mut FrameContext) -> Vec<WasmEvent>;
}

Extract shared signal processing (phase extraction, variance tracking, BPM estimation) into reusable pipeline stages.

Priority 4: MEDIUM -- GaussianSplatWebView.web.tsx Decomposition

Estimated effort: 1 day Impact: Reduces CC from 70 to approximately 10-15 per component

Split into:

  • SceneManager -- Three.js initialization, camera, lighting
  • SkeletonRenderer -- body parts, keypoints, bones
  • SignalFieldRenderer -- grid, heatmap visualization
  • useFrameAdapter -- data parsing hook

Priority 5: MEDIUM -- edge_processing.c Pipeline Decomposition

Estimated effort: 1-2 days Impact: Reduces process_frame CC from 40 to ~10; improves stack safety

Split into stage functions:

c
static void stage_phase_extract(frame_ctx_t *ctx);
static void stage_variance_update(frame_ctx_t *ctx);
static void stage_subcarrier_select(frame_ctx_t *ctx);
static void stage_bandpass_filter(frame_ctx_t *ctx);
static void stage_bpm_estimate(frame_ctx_t *ctx);
static void stage_presence_detect(frame_ctx_t *ctx);
static void stage_fall_detect(frame_ctx_t *ctx);

Priority 6: LOW -- Python Status Formatter Decomposition

Estimated effort: 0.5 days Impact: Reduces _print_text_status CC from 18 to ~5 per formatter

Split _print_text_status (126 lines) into per-component formatters: _format_api_status, _format_hardware_status, _format_streaming_status, etc.


9. Quality Gate Recommendations

Proposed Complexity Thresholds for CI/CD

MetricWarnFailCurrent Violations
File size> 500 lines> 1,000 lines92 warn, 25 fail
Function CC> 15> 25~150 warn, ~74 fail
Function lines> 50> 100~360 warn, ~94 fail
Nesting depth> 4> 6~215 warn, ~30 fail
Parameter count> 5> 7~43 warn, ~10 fail
  1. Block new functions with CC > 25 in CI (addresses future growth)
  2. Block new files exceeding 500 lines (enforces project guideline)
  3. Add complexity linting via cargo clippy with custom lints or complexity-rs
  4. Prioritize the sensing-server decomposition -- it is the single largest contributor to technical debt in the project

10. Complexity Distribution Charts (Text)

Rust Cyclomatic Complexity Distribution

CC Range    | Functions | Percentage | Bar
------------|-----------|------------|----------------------------------
  1-5       |     5,728 |     86.2%  | ####################################
  6-10      |       682 |     10.3%  | ####
 11-15      |       107 |      1.6%  | #
 16-20      |        50 |      0.8%  | 
 21-30      |        41 |      0.6%  | 
 31-50      |        24 |      0.4%  | 
   >50      |         9 |      0.1%  | 

Python Cyclomatic Complexity Distribution

CC Range    | Functions | Percentage | Bar
------------|-----------|------------|----------------------------------
  1-5       |       740 |     83.3%  | ####################################
  6-10      |       132 |     14.9%  | ######
 11-15      |        13 |      1.5%  | #
 16-20      |         3 |      0.3%  | 

C Firmware Cyclomatic Complexity Distribution

CC Range    | Functions | Percentage | Bar
------------|-----------|------------|----------------------------------
  1-5       |        73 |     50.3%  | ####################################
  6-10      |        50 |     34.5%  | #########################
 11-15      |         6 |      4.1%  | ###
 16-20      |         8 |      5.5%  | ####
 21-30      |         3 |      2.1%  | ##
   >30      |         5 |      3.4%  | ##

Appendix A: Methodology

Metrics Calculated

  • Cyclomatic Complexity (CC): McCabe's cyclomatic complexity counting decision points (if, else if, match, for, while, boolean operators, match arms)
  • Cognitive Complexity: Approximated via nesting depth and CC combination
  • Function Length: Raw line count from function signature to closing brace
  • Nesting Depth: Maximum brace/indent depth within function body
  • Parameter Count: Number of non-self parameters
  • File Size: Total lines including comments and blank lines

Tools Used

  • Custom Python AST analysis for Python files
  • Custom regex-based analysis for Rust, C, and TypeScript files
  • AST parsing provides higher accuracy for Python; regex-based analysis may slightly overcount CC for Rust (e.g., match arms in comments) but provides consistent cross-language comparison

Limitations

  • CC for Rust match arms counted via => may include non-decision match arms
  • TypeScript analysis captures top-level and exported functions but may miss deeply nested callbacks
  • C analysis requires function signatures to start at column 0
  • Dead code detection is heuristic-only (unused imports not checked at scale)

Report generated by QE Code Complexity Analyzer v3 Codebase snapshot: commit 85434229 on branch qe-reports