feat: cognitive & cyclomatic complexity metrics#130
Conversation
Add `codegraph path <from> <to>` — BFS shortest-path search on the call graph. Given two symbol names, finds the shortest call chain with hop count, intermediate nodes, edge kinds, and alternate path count. Supports --reverse, --max-depth, --kinds, --from-file/--to-file, -T, -j, -k flags. Exposed as symbol_path MCP tool. Impact: 4 functions changed, 3 affected
- Create docs/use-cases/titan-paradigm.md — maps Johannes R.'s multi-agent codebase cleanup architecture (RECON, GAUNTLET, GLOBAL SYNC, STATE MACHINE) to codegraph commands, roadmap items, and post-LLM-integration recommendations - Update roadmap/BACKLOG.md: mark #4 (node classification), #9 (git change coupling), #1 (dead code), #2 (shortest path), #12 (execution flow) as DONE; add 6 new Titan Paradigm-inspired items (#21-#26): composite audit, batch querying, triage priority queue, change validation predicates, graph snapshots, MCP orchestration tools - Update README.md: add roles + co-change to features table, differentiators, commands section, agent template, common flags, comparison table; update MCP tool count 18 → 19 - Update docs/recommended-practices.md: update MCP tool count and tool list, add roles/co-change/path to CLAUDE.md template and developer workflow, add "Understand architectural roles" and "Surface hidden coupling" sections, add co-change step to setup checklist - Add full examples with real output for roles, co-change, and path to docs/examples/CLI.md and docs/examples/MCP.md - Update GitHub repo description with new capabilities
- Restore Phase 3 (Architectural Refactoring) to ROADMAP - Renumber phases 4-8 and all cross-references - Fix MCP tool count per Greptile review
Address Greptile review comments on #121: - Update MCP tool counts from 18/19 to 21 (22 in multi-repo mode) across README, recommended-practices, dogfood skill, titan-paradigm - Add missing execution_flow and list_entry_points to tool enumeration - Renumber new backlog items 21-26 → 27-32 to avoid collision with existing items 21-22
Adds a benchmark suite that measures how much codegraph reduces token usage when AI agents navigate the Next.js codebase (~4k TS files). - scripts/token-benchmark-issues.js: 5 real Next.js PRs as test cases - scripts/token-benchmark.js: runner using Claude Agent SDK (baseline vs codegraph MCP), with --perf flag for build/query benchmarks - scripts/update-token-report.js: JSON → markdown report generator - docs/benchmarks/: methodology docs and placeholder report Impact: 21 functions changed, 7 affected
…verage benchmark.js now measures no-op rebuilds, 1-file rebuilds, and query latency (fn-deps, fn-impact, path, roles) alongside full builds. update-benchmark-report.js renders new Incremental Rebuilds and Query Latency sections in BUILD-BENCHMARKS.md and adds incremental/query rows to the README performance table. All new fields are additive for backward compatibility. Impact: 5 functions changed, 2 affected
Extract version from benchmark result JSON and include it in branch names, commit messages, PR titles, and PR bodies across all 4 benchmark jobs (build, embedding, query, incremental).
Resolve conflicts: - benchmark.yml: keep version-in-branch-name convention - README.md: take main's dual-engine performance table - BUILD-BENCHMARKS.md: main's dual-engine data + incremental/query sections - update-benchmark-report.js: take main's clearer regex comment Impact: 12 functions changed, 13 affected
Take main's latest benchmark numbers (PR #125) while preserving the new incremental rebuild and query latency fields from the branch.
Nested/closure functions (e.g. nodeId inside exportMermaid) were incorrectly classified as [dead] because the caller selection loop picked the last definition where line <= call.line, creating self-call edges that got filtered out. Now uses endLine to find the innermost enclosing scope, so calls within an outer function correctly attribute the outer function as caller rather than the nested function itself. Fixes false-positive [dead] for nodeId in branch-compare.js, export.js, and queries.js. Impact: 1 functions changed, 17 affected
Compute per-function complexity during build via single-traversal DFS of tree-sitter ASTs: cognitive (SonarSource), cyclomatic (McCabe), and max nesting depth. Stores results in new function_complexity table (migration v8) and surfaces them in stats, context, explain, and a dedicated `complexity` CLI command + MCP tool. Adds manifesto config section with warn thresholds (cognitive: 15, cyclomatic: 10, maxNesting: 4) seeding the future rule engine. Phase 1 supports JS/TS/TSX; unsupported languages are skipped gracefully. Impact: 18 functions changed, 32 affected
|
Claude finished @carlos-alm's task —— View job PR Review: Cognitive & Cyclomatic Complexity MetricsTodo List:
Phase 1: Root Cause Analysis ✅Problem Being Solved: This PR addresses the lack of complexity metrics in codegraph, which limits the tool's ability to identify and analyze function-level code quality issues. Issues #21 and #6 specifically requested cognitive complexity and cyclomatic complexity features. Why This Approach: The implementation follows established complexity calculation standards:
Risk Assessment: ✅ LOW RISK - This is a pure additive feature with no changes to existing functionality. The approach is sound and well-architected. Phase 2: Configuration Change Detection ✅Analysis: No high-risk configuration changes detected:
The PR adds a new Phase 3: Test Integrity ✅Comprehensive Test Coverage:
No Test Integrity Issues: Tests are properly structured with realistic expectations, no weakened assertions, and thorough coverage. Phase 4: Code Quality Review ✅Security:
Architecture:
Performance:
Integration Quality:
Minor Considerations
Final AssessmentRoot Cause AnalysisProblem Being Solved: Adding essential code quality metrics (cognitive/cyclomatic complexity) that were missing from the codegraph tool, directly addressing user requests in issues #21 and #6. Why This Approach: Mathematically sound implementation of established complexity algorithms with efficient single-pass computation and proper integration into existing architecture. Risk Assessment: Very low risk - pure additive feature with comprehensive testing and no changes to existing functionality. Critical ConcernsNone identified. This is a well-architected feature addition with excellent test coverage and proper security practices. Final Recommendation
Exceptional qualities: Sophisticated algorithm implementation, comprehensive test coverage (30 total tests), proper database design, seamless CLI/MCP integration, and thoughtful configurability. This demonstrates excellent software engineering practices. |
Greptile SummaryThis PR adds comprehensive complexity metrics (cognitive & cyclomatic complexity, max nesting depth) to codegraph, computed via single-traversal DFS of tree-sitter ASTs at build time. The implementation follows SonarSource's cognitive complexity spec and McCabe's cyclomatic complexity. Key Changes:
Test Coverage:
Issues Found:
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
Start[Build Graph] --> Parse[Parse Source Files]
Parse --> Extract[Extract Function Definitions]
Extract --> AST[Get tree-sitter AST]
AST --> DFS[Single-Pass DFS Traversal]
DFS --> Branch{Node Type?}
Branch -->|if/for/while/switch| IncCog["+1 Cognitive<br/>+1 Cyclomatic<br/>+1 Nesting"]
Branch -->|else-if| ElseIf["+1 Cognitive<br/>+1 Cyclomatic<br/>NO Nesting"]
Branch -->|Logical Operators| Logic["Check Sequence<br/>+1 Cognitive if changed<br/>+1 Cyclomatic always"]
Branch -->|switch_case| Case["+1 Cyclomatic only"]
Branch -->|Nested Function| Nest["+1 Nesting"]
IncCog --> Track[Track Max Nesting]
ElseIf --> Track
Logic --> Track
Case --> Track
Nest --> Track
Track --> Result[Return Metrics:<br/>cognitive, cyclomatic, maxNesting]
Result --> Upsert[Upsert to function_complexity table]
Upsert --> Query[Query Commands]
Query --> CLI[CLI: codegraph complexity]
Query --> MCP[MCP: complexity tool]
Query --> Stats[Enhanced stats/context/explain]
Last reviewed commit: 1b5e20d |
| if (aboveThreshold) { | ||
| const conditions = []; | ||
| if (thresholds.cognitive?.warn != null) { | ||
| conditions.push(`fc.cognitive >= ${thresholds.cognitive.warn}`); | ||
| } | ||
| if (thresholds.cyclomatic?.warn != null) { | ||
| conditions.push(`fc.cyclomatic >= ${thresholds.cyclomatic.warn}`); | ||
| } | ||
| if (thresholds.maxNesting?.warn != null) { | ||
| conditions.push(`fc.max_nesting >= ${thresholds.maxNesting.warn}`); | ||
| } | ||
| if (conditions.length > 0) { | ||
| having = `AND (${conditions.join(' OR ')})`; | ||
| } |
There was a problem hiding this comment.
Threshold values are directly interpolated into SQL without validation. While these come from config (not user input), a malicious .codegraphrc.json could inject SQL. Use parameterized queries:
| if (aboveThreshold) { | |
| const conditions = []; | |
| if (thresholds.cognitive?.warn != null) { | |
| conditions.push(`fc.cognitive >= ${thresholds.cognitive.warn}`); | |
| } | |
| if (thresholds.cyclomatic?.warn != null) { | |
| conditions.push(`fc.cyclomatic >= ${thresholds.cyclomatic.warn}`); | |
| } | |
| if (thresholds.maxNesting?.warn != null) { | |
| conditions.push(`fc.max_nesting >= ${thresholds.maxNesting.warn}`); | |
| } | |
| if (conditions.length > 0) { | |
| having = `AND (${conditions.join(' OR ')})`; | |
| } | |
| if (aboveThreshold) { | |
| const conditions = []; | |
| if (thresholds.cognitive?.warn != null) { | |
| const val = Number(thresholds.cognitive.warn); | |
| if (!isNaN(val)) conditions.push(`fc.cognitive >= ${val}`); | |
| } | |
| if (thresholds.cyclomatic?.warn != null) { | |
| const val = Number(thresholds.cyclomatic.warn); | |
| if (!isNaN(val)) conditions.push(`fc.cyclomatic >= ${val}`); | |
| } | |
| if (thresholds.maxNesting?.warn != null) { | |
| const val = Number(thresholds.maxNesting.warn); | |
| if (!isNaN(val)) conditions.push(`fc.max_nesting >= ${val}`); | |
| } | |
| if (conditions.length > 0) { | |
| having = `AND (${conditions.join(' OR ')})`; | |
| } | |
| } |
|
Addressed Greptile's review comment: added \ coercion with \ guards on threshold values interpolated into SQL in . Non-numeric config values are now silently skipped instead of interpolated. All 30 complexity tests pass. |
Update README, CLAUDE.md, BACKLOG, titan-paradigm, recommended-practices, and CLI/MCP examples to reflect today's merged PRs: complexity metrics (#130/#139), Louvain community detection (#133/#134), and manifesto rule engine (#138). Updates MCP tool count from 21 to 24 (25 in multi-repo), marks backlog items 6/11/21/22 as done, and adds real CLI output examples.
Update README, CLAUDE.md, BACKLOG, titan-paradigm, recommended-practices, and CLI/MCP examples to reflect today's merged PRs: complexity metrics (#130/#139), Louvain community detection (#133/#134), and manifesto rule engine (#138). Updates MCP tool count from 21 to 24 (25 in multi-repo), marks backlog items 6/11/21/22 as done, and adds real CLI output examples.
* fix: strict type validation for threshold values in complexity queries
Replace loose `!= null` checks with `typeof === 'number' && Number.isFinite()`
to prevent `Number("")`, `Number(null)`, and `Number(true)` from silently
coercing into valid SQL values. Add integration test verifying exceeds
arrays and summary.aboveWarn are correctly computed.
Addresses Greptile review feedback on #136.
Impact: 2 functions changed, 3 affected
* docs: add complexity, communities, and manifesto to all docs
Update README, CLAUDE.md, BACKLOG, titan-paradigm, recommended-practices,
and CLI/MCP examples to reflect today's merged PRs: complexity metrics
(#130/#139), Louvain community detection (#133/#134), and manifesto rule
engine (#138). Updates MCP tool count from 21 to 24 (25 in multi-repo),
marks backlog items 6/11/21/22 as done, and adds real CLI output examples.
* fix: remove redundant condition in paginate guard clauses
When limit === undefined, limit !== 0 is always true — the && check
was dead code. Simplified to just check limit === undefined.
Impact: 2 functions changed, 18 affected
* docs: update dogfood report with fix statuses
All 4 bugs now fixed (PR #117 merged, #116 closed via reverse-dep
cascade). 3 of 4 suggestions addressed. MCP tool counts updated
18→23 / 19→24. Rating upgraded 7/10 → 9/10 post-fix.
* fix: rename misleading test to match actual behavior
Test was named "handles non-numeric thresholds gracefully" but only
validated baseline exceeds/aboveWarn with valid thresholds. Actual
non-numeric threshold tests exist separately. Renamed to "produces
correct exceeds and aboveWarn with valid thresholds".
* fix: update stale MCP tool count in dogfood skill (21→24)
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* fix: strict type validation for threshold values in complexity queries
Replace loose `!= null` checks with `typeof === 'number' && Number.isFinite()`
to prevent `Number("")`, `Number(null)`, and `Number(true)` from silently
coercing into valid SQL values. Add integration test verifying exceeds
arrays and summary.aboveWarn are correctly computed.
Addresses Greptile review feedback on #136.
Impact: 2 functions changed, 3 affected
* docs: add complexity, communities, and manifesto to all docs
Update README, CLAUDE.md, BACKLOG, titan-paradigm, recommended-practices,
and CLI/MCP examples to reflect today's merged PRs: complexity metrics
(#130/#139), Louvain community detection (#133/#134), and manifesto rule
engine (#138). Updates MCP tool count from 21 to 24 (25 in multi-repo),
marks backlog items 6/11/21/22 as done, and adds real CLI output examples.
* fix: remove redundant condition in paginate guard clauses
When limit === undefined, limit !== 0 is always true — the && check
was dead code. Simplified to just check limit === undefined.
Impact: 2 functions changed, 18 affected
* docs: update dogfood report with fix statuses
All 4 bugs now fixed (PR #117 merged, #116 closed via reverse-dep
cascade). 3 of 4 suggestions addressed. MCP tool counts updated
18→23 / 19→24. Rating upgraded 7/10 → 9/10 post-fix.
* fix: rename misleading test to match actual behavior
Test was named "handles non-numeric thresholds gracefully" but only
validated baseline exceeds/aboveWarn with valid thresholds. Actual
non-numeric threshold tests exist separately. Renamed to "produces
correct exceeds and aboveWarn with valid thresholds".
* fix: update stale MCP tool count in dogfood skill (21→24)
* feat: add complexity analysis for Python, Go, Rust, Java, C#, Ruby, PHP
Parameterize the complexity algorithm to support all 10 languages instead
of just JS/TS/TSX. Add per-language COMPLEXITY_RULES, HALSTEAD_RULES, and
COMMENT_PREFIXES with three else-if detection patterns (else-wraps-if,
explicit elif, alternative field). Guard against tree-sitter keyword leaf
tokens that share node type names with their parent constructs.
Impact: 4 functions changed, 4 affected
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Summary
function_complexitytable (migration v8) with indexes; incremental cleanup integrated into builder pipelinecodegraph complexityCLI command with sorting, filtering (file/kind/target), threshold-aware output, and JSON modestats,context, andexplaincommands with complexity datacomplexitytool exposing all query options to AI agentsmanifesto.rules) with configurable warn/fail thresholds seeding the future rule engineTest plan
complexitytool routes tocomplexityDatawith all argsnode src/cli.js build .logs "Complexity: 63 functions analyzed"node src/cli.js complexity --limit 5shows top complex functionsnode src/cli.js stats -Tincludes complexity summary lineCloses #21, closes #6. Seeds #22.