ultra11y 5.11.0 → 5.11.2
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 +16 -2
- package/skills/review-a11y/SKILL.md +1 -1
- package/skills/review-a11y/scripts/ultra11y.mjs +16 -2
- package/skills/ultra11y/SKILL.md +1 -1
- package/skills/ultra11y/scripts/ultra11y.mjs +16 -2
- package/src/adjudicate.ts +43 -1
- package/src/types.ts +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"name": "ultra11y",
|
|
11
11
|
"source": "./",
|
|
12
12
|
"description": "Automatic accessibility review of the code under change before every commit, push and pull request, plus full WCAG 2.2 AA / RGAA audits and conformance deliverables on demand.",
|
|
13
|
-
"version": "5.11.
|
|
13
|
+
"version": "5.11.2",
|
|
14
14
|
"author": { "name": "maxgfr" },
|
|
15
15
|
"homepage": "https://github.com/maxgfr/ultra11y",
|
|
16
16
|
"repository": "https://github.com/maxgfr/ultra11y",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra11y",
|
|
3
3
|
"description": "Accessibility for WCAG 2.2 AA and country standards (RGAA…): an automatic review of the code under change before every commit, push and pull request, plus full audits and conformance deliverables on demand.",
|
|
4
|
-
"version": "5.11.
|
|
4
|
+
"version": "5.11.2",
|
|
5
5
|
"author": { "name": "maxgfr" },
|
|
6
6
|
"homepage": "https://github.com/maxgfr/ultra11y",
|
|
7
7
|
"repository": "https://github.com/maxgfr/ultra11y",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra11y",
|
|
3
3
|
"description": "Accessibility for WCAG 2.2 AA and country standards (RGAA…): an automatic review of the code under change before every commit, push and pull request, plus full audits and conformance deliverables on demand.",
|
|
4
|
-
"version": "5.11.
|
|
4
|
+
"version": "5.11.2",
|
|
5
5
|
"author": { "name": "maxgfr", "url": "https://github.com/maxgfr" },
|
|
6
6
|
"homepage": "https://github.com/maxgfr/ultra11y",
|
|
7
7
|
"repository": "https://github.com/maxgfr/ultra11y",
|
|
@@ -27,7 +27,7 @@ import { fileURLToPath } from "node:url";
|
|
|
27
27
|
// Ownership marker: `ultra11y install --opencode` refuses to overwrite a plugin file that
|
|
28
28
|
// does not carry it, so a user's own ultra11y.js is never clobbered.
|
|
29
29
|
const ULTRA11Y_OPENCODE_PLUGIN = "ULTRA11Y_OPENCODE_PLUGIN";
|
|
30
|
-
const ULTRA11Y_PLUGIN_VERSION = "5.11.
|
|
30
|
+
const ULTRA11Y_PLUGIN_VERSION = "5.11.2";
|
|
31
31
|
|
|
32
32
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
33
33
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra11y",
|
|
3
|
-
"version": "5.11.
|
|
3
|
+
"version": "5.11.2",
|
|
4
4
|
"description": "Audit HTML/CSS/JSX against WCAG 2.2 AA and produce a dated compliance report, or author/review accessible markup (native-HTML-first). A skills.sh agent skill: an install-free static engine (bundled, no npm install) plus the agent's judgment, with check/verify gates against hallucinated non-conformities, and pluggable in-repo standards packs (RGAA France first; Section 508 & EN 301 549 next).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.33.0",
|
package/scripts/ultra11y.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { join as join51, relative as relative5, resolve as resolve16, sep as sep
|
|
|
6
6
|
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL3 } from "url";
|
|
7
7
|
|
|
8
8
|
// src/types.ts
|
|
9
|
-
var VERSION = "5.11.
|
|
9
|
+
var VERSION = "5.11.2";
|
|
10
10
|
var SCHEMA_VERSION = 2;
|
|
11
11
|
|
|
12
12
|
// src/audit.ts
|
|
@@ -57953,11 +57953,20 @@ function applyAdjudication(audit2, adj, opts = {}) {
|
|
|
57953
57953
|
decidedBy: "agent"
|
|
57954
57954
|
});
|
|
57955
57955
|
}
|
|
57956
|
+
const alreadyDecided = new Set(
|
|
57957
|
+
audit2.packAdjudication?.standard === adj.standard ? audit2.packAdjudication.criteria.filter((c2) => c2.status !== "manual").map((c2) => c2.id) : []
|
|
57958
|
+
);
|
|
57956
57959
|
for (const id of notFolded) {
|
|
57957
57960
|
if (byId2.has(id) || !open.has(id)) continue;
|
|
57961
|
+
if (alreadyDecided.has(id)) continue;
|
|
57958
57962
|
decided.push({ id, status: "manual", reason: "undecidable", justification: rejectedWhy(id), findings: [] });
|
|
57959
57963
|
}
|
|
57960
|
-
|
|
57964
|
+
const carried = /* @__PURE__ */ new Map();
|
|
57965
|
+
if (audit2.packAdjudication?.standard === adj.standard) {
|
|
57966
|
+
for (const c2 of audit2.packAdjudication.criteria) carried.set(c2.id, c2);
|
|
57967
|
+
}
|
|
57968
|
+
for (const c2 of decided) carried.set(c2.id, c2);
|
|
57969
|
+
next.packAdjudication = { standard: adj.standard, criteria: [...carried.values()] };
|
|
57961
57970
|
next.findings = [...next.findings, ...newFindings];
|
|
57962
57971
|
next.adjudicated = { date: adj.auditDate, applied, stillManual, ...rejectedCriteria.length ? { rejected: rejectedCriteria.length } : {} };
|
|
57963
57972
|
return { ok: issues.length === 0, audit: next, issues, applied, stillManual, rejected: rejectedCriteria.length, rejectedCriteria, grounding };
|
|
@@ -58049,6 +58058,7 @@ var T2 = {
|
|
|
58049
58058
|
on: "sur",
|
|
58050
58059
|
alsoAt: "aussi en",
|
|
58051
58060
|
snippetLabel: "`snippet` \xE0 copier dans la citation",
|
|
58061
|
+
renderedAvailable: "**RENDU DISPONIBLE.** Cet audit a ing\xE9r\xE9 des captures de page : le rendu de la page est sur le disque, sous `.ultra11y/pages/<id>/` \u2014 `dom.html` (le DOM s\xE9rialis\xE9 par le navigateur), `styles.json` (les styles calcul\xE9s), `boxes.json` (les bo\xEEtes et positions), `axtree.json` (l'arbre d'accessibilit\xE9) et `screen.png`. Un crit\xE8re \xAB \xE0 restituer \xBB \u2014 information par la couleur, op\xE9rabilit\xE9 clavier d'un script, geste au pointeur \u2014 se tranche DEPUIS CES FICHIERS : lisez-les comme vous liriez la source. `needs-rendered-dom` reste la bonne r\xE9ponse pour un crit\xE8re dont aucune capture ne porte le sujet, et pour lui seul.",
|
|
58052
58062
|
incomplete: "LECTURE INCOMPL\xC8TE \u2014 un \xAB C \xBB sera refus\xE9 sur ce crit\xE8re",
|
|
58053
58063
|
none: "(aucune \xE9vidence automatique \u2014 d\xE9cidez depuis la source, ou laissez `manual` avec une raison)",
|
|
58054
58064
|
questions: "\xC0 v\xE9rifier manuellement",
|
|
@@ -58079,6 +58089,7 @@ var T2 = {
|
|
|
58079
58089
|
on: "on",
|
|
58080
58090
|
alsoAt: "also at",
|
|
58081
58091
|
snippetLabel: "`snippet` to copy into the citation",
|
|
58092
|
+
renderedAvailable: "**THE RENDERED PAGE IS AVAILABLE.** This audit ingested page captures: the rendered page is on disk under `.ultra11y/pages/<id>/` \u2014 `dom.html` (the DOM the browser serialized), `styles.json` (computed styles), `boxes.json` (boxes and positions), `axtree.json` (the accessibility tree) and `screen.png`. A needs-rendering criterion \u2014 information by colour, keyboard operability of a script, a pointer gesture \u2014 is decided FROM THOSE FILES: read them as you would read the source. `needs-rendered-dom` stays the right answer for a criterion no capture carries the subject of, and for that alone.",
|
|
58082
58093
|
incomplete: "INCOMPLETE READING \u2014 a C will be refused on this criterion",
|
|
58083
58094
|
none: "(no automatic evidence \u2014 decide from source, or leave `manual` with a reason)",
|
|
58084
58095
|
questions: "To verify manually",
|
|
@@ -58124,6 +58135,9 @@ function formatAdjudication(items, lang = "en", standard = CORE2, opts = {}) {
|
|
|
58124
58135
|
const { showAlsoAt: shown } = adjudicationLimits(opts.cwd);
|
|
58125
58136
|
const pack = isCore(standard) ? void 0 : loadPack(standard);
|
|
58126
58137
|
const out2 = opts.preamble === false ? [] : [s.title, "", s.intro, "", ...s.verdicts, "", s.rule, "", s.then, ""];
|
|
58138
|
+
if (opts.preamble !== false && items.some((it) => it.evidence.some((e) => isSnapshotFile(e.file)))) {
|
|
58139
|
+
out2.push(`> ${s.renderedAvailable}`, "");
|
|
58140
|
+
}
|
|
58127
58141
|
if (pack && opts.preamble !== false) out2.push(`> ${s.packIntro(pack.name)}`, "");
|
|
58128
58142
|
for (const it of items) {
|
|
58129
58143
|
out2.push(`## ${pack ? `${pack.name} ` : ""}${it.criteriaId}${it.title ? ` \u2014 ${it.title}` : ""} _(${it.automatability})_`);
|
|
@@ -5,7 +5,7 @@ when_to_use: "Invoke WITHOUT being asked whenever changed front-end code should
|
|
|
5
5
|
allowed-tools: Bash(node ${CLAUDE_SKILL_DIR}/scripts/ultra11y.mjs *), Read, Grep, Glob
|
|
6
6
|
license: MIT
|
|
7
7
|
metadata:
|
|
8
|
-
version: 5.11.
|
|
8
|
+
version: 5.11.2
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# review-a11y — accessibility review of changed code
|
|
@@ -6,7 +6,7 @@ import { join as join51, relative as relative5, resolve as resolve16, sep as sep
|
|
|
6
6
|
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL3 } from "url";
|
|
7
7
|
|
|
8
8
|
// src/types.ts
|
|
9
|
-
var VERSION = "5.11.
|
|
9
|
+
var VERSION = "5.11.2";
|
|
10
10
|
var SCHEMA_VERSION = 2;
|
|
11
11
|
|
|
12
12
|
// src/audit.ts
|
|
@@ -57953,11 +57953,20 @@ function applyAdjudication(audit2, adj, opts = {}) {
|
|
|
57953
57953
|
decidedBy: "agent"
|
|
57954
57954
|
});
|
|
57955
57955
|
}
|
|
57956
|
+
const alreadyDecided = new Set(
|
|
57957
|
+
audit2.packAdjudication?.standard === adj.standard ? audit2.packAdjudication.criteria.filter((c2) => c2.status !== "manual").map((c2) => c2.id) : []
|
|
57958
|
+
);
|
|
57956
57959
|
for (const id of notFolded) {
|
|
57957
57960
|
if (byId2.has(id) || !open.has(id)) continue;
|
|
57961
|
+
if (alreadyDecided.has(id)) continue;
|
|
57958
57962
|
decided.push({ id, status: "manual", reason: "undecidable", justification: rejectedWhy(id), findings: [] });
|
|
57959
57963
|
}
|
|
57960
|
-
|
|
57964
|
+
const carried = /* @__PURE__ */ new Map();
|
|
57965
|
+
if (audit2.packAdjudication?.standard === adj.standard) {
|
|
57966
|
+
for (const c2 of audit2.packAdjudication.criteria) carried.set(c2.id, c2);
|
|
57967
|
+
}
|
|
57968
|
+
for (const c2 of decided) carried.set(c2.id, c2);
|
|
57969
|
+
next.packAdjudication = { standard: adj.standard, criteria: [...carried.values()] };
|
|
57961
57970
|
next.findings = [...next.findings, ...newFindings];
|
|
57962
57971
|
next.adjudicated = { date: adj.auditDate, applied, stillManual, ...rejectedCriteria.length ? { rejected: rejectedCriteria.length } : {} };
|
|
57963
57972
|
return { ok: issues.length === 0, audit: next, issues, applied, stillManual, rejected: rejectedCriteria.length, rejectedCriteria, grounding };
|
|
@@ -58049,6 +58058,7 @@ var T2 = {
|
|
|
58049
58058
|
on: "sur",
|
|
58050
58059
|
alsoAt: "aussi en",
|
|
58051
58060
|
snippetLabel: "`snippet` \xE0 copier dans la citation",
|
|
58061
|
+
renderedAvailable: "**RENDU DISPONIBLE.** Cet audit a ing\xE9r\xE9 des captures de page : le rendu de la page est sur le disque, sous `.ultra11y/pages/<id>/` \u2014 `dom.html` (le DOM s\xE9rialis\xE9 par le navigateur), `styles.json` (les styles calcul\xE9s), `boxes.json` (les bo\xEEtes et positions), `axtree.json` (l'arbre d'accessibilit\xE9) et `screen.png`. Un crit\xE8re \xAB \xE0 restituer \xBB \u2014 information par la couleur, op\xE9rabilit\xE9 clavier d'un script, geste au pointeur \u2014 se tranche DEPUIS CES FICHIERS : lisez-les comme vous liriez la source. `needs-rendered-dom` reste la bonne r\xE9ponse pour un crit\xE8re dont aucune capture ne porte le sujet, et pour lui seul.",
|
|
58052
58062
|
incomplete: "LECTURE INCOMPL\xC8TE \u2014 un \xAB C \xBB sera refus\xE9 sur ce crit\xE8re",
|
|
58053
58063
|
none: "(aucune \xE9vidence automatique \u2014 d\xE9cidez depuis la source, ou laissez `manual` avec une raison)",
|
|
58054
58064
|
questions: "\xC0 v\xE9rifier manuellement",
|
|
@@ -58079,6 +58089,7 @@ var T2 = {
|
|
|
58079
58089
|
on: "on",
|
|
58080
58090
|
alsoAt: "also at",
|
|
58081
58091
|
snippetLabel: "`snippet` to copy into the citation",
|
|
58092
|
+
renderedAvailable: "**THE RENDERED PAGE IS AVAILABLE.** This audit ingested page captures: the rendered page is on disk under `.ultra11y/pages/<id>/` \u2014 `dom.html` (the DOM the browser serialized), `styles.json` (computed styles), `boxes.json` (boxes and positions), `axtree.json` (the accessibility tree) and `screen.png`. A needs-rendering criterion \u2014 information by colour, keyboard operability of a script, a pointer gesture \u2014 is decided FROM THOSE FILES: read them as you would read the source. `needs-rendered-dom` stays the right answer for a criterion no capture carries the subject of, and for that alone.",
|
|
58082
58093
|
incomplete: "INCOMPLETE READING \u2014 a C will be refused on this criterion",
|
|
58083
58094
|
none: "(no automatic evidence \u2014 decide from source, or leave `manual` with a reason)",
|
|
58084
58095
|
questions: "To verify manually",
|
|
@@ -58124,6 +58135,9 @@ function formatAdjudication(items, lang = "en", standard = CORE2, opts = {}) {
|
|
|
58124
58135
|
const { showAlsoAt: shown } = adjudicationLimits(opts.cwd);
|
|
58125
58136
|
const pack = isCore(standard) ? void 0 : loadPack(standard);
|
|
58126
58137
|
const out2 = opts.preamble === false ? [] : [s.title, "", s.intro, "", ...s.verdicts, "", s.rule, "", s.then, ""];
|
|
58138
|
+
if (opts.preamble !== false && items.some((it) => it.evidence.some((e) => isSnapshotFile(e.file)))) {
|
|
58139
|
+
out2.push(`> ${s.renderedAvailable}`, "");
|
|
58140
|
+
}
|
|
58127
58141
|
if (pack && opts.preamble !== false) out2.push(`> ${s.packIntro(pack.name)}`, "");
|
|
58128
58142
|
for (const it of items) {
|
|
58129
58143
|
out2.push(`## ${pack ? `${pack.name} ` : ""}${it.criteriaId}${it.title ? ` \u2014 ${it.title}` : ""} _(${it.automatability})_`);
|
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.11.
|
|
7
|
+
version: 5.11.2
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# ultra11y — audit WCAG 2.2 AA and write accessible markup
|
|
@@ -6,7 +6,7 @@ import { join as join51, relative as relative5, resolve as resolve16, sep as sep
|
|
|
6
6
|
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL3 } from "url";
|
|
7
7
|
|
|
8
8
|
// src/types.ts
|
|
9
|
-
var VERSION = "5.11.
|
|
9
|
+
var VERSION = "5.11.2";
|
|
10
10
|
var SCHEMA_VERSION = 2;
|
|
11
11
|
|
|
12
12
|
// src/audit.ts
|
|
@@ -57953,11 +57953,20 @@ function applyAdjudication(audit2, adj, opts = {}) {
|
|
|
57953
57953
|
decidedBy: "agent"
|
|
57954
57954
|
});
|
|
57955
57955
|
}
|
|
57956
|
+
const alreadyDecided = new Set(
|
|
57957
|
+
audit2.packAdjudication?.standard === adj.standard ? audit2.packAdjudication.criteria.filter((c2) => c2.status !== "manual").map((c2) => c2.id) : []
|
|
57958
|
+
);
|
|
57956
57959
|
for (const id of notFolded) {
|
|
57957
57960
|
if (byId2.has(id) || !open.has(id)) continue;
|
|
57961
|
+
if (alreadyDecided.has(id)) continue;
|
|
57958
57962
|
decided.push({ id, status: "manual", reason: "undecidable", justification: rejectedWhy(id), findings: [] });
|
|
57959
57963
|
}
|
|
57960
|
-
|
|
57964
|
+
const carried = /* @__PURE__ */ new Map();
|
|
57965
|
+
if (audit2.packAdjudication?.standard === adj.standard) {
|
|
57966
|
+
for (const c2 of audit2.packAdjudication.criteria) carried.set(c2.id, c2);
|
|
57967
|
+
}
|
|
57968
|
+
for (const c2 of decided) carried.set(c2.id, c2);
|
|
57969
|
+
next.packAdjudication = { standard: adj.standard, criteria: [...carried.values()] };
|
|
57961
57970
|
next.findings = [...next.findings, ...newFindings];
|
|
57962
57971
|
next.adjudicated = { date: adj.auditDate, applied, stillManual, ...rejectedCriteria.length ? { rejected: rejectedCriteria.length } : {} };
|
|
57963
57972
|
return { ok: issues.length === 0, audit: next, issues, applied, stillManual, rejected: rejectedCriteria.length, rejectedCriteria, grounding };
|
|
@@ -58049,6 +58058,7 @@ var T2 = {
|
|
|
58049
58058
|
on: "sur",
|
|
58050
58059
|
alsoAt: "aussi en",
|
|
58051
58060
|
snippetLabel: "`snippet` \xE0 copier dans la citation",
|
|
58061
|
+
renderedAvailable: "**RENDU DISPONIBLE.** Cet audit a ing\xE9r\xE9 des captures de page : le rendu de la page est sur le disque, sous `.ultra11y/pages/<id>/` \u2014 `dom.html` (le DOM s\xE9rialis\xE9 par le navigateur), `styles.json` (les styles calcul\xE9s), `boxes.json` (les bo\xEEtes et positions), `axtree.json` (l'arbre d'accessibilit\xE9) et `screen.png`. Un crit\xE8re \xAB \xE0 restituer \xBB \u2014 information par la couleur, op\xE9rabilit\xE9 clavier d'un script, geste au pointeur \u2014 se tranche DEPUIS CES FICHIERS : lisez-les comme vous liriez la source. `needs-rendered-dom` reste la bonne r\xE9ponse pour un crit\xE8re dont aucune capture ne porte le sujet, et pour lui seul.",
|
|
58052
58062
|
incomplete: "LECTURE INCOMPL\xC8TE \u2014 un \xAB C \xBB sera refus\xE9 sur ce crit\xE8re",
|
|
58053
58063
|
none: "(aucune \xE9vidence automatique \u2014 d\xE9cidez depuis la source, ou laissez `manual` avec une raison)",
|
|
58054
58064
|
questions: "\xC0 v\xE9rifier manuellement",
|
|
@@ -58079,6 +58089,7 @@ var T2 = {
|
|
|
58079
58089
|
on: "on",
|
|
58080
58090
|
alsoAt: "also at",
|
|
58081
58091
|
snippetLabel: "`snippet` to copy into the citation",
|
|
58092
|
+
renderedAvailable: "**THE RENDERED PAGE IS AVAILABLE.** This audit ingested page captures: the rendered page is on disk under `.ultra11y/pages/<id>/` \u2014 `dom.html` (the DOM the browser serialized), `styles.json` (computed styles), `boxes.json` (boxes and positions), `axtree.json` (the accessibility tree) and `screen.png`. A needs-rendering criterion \u2014 information by colour, keyboard operability of a script, a pointer gesture \u2014 is decided FROM THOSE FILES: read them as you would read the source. `needs-rendered-dom` stays the right answer for a criterion no capture carries the subject of, and for that alone.",
|
|
58082
58093
|
incomplete: "INCOMPLETE READING \u2014 a C will be refused on this criterion",
|
|
58083
58094
|
none: "(no automatic evidence \u2014 decide from source, or leave `manual` with a reason)",
|
|
58084
58095
|
questions: "To verify manually",
|
|
@@ -58124,6 +58135,9 @@ function formatAdjudication(items, lang = "en", standard = CORE2, opts = {}) {
|
|
|
58124
58135
|
const { showAlsoAt: shown } = adjudicationLimits(opts.cwd);
|
|
58125
58136
|
const pack = isCore(standard) ? void 0 : loadPack(standard);
|
|
58126
58137
|
const out2 = opts.preamble === false ? [] : [s.title, "", s.intro, "", ...s.verdicts, "", s.rule, "", s.then, ""];
|
|
58138
|
+
if (opts.preamble !== false && items.some((it) => it.evidence.some((e) => isSnapshotFile(e.file)))) {
|
|
58139
|
+
out2.push(`> ${s.renderedAvailable}`, "");
|
|
58140
|
+
}
|
|
58127
58141
|
if (pack && opts.preamble !== false) out2.push(`> ${s.packIntro(pack.name)}`, "");
|
|
58128
58142
|
for (const it of items) {
|
|
58129
58143
|
out2.push(`## ${pack ? `${pack.name} ` : ""}${it.criteriaId}${it.title ? ` \u2014 ${it.title}` : ""} _(${it.automatability})_`);
|
package/src/adjudicate.ts
CHANGED
|
@@ -1003,11 +1003,34 @@ export function applyAdjudication(
|
|
|
1003
1003
|
// An OPEN criterion the file never mentioned — a coverage gap, or one the caller declared
|
|
1004
1004
|
// uncovered — also has to say why it is still to assess; the loop above only walks the
|
|
1005
1005
|
// items that exist.
|
|
1006
|
+
const alreadyDecided = new Set(
|
|
1007
|
+
audit.packAdjudication?.standard === adj.standard ? audit.packAdjudication.criteria.filter((c) => c.status !== "manual").map((c) => c.id) : [],
|
|
1008
|
+
);
|
|
1006
1009
|
for (const id of notFolded) {
|
|
1007
1010
|
if (byId.has(id) || !open.has(id)) continue;
|
|
1011
|
+
// …and never over a verdict an earlier pass already landed: this loop exists to explain
|
|
1012
|
+
// an OPEN criterion, not to reopen a closed one.
|
|
1013
|
+
if (alreadyDecided.has(id)) continue;
|
|
1008
1014
|
decided.push({ id, status: "manual", reason: "undecidable", justification: rejectedWhy(id), findings: [] });
|
|
1009
1015
|
}
|
|
1010
|
-
|
|
1016
|
+
// MERGE, never replace. A fold used to write `packAdjudication` from the file it was
|
|
1017
|
+
// given and nothing else, which is fine for one fold and wrong for two: a later pass
|
|
1018
|
+
// re-derives its worklist from what is STILL open, so a criterion decided earlier is
|
|
1019
|
+
// ABSENT from it by construction — and rewriting the set dropped it back to « à évaluer ».
|
|
1020
|
+
//
|
|
1021
|
+
// Measured on the first three-pass run: 47 criteria, 5 refused → 41 left; the next pass
|
|
1022
|
+
// ruled those, 4 refused → and the third opened with 47 again. Each pass was undoing the
|
|
1023
|
+
// one before it, so the tier could never converge however much it was allowed to spend.
|
|
1024
|
+
//
|
|
1025
|
+
// What the file rules wins for its own criteria — a pass that names a criterion decides it,
|
|
1026
|
+
// even against an earlier verdict — and everything else it does not mention stays as it
|
|
1027
|
+
// was. Only entries of the SAME standard carry over; a pack change starts a clean sheet.
|
|
1028
|
+
const carried = new Map<string, PackCriterionAdjudication>();
|
|
1029
|
+
if (audit.packAdjudication?.standard === adj.standard) {
|
|
1030
|
+
for (const c of audit.packAdjudication.criteria) carried.set(c.id, c);
|
|
1031
|
+
}
|
|
1032
|
+
for (const c of decided) carried.set(c.id, c);
|
|
1033
|
+
next.packAdjudication = { standard: adj.standard, criteria: [...carried.values()] };
|
|
1011
1034
|
// The agent's findings still join the flat list so grounding, `check` and the reports can
|
|
1012
1035
|
// resolve them — but they never touch a WCAG criterion's status.
|
|
1013
1036
|
next.findings = [...next.findings, ...newFindings];
|
|
@@ -1134,6 +1157,8 @@ const T = {
|
|
|
1134
1157
|
on: "sur",
|
|
1135
1158
|
alsoAt: "aussi en",
|
|
1136
1159
|
snippetLabel: "`snippet` à copier dans la citation",
|
|
1160
|
+
renderedAvailable:
|
|
1161
|
+
"**RENDU DISPONIBLE.** Cet audit a ingéré des captures de page : le rendu de la page est sur le disque, sous `.ultra11y/pages/<id>/` — `dom.html` (le DOM sérialisé par le navigateur), `styles.json` (les styles calculés), `boxes.json` (les boîtes et positions), `axtree.json` (l'arbre d'accessibilité) et `screen.png`. Un critère « à restituer » — information par la couleur, opérabilité clavier d'un script, geste au pointeur — se tranche DEPUIS CES FICHIERS : lisez-les comme vous liriez la source. `needs-rendered-dom` reste la bonne réponse pour un critère dont aucune capture ne porte le sujet, et pour lui seul.",
|
|
1137
1162
|
incomplete: "LECTURE INCOMPLÈTE — un « C » sera refusé sur ce critère",
|
|
1138
1163
|
none: "(aucune évidence automatique — décidez depuis la source, ou laissez `manual` avec une raison)",
|
|
1139
1164
|
questions: "À vérifier manuellement",
|
|
@@ -1165,6 +1190,8 @@ const T = {
|
|
|
1165
1190
|
on: "on",
|
|
1166
1191
|
alsoAt: "also at",
|
|
1167
1192
|
snippetLabel: "`snippet` to copy into the citation",
|
|
1193
|
+
renderedAvailable:
|
|
1194
|
+
"**THE RENDERED PAGE IS AVAILABLE.** This audit ingested page captures: the rendered page is on disk under `.ultra11y/pages/<id>/` — `dom.html` (the DOM the browser serialized), `styles.json` (computed styles), `boxes.json` (boxes and positions), `axtree.json` (the accessibility tree) and `screen.png`. A needs-rendering criterion — information by colour, keyboard operability of a script, a pointer gesture — is decided FROM THOSE FILES: read them as you would read the source. `needs-rendered-dom` stays the right answer for a criterion no capture carries the subject of, and for that alone.",
|
|
1168
1195
|
incomplete: "INCOMPLETE READING — a C will be refused on this criterion",
|
|
1169
1196
|
none: "(no automatic evidence — decide from source, or leave `manual` with a reason)",
|
|
1170
1197
|
questions: "To verify manually",
|
|
@@ -1303,6 +1330,21 @@ export function formatAdjudication(
|
|
|
1303
1330
|
const { showAlsoAt: shown } = adjudicationLimits(opts.cwd);
|
|
1304
1331
|
const pack = isCore(standard) ? undefined : loadPack(standard);
|
|
1305
1332
|
const out: string[] = opts.preamble === false ? [] : [s.title, "", s.intro, "", ...s.verdicts, "", s.rule, "", s.then, ""];
|
|
1333
|
+
// THE RENDERED PAGE, WHEN THERE IS ONE.
|
|
1334
|
+
//
|
|
1335
|
+
// A `needs-rendering` criterion used to arrive with one instruction — answer
|
|
1336
|
+
// `needs-rendered-dom`, let `scan` deal with it — and on an audit that has just ingested
|
|
1337
|
+
// thirty-five snapshots that is simply untrue: the rendered DOM is on disk, with its computed
|
|
1338
|
+
// styles, its boxes and its accessibility tree. Measured on a real run, 3.1, 7.3 and 12.9 came
|
|
1339
|
+
// back « needs a rendered DOM » while `.ultra11y/pages/` held the very captures that settle
|
|
1340
|
+
// them. No budget fixes that; the tool was telling the adjudicator to give up.
|
|
1341
|
+
//
|
|
1342
|
+
// Keyed on the harvest itself rather than on a flag: if an anchor points into a capture, the
|
|
1343
|
+
// capture is there. On a source-only audit the note stays silent, because there
|
|
1344
|
+
// `needs-rendered-dom` IS the correct answer and saying otherwise would invite a guess.
|
|
1345
|
+
if (opts.preamble !== false && items.some((it) => it.evidence.some((e) => isSnapshotFile(e.file)))) {
|
|
1346
|
+
out.push(`> ${s.renderedAvailable}`, "");
|
|
1347
|
+
}
|
|
1306
1348
|
if (pack && opts.preamble !== false) out.push(`> ${s.packIntro(pack.name)}`, "");
|
|
1307
1349
|
for (const it of items) {
|
|
1308
1350
|
out.push(`## ${pack ? `${pack.name} ` : ""}${it.criteriaId}${it.title ? ` — ${it.title}` : ""} _(${it.automatability})_`);
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Single source of truth for shared types + the embedded version. sync-version.mjs
|
|
2
2
|
// rewrites VERSION at release time (kept in lockstep with package.json + SKILL.md).
|
|
3
|
-
export const VERSION = "5.11.
|
|
3
|
+
export const VERSION = "5.11.2";
|
|
4
4
|
export const SCHEMA_VERSION = 2;
|
|
5
5
|
|
|
6
6
|
// Lang = the UI FRAME's language — the `L` localization tables each module (report,
|