Module: Moult::Confidence
- Defined in:
- lib/moult/confidence.rb,
lib/moult/confidence/rules.rb
Overview
The per-finding confidence model — one of Moult's two protected APIs (the other being the JSON output contract). It answers a single, deliberately humble question: how likely is this definition to actually be dead? It never asserts certain death (Moult's core principle); the highest a finding can score is still a confidence, and every contributing factor is recorded as a Reason so the judgement is auditable.
Confidence.score is a pure function of a Context of already-gathered facts: no IO, no rubydex, no Rails detection happens here. That keeps it trivially unit-testable and lets each Rules::Rule be exercised in isolation. The fact gathering lives in DeadCode; the conventions live in RailsConventions.
Defined Under Namespace
Modules: Rules Classes: Context, Finding, Reason
Constant Summary collapse
- CATEGORY =
"dead_code"- BASE =
Base likelihood before any rule fires, keyed by [kind, visibility]. A private method with no caller is the strongest candidate (nothing outside its class can reach it); public symbols are weakest because they are the natural API surface and the place metaprogramming/Rails reach in.
{ [:method, :private] => 0.75, [:method, :protected] => 0.6, [:method, :public] => 0.4, [:constant, :private] => 0.6, [:constant, :public] => 0.5 }.freeze
- DEFAULT_BASE =
0.45
Class Method Summary collapse
Class Method Details
.score(ctx, rules: Rules::DEFAULT_RULES) ⇒ Finding
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/moult/confidence.rb', line 76 def score(ctx, rules: Rules::DEFAULT_RULES) base = BASE.fetch([ctx.kind, ctx.visibility], DEFAULT_BASE) reasons = [Reason.new(rule: :base_score, delta: base, detail: "base for #{ctx.kind}/#{ctx.visibility}")] caps = [] rules.each do |rule| next unless rule.applies?(ctx) reasons << Reason.new(rule: rule.name, delta: rule.delta, detail: rule.detail_for(ctx)) caps << rule.cap if rule.cap end raw = reasons.sum(&:delta) bounded = caps.empty? ? raw : [raw, caps.min].min confidence = bounded.clamp(0.0, 1.0).round(2) Finding.new( symbol_id: ctx.symbol_id, kind: ctx.kind, name: ctx.name, span: ctx.span, path: ctx.path, confidence: confidence, category: CATEGORY, reasons: reasons, runtime: ctx.runtime ) end |