Appendix C - 9. Standards / WCAG rule engine
The Structure of Standards / WCAG rule engine — its shape at a glance:
The engine walks the typed model, produces findings, and maps each finding to the standard criterion it closes. The scope document, kept in sync, records which criteria are covered, gaps, or aspirational.
flowchart LR Model[(Typed document model)] --> Engine[Rule engine] Engine -->|findings| Map[Finding → criterion] Map --> Claim([per-criterion conformance]) Map -. same-commit sync .-> Scope[(Coverage scope doc)]
Accessible description: the rule engine walks the typed document model and produces findings, then maps each finding to the exact standard criterion it closes, yielding a per-criterion conformance claim. A coverage scope document is kept in sync in the same commit, recording which criteria are covered, gaps, or aspirational.
Projected from the catalogue entry validation-and-conformance / Standards / WCAG rule engine.
On this page: Intent · Motivation · Applicability · Structure · Sample Code · Consequences · Example use within DocAble · Related Patterns
Intent
Intent — A rule engine that maps each finding to the exact external-standard clause it closes, turning "does this conform?" into a deterministic, standards-grounded predicate rather than a judgement call (our instance: the WCAG 2.1 AA / Section 508 / PDF-UA accessibility rule engine).
Motivation
"Is this document accessible?" needs a precise, standards-grounded answer, not a fuzzy score. Without one, the tool either ships a document that claims conformance while missing success criteria, or runs checks that aren't tied to any standard (so "we check X" doesn't map to "we close SC Y"). The failure is an unfounded conformance claim, and it recurs per document and per new check.
Applicability
- A rule engine producing findings, and a standards taxonomy (the WCAG/508/PDF-UA SCs).
- A mapping from each check to the SC(s) it closes.
- A scope doc kept in sync (the same-commit discipline) so coverage claims don't drift from the engine.
Structure
The Structure diagram appears at the top of this page.
Sample Code
The engine turns a pile of findings into a clause-by-clause conformance claim by mapping each finding to the criterion it closes. A fuzzy score can't say which criterion a check satisfies; this mapping can, so the claim is auditable. The same-commit rule keeps the coverage doc from drifting away from the engine.
from dataclasses import dataclass
@dataclass(frozen=True)
class Finding:
check_id: str
criterion: str # the exact standard clause this finding closes, e.g. "1.1.1"
def conformance(findings: list[Finding], in_scope: set[str]) -> dict[str, str]:
"""Map findings to the criteria they close, so conformance is auditable per
clause rather than a single opaque score. A criterion with no finding and no
check is a coverage gap, not a silent pass."""
closed = {f.criterion for f in findings}
return {c: ("covered" if c in closed else "gap") for c in sorted(in_scope)}
# the coverage scope set is the source of truth for what's in scope; it must be
# updated in the SAME change that adds a check closing a new criterion, or the
# claim drifts from the engine.
Consequences
- Coverage is only as complete as the mapped checks. Unmapped SCs are coverage-gaps or aspirational; honesty about this is the scope doc's whole job.
- The mapping must track the standard. WCAG revisions and new SCs require engine + doc updates.
- Per-pass rule-fail is staging-only (the prod gate is coarser).
Example use within DocAble
CheckRunner.ComputeStandards— the finding → SC mapping.- The staging per-pass rule-engine check (new findings surfaced on a dedicated JSON marker).
- The WCAG-scope-mapping doc (Covered / Coverage-gap / Aspirational status).
Related Patterns
- Layer — with content-validator: fidelity (nothing lost) + conformance (standards met) are the two product gates over the artifact.
- Counterpart — the WCAG-scope doc keeps the coverage claims honest (like the DoD ↔ rule index pairing on the agent side).
- Consumer — reads the canonical-walkers (
RuleWalkers) that traverse the typed models to produce findings.