WCAG Remediation Coverage
This document maps every WCAG success criterion and axe-core rule we detect against what the remediation service actually fixes. It answers the question: after remediation, which violations will be gone, which will remain, and which were never checked?
Last updated: 2026-03-07 (updated to reflect 14 total new auto-fixes: 7 from prior session + 7 Tier 1 deterministic fixes)
How the Remediation Service Works
Two services apply fixes in sequence:
-
html-remediator.tsβ Runs before axe-core. Applies static regex fixes (lang, headings, landmarks, tables, skip link) and calls a vision AI model (Gemini, Claude, or GPT-4o) to generate descriptive alt text for images. -
axe-fixer.tsβ Runs after an initial axe-core audit. Applies deterministic regex fixes for 20 known violation types, then re-runs axe-core (up to 3 iterations). Reverts any change that increases the violation count.
Neither service modifies the semantic content of the document β they can add missing structural markup and set safe default attribute values, but they cannot rewrite prose, determine the correct language for a passage, or know what an unlabeled button is supposed to do.
Part 1: Violations the Service CAN Fix
1A β Fully Fixed (reliable, correct output)
These violations are deterministically correctable. The fix is structurally sound and will pass re-audit.
| Violation | WCAG SC | Level | Fix Applied | Service |
|---|---|---|---|---|
Missing lang on <html> | 3.1.1 | A | Adds lang="en" | Both |
Missing <title> element | 2.4.2 | A | Inserts <title>Document</title> into <head> | Both |
Missing <main> landmark | 2.4.1 | A | Wraps body content in <main role="main"> | Both |
| Missing skip navigation link | 2.4.1 | A | Inserts <a href="#main-content" class="skip-link"> after <body> | html-remediator |
| Missing viewport meta tag | 1.4.4 | AA | Inserts <meta name="viewport" content="width=device-width, initial-scale=1.0"> | axe-fixer |
Skipped heading levels (h1 β h3) | 1.3.1 | AA | Remaps heading levels to sequential order | Both |
Table with no <th> | 1.3.1 | A | Promotes first-row <td> cells to <th scope="col"> | html-remediator |
<th> with missing or invalid scope | 1.3.1 | A | Adds scope="col" in <thead>, scope="row" for first <th> in <tbody>; removes invalid scope values | html-remediator |
Duplicate element id attributes | 4.1.1 | A | Appends -2, -3 suffix to duplicate IDs and updates all aria-labelledby, aria-describedby, aria-controls, aria-owns, and for references to renamed IDs | Static validator |
Invalid ARIA role attribute (e.g., role="dropdown") | 4.1.2 | A | Removes the invalid role attribute β element falls back to its implicit semantic role | Static validator |
Empty <h1>β<h6> element | 1.3.1 | A | Removes the empty heading element | Static validator |
Orphan <li> outside <ul> or <ol> | 1.3.1 | A | Wraps orphan <li> elements in <ul> | Both |
Non-<li> direct children of <ul> or <ol> | 1.3.1 | A | Wraps invalid children in <li> using DOM parsing; nested lists are preserved | Static validator |
<dl> with invalid child elements | 1.3.1 | A | Wraps invalid direct children of <dl> in <dd> using DOM parsing | Static validator |
Layout table (no <th>, cells contain only block elements) | 1.3.2 | A | Adds role="presentation" to the table β suppresses screen reader table semantics. Does not convert layout to CSS. | Static validator |
| Missing ARIA live region (forms or feedback elements present) | 4.1.3 | AA | Adds aria-live="polite" role="status" aria-atomic="true" to feedback-pattern elements; if none are present, injects a visually-hidden announcer <div> after <body> | Static validator |
text-align: justify in styles | 1.4.8 | AAA | Removes from all inline styles and <style> blocks document-wide | Static validator |
user-select: none in styles | 1.4.8 | AAA | Removes from all inline styles and <style> blocks document-wide | Static validator |
<listitem> not in list | 1.3.1 | A | Same as orphan <li> β wraps in <ul> | axe-fixer |
| Content outside landmark regions | Best Practice | β | Wraps orphan body content in <section role="region" aria-label="Content"> | axe-fixer |
| Duplicate landmark regions | Best Practice | β | Adds unique aria-label attributes to duplicate <nav>, <aside>, <section>, <form> elements | axe-fixer |
| Scrollable region not keyboard accessible | 2.1.1 | A | Adds tabindex="0" to scrollable overflow containers | axe-fixer |
SVG with role="img" and no label | 1.1.1 | A | Adds aria-label="Mathematical expression" | axe-fixer |
1B β Partially Fixed (fix is applied, but quality is limited or context-dependent)
These violations receive an automated fix that will satisfy the rule validator, but the result is a generic placeholder that does not communicate real meaning. A human or AI review pass is needed to complete the fix.
| Violation | WCAG SC | Level | Fix Applied | Limitation |
|---|---|---|---|---|
<img> missing alt attribute | 1.1.1 | A | AI path (html-remediator): Vision model generates a contextual description. Fallback (axe-fixer): Adds alt="Image" | The AI path requires a configured API key and image accessibility; the fallback alt="Image" is still a 1.1.1 violation for meaningful content β it tells a screen reader nothing |
Empty <a href> (no link text) | 2.4.4 | A | Adds aria-label="Link" | βLinkβ communicates nothing about the destination β must be revised by a human |
Empty <button> | 4.1.2 | A | Adds aria-label="Button" | βButtonβ communicates nothing about the action |
Unlabeled <input> | 1.3.1 | A | Adds aria-label="Input field" | βInput fieldβ communicates nothing about what data to enter |
| Color contrast below 4.5:1 (AA) | 1.4.3 | AA | Forces color: #1a1a1a !important; background-color: #ffffff !important on the failing element | Overrides author styles β may break the visual design; ratio is corrected but design is not restored |
| Color contrast below 7:1 (AAA) | 1.4.6 | AAA | Same approach as AA contrast fix | Same limitation |
| Image-only links | 2.4.4 | A | Adds aria-label from the contained <img> alt text | Only works if the <img> has meaningful alt; if alt is also generic, the link label will be too |
Non-SVG element with role="img" and no label | 1.1.1 | A | Adds aria-label="Image" | Generic β does not describe the image content; requires human review |
<input type="submit/button"> with no accessible name | 4.1.2 | A | Adds value="Submit" | βSubmitβ may not match the actual button purpose |
Form field labeled only by title attribute | Best Practice | β | Copies title value to aria-label | No content knowledge required β value is already present in title; fix quality matches the existing title text |
<select> with no accessible name | 1.3.1 | A | Adds aria-label="Select an option" | Generic β does not describe what is being selected |
Part 2: Violations Detected But NOT Fixed
These violations appear in the audit report and are presented to the user with guidance, but the conversion service makes no change to the HTML. They require human judgment, content knowledge, design decisions, or structural changes that cannot be made without understanding the document.
2A β Static Validator Detects, No Fix Applied
| Violation | WCAG SC | Level | Why Not Fixed |
|---|---|---|---|
Invalid lang attribute value (e.g., lang="english" instead of lang="en") | 3.1.1 | A | Cannot determine the correct BCP 47 code from context |
Present-but-meaningless alt text (e.g., alt="image", alt="photo", alt="img_001.png") | 1.1.1 | A | Rewriting requires understanding what the image depicts β needs AI vision or human review |
| Generic or non-descriptive heading text (βSection 2β, βContinuedβ, β1.β) | 2.4.6 | AA | Rewriting heading text requires understanding the documentβs content |
Empty <th> (table header with no text) | 1.3.1 | A | Cannot supply the missing header label without knowing what column it represents |
<th> missing scope in complex multi-span tables | 1.3.1 | A | Position-based scope inference is unreliable for merged cells β requires human review |
| Block element nested inside inline / anchor-inside-anchor | 4.1.1 | A | No safe generic fix β restructuring may change document meaning |
| ARIA attribute incompatible with element role | 4.1.2 | A | Reported as a warning; stripping the attribute would be unsafe without knowing the intended widget pattern |
| Color-only information in text content | 1.4.1 | A | Content rewrite required β cannot add semantic meaning (icon, label) without knowing the intent |
| Sensory-only instructions (βclick the red button on the rightβ) | 1.3.3 | A | Prose rewrite required |
| Image of text (image whose alt is full prose content) | 1.4.5 | AA | Cannot convert a rasterized image to actual HTML text |
Non-Latin script without lang annotation | 3.1.2 | AA | Script is detected, but the correct BCP 47 code cannot be inferred without language-detection |
| Same visible label on elements of different types | 3.2.4 | AA | May be intentional β requires content review |
Color contrast via CSS cascade / var() / inherit | 1.4.3 | AA | External stylesheets and CSS variables cannot be resolved by static HTML analysis |
color-contrast-enhanced (7:1 AAA) via cascade | 1.4.6 | AAA | Same as above β axe-core checks this at render time but no static fix is possible |
| Non-descriptive link purpose (same text, different destinations) | 2.4.9 | AAA | Requires content rewrite to differentiate links |
| Non-descriptive section headings | 2.4.10 | AAA | Cannot insert headings without knowing where section boundaries belong |
| Unexpanded abbreviations | 3.1.4 | AAA | Expansion text requires a domain-specific dictionary |
2B β axe-core Detects, Not in Fix Registry
These violations appear in axe-core audit results. The fix engine (axe-fixer.ts) does not have a fix function for them.
| axe Rule ID | WCAG SC | Level | Why Not Fixed |
|---|---|---|---|
area-alt | 1.1.1 | A | Image map <area> elements need descriptive alt β requires content knowledge |
input-image-alt | 1.1.1 | A | <input type="image"> needs alt β requires content knowledge |
object-alt | 1.1.1 | A | <object> elements need fallback text β requires content knowledge |
summary-name | 4.1.2 | A | <summary> without discernible text |
bypass | 2.4.1 | A | Skip mechanism missing β partially addressed by html-remediatorβs skip link, but if axe flags this after remediation the skip link target may be broken |
aria-hidden-focus | 4.1.2 | A | Focusable element inside aria-hidden="true" β removing aria-hidden may expose content that was intentionally hidden |
aria-hidden-body | 4.1.2 | A | Cannot safely remove aria-hidden from <body> |
nested-interactive | 4.1.2 | A | Structural HTML issue β restructuring may break layout |
form-field-multiple-labels | 1.3.1 | A | Multiple <label> elements for one input β requires knowing which label is correct |
td-headers-attr | 1.3.1 | A | headers attribute references non-existent IDs β requires table restructuring |
th-has-data-cells | 1.3.1 | A | Table header with no associated data cells β structural table issue |
frame-title | 4.1.2 | A | <iframe> without an accessible name β requires knowing what the frame contains |
frame-title-unique | 4.1.2 | A | Duplicate frame titles β requires knowing each frameβs purpose |
no-autoplay-audio | 1.4.2 | A | Audio autoplay β removing the autoplay attribute may break intended behavior |
video-caption | 1.2.2 | A | Video without captions β caption generation requires a transcription service |
non-text-contrast | 1.4.11 | AA | UI component and focus indicator contrast β CSS-dependent, cannot override safely |
focus-visible | 2.4.7 | AA | Focus indicator not visible β CSS-dependent |
target-size | 2.5.8 | AA | Touch target too small β requires CSS layout changes |
autocomplete-valid | 1.3.5 | AA | Invalid autocomplete attribute value β removing it may be correct but context-dependent |
avoid-inline-spacing | 1.4.12 | AA | Inline CSS locks text spacing β removing specific inline properties requires knowing which properties to target |
valid-lang | 3.1.2 | AA | Invalid lang attribute on element β correct code cannot be inferred |
color-contrast (via CSS cascade) | 1.4.3 | AA | Color contrast failures caused by external stylesheets, CSS variables, or inherit β cannot be resolved by regex on HTML alone |
identical-links-same-purpose | 2.4.9 | AAA | Same visible text, different href β requires content understanding to resolve |
blink / marquee | 2.2.2 | A | Elements exist but removing them changes document content |
aria-* rules (braille, deprecated roles, conditional attrs, prohibited attrs, required children/parent, etc.) | 4.1.2 | A | Complex ARIA structural requirements β cannot correct without knowing the intended widget pattern |
Various landmark best-practice rules (landmark-banner-is-top-level, landmark-contentinfo-is-top-level, etc.) | Best Practice | β | Require document restructuring |
page-has-heading-one | Best Practice | β | Cannot add an <h1> without knowing what the document title should be |
image-redundant-alt | Best Practice | β | Alt text duplicates surrounding visible text β requires content review |
presentation-role-conflict | Best Practice | β | Element has conflicting semantic role β requires structural review |
table-duplicate-name | Best Practice | β | <caption> and summary are identical β requires content review |
2C β Browser Checks Detect, No Fix Applied
These checks run in Puppeteer and produce detailed diagnostic results, but no HTML transformation is performed. The underlying cause (fixed-width CSS, fixed-height containers, positive tabindex values) requires manual CSS or HTML changes.
| Check | WCAG SC | Level | What Is Detected | Why Not Fixed |
|---|---|---|---|---|
checkResizeText() β horizontal overflow at 200% zoom | 1.4.4 | AA | Elements where scrollWidth > innerWidth and overflow:hidden elements where content is clipped at zoom | Fixed-width tables and absolute layouts from PDF reconstruction require CSS rewrite β no safe generic transform |
checkResizeText() β content clipping at 200% zoom | 1.4.4 | AA | Specific elements with overflow: hidden that clip content at 200% | Same as above |
checkTextSpacing() β content clipping after WCAG spacing overrides | 1.4.12 | AA | Elements with overflow: hidden where scrollHeight increases past clientHeight after forced spacing | Fixed-height containers need their height removed or changed to min-height β unsafe to automate |
checkFocusOrder() β tab sequence disrupted by positive tabindex | 2.4.3 | A | Elements whose tab position differs from DOM position by more than 2 | Removing positive tabindex values may break intentional keyboard navigation patterns; tabindex on each flagged element must be reviewed individually |
checkFocusOrder() β interactive element removed from tab sequence | 2.4.3 | A | tabindex="-1" on elements with no alternative keyboard path | Cannot determine whether the removal was intentional |
Part 3: Not Checked β Cannot Be Tested
These WCAG success criteria are not evaluated by any layer of the pipeline. No violation is detected, no report entry is generated, and no fix is applied. They require live media playback, real keyboard/pointer interaction, form submission, or device capabilities that are absent from a static document conversion pipeline. Users whose documents may involve these criteria must perform manual verification.
Not Checked (require live interaction or media)
| WCAG SC | Level | Reason |
|---|---|---|
| 1.2.1 Audio-only / Video-only | A | Requires media playback |
| 1.2.2 Captions (Prerecorded) | A | Requires reading caption tracks |
| 1.2.3 Audio Description or Media Alternative | A | Requires media playback |
| 1.2.4 Captions (Live) | AA | Requires live stream |
| 1.2.5 Audio Description (Prerecorded) | AA | Requires media playback |
| 1.4.13 Content on Hover or Focus | AA | Requires triggering hover/focus states |
| 2.1.2 No Keyboard Trap | A | Requires live keyboard navigation |
| 2.3.1 Three Flashes | A | Requires frame-by-frame animation measurement |
| 3.2.1 On Focus | A | Requires triggering focus events |
| 3.2.2 On Input | A | Requires triggering input events |
| 3.3.1 Error Identification | A | Requires form submission with invalid data |
| 3.3.3 Error Suggestion | AA | Requires form submission |
| 3.3.4 Error Prevention | AA | Requires form submission |
Not Applicable to This Product
| WCAG SC | Level | Reason |
|---|---|---|
| 1.3.4 Orientation | AA | Converted documents do not lock orientation |
| 1.3.5 Identify Input Purpose | AA | autocomplete is for account forms, not converted document tables |
| 2.1.4 Character Key Shortcuts | AA | No single-character shortcuts in converted output |
| 2.2.1 Timing Adjustable | A | No time limits in static documents |
| 2.2.2 Pause, Stop, Hide | A | No auto-updating or animated content |
| 2.2.6 Timeouts | AAA | No session timeouts |
| 2.4.5 Multiple Ways | AA | Single document β no site-level navigation |
| 2.5.1 Pointer Gestures | A | No multi-touch gestures in static output |
| 2.5.2 Pointer Cancellation | A | No interaction flows |
| 2.5.4 Motion Actuation | A | Static document |
| 3.2.3 Consistent Navigation | AA | No multi-page navigation |
| 3.2.5 Change on Request | AAA | No dynamic context changes |
| 3.3.5 Help | AAA | Context-sensitive help is a web-app concept |
| 3.3.6 Error Prevention (All) | AAA | No user data submission |
Summary
What Gets Fixed Automatically
| Category | Count | Notes |
|---|---|---|
| Fully fixed (reliable, correct output) | 27 violations | Document structure, landmarks, heading levels, table headers, list structure (orphan + non-li children), definition list, layout tables, live regions, visual presentation, duplicate IDs, invalid ARIA roles |
| Partially fixed (generic placeholder) | 11 violations | Empty interactive elements get generic labels; images get AI-generated alt or alt="Image" fallback; inline contrast forced to best black/white choice; non-SVG role="img", submit buttons, title-only labels, unlabeled selects |
What Remains After Remediation (Detected, Not Fixed)
These violations appear in the report. The user must resolve them.
| Category | Count | Notes |
|---|---|---|
| Static checks β detected, no fix | 17 violations | Require content knowledge: lang codes, meaningful alt text, heading content, complex table structure, ARIA intent, color-only prose, sensory instructions |
| axe-core rules β not in fix registry | 30+ rules | Media content, complex ARIA, CSS-dependent contrast, iframe titles, form structure |
| Browser checks β detected only | 3 checks (5 failure types) | Fixed-width overflow, text spacing clipping, tab order disruption β require CSS or markup restructuring |
What Cannot Be Tested (Not Checked By Any Layer)
No report entry is produced for these. Manual verification is required.
| Category | Count | Notes |
|---|---|---|
| Require live media or interaction | 13 criteria | Media captions/descriptions, keyboard traps, flash threshold, form submission events, hover/focus popups |
| Not applicable to static document output | 14 criteria | Orientation lock, timing, multi-page navigation, pointer gestures, session timeouts |
The Most Common Remaining Violations in PDF-to-HTML Output
These are the violations most likely to appear in the final report that the service cannot automatically resolve:
| Violation | Frequency | Fix Required |
|---|---|---|
image-alt-meaningful β AI alt is present-but-generic | High | Human review of every generated alt text |
link-name β empty links get aria-label="Link" | Medium | Add descriptive purpose to each empty link |
button-name β empty buttons get aria-label="Button" | Medium | Add descriptive action to each empty button |
heading-descriptive β headings contain only numbers or βSection Nβ | High | Rewrite heading text with meaningful labels |
th-has-scope / td-headers-attr in complex tables | Medium | Manual scope and headers attribute review |
color-contrast via CSS cascade | Medium | Fix CSS stylesheet; inline auto-fix is best-effort only |
| 1.4.4 Resize Text β fixed-width tables overflow at zoom | High | Replace pixel widths with max-width: 100% or percentages |
| 1.4.12 Text Spacing β fixed-height containers clip | Medium | Replace height: Npx with min-height: Npx |
non-text-contrast β UI component colors | Low | CSS changes to borders, icons, focus indicators |
lang-of-parts β embedded non-Latin script | Medium | Add lang attribute to affected spans; requires language detection |