Equall

Scoring

How the 0–100 score is computed — formula, severity weights, and rank-damped severity summing (score model 2).

The formula

The score is a function of the deduplicated, non-ignored issue set only. File count never appears in it, and no single criterion is capped:

weights_by_criterion  = severity_weight of each issue, grouped by WCAG criterion
                         (unmapped issues are grouped per rule, key `_<scanner>:<rule_id>`)
penalty               = Σ over each criterion of Σ w(i) / i
                         — weights sorted descending, i = 1-indexed rank
score                 = max(0, round(100 × exp(-k × penalty) × 100) / 100)

With k = 0.01. The curve is asymptotic — no scan ever scores exactly 0 — and the result carries two decimal places: small fixes inside a heavily repeated criterion move the number by fractions of a point, and integer rounding would swallow them.

Severity weights

SeverityWeight
critical10
serious5
moderate2
minor1

Critical issues cost 10× more than minor ones. Two critical issues outweigh twenty minor ones.

Rank-damped severity summing

Within a criterion, weights are sorted heaviest-first and each is divided by its rank (w₁/1 + w₂/2 + w₃/3 + …). Repetition saturates smoothly instead of hitting a hard cap — a 30th identical failure on the same criterion weighs little, but it's never zero, and every fix is credited at its own severity rather than the group's maximum. Going from 30 missing alt attributes to 5 now strictly raises the score; under the previous model, capped per-criterion penalties made that fix invisible.

File count is not an input at all. Adding clean files, or scanning a single in-memory buffer instead of a full repo, cannot move the score in either direction — the previous density scaling (dividing the penalty by a log of files scanned) let padding a repo with inert files raise the score, and structurally punished single-buffer scans.

Score model versioning

Every ScanResult (and --json output) carries score_model, a version stamp bumped only when the formula or its input semantics change. This document describes model 2. Scores from different score_model values are not comparable — re-scan both sides of any before/after comparison with the same CLI version. The score is a trend indicator (is this codebase's accessibility getting better or worse across scans of the same model?), not a conformance grade — the conformance level below is the absolute, WCAG-aligned verdict.

Criteria beyond your target level

Only criteria at or below your target level count toward the score. A Level AAA finding (for example 3.1.5 Reading Level) under the default AA target does not penalize the score — AAA is not part of AA conformance. These beyond-target findings are shown in a separate Advisory section of the output rather than under "WCAG Violations", and they never appear in the critical/serious conformance counts. Raise --level AAA if you want them scored.

Conformance level

Separately from the score, Equall computes a WCAG conformance level: None, Partial A, A, AA, or AAA. The rule:

  • Any Level A violation → Partial A
  • Zero Level A, any Level AA violation → A
  • Zero Level A and AA, any Level AAA → AA
  • All clean → the target level, provided the scan actually exercised at least one criterion — otherwise None

"Exercised" here means summary.criteria_tested (the coverage-derived, genuinely-tested set), not "an issue was found there" — so a clean scan with real coverage reports its target level, not None. None is now reserved for scans where nothing was genuinely tested at all (e.g. no scannable files matched).

Best-practice issues (no WCAG mapping) never affect the conformance level — they only appear in the Best-Practice Recommendations section of the output.

On this page