ultra11y 5.3.4 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.opencode/plugins/ultra11y.js +1 -1
- package/package.json +1 -1
- package/scripts/ultra11y.mjs +1700 -1276
- package/skills/review-a11y/SKILL.md +1 -1
- package/skills/review-a11y/scripts/ultra11y.mjs +1700 -1276
- package/skills/ultra11y/SKILL.md +2 -2
- package/skills/ultra11y/references/ci.md +46 -4
- package/skills/ultra11y/references/judgment.md +25 -12
- package/skills/ultra11y/references/pages.md +13 -4
- package/skills/ultra11y/scripts/ultra11y.mjs +1700 -1276
- package/src/adjudicate.ts +159 -37
- package/src/audit.ts +163 -2
- package/src/cli.ts +204 -18
- package/src/ledger.ts +250 -0
- package/src/orchestrate-templates.ts +2 -2
- package/src/report.ts +24 -6
- package/src/rules/rendered.ts +39 -1
- package/src/types.ts +10 -3
package/skills/ultra11y/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: "Use to AUDIT existing HTML/CSS/JSX against WCAG 2.2 AA accessibili
|
|
|
4
4
|
when_to_use: "Invoke when the user asks for an accessibility AUDIT or a formal deliverable: audit a repo, site or page against WCAG 2.2 AA or a country standard (RGAA, Section 508, EN 301 549); produce a dated conformance report, a criterion grid, a PRD backlog, or tickets (GitHub/GitLab/Jira); author accessible markup from scratch; wire the repo gate (init --hook/--ci) or a rendered-DOM capture pipeline. For a review of the code UNDER CHANGE (diff, branch, PR), use the `review-a11y` skill instead."
|
|
5
5
|
license: MIT
|
|
6
6
|
metadata:
|
|
7
|
-
version: 5.
|
|
7
|
+
version: 5.4.0
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# ultra11y — audit WCAG 2.2 AA and write accessible markup
|
|
@@ -54,7 +54,7 @@ adjudicates. So the engine's clean run is a starting point, never a verdict —
|
|
|
54
54
|
> decides what its terms mean. An auditor block that cites `8.3.1` after reading it is
|
|
55
55
|
> grounded; one that cites it from memory is a guess wearing a reference. Before auditing
|
|
56
56
|
> against a country standard, run the plan (`ultra11y_method`): it tells you how many of its
|
|
57
|
-
> criteria no tool will decide for you — for RGAA, **
|
|
57
|
+
> criteria no tool will decide for you — for RGAA, **59 of 106**. See `references/mcp.md`.
|
|
58
58
|
> 6. **The FINAL rendered semantic HTML must be correct.** The engine sees only source; a
|
|
59
59
|
> component library (DSFR/MUI…) or `.vue`/`.svelte`/`.astro` SFC hides the real markup, so
|
|
60
60
|
> a green source audit is not proof. Verify the produced semantic HTML — install the
|
|
@@ -62,12 +62,54 @@ run and an RGAA run coexist rather than overwriting each other. The Markdown rep
|
|
|
62
62
|
through `check` before being uploaded, so CI cannot publish a report citing an invented
|
|
63
63
|
criterion.
|
|
64
64
|
|
|
65
|
-
##
|
|
65
|
+
## The verdict ledger (`ledger`) — a complete grid in CI, with no model
|
|
66
66
|
|
|
67
67
|
Of the 55 WCAG 2.2 AA criteria the engine decides a handful; **38 are judgment calls**, and
|
|
68
|
-
under RGAA **
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
under RGAA **59 of 106** can only ever derive `manual`. Inside a coding agent the agent rules on
|
|
69
|
+
them. In CI nobody does — so before the ledger, a CI grid was partial by construction and the
|
|
70
|
+
only way to close it was to pay for an agent pass on every run.
|
|
71
|
+
|
|
72
|
+
A **ledger** is a file of verdicts committed to the audited repository
|
|
73
|
+
(`.ultra11y/verdicts/<standard>.json`), each carrying its justification, its citations, and a
|
|
74
|
+
FINGERPRINT of the evidence it was ruled against:
|
|
75
|
+
|
|
76
|
+
```yaml
|
|
77
|
+
- uses: maxgfr/ultra11y@v5
|
|
78
|
+
with:
|
|
79
|
+
standard: rgaa
|
|
80
|
+
ledger: 'true' # or an explicit path
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Replaying it is **a re-verification, not a cache hit**. Every stored verdict is rebuilt into an
|
|
84
|
+
ordinary adjudication over the evidence re-derived from the audit in front of it, and folded
|
|
85
|
+
through the same `applyAdjudication` — same coverage checks in both directions, same citation
|
|
86
|
+
matching against the criterion's own anchors, same content-level re-grounding. A verdict nobody
|
|
87
|
+
can prove is refused in CI exactly as it would be in a session.
|
|
88
|
+
|
|
89
|
+
Three properties are worth knowing:
|
|
90
|
+
|
|
91
|
+
- **A stale verdict is dropped, never carried.** When the code under a criterion changes, the
|
|
92
|
+
evidence changes with it, the fingerprint stops matching, and the criterion returns to « à
|
|
93
|
+
évaluer » saying so — with the date it was recorded and both evidence counts. A verdict that
|
|
94
|
+
silently outlives the code it described is the one thing a conformance deliverable cannot
|
|
95
|
+
afford. The log names every stale and every uncovered criterion, so a refresh pass knows
|
|
96
|
+
exactly what to re-adjudicate.
|
|
97
|
+
- **A reformatting is not a change.** The fingerprint ignores line numbers and the replay
|
|
98
|
+
re-anchors stored citations onto today's lines, so adding a comment at the top of a file does
|
|
99
|
+
not invalidate every verdict in it.
|
|
100
|
+
- **A missing or refused ledger never fails the job.** The criteria stay « à évaluer », which is
|
|
101
|
+
where they would have been without one.
|
|
102
|
+
|
|
103
|
+
To FILL it, run an adjudication with `ledger` set: the accepted verdicts are recorded on the way
|
|
104
|
+
out. Only accepted ones — a refused verdict in the ledger would be laundered back in on the next
|
|
105
|
+
replay. A defensible split is a weekly (or `workflow_dispatch`) job that adjudicates and commits
|
|
106
|
+
the refreshed ledger, and a pull-request job that only replays it.
|
|
107
|
+
|
|
108
|
+
## Adjudicating the judgment criteria in CI (`adjudicate`)
|
|
109
|
+
|
|
110
|
+
`adjudicate` is what FILLS the ledger — opt-in, in two modes. It runs **after** the replay, so a
|
|
111
|
+
paid pass only ever covers what the ledger did not: on a repository whose ledger is current, it
|
|
112
|
+
has nothing left to rule on and costs nothing.
|
|
71
113
|
|
|
72
114
|
```yaml
|
|
73
115
|
env:
|
|
@@ -117,7 +117,7 @@ Then `node scripts/ultra11y.mjs verify --apply VERIFY.todo.json` is green again
|
|
|
117
117
|
## Under a country standard, the worklist speaks that standard
|
|
118
118
|
|
|
119
119
|
`verify --manual --standard rgaa` keys the worklist by **RGAA criteria**, not WCAG success
|
|
120
|
-
criteria — which is the granularity that matters, since
|
|
120
|
+
criteria — which is the granularity that matters, since 59 of RGAA's 106 criteria can only
|
|
121
121
|
ever derive `manual`. Each item carries, inline:
|
|
122
122
|
|
|
123
123
|
- the criterion's **numbered tests, in full** (`11.2.1` … `11.2.6`) — what actually has to be
|
|
@@ -163,15 +163,27 @@ gate refuses:
|
|
|
163
163
|
|
|
164
164
|
| It returns | The gate does |
|
|
165
165
|
|---|---|
|
|
166
|
-
| `C`/`NA` with no justification |
|
|
167
|
-
| `NC` citing nothing, or a `file:line` that does not resolve against real source |
|
|
168
|
-
| `NC` citing a `normativeRef` belonging to another criterion |
|
|
169
|
-
| `manual` with no reason |
|
|
166
|
+
| `C`/`NA` with no justification | refuses THAT criterion |
|
|
167
|
+
| `NC` citing nothing, or a `file:line` that does not resolve against real source | refuses it |
|
|
168
|
+
| `NC` citing a `normativeRef` belonging to another criterion | refuses it |
|
|
169
|
+
| `manual` with no reason | refuses it |
|
|
170
170
|
| a verdict for a criterion nobody asked about | dropped before it reaches the gate |
|
|
171
|
-
| fewer verdicts than criteria (a
|
|
171
|
+
| fewer verdicts than criteria (a bounded `--max` run, a failed batch) | the missing ones stay « à évaluer »; the rest lands |
|
|
172
172
|
| all `manual` with reasons | **accepts** — that is a correct answer, not a failure |
|
|
173
173
|
|
|
174
|
-
|
|
174
|
+
**The fold is fail-closed per VERDICT, not per FILE.** No refused verdict is ever applied, and a
|
|
175
|
+
refusal costs its own criterion and nothing else: that criterion stays « à évaluer » carrying the
|
|
176
|
+
refusal as its reason, and every verdict that proved itself lands. This is not a loosening of the
|
|
177
|
+
gate — every check above is unchanged — it is a change of blast radius, and it was measured:
|
|
178
|
+
a CI run filled 95 of 96 verdicts correctly, one came back `null`, and the old file-level fold
|
|
179
|
+
discarded all 96, so a $16 adjudication published « à évaluer » across the whole grid in a job
|
|
180
|
+
that reported success.
|
|
181
|
+
|
|
182
|
+
`--strict` restores the all-or-nothing fold for a caller who genuinely wants it (a deliverable
|
|
183
|
+
signed off in one pass); there, a rejected adjudication leaves `audit-latest.json` untouched.
|
|
184
|
+
|
|
185
|
+
Whatever lands can be RECORDED with `--ledger <path>` and replayed on a later run with no model
|
|
186
|
+
in the loop — see `references/ci.md`.
|
|
175
187
|
|
|
176
188
|
**Strictly opt-in.** With no key the command explains itself and exits 2; nothing else in the
|
|
177
189
|
engine changes.
|
|
@@ -184,8 +196,9 @@ while an agent can open the cited files, which is what *link purpose in context*
|
|
|
184
196
|
Both skip themselves when `ANTHROPIC_API_KEY` is absent from the job environment, and both
|
|
185
197
|
absorb their own failure rather than taking the audit down with them. See `references/ci.md`.
|
|
186
198
|
|
|
187
|
-
`--max` bounds the spend and says out loud which criteria it did not submit. It
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
199
|
+
`--max` bounds the spend and says out loud which criteria it did not submit. It now composes
|
|
200
|
+
with `--apply`: the fold is per-verdict, so a bounded run lands what it covered and the rest stay
|
|
201
|
+
« à évaluer » — which is exactly what bounding spend is for. (It used to be refused outright, and
|
|
202
|
+
rightly so while the fold was all-or-nothing: the pair could only ever bill a full run to
|
|
203
|
+
guarantee a coverage failure. That refusal survives under `--apply --strict`, where it is still
|
|
204
|
+
true.)
|
|
@@ -292,10 +292,19 @@ criterion means one definite failure fired *somewhere* — not that the engine c
|
|
|
292
292
|
criterion. On a page where the failure did not fire, the engine knows "no definite failure
|
|
293
293
|
here", which is not "conforming": alt relevance, link purpose and reading order are still
|
|
294
294
|
nobody's verdict. So only the `static` criteria (the ones with an applicability predicate and
|
|
295
|
-
rules, `src/audit.ts` `APPLICABLE`) earn `C` by silence — under RGAA that is
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
295
|
+
rules, `src/audit.ts` `APPLICABLE`) earn `C` by silence — under RGAA that is **8.3 and 8.5, and
|
|
296
|
+
those two only**. 4.10, 8.4 and 8.6 look like they should qualify and do not: each is flagged
|
|
297
|
+
`judgment: true`, because the criterion asks more than its mapped success criterion does (8.6
|
|
298
|
+
asks whether the page title is *pertinent*; 2.4.2 only that a title exists), so `judgmentGuard`
|
|
299
|
+
turns their `C` into `manual` on purpose. Everything else stays « à évaluer » until `scan`, the
|
|
300
|
+
snapshot tier or an adjudication decides it. Before this rule a page with no images scored 100%
|
|
301
|
+
on « chaque image a-t-elle une alternative pertinente ? », a rate computed over criteria nobody
|
|
302
|
+
had assessed.
|
|
303
|
+
|
|
304
|
+
What a criterion CAN be decided as, without any of that, is a separate question: since the
|
|
305
|
+
engine learned to prove applicability (`src/audit.ts` `SUBJECT_MATTER`), a criterion whose
|
|
306
|
+
subject matter is absent from the whole scope closes as a justified `NA` — so a repository with
|
|
307
|
+
no media reports RGAA theme 4 as not applicable rather than as « à évaluer ».
|
|
299
308
|
|
|
300
309
|
A non-normative recommendation never flips a page criterion to `NC`, exactly as in core.
|
|
301
310
|
|