references/act.md
A supporting file of the ultra11y skill.
ACT conformance — how this engine scores against a corpus it did not write
The recall matrix in this repository proves that each rule fires on the defect written FOR it.
That is circular. The W3C ACT-Rules Community Group publishes rules
with passed / failed / inapplicable examples authored independently of this project, so running
the engine over them measures something a self-authored fixture cannot.
How to read this. An ACT example asserts something about ITS OWN rule and nothing else, so each
case is judged only with the engine rules mapped to that ACT rule — never with the whole engine.
Only normative findings count (an advisory recommendation never flips a criterion, so it cannot
fail a case either). Rules needing a rendered page or a human call are declared, not scored — saying
so beats quietly scoring zero.
Summary
| Corpus | 1134 examples across 91 ACT rules |
| Source | https://act-rules.github.io/testcases.json |
| Rules scored | 40 |
| Failed examples caught | 125 / 176 |
| Clean examples left alone | 364 / 364 — no unexplained false positive |
| Consistent | 9 |
| Divergent (documented, 9 cases) | 3 |
| Partially consistent | 28 |
| Inconsistent | 0 |
| Declared gaps (static, not implemented) | 5 |
Partially consistent is the ACT Rules Format's own term for a tool that never reports a false positive but does not catch everything — it is a coverage statement, not an error. Divergent means every deviation on that rule is listed below with the argument for it.
Scored rules
| ACT rule | WCAG | Engine rules | Verdict | Caught |
|---|---|---|---|---|
| Image has non-empty accessible name | 1.1.1 | img-alt-missing | 🟨 partially consistent | 4/5 |
| Letter spacing in style attributes is not !important | 1.4.12 | letter-spacing-important | 🟨 partially consistent | 3/4 |
| HTML page has non-empty title | 2.4.2 | title-missing-empty | 🟨 partially consistent | 4/5 |
| Visible label is part of accessible name | 2.5.3 | label-in-name-mismatch | 🟦 divergent (documented) | 3/3 |
| Element with presentational children has no focusable content | 4.1.2 | presentational-children-focusable | 🟨 partially consistent | 2/3 |
| Id attribute value is unique | 4.1.1 | duplicate-id | ✅ consistent | 3/3 |
| Element marked as decorative is not exposed | — | decorative-marked-exposed | ✅ consistent | 3/3 |
| Audio or video element that plays automatically has a control mechanism | — | autoplay-media | 🟦 divergent (documented) | 5/5 |
| Element with role attribute has required states and properties | 4.1.2 | aria-required-attr | 🟨 partially consistent | 1/2 |
| Image button has non-empty accessible name | 1.1.1, 4.1.2 | input-image-alt-missing | 🟨 partially consistent | 2/3 |
| HTML page lang and xml:lang attributes have matching values | 3.1.1 | html-lang-xml-lang-mismatch | ✅ consistent | 2/2 |
| ARIA state or property is permitted | — | aria-prohibited-attr | 🟨 partially consistent | 0/2 |
| ARIA attribute is defined in WAI-ARIA | — | invalid-aria-attr | ✅ consistent | 2/2 |
| Role attribute has valid value | 1.3.1 | invalid-aria-role | ✅ consistent | 2/2 |
| ARIA state or property has valid value | — | invalid-aria-value, live-region-conflict | 🟨 partially consistent | 9/10 |
| Element with aria-hidden has no content in sequential focus navigation | 4.1.2 | aria-hidden-focusable | 🟨 partially consistent | 5/6 |
| Autocomplete attribute has valid value | 1.3.5 | autocomplete-token-invalid | ✅ consistent | 5/5 |
| Line height in style attributes is not !important | 1.4.12 | line-height-important | 🟨 partially consistent | 4/6 |
| SVG element with explicit role has non-empty accessible name | 1.1.1 | img-alt-missing | 🟨 partially consistent | 2/4 |
| Audio or video element avoids automatically playing audio | 1.4.2 | autoplay-media | 🟦 divergent (documented) | 2/2 |
| Object element rendering non-text content has non-empty accessible name | 1.1.1 | object-embed-no-name | 🟨 partially consistent | 2/4 |
| Button has non-empty accessible name | 4.1.2 | button-empty-name, icon-only-control-unnamed | 🟨 partially consistent | 4/5 |
| Word spacing in style attributes is not !important | 1.4.12 | word-spacing-important | 🟨 partially consistent | 3/4 |
| Headers attribute specified on a cell refers to cells in the same table element | 1.3.1 | headers-attr-dangling | ✅ consistent | 4/4 |
| Meta viewport allows for zoom | 1.4.4 | meta-viewport-zoom-block | 🟨 partially consistent | 3/4 |
| HTML page has lang attribute | 3.1.1 | html-lang-missing | 🟨 partially consistent | 3/4 |
| ARIA required owned elements | 1.3.1 | aria-required-children | 🟨 partially consistent | 3/7 |
| Meta element has no refresh delay | 2.2.1, 2.2.4, 3.2.5 | meta-refresh-redirect | 🟨 partially consistent | 3/4 |
| HTML page lang attribute has valid language tag | 3.1.1 | lang-invalid | 🟨 partially consistent | 1/4 |
| Meta element has no refresh delay (no exception) | 2.2.4, 3.2.5 | meta-refresh-redirect | 🟨 partially consistent | 2/4 |
| Link has non-empty accessible name | 2.4.4, 2.4.9, 4.1.2 | link-empty-name, icon-only-control-unnamed | 🟨 partially consistent | 7/11 |
| Iframe element has non-empty accessible name | 4.1.2 | iframe-title-missing | 🟨 partially consistent | 3/4 |
| Table header cell has assigned cells | 1.3.1 | th-no-data-cells | 🟨 partially consistent | 0/3 |
| Element with lang attribute has valid language tag | 3.1.2 | lang-invalid, inline-lang-change-missing | 🟨 partially consistent | 6/9 |
| Form field has non-empty accessible name | 4.1.2 | control-label-missing | 🟨 partially consistent | 4/7 |
| Attribute is not duplicated | 4.1.1 | duplicate-attribute | ✅ consistent | 3/3 |
| Video element auditory content has captions | — | media-no-track | 🟨 partially consistent | 0/4 |
| ARIA required context role | 1.3.1 | aria-required-parent | 🟨 partially consistent | 2/4 |
| Heading has non-empty accessible name | 1.3.1 | empty-heading | 🟨 partially consistent | 7/8 |
| Menuitem has non-empty accessible name | 4.1.2 | menuitem-empty-name | ✅ consistent | 2/2 |
Notes and documented divergences
- Letter spacing in style attributes is not !important — definite below-threshold author-important values; computed-unit cases remain rendered
- Visible label is part of accessible name · reports on Passed Example 6: an icon FONT renders the text 'search' as a glyph, so the visible label is not the text in the DOM — a fact only the rendered page carries
- Audio or video element that plays automatically has a control mechanism · reports on Inapplicable Example 2: the source cannot tell that the referenced media has no audio track
- Audio or video element that plays automatically has a control mechanism · reports on Passed Example 3: the pause mechanism is a custom button wired in JavaScript, not a native
controlsattribute - ARIA state or property is permitted — covers the name-prohibited roles; the full per-role permitted-attribute matrix is not encoded
- Element with aria-hidden has no content in sequential focus navigation · reports on Passed Example 4: a focus-sentinel link inside an aria-hidden wrapper: it IS reachable by Tab, and only a runtime focus handler bounces it back — the same call axe-core makes
- Line height in style attributes is not !important — definite below-threshold author-important values; computed-unit cases remain rendered
- SVG element with explicit role has non-empty accessible name — role=img on <svg> is handled by the same rule
- Audio or video element avoids automatically playing audio · reports on Inapplicable Example 2: the source cannot tell that the referenced media file is silent
- Audio or video element avoids automatically playing audio · reports on Passed Example 3: the pause mechanism is a custom button wired in JavaScript, not a native
controlsattribute - Audio or video element avoids automatically playing audio · reports on Passed Example 2: a #t= media fragment shortening playback below 3s is not resolvable from source
- Word spacing in style attributes is not !important — definite below-threshold author-important values; computed-unit cases remain rendered
- Meta element has no refresh delay (no exception) — this variant drops the >20h exception the engine honours, so long delays are knowingly not reported
- Iframe element has non-empty accessible name · reports on Inapplicable Example 3: a tabindex=-1 iframe is still exposed to assistive tech and still needs a title (RGAA 2.1 requires one unconditionally)
- Table header cell has assigned cells — only the explicit
headers-wired shape is decided; scope-based assignment needs a full table model - Element with lang attribute has valid language tag · reports on Inapplicable Example 2: lang="" on an element carrying text declares no language for that text; ACT deems the rule inapplicable, this engine reports it under 3.1.2
- Form field has non-empty accessible name —
placeholder-as-labelis deliberately NOT mapped: a placeholder does contribute to the accessible name, so ACT passes it — ultra11y still reports it, as a stricter house rule under 3.3.2. - Video element auditory content has captions — presence of a caption track; whether the captions are accurate is a judgment call
Declared gaps — statically decidable, not implemented yet
| ACT rule | WCAG | Why it is not covered |
|---|---|---|
| Document has heading for non-repeated content | — | a heading for the non-repeated content (h1-missing is advisory, so it does not count) |
| Document has a landmark with non-repeated content | — | ACT asks that the non-repeated content sit in SOME landmark — a weaker claim than missing-main-landmark, which requires a <main>, so the two are not equivalent |
| Bypass Blocks of Repeated Content | 2.4.1 | presence of a bypass mechanism (landmark or skip link) |
| No keyboard shortcut uses only printable characters | 2.1.4 | 2.1.4 single-character keyboard shortcuts |
| Document has an instrument to move focus to non-repeated content | — | presence of a bypass instrument |
Out of the static engine's reach — routed, not ignored
The corpus is vendored at scripts/vendor/act-testcases.json (refreshed by
pnpm run build:act:refresh, and daily by the act-refresh workflow) so the suite stays
offline and deterministic.
ACT-Rules Community Group test cases are © their contributors under the W3C Software and
Document License — see NOTICE.