๐ Technical Design 008 โ Automated Complexity Metrics Enforcement¶
| Field | Value |
|---|---|
| ID | TD-008 |
| Title | Automated Complexity Metrics Enforcement |
| Status | Completed |
| Owner | Reflection maintainers |
| Audience | Contributors and maintainers |
| Created | 2025-09-30 |
| Last Updated | 2025-09-30 |
| Reviewers | |
| Approvers | |
| Tracking | |
| Related | 002-refactor-high-fidelity-type-hint-provider task |
๐งญ 1. Summary¶
This design introduces automated tooling to enforce code complexity metrics across the loryth.common codebase, preventing complexity regression and maintaining code readability standards. The system will integrate with CI/CD pipelines to automatically detect and flag violations of established complexity thresholds.
At a glance:
- Integrate cyclomatic complexity linting (max 10 per method)
- Add cognitive complexity measurement (max 15 per method)
- Enforce method length limits (max 50 lines per method)
- Monitor nesting depth constraints (max 3 levels)
- Provide actionable feedback for complexity violations
- Support incremental adoption across existing codebase
๐ 2. Context and Problem Statement¶
The loryth.common reflection subsystem has undergone significant refactoring to improve maintainability, including module splitting (TD-004) and upcoming provider refactoring. However, without automated enforcement, complexity can gradually increase over time, leading to:
- Reduced readability: Complex methods become harder to understand and review
- Maintenance burden: High complexity increases bug likelihood and debugging time
- Testing difficulty: Complex code paths are harder to test comprehensively
- Knowledge silos: Complex code requires domain expertise to modify safely
Currently, complexity assessment relies on manual code review, which is: - Inconsistent: Different reviewers apply different standards - Reactive: Issues are caught after code is written, not prevented - Subjective: Lacks objective, measurable criteria - Time-consuming: Manual complexity assessment slows down reviews
2.1 Goals¶
- Prevent complexity regression: Automatically detect when new code exceeds complexity thresholds
- Standardize quality metrics: Establish consistent, objective standards across all contributors
- Improve code quality: Encourage writing readable, maintainable code through early feedback
- Accelerate reviews: Reduce manual effort in assessing code complexity during reviews
- Enable continuous improvement: Track complexity trends over time for informed refactoring decisions
- Support incremental adoption: Allow existing code to be gradually improved without blocking new development
2.2 Non-Goals (Out of Scope)¶
- Automatic code refactoring: Tool will flag violations but not automatically fix them
- Performance metrics: Focus is on readability/maintainability, not runtime performance
- Domain-specific complexity: Will not measure reflection-specific complexity patterns
- Complete coverage initially: May start with subset of codebase and expand incrementally
- Custom complexity algorithms: Will use established, well-understood metrics
- IDE integration: Focus on CI/CD integration first, IDE plugins are future work
2.3 Assumptions and Constraints¶
- Python 3.13 environment: Tooling must work with current development setup
- CI/CD integration: Must integrate with existing Makefile and testing workflows
- Developer workflow: Should not significantly slow down development cycles
- Existing codebase: Some legacy code may exceed thresholds temporarily
- Tool availability: Prefer established, maintained tools over custom implementations
- Alpha stage: Can introduce breaking changes to development workflow if needed
๐งฉ 3. Design Overview¶
The design implements a tool-centric approach to complexity enforcement using established Python tooling integrated into the local development workflow via Makefile targets. The system provides immediate feedback during development through granular make rules following existing project conventions.
The solution combines multiple complementary metrics to provide comprehensive complexity assessment while remaining practical for daily development use.
3.1 Complexity Measurement Tools¶
| Tool | Purpose | Integration |
|---|---|---|
| radon/mccabe | Cyclomatic complexity analysis (max 10 per method) | make cyclomatic-lint |
| cognitive-complexity | Human-perceived complexity assessment (max 15 per method) | make cognitive-lint |
| Custom AST analyzer | Method length validation (max 50 lines per method) | make method-length-lint |
| Custom AST analyzer | Nesting depth checking (max 3 levels) | make nesting-depth-lint |
3.2 Configuration and Thresholds¶
Centralized Configuration: All thresholds and tool settings managed in pyproject.toml Threshold Standards: Industry-standard limits with exemption support for legacy code Granular Control: Individual tool configuration with file/pattern exclusions Consistent Reporting: Standardized output format across all complexity tools
3.3 Integration Points¶
Makefile Integration: Following existing project patterns (ruff-lint, mypy-lint) Aggregate Target: make complexity-lint runs all complexity checks Individual Targets: Granular rules for each specific metric Future Extension: Prepared for CI integration when project adds automated workflows
๐ 4. Implementation Details¶
4.1 Cyclomatic Complexity Enforcement¶
Tool: radon or mccabe (via flake8-mccabe)
# Makefile target
.PHONY: cyclomatic-lint
cyclomatic-lint:
@echo -e "\033[0;1;36m[$(name)] Checking cyclomatic complexity...\033[0m"
$(python) -m radon cc $(source) --min=B --max=10 --exclude="*/__init__.py"
# Configuration (pyproject.toml)
[tool.radon]
cc_min = "B" # Grade B = complexity 6-10
exclude = "tests/*,docs/*,*/__init__.py"
show_complexity = true
max_complexity = 10
Behavior: - Threshold: Maximum cyclomatic complexity of 10 per method/function - Scope: All source code under src/loryth/common/ - Reporting: Grade-based output (A=1-5, B=6-10, C=11-20, etc.) - Integration: Part of make lint command and CI pipeline
Error handling: - Violations: Exit code 1 when any method exceeds threshold - Reporting: Detailed output showing violating methods and their scores - Exemptions: Configuration-based exclusions for specific files/patterns
4.2 Cognitive Complexity Analysis¶
Tool: cognitive-complexity or custom implementation
# Makefile target
.PHONY: cognitive-lint
cognitive-lint:
@echo -e "\033[0;1;36m[$(name)] Checking cognitive complexity...\033[0m"
$(python) -m cognitive_complexity $(source) --max-complexity 15
# Configuration (pyproject.toml)
[tool.cognitive-complexity]
max_complexity = 15
exclude = ["tests/", "docs/", "*/__init__.py"]
Behavior: - Threshold: Maximum cognitive complexity of 15 per method/function - Scope: Focus on main implementation files, exclude tests initially - Measurement: Counts nested structures, boolean logic, and recursion - Integration: Separate check from cyclomatic complexity
Error handling: - Violations: Clear error messages with specific complexity contributors - Guidance: Suggest refactoring strategies for common violation patterns - Context: Show complexity breakdown by construct type
4.3 Method Length Monitoring¶
Tool: Custom implementation via AST analysis
# Makefile target
.PHONY: method-length-lint
method-length-lint:
@echo -e "\033[0;1;36m[$(name)] Checking method length...\033[0m"
$(python) scripts/check_method_length.py $(source) --max-lines 50
# Configuration (pyproject.toml)
[tool.method-length-checker]
max_lines = 50
exclude_patterns = ["test_*", "__init__"]
count_docstrings = false
count_comments = false
Behavior: - Threshold: Maximum 50 lines per method/function (excluding docstrings/comments) - Scope: All methods and functions in source code - Counting: Logical lines only, excluding whitespace and documentation - Reporting: List of violating methods with actual line counts
4.4 Nesting Depth Validation¶
Tool: Custom AST analyzer
# Makefile target
.PHONY: nesting-depth-lint
nesting-depth-lint:
@echo -e "\033[0;1;36m[$(name)] Checking nesting depth...\033[0m"
$(python) scripts/check_nesting_depth.py $(source) --max-depth 3
# Configuration (pyproject.toml)
[tool.nesting-depth-checker]
max_depth = 3
check_comprehensions = true
exclude_patterns = ["test_*", "__init__"]
Behavior: - Threshold: Maximum 3 levels of nesting (excluding module/class level) - Scope: All control flow structures (if/for/while/try/with) - Analysis: Static analysis via AST traversal - Reporting: Show exact location and depth of violations
โ๏ธ 5. Semantics¶
5.1 Metric Calculation Standards¶
Cyclomatic Complexity: - Each decision point adds 1 to complexity - Base complexity starts at 1 - Boolean operators (and/or) in conditions add 1 each - Exception handlers add 1 per except clause
Cognitive Complexity: - Nested structures increase score more than sequential structures - Recursion and jumps (break/continue) add cognitive load - Boolean logic in conditions contributes to cognitive burden
Method Length: - Count only logical lines (exclude blank lines, comments, docstrings) - Include method signature in line count - Multi-line expressions count as multiple lines
Nesting Depth: - Count indentation levels within methods/functions - Each control structure (if/for/while/try/with) adds one level - List/dict comprehensions count as nesting
5.2 Integration Workflow¶
Development cycle: 1. Local development: Individual complexity checks via granular make targets 2. Aggregate checking: make complexity-lint runs all complexity tools 3. Integration with existing lint: Enhanced make lint includes complexity checks 4. Reporting: Clear violation messages with actionable guidance
Error handling strategy: - Fail fast: Stop on any threshold violation with clear error messages - Specific guidance: Detailed information on which metrics were violated - Actionable advice: Suggest refactoring patterns for common violations
5.3 Configuration Management¶
Centralized settings: All thresholds configured in pyproject.toml Environment flexibility: Different thresholds for test vs. production code Exemption handling: File-pattern and method-name based exclusions Threshold evolution: Ability to gradually tighten thresholds over time
๐งช 6. Examples (concise)¶
6.1 Makefile Integration¶
# Enhanced lint target
.PHONY: lint
lint: ruff-lint mypy-lint complexity-lint
# Aggregate complexity target
.PHONY: complexity-lint
complexity-lint: cyclomatic-lint cognitive-lint method-length-lint nesting-depth-lint
# Individual complexity targets
.PHONY: cyclomatic-lint
cyclomatic-lint:
@echo -e "\033[0;1;36m[$(name)] Checking cyclomatic complexity...\033[0m"
$(python) -m radon cc $(source) --min=B --max=10
.PHONY: cognitive-lint
cognitive-lint:
@echo -e "\033[0;1;36m[$(name)] Checking cognitive complexity...\033[0m"
$(python) -m cognitive_complexity $(source) --max-complexity 15
6.2 Configuration Example¶
# pyproject.toml
[tool.complexity-enforcement]
cyclomatic_max = 10
cognitive_max = 15
method_length_max = 50
nesting_depth_max = 3
[tool.complexity-enforcement.exclusions]
files = ["tests/*", "docs/*", "*/__init__.py"]
methods = ["test_*", "_test_*"]
[tool.complexity-enforcement.reporting]
output_format = "json"
trend_tracking = true
dashboard_url = "https://complexity-dashboard.internal"
6.3 Violation Reporting¶
# Example output for violations
โ Complexity violations found:
Cyclomatic Complexity:
src/loryth/common/reflection/high_fidelity_type_hints.py:231
_resolve_hints_obj: 15 (threshold: 10)
Cognitive Complexity:
src/loryth/common/reflection/high_fidelity_type_hints.py:547
_deep_resolve: 18 (threshold: 15)
Method Length:
src/loryth/common/reflection/high_fidelity_type_hints.py:231
_resolve_hints_obj: 207 lines (threshold: 50)
๐ก Suggested fixes:
- Extract nested logic into separate methods
- Reduce boolean logic complexity in conditions
- Break large methods into focused helper functions
โ 7. Acceptance Criteria¶
- Cyclomatic complexity checking integrated with maximum threshold of 10
- Cognitive complexity analysis implemented with maximum threshold of 15
- Method length validation enforces 50-line maximum per method
- Nesting depth checking prevents more than 3 levels of indentation
- All complexity checks integrated into
make lintcommand - Granular Makefile targets for individual complexity checks
- Ready for future CI integration when project adds automated workflows
- Clear, actionable error messages for all violation types
- Configuration centralized in
pyproject.tomlwith exemption support - Existing codebase baseline established (violations tracked but not blocking initially)
- Documentation updated with complexity standards and tooling usage
- Tool performance impact is minimal (< 30 seconds added to local lint)
- Complexity trend tracking implemented for continuous improvement
- Developer workflow documentation updated with complexity checking guidance
๐ 8. Rollout and Migration¶
Phase 1: Tool Integration¶
- Research and select tools: Evaluate radon, mccabe, cognitive-complexity options
- Create configuration: Set up thresholds and exclusions in pyproject.toml
- Implement checking scripts: Create Makefile targets following project conventions
- Local testing: Validate tools work correctly on current codebase
Phase 2: Baseline Establishment¶
- Audit existing code: Run tools on entire codebase to identify current violations
- Document exceptions: Create exemption list for legacy code that exceeds thresholds
- Create tracking: Establish baseline metrics for trend analysis
- Developer communication: Announce new standards and tooling
Phase 3: Makefile Integration¶
- Add granular targets: Implement individual complexity check targets
- Enhance aggregate lint: Update
make lintto include complexity checks - Configure reporting: Set up clear violation reporting with actionable guidance
- Documentation: Update contributor guides with complexity requirements
Phase 4: Enforcement and Improvement¶
- Monitor compliance: Track adherence to complexity standards
- Refactor violations: Gradually address existing codebase violations
- Tighten thresholds: Consider reducing thresholds as code quality improves
- Expand coverage: Apply complexity checking to additional modules
Future Work: Address Existing Violations¶
Complexity metrics enforcement is now active but identifies existing violations throughout the codebase. These should be addressed incrementally:
High Priority Violations (HighFidelityTypeHintProvider): - _deep_resolve: Cyclomatic 38, Cognitive 111, Lines 92, Nesting 5 - _resolve_hints_obj: Cyclomatic 36, Cognitive 67, Lines 188, Nesting 4 - _resolve_single_with_augmentation: Cyclomatic 11, Cognitive 19, Lines 84
Medium Priority Violations (Reflection Subsystem): - member_builder.py::_build_type: Cyclomatic 34, Cognitive 91, Lines 127, Nesting 5 - safe_callable_invoker.py::invoke: Cyclomatic 18, Cognitive 41, Lines 63, Nesting 5 - type_checker.py::_matches: Cyclomatic 26, Cognitive 63, Lines 64, Nesting 5 - Various forward reference handling and property resolution methods
Lower Priority Violations: - semantic_version.py::__lt__: Cyclomatic 12, Cognitive 20 - state_machine.py::__init__: Cognitive 23, Nesting 4 - di/extract_dependencies.py::extract_dependencies: Cognitive 20
Recommended Approach: 1. Start with HighFidelityTypeHintProvider refactoring (Task 002 already planned) 2. Address reflection subsystem violations incrementally during regular maintenance 3. Consider raising thresholds temporarily for specific legacy methods if needed
Future Work: CI Integration¶
When the project adds CI/CD pipelines, complexity checks can be easily integrated by leveraging the existing Makefile targets in automated workflows.
โ ๏ธ 9. Risks and Mitigations¶
Technical Risks¶
Risk: Tool performance impact slows down local development - Mitigation: Benchmark tools and optimize for speed; provide granular targets for quick individual checks
Risk: False positives from complexity analysis tools - Mitigation: Establish exemption patterns; fine-tune tool configurations; provide override mechanisms
Risk: Incompatibility with Python 3.13 or existing toolchain - Mitigation: Test tools thoroughly in development environment; have fallback tool options
Adoption Risks¶
Risk: Developer resistance to additional complexity constraints - Mitigation: Provide clear rationale and guidance; start with warnings before enforcement; show examples of improvement
Risk: Blocking development velocity with strict enforcement - Mitigation: Phase in enforcement gradually; provide clear guidance on addressing violations; maintain reasonable thresholds; granular targets allow checking specific metrics
Risk: Tool maintenance burden and dependency management - Mitigation: Prefer well-maintained, popular tools; have multiple tool options; keep configuration simple
Operational Risks¶
Risk: Inconsistent enforcement across different development environments - Mitigation: Centralize configuration in pyproject.toml; provide clear setup documentation; Makefile ensures consistent execution
Risk: Complexity threshold drift over time without review - Mitigation: Regular review cycles; trend tracking; documented threshold rationale
๐ 10. Progress¶
Legend: [x] = complete, [ ] = pending
Phase 1: Tool Integration โ COMPLETE¶
- Research and evaluate complexity analysis tools
- Set up cyclomatic complexity checking (radon/mccabe)
- Implement cognitive complexity analysis
- Create method length validation
- Add nesting depth checking
- Configure pyproject.toml with thresholds and exclusions
- Create Makefile targets for complexity checks
Phase 2: Baseline and Configuration โ COMPLETE¶
- Audit existing codebase for current complexity violations
- Document exemptions for legacy code (via pyproject.toml exclusions)
- Establish baseline metrics for tracking
- Configure violation reporting format
- Test local development workflow
Phase 3: Makefile Integration โ COMPLETE¶
- Add granular complexity check targets to Makefile
- Enhance
make lintto include complexity checks - Configure clear violation reporting
- Update developer documentation
- Validate performance impact on local development
- Prepare for future CI integration
๐ 11. Changelog¶
- 2025-09-30 โ Initial design based on refactoring task 002 requirements and industry complexity standards
- 2025-09-30 โ Implementation completed: all complexity metrics tooling functional and integrated with Makefile
๐ 12. Glossary¶
- Cyclomatic Complexity: Metric measuring the number of decision points in code (if statements, loops, etc.)
- Cognitive Complexity: Metric assessing how difficult code is for humans to understand, considering nesting and logical complexity
- Method Length: Count of logical lines of code within a single method or function
- Nesting Depth: Maximum levels of indentation within control flow structures
- Static Analysis: Automated code analysis without executing the program
- Threshold: Maximum allowed value for a complexity metric before violations are flagged
- Baseline: Current state measurement used as reference point for tracking improvements
- AST: Abstract Syntax Tree, internal representation of code structure used for analysis