Rule Authoring Guide

Overview

Rules are the core detection units in A11YSmith. Each rule analyzes page evidence and produces zero or more findings.

Rule Interface

Every rule implements the WebRule interface:

interface WebRule {
  rule_id: string; // e.g., 'web-buttons-vs-links'
  title: string; // Human-readable title
  detect(evidence: PageEvidence): RuleDetection[];
}

PageEvidence

Rules receive collected evidence about a page:

interface PageEvidence {
  url: string;
  html: string; // Full DOM snapshot
  axeResults: AxeViolation[]; // axe-core violations
  accessibilityTree: AccessibilityNode | null;
  consoleMessages: string[];
  timestamp: string;
}

RuleDetection

Each detection must include:

RuleDetection fields
Field Required Description
detected Yes Whether the issue was found
title Yes Short, component-focused title
summary Yes One paragraph description
impact_statement Yes Who is affected, how, with what AT
expected_behavior Yes What should happen
actual_behavior Yes What does happen
suggested_fix Yes Primary recommendation
severity Yes highest, high, medium, low
confidence Yes high, medium, low
confidence_rationale Yes Why this confidence level
verdict Yes fail, recommended_improvement, needs_discussion, informational_note
target_standard_ids Yes Target standard references
wcag_sc_ids Yes WCAG SC references
validation_steps Yes How to confirm the fix
caveats Yes What is uncertain

Creating a New Rule

  1. Create a file in packages/web-auditor/src/rules/
  2. Implement the WebRule interface
  3. Register it in packages/web-auditor/src/rules/index.ts
  4. Add passing and failing test fixtures
  5. Write tests in packages/web-auditor/src/__tests__/

Testing Rules

Rules are tested against HTML string fixtures (no browser needed):

const evidence = {
  url: 'https://example.com',
  html: '<div onclick="submit()">Submit</div>',
  axeResults: [],
  accessibilityTree: null,
  consoleMessages: [],
  timestamp: '2026-03-16T12:00:00Z',
};

const detections = rule.detect(evidence);
expect(detections.filter((d) => d.detected)).toHaveLength(1);

Standards Mapping

Every rule must declare which standards it maps to, following the standards precedence rules: Target standards first, WCAG as fallback.