feat: Halstead metrics and Maintainability Index#139
Conversation
Greptile SummaryThis PR adds comprehensive code health metrics (Halstead + Maintainability Index) and pagination to codegraph. The implementation computes MI, volume, difficulty, effort, and bugs estimate from tree-sitter AST during build, storing them in 14 new DB columns (migration v9). The Key changes:
Implementation quality:
Confidence Score: 5/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Build Phase] --> B[Parse Function AST]
B --> C[computeFunctionComplexity]
B --> D[computeHalsteadMetrics]
B --> E[computeLOCMetrics]
C --> F[Cognitive/Cyclomatic]
D --> G[Operators/Operands Count]
E --> H[LOC/SLOC/Comments]
G --> I[Calculate Volume/Difficulty/Effort/Bugs]
H --> J[Calculate Comment Ratio]
F --> K[computeMaintainabilityIndex]
I --> K
J --> K
K --> L[MI Score 0-100]
L --> M[Store in function_complexity table]
N[Query Phase] --> O{Pagination Active?}
O -->|Yes| P[Apply MCP Limits]
O -->|No| Q[Return All Results]
P --> R[paginateResult]
Q --> S[Return Data]
R --> S
T[Display] --> U{--health flag?}
U -->|Yes| V[Show Halstead + MI columns]
U -->|No| W[Show default + MI column]
X[Threshold Check] --> Y{MI > 0?}
Y -->|Yes| Z[Check MI <= warn threshold]
Y -->|No| AA[Skip - uncomputed row]
Z --> AB[Mark as exceeds if true]
Last reviewed commit: e14b3a3 |
src/complexity.js
Outdated
| conditions.push(`fc.max_nesting >= ${thresholds.maxNesting.warn}`); | ||
| } | ||
| if (thresholds.maintainabilityIndex?.warn != null) { | ||
| conditions.push(`fc.maintainability_index <= ${thresholds.maintainabilityIndex.warn}`); |
There was a problem hiding this comment.
inconsistent with the exceeds check — should exclude maintainability_index = 0 (uncomputed old rows)
| conditions.push(`fc.maintainability_index <= ${thresholds.maintainabilityIndex.warn}`); | |
| conditions.push(`fc.maintainability_index > 0 AND fc.maintainability_index <= ${thresholds.maintainabilityIndex.warn}`); |
There was a problem hiding this comment.
Already handled — the current code at this line already includes the > 0 guard:
conditions.push(`fc.maintainability_index > 0 AND fc.maintainability_index <= ${thresholds.maintainabilityIndex.warn}`);The review was generated against an earlier commit; this was fixed before the review landed.
|
Claude finished @carlos-alm's task —— View job PR Review: Halstead Metrics and Maintainability Index
|
06b6148 to
e14b3a3
Compare
|
Claude finished @carlos-alm's task —— View job PR Review: Halstead Metrics and Maintainability Index
|
Add formal code health metrics per function: Halstead volume, difficulty,
effort, bugs estimate, LOC/SLOC, and the industry-standard Maintainability
Index (MI) normalized to 0-100 (Microsoft convention). MI below 20 flags
functions needing refactoring attention.
- DB migration v9: 14 new columns on function_complexity table
- HALSTEAD_RULES registry for JS/TS/TSX operator/operand classification
- computeHalsteadMetrics(), computeLOCMetrics(), computeMaintainabilityIndex()
- complexity command: MI column in default view, --health flag for full
Halstead view, --sort mi|volume|effort|bugs|loc options
- stats/context/explain commands surface MI per function
- MCP tool schema updated with new sort values and health property
- Config: maintainabilityIndex threshold { warn: 20, fail: null }
- 29 new tests (18 unit + 11 integration)
Impact: 16 functions changed, 30 affected
Impact: 16 functions changed, 30 affected
…sults Add offset/limit pagination to data functions so MCP clients get bounded results with metadata to request more, and CLI consumers can process results incrementally via NDJSON. - New src/paginate.js with paginate(), paginateResult(), MCP_DEFAULTS, MCP_MAX_LIMIT utilities - Pagination support in listFunctionsData, queryNameData, whereData, rolesData, listEntryPointsData - Export limiting for DOT/Mermaid (truncation comments) and JSON (edge pagination) - MCP tool schemas updated with limit/offset props and sensible defaults (e.g. list_functions: 100, query_function: 50) - CLI --limit, --offset, --ndjson flags on query, where, roles, flow - Programmatic API exports from index.js - 33 new integration tests covering all pagination scenarios Impact: 19 functions changed, 18 affected
The --above-threshold filter for maintainabilityIndex now requires MI > 0, consistent with the exceeds array logic that already guards against uncomputed rows from pre-migration databases. Impact: 1 functions changed, 4 affected Impact: 1 functions changed, 1 affected
e14b3a3 to
e81fd6e
Compare
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
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_complexity— existing rows get defaults, no data losscomplexitycommand gains MI column in default view,--healthflag for full Halstead view, and--sort mi|volume|effort|bugs|locoptionsstats,context, andexplaincommands surface MI per functionhealthpropertymaintainabilityIndex: { warn: 20, fail: null }(Microsoft convention)Test plan
npm run lint— cleannpm test— 729 passed, 0 failedcodegraph build .— rebuilds with new metrics (435 functions analyzed)codegraph complexity -T— MI column visible in default viewcodegraph complexity --health -T— full Halstead health viewcodegraph complexity --sort mi -T— sorts by worst MI firstcodegraph complexity --sort mi -T -j— JSON includes halstead objectcodegraph stats -T— shows avg MI / min MI in complexity summarycodegraph explain <fn> -T— shows MI per function