Module: Menuconform::Scorer
- Defined in:
- lib/menuconform/scorer.rb
Overview
The published SPEC §7 scoring formula. Pure function of the findings and the weights below — same findings, same rules version, same score.
Constant Summary collapse
- WEIGHTS =
{ "error" => 5.0, "warn" => 2.0, "info" => 0.5 }.freeze
- PER_RULE_CAP =
15.0- CART_CAP_RULES =
%w[CART-001 CART-002 CART-003].freeze
- CART_CAP =
49- SCHEMA_CAP_RULE =
"STRUCT-001"- SCHEMA_CAP =
59
Class Method Summary collapse
-
.score(findings) ⇒ Object
findings: [Finding] with severities set.
Class Method Details
.score(findings) ⇒ Object
findings: [Finding] with severities set. Returns a breakdown hash.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/menuconform/scorer.rb', line 17 def score(findings) deductions = findings.group_by(&:rule).sort.map do |rule, group| severity = group.first.severity raw_points = group.size * WEIGHTS.fetch(severity) points = [raw_points, PER_RULE_CAP].min { "rule" => rule, "severity" => severity, "count" => group.size, "points" => points, "capped" => raw_points > PER_RULE_CAP } end raw = 100.0 - deductions.sum { |d| d["points"] } capped = [raw, 0.0].max hard_caps = [] if findings.any? { |f| CART_CAP_RULES.include?(f.rule) } && capped > CART_CAP hard_caps << { "reason" => "cart-blocking findings present (CART-001/002/003)", "cap" => CART_CAP } capped = CART_CAP end if findings.any? { |f| f.rule == SCHEMA_CAP_RULE } && capped > SCHEMA_CAP hard_caps << { "reason" => "document fails schema validation (STRUCT-001)", "cap" => SCHEMA_CAP } capped = SCHEMA_CAP end { "score" => capped.round, # Ruby rounds half away from zero: half-up for our range "base" => 100, "deductions" => deductions, "raw_score" => raw, "hard_caps" => hard_caps } end |