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: "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: "Accessibility area score (0-100, higher is better), its contribution weight in percent, and estimated_lost_points relative to 100.",
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,
},
];