Class: ChurnVsComplexity::RiskClassifier

Inherits:
Object
  • Object
show all
Defined in:
lib/churn_vs_complexity/risk_classifier.rb

Overview

Classifies files into low/medium/high risk based on gamma score (harmonic mean of churn and complexity).

IMPORTANT: Complexity scores are NOT comparable across languages. Each language uses a different tool with a different numeric scale. All tools sum per-function scores across the file, but the magnitude differs:

Language       Tool      Metric                Trivial  Complex (~100 LOC)  Real-world range
Ruby           Flog      Code pain (weighted)  0        ~286                0-88
JavaScript/TS  ESLint    Cyclomatic complexity  3        ~62                 10-50
Python         Radon     Cyclomatic complexity  1        ~44                 5-50
Java           PMD       Cyclomatic complexity  1        ~39                 1-40
Go             gocognit  Cognitive complexity   0        ~87                 0-50
Kotlin         lizard    Cyclomatic complexity  1        ~40                 1-40
Rust           lizard    Cyclomatic complexity  1        ~40                 1-40
Swift          lizard    Cyclomatic complexity  1        ~40                 1-40

The DEFAULT_LOW and DEFAULT_HIGH thresholds below are rough midpoints suitable for Java/Python/JS. They are too aggressive for Ruby (Flog scores 3-7x higher) and Go (cognitive complexity penalises nesting). Use the constructor to pass language-appropriate thresholds.

Constant Summary collapse

DEFAULT_LOW =
10
DEFAULT_HIGH =
25
LANGUAGE_DEFAULTS =
{
  ruby: { low: 30, high: 70 },
  go: { low: 15, high: 40 },
}.freeze
RECOMMENDATIONS =
{
  'low' => 'Safe for quick changes.',
  'medium' => 'Exercise judgement; consider tests for non-trivial changes.',
  'high' => 'Write tests before modifying. Consider multi-agent review.',
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(low: DEFAULT_LOW, high: DEFAULT_HIGH, language: nil) ⇒ RiskClassifier

Returns a new instance of RiskClassifier.



40
41
42
43
44
# File 'lib/churn_vs_complexity/risk_classifier.rb', line 40

def initialize(low: DEFAULT_LOW, high: DEFAULT_HIGH, language: nil)
  defaults = LANGUAGE_DEFAULTS.fetch(language, {})
  @low = defaults.fetch(:low, low)
  @high = defaults.fetch(:high, high)
end

Class Method Details

.classify(gamma_score:) ⇒ Object



58
59
60
# File 'lib/churn_vs_complexity/risk_classifier.rb', line 58

def self.classify(gamma_score:)
  new.classify(gamma_score:)
end

Instance Method Details

#classify(gamma_score:) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
# File 'lib/churn_vs_complexity/risk_classifier.rb', line 46

def classify(gamma_score:)
  risk = if gamma_score < @low
           'low'
         elsif gamma_score > @high
           'high'
         else
           'medium'
         end

  { risk:, recommendation: RECOMMENDATIONS[risk] }
end