Add an optional Cognitive Complexity gate (Campbell 2018) - #27
Merged
Merged
Conversation
Change-impact and the curve measure how a change MOVES; they cannot see a method that is simply hard to read (working code with deep decision nesting) — the shape AI code generators reliably produce. This adds an absolute, per-method readability gate, independent of the change-impact composite, so a small diff can pass on impact yet block for leaving a tangled method behind. - core/cognitive.py: a language-agnostic estimator of Cognitive Complexity, computed in the lizard pass (C-family via braces, Python via indentation, brace default otherwise). Flat sequential code costs nothing; nesting is penalised. Calibrated in tests against PMD (Java) and hand-verified values; documented simplifications (ternary/lambda). - Unit.cognitive + LizardPlugin populates it; ChangeScore carries cognitive_max + offenders. - Scoped to the methods the change TOUCHED (new files, or functions overlapping the added line ranges) — never re-flags pre-existing, accepted complexity elsewhere in a touched file. - GateConfig.cognitive_max (default null = off) + blocks_cognitive(); --cognitive-max CLI flag; cognitive section in json/text/markdown output naming the methods to break up; action.yml input. - Independent of the curve/absolute impact gate; OR'd into the block decision. Off by default; the change-impact composite, seed distribution and WMC/GodClass definitions are unchanged. 16 new tests; full suite green (106). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
Change impact: 205,320
|
| field | value |
|---|---|
| files changed | 8 |
| scope | vs origin/main (merge-base..HEAD) |
Over the block threshold. This will fail once enforcement is set to
block.
Files to consider for refactoring
| cost | file | existing | new | fns changed | fns new |
|---|---|---|---|---|---|
| 18,434 | impact_gate/report.py |
11,378 | 7,056 | 3 | 3 |
| 2,778 | impact_gate/cli.py |
2,778 | 0 | 2 | 0 |
| 2,109 | impact_gate/engine.py |
576 | 1,533 | 1 | 2 |
| 1,392 | impact_gate/config.py |
468 | 924 | 1 | 3 |
| 774 | impact_gate/core/cognitive.py |
0 | 774 | 0 | 10 |
Top cost drivers. Simplify or refactor these.
| cost | location | class | CC | WMC_other | kind |
|---|---|---|---|---|---|
| 9,625 | impact_gate/report.py:render_markdown |
file scope | 25 | 35 | mutation |
| 3,920 | impact_gate/report.py:_cognitive_lines |
file scope | 5 | 56 | godclass |
| 2,508 | impact_gate/cli.py:_cmd_score |
file scope | 11 | 38 | mutation |
| 2,016 | impact_gate/report.py:cognitive_report |
file scope | 3 | 56 | godclass |
| 1,120 | impact_gate/report.py:_cognitive_offenders |
file scope | 4 | 56 | godclass |
Methods over the cognitive-complexity limit (20)
Break these into smaller methods — reduce nesting/decision depth (sequential code is fine).
| cognitive | location | class |
|---|---|---|
| 24 | impact_gate/report.py:render_markdown |
file scope |
…he line
- .github/workflows/impact.yml: run impact-gate on itself with cognitive-max 20 (enforcement
stays warn — report over-limit methods on every PR without failing the build).
- Simplify the gate's own hot methods so this PR's touched code is under 20:
- _cognitive_c: dict-dispatch on token type via a small _CScan state object (27 -> 11).
- score_change: extract the cognitive collection into _collect_cognitive (21 -> 15).
Calibration unchanged (106 tests green). Pre-existing over-limit methods elsewhere are
untouched here, so the changed-method scope leaves them alone; warn surfaces them when a
future PR edits them.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The change-impact composite (and the curve) measure how a change moves — they cannot see a method that is simply hard to read: working code with deep decision nesting. That is the shape AI code generators reliably produce, so it is the gate worth adding for AI-augmented review.
This adds an absolute, per-method gate on Cognitive Complexity (Campbell 2018), independent of the change-impact model. A small diff can pass on impact yet block here for leaving a tangled method behind. Off by default.
What
core/cognitive.py— a language-agnostic estimator, computed in the existing lizard pass (C-family via braces, Python via indentation, brace default otherwise). Flat/sequential code costs nothing; nesting is penalised (eachif/loop/switch/catchcosts 1 + its depth).Unit.cognitivepopulated byLizardPlugin;ChangeScorecarriescognitive_max+ offenders.GateConfig.cognitive_max(defaultnull= off) +blocks_cognitive();--cognitive-max NCLI flag;cognitivesection in json/text/markdown naming the methods to break up;action.ymlinput.Design notes
Tests
16 new tests (
tests/test_cognitive.py) covering the estimator (incl. the PMD-calibrated nesting value, boolean runs, Python, flat=0), the plugin field, changed-method scoping, the gate, and output. Full suite green (106 passed).Usage
```sh
impact-gate score --enforcement block --cognitive-max 15 # SonarSource's line
```
🤖 Generated with Claude Code