Skip to content

feat(analyzer): architectural anti-pattern detection (#69)#101

Merged
zaebee merged 6 commits into
mainfrom
feat/issue-69-anti-pattern-detection
Jun 9, 2026
Merged

feat(analyzer): architectural anti-pattern detection (#69)#101
zaebee merged 6 commits into
mainfrom
feat/issue-69-anti-pattern-detection

Conversation

@zaebee

@zaebee zaebee commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • src/cgis/query/anomaly.py — frozen Pydantic models: AnomalyType, ArchitecturalAnomaly, ArchitecturalReport
  • src/cgis/query/analyzer.pyAnalyzerEngine with three detectors:
    • detect_cycles() — iterative Tarjan SCC on IMPORTS edges; severity scales with cycle length
    • detect_zone_of_pain() — Uncle Bob D-distance (I + A - 1); flags stable-concrete classes (D ≥ 0.70, Ca ≥ 3)
    • detect_god_objects() — classes with ≥ 10 methods AND ≥ 5 efferent targets
  • tests/unit/test_analyzer.py — 18 tests covering Tarjan correctness, external-node filtering, threshold boundaries, and full run() report
  • src/cgis/cli.py — new cgis analyze command with --db, --min-severity, --format text|json
  • .pre-commit-config.yaml — added missing packages to mypy additional_dependencies (rich, typer, tree-sitter*)

Design notes

  • Tarjan SCC is implemented iteratively (work-stack) to avoid Python's recursion limit on large graphs
  • _ZONE_OF_PAIN_MIN_AFFERENT = 3 threshold avoids false positives on low-usage classes
  • All helper functions extracted to module level to stay under C901 complexity limit
  • External nodes (NodeNamespace.EXTERNAL) are excluded from all detectors

Test plan

  • make format && make lint && make type-check && make pytest && make doc-coverage — all green (301 tests)
  • cgis analyze --db graph.db on a real codebase snapshot
  • Verify --min-severity filtering works in text and JSON output

Closes #69

🤖 Generated with Claude Code

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@zaebee zaebee force-pushed the feat/issue-69-anti-pattern-detection branch 2 times, most recently from aa40828 to fd15f09 Compare June 9, 2026 02:01
Repository owner deleted a comment from github-actions Bot Jun 9, 2026
Repository owner deleted a comment from github-actions Bot Jun 9, 2026
Repository owner deleted a comment from github-actions Bot Jun 9, 2026
zaebee and others added 5 commits June 9, 2026 02:38
Adds AnalyzerEngine with three detectors:
- detect_cycles()       — iterative Tarjan SCC on IMPORTS edges; each
                          cycle emitted as CIRCULAR_DEPENDENCY anomaly
                          with severity scaling by cycle length
- detect_zone_of_pain() — Uncle Bob D-distance metric (afferent/efferent
                          coupling + abstractness via EXTENDS/metadata);
                          flags stable-concrete classes (D >= 0.70)
- detect_god_objects()  — classes with >= 10 methods AND >= 5 efferent
                          targets flagged as GOD_OBJECT

New CLI command: cgis analyze [--db graph.db] [--min-severity 0.5]
                               [--format text|json]

18 unit tests covering Tarjan algorithm correctness, external-node
filtering, threshold boundaries, and the full run() report.

Also adds missing packages to pre-commit mypy additional_dependencies
(rich, typer, tree-sitter*) so the hook has the same dependency set
as the local venv.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace chained startswith() with tuple argument
- Extract _pop_scc() helper from _tarjan_step to reduce cognitive
  complexity from 16 to 9 (limit is 15)
- Use pytest.approx() for floating-point equality assertion

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BLOCKER #1: sort adjacency keys in _tarjan_scc for deterministic output
  order across runs (dict insertion order isn't stable after DB queries).

BLOCKER #2: remove EXTENDS-based abstractness heuristic from
  _get_abstract_fqns. Marking the child of an EXTENDS edge as abstract
  is wrong (e.g. UserService(Base) is concrete). Only node metadata
  is_abstract is authoritative.

MAJOR #2: add tests for raw_import: filtering and empty adj in Tarjan.

BLOCKER #3, MAJOR #1, MINORs: not applied — #3 is a misread (external
calls are already counted via fallback), #1 is pedantic, MINORs are
edge cases / out-of-scope feature requests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MINOR-1: add inline rationale comments to all threshold constants.

MAJOR-2: add explicit empty-graph tests for detect_zone_of_pain and
  detect_god_objects (run() already covers this via test_run_empty_graph,
  but focused tests are clearer).

MAJOR-4: add self-calls test — methods calling siblings in the same
  class must NOT inflate efferent coupling (correct behavior confirmed).

MAJOR-1: add test documenting that raw_call: targets count as efferent
  coupling (external calls are real dependencies).

Skipped: BLOCKER-1 (annotations already present — hallucination),
BLOCKER-2 (FUNCTION→class coupling is out of CLASS-metric scope),
BLOCKER-3 (ID collision is edge case, same issue as prev review MINOR),
MAJOR-3 (DECLARES alongside CONTAINS is safe fallback), MINORs 2-4.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Clarify _ZONE_OF_PAIN_DISTANCE comment: D > 0.7 AND I <= 0.3
- Add boundary tests: 9-method class not flagged (one below threshold),
  high-instability class (I≈0.33) not in Zone of Pain

Skipped: all three BLOCKERs (two hallucinations + one misclassified),
two MAJORs (hallucination + scope creep), MINORs 2-4.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@zaebee zaebee force-pushed the feat/issue-69-anti-pattern-detection branch from d21f6c8 to ccc6569 Compare June 9, 2026 02:38
Repository owner deleted a comment from github-actions Bot Jun 9, 2026
@zaebee

zaebee commented Jun 9, 2026

Copy link
Copy Markdown
Owner Author

/guardian review

Multiple calls to the same unresolved target count as one efferent
entry (set semantics). Validates the 1/4 valid finding from Gemini
Flash Lite review.

Also restrict pre-commit mypy hook to src/ only — tests/ imports cgis
as a local package not available in the hook's isolated virtualenv,
matching what make type-check already does.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Jun 9, 2026

Copy link
Copy Markdown

Repository owner deleted a comment from github-actions Bot Jun 9, 2026
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

LGTM — no defects found in this diff.

The implementation is highly robust, clean, and complies fully with both the engineering standards and the semantic ontology.

Key areas verified:

  1. Iterative Tarjan's SCC Algorithm: Verified that the DFS walk state machine in _tarjan_step correctly emulates the backtracking step (updating parent lowlink when a child finishes execution) and correctly identifies disjoint components without triggering recursion limits or raising IndexError on empty or cyclic graphs.
  2. Division-by-Zero Protection: Confirmed that detect_zone_of_pain protects against division by zero in the instability calculation ($I = Ce / (Ca + Ce)$) via the conditional guard if total == 0 or ca_count < _ZONE_OF_PAIN_MIN_AFFERENT: continue.
  3. Efferent/Afferent Coupling Deduplication: Verified that detect_god_objects and _compute_class_coupling correctly use sets to deduplicate multiple references to the same target class (and handle raw_call: prefixes cleanly as external boundaries), preventing inflated coupling counts.
  4. Test Coverage: Checked that the unit tests exhaustively cover complex edge cases including single-node self-loops, external/unresolved edge filtration, empty graphs, and boundary metrics threshold matching.

🤖 gemini-3.5-flash · 14,532 prompt + 287 completion = 14,819 tokens · graph 0/4 files (0%)

@zaebee zaebee merged commit fd2440c into main Jun 9, 2026
3 checks passed
@zaebee zaebee deleted the feat/issue-69-anti-pattern-detection branch June 9, 2026 03:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Architectural Anti-Pattern Detection (God Objects, Cycles, and the Zone of Pain)

1 participant