auditmysite 1.7.2

Resource-efficient WCAG 2.2 AA Accessibility Checker in Rust
Documentation
//! The canonical metric table.
//!
//! Ported 1:1 from `src/output/json.rs`'s former hand-written
//! `metric_context()` vec (same `field`/`unit`/`meaning` text — see that
//! function, which now derives its output from `REGISTRY` instead of the
//! other way around). Order matters: it is preserved so that the generated
//! JSON `score_definitions`/`count_definitions` arrays keep their current
//! element order.

use super::{Aggregation, Direction, MetricKind, MetricSpec, Scope, FIVE_BAND};

const REVIEWED_AT: &str = "2026-07-16";

pub const REGISTRY: &[MetricSpec] = &[
    MetricSpec {
        id: "accessibility_score",
        json_path: "summary.accessibility_score",
        kind: MetricKind::Score,
        unit: "points",
        band_set: Some(&FIVE_BAND),
        direction: Direction::HigherIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::WeightedAverage,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#accessibility-score",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Canonical accessibility score. With dual-viewport data it is 70% mobile and 30% desktop; otherwise it is the measured single-viewport score. It covers automatically evaluated WCAG findings only.",
        meaning_batch_override: Some("Average of the canonical page accessibility scores. Each dual-viewport page score is 70% mobile and 30% desktop; single-viewport pages use their measured accessibility score."),
    },
    MetricSpec {
        id: "overall_score",
        json_path: "summary.overall_score",
        kind: MetricKind::Score,
        unit: "points",
        band_set: Some(&FIVE_BAND),
        direction: Direction::HigherIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::WeightedAverage,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#overall-score",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Weighted score across contributing measured modules. In a dual-viewport audit, viewport module results are blended first and Security contributes 10% when available.",
        meaning_batch_override: Some("Average of the page-level overall scores across the audited URLs."),
    },
    MetricSpec {
        id: "overall_score_alias",
        json_path: "summary.score",
        kind: MetricKind::Score,
        unit: "points",
        band_set: Some(&FIVE_BAND),
        direction: Direction::HigherIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::WeightedAverage,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#overall-score-alias",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Compatibility alias for summary.overall_score.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "grade_certificate",
        json_path: "summary.grade / summary.certificate",
        kind: MetricKind::Classification,
        unit: "classification",
        band_set: None,
        direction: Direction::HigherIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#grade-certificate",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Classification derived from summary.overall_score; risk gates can restrict the certificate without changing the numeric score.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "module_score",
        json_path: "pages[].module_scores[].score",
        kind: MetricKind::Score,
        unit: "points",
        band_set: None,
        direction: Direction::HigherIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#module-score",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Module-specific 0-100 score. Scores from different modules use different measured or heuristic inputs and are not interchangeable raw measurements.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "module_dimension_score",
        json_path: "pages[].detail.modules.*.score and nested dimension scores",
        kind: MetricKind::Score,
        unit: "points",
        band_set: None,
        direction: Direction::HigherIsBetter,
        scope: Scope::Single,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#module-dimension-score",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Module- or dimension-specific 0-100 score; higher is better. The surrounding module and measurement_type identify whether the value is measured or heuristic.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "viewport_scores",
        json_path: "pages[].detail.viewport_scores",
        kind: MetricKind::Score,
        unit: "points",
        band_set: None,
        direction: Direction::HigherIsBetter,
        scope: Scope::Single,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#viewport-scores",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Desktop and mobile accessibility/overall scores on the 0-100 scale. weighted_overall is the 70% mobile and 30% desktop module blend before the optional Security contribution; the canonical accessibility blend is recorded in score_breakdown.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "accessibility_subcategory_scores",
        json_path: "pages[].detail.accessibility_subcategory_scores",
        kind: MetricKind::Score,
        unit: "points",
        band_set: None,
        direction: Direction::HigherIsBetter,
        scope: Scope::Single,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#subcategory-scores",
        reference_urls: &[],
        reviewed_at: "2026-09-16",
        pdf_component: None,
        meaning: "Accessibility score per subcategory on the 0-100 scale; the module's own scorer re-run on each subcategory's violations, so a subcategory without violations scores 100.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "security_category_scores",
        json_path: "pages[].detail.security_category_scores",
        kind: MetricKind::Score,
        unit: "points",
        band_set: None,
        direction: Direction::HigherIsBetter,
        scope: Scope::Single,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#subcategory-scores",
        reference_urls: &[],
        reviewed_at: "2026-09-16",
        pdf_component: None,
        meaning: "Security score per category on the 0-100 scale; omitted when the Security module did not run.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "named_module_score",
        json_path: "summary.*_score / pages[].*_score",
        kind: MetricKind::Score,
        unit: "points",
        band_set: None,
        direction: Direction::HigherIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#named-module-score",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Named module score on the 0-100 scale; higher is better. Throttled and Lighthouse performance scores are lab results, not field/RUM data.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "overall_score_weight_basis",
        json_path: "summary.overall_score_weight_basis",
        kind: MetricKind::Count,
        unit: "percent",
        band_set: None,
        direction: Direction::HigherIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#overall-score-weight-basis",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Sum of the module weights that actually fed overall_score, out of 100. Below 100 the score was renormalised over the modules that measured successfully, so it is not comparable with a run over a different module set.",
        meaning_batch_override: Some("Lowest module-weight basis across the audited pages, out of 100. overall_score_weight_basis_uniform says whether the pages agreed; false means overall_score values from different module sets were averaged."),
    },
    MetricSpec {
        id: "accessibility_score_breakdown",
        json_path: "summary.accessibility_score_breakdown[]",
        kind: MetricKind::Score,
        unit: "points and percent",
        band_set: None,
        direction: Direction::HigherIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#accessibility-score-breakdown",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Per area: score is that area run through the accessibility scorer on its own (0-100, higher is better) and does not average back to accessibility_score; estimated_lost_points is the area's share of the points the score actually lost and sums to exactly 100 minus accessibility_score; weight_pct is that same share in percent.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "risk_score",
        json_path: "pages[].risk.score",
        kind: MetricKind::Risk,
        unit: "risk points",
        band_set: None,
        direction: Direction::LowerIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#risk-score",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Independent 0-100 risk index; unlike quality scores, higher means more risk. The adjacent level, threshold, and driven_by fields explain its classification.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "principle_coverage_ratio",
        json_path: "pages[].principle_coverage.*.ratio",
        kind: MetricKind::Ratio,
        unit: "ratio",
        band_set: None,
        direction: Direction::HigherIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#principle-coverage-ratio",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Share from 0 to 1 of automatically evaluated checks without a finding for that WCAG principle; it is coverage context and does not affect the score.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "finding_priority_score",
        json_path: "pages[].findings[].priority_score",
        kind: MetricKind::Ranking,
        unit: "relative priority",
        band_set: None,
        direction: Direction::Neutral,
        scope: Scope::Both,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#finding-priority-score",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Unbounded ranking value calculated as severity weight multiplied by occurrence reach and divided by estimated effort; higher values should be addressed earlier and are not percentages.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "finding_score_impact",
        json_path: "pages[].findings[].score_impact",
        kind: MetricKind::Impact,
        unit: "penalty points",
        band_set: None,
        direction: Direction::Neutral,
        scope: Scope::Both,
        aggregation: Aggregation::None,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#finding-score-impact",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Rule-specific base and maximum deductions used by accessibility scoring; scaling states how repeated occurrences are condensed.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "violation_occurrence_count",
        json_path: "violation_count / occurrence_counts",
        kind: MetricKind::Count,
        unit: "WCAG occurrences",
        band_set: None,
        direction: Direction::LowerIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::Sum,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#violation-occurrence-count",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Affected WCAG element or page occurrences; repeated instances of the same rule count separately.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "violated_rule_severity_count",
        json_path: "violated_rule_count / severity_counts",
        kind: MetricKind::Count,
        unit: "distinct WCAG finding groups",
        band_set: None,
        direction: Direction::LowerIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::Sum,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#violated-rule-severity-count",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Distinct violated WCAG rule groups, not affected elements.",
        meaning_batch_override: None,
    },
    MetricSpec {
        id: "finding_occurrence_count_all_categories",
        json_path: "finding_count / finding_occurrence_count",
        kind: MetricKind::Count,
        unit: "all-category findings",
        band_set: None,
        direction: Direction::LowerIsBetter,
        scope: Scope::Both,
        aggregation: Aggregation::Sum,
        needs_explanation: true,
        docs_url: "docs/OUTPUT_CONTRACT.md#finding-occurrence-count-all-categories",
        reference_urls: &[],
        reviewed_at: REVIEWED_AT,
        pdf_component: None,
        meaning: "Finding rows and occurrences across WCAG, SEO, and every other reported category.",
        meaning_batch_override: None,
    },
];