ultra11y 5.35.0 → 5.35.1

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.
@@ -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.35.0",
13
+ "version": "5.35.1",
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.35.0",
4
+ "version": "5.35.1",
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.35.0",
4
+ "version": "5.35.1",
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.35.0";
30
+ const ULTRA11Y_PLUGIN_VERSION = "5.35.1";
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.35.0",
3
+ "version": "5.35.1",
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",
@@ -6,7 +6,7 @@ import { join as join53, 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.35.0";
9
+ var VERSION = "5.35.1";
10
10
  var SCHEMA_VERSION = 2;
11
11
  var INAPPLICABLE_STATUS = "C";
12
12
 
@@ -54611,8 +54611,24 @@ function derivePackResults(audit2, packKey, pageId) {
54611
54611
  }
54612
54612
  function findingsForStandard(audit2, standard) {
54613
54613
  if (standard === CORE_KEY) return audit2.findings;
54614
- const mine = (audit2.packFindings ?? []).filter((f) => f.ruleId.startsWith(`pack:${standard}:`));
54615
- return mine.length ? [...audit2.findings, ...mine] : audit2.findings;
54614
+ const eligible = new Set(
54615
+ [
54616
+ ...audit2.findings,
54617
+ ...(audit2.packFindings ?? []).filter((finding) => finding.ruleId.startsWith(`pack:${standard}:`)),
54618
+ ...audit2.packAdjudication?.standard === standard ? audit2.packAdjudication.criteria.flatMap((criterion) => criterion.findings) : []
54619
+ ].map(findingId)
54620
+ );
54621
+ const seen = /* @__PURE__ */ new Set();
54622
+ const out2 = [];
54623
+ for (const criterion of derivePackResults(audit2, standard)) {
54624
+ for (const finding of criterion.findings) {
54625
+ const id = findingId(finding);
54626
+ if (!eligible.has(id) || seen.has(id)) continue;
54627
+ seen.add(id);
54628
+ out2.push(finding);
54629
+ }
54630
+ }
54631
+ return out2;
54616
54632
  }
54617
54633
 
54618
54634
  // src/standards/vocabulary.ts
@@ -59499,6 +59515,12 @@ function applyAdjudication(audit2, adj, opts = {}) {
59499
59515
  };
59500
59516
  const uncovered = (criteriaId) => notFolded.add(criteriaId);
59501
59517
  canonicalizeAdjudication(adj);
59518
+ const itemCounts = /* @__PURE__ */ new Map();
59519
+ for (const item of adj.items) itemCounts.set(item.criteriaId, (itemCounts.get(item.criteriaId) ?? 0) + 1);
59520
+ for (const [criteriaId, count] of itemCounts) {
59521
+ if (count > 1)
59522
+ blame(criteriaId, `criterion ${criteriaId}: duplicate criterion id appears ${count} times in the adjudication \u2014 no implicit winner is accepted`);
59523
+ }
59502
59524
  const byId2 = new Map(adj.items.map((it) => [it.criteriaId, it]));
59503
59525
  const packMode = !isCore(adj.standard);
59504
59526
  const open = /* @__PURE__ */ new Set();
@@ -60415,6 +60437,20 @@ var BATCH_SIZE = 8;
60415
60437
  var CONCURRENCY = 4;
60416
60438
  var MAX_ATTEMPTS = 4;
60417
60439
  var MAX_TOKENS = 16e3;
60440
+ function batchWorklist(items, render2, size = BATCH_SIZE) {
60441
+ if (!Number.isInteger(size) || size < 1) throw new Error(`batch size must be a positive integer (got ${size})`);
60442
+ const ids = items.map((item) => item.criteriaId);
60443
+ if (new Set(ids).size !== ids.length) {
60444
+ const duplicate = [...new Set(ids.filter((id, index) => ids.indexOf(id) !== index))];
60445
+ throw new Error(`worklist contains duplicate criterion id(s): ${duplicate.join(", ")}`);
60446
+ }
60447
+ const batches = [];
60448
+ for (let i2 = 0; i2 < items.length; i2 += size) {
60449
+ const slice = items.slice(i2, i2 + size);
60450
+ batches.push({ items: slice, prompt: render2(slice) });
60451
+ }
60452
+ return batches;
60453
+ }
60418
60454
  function apiKeyFromEnv() {
60419
60455
  const k = process.env.ANTHROPIC_API_KEY?.trim();
60420
60456
  return k || void 0;
@@ -60536,7 +60572,7 @@ function verdictsOf(res) {
60536
60572
  if (!Array.isArray(input?.verdicts)) throw new Error("ultra11y judge: the model's tool call carried no verdicts array.");
60537
60573
  return input.verdicts;
60538
60574
  }
60539
- async function judgeBatch(items, prompt, opts) {
60575
+ async function judgeBatch(_items, prompt, opts) {
60540
60576
  if (!opts.apiKey) throw new Error("ultra11y judge: the Messages backend needs an API key (ANTHROPIC_API_KEY or --api-key).");
60541
60577
  const res = await callOnce(
60542
60578
  {
@@ -60549,8 +60585,22 @@ async function judgeBatch(items, prompt, opts) {
60549
60585
  },
60550
60586
  opts
60551
60587
  );
60552
- const known = new Set(items.map((i2) => i2.criteriaId));
60553
- return verdictsOf(res).filter((v) => known.has(v.criteriaId));
60588
+ return verdictsOf(res);
60589
+ }
60590
+ function validateBatchVerdicts(items, landed) {
60591
+ const expected = new Set(items.map((item) => item.criteriaId));
60592
+ const counts = /* @__PURE__ */ new Map();
60593
+ for (const verdict of landed) counts.set(verdict.criteriaId, (counts.get(verdict.criteriaId) ?? 0) + 1);
60594
+ const duplicate = new Set([...counts].filter(([, count]) => count > 1).map(([id]) => id));
60595
+ const unknown = [...new Set(landed.map((v) => v.criteriaId).filter((id) => !expected.has(id)))];
60596
+ const accepted = landed.filter((verdict) => expected.has(verdict.criteriaId) && !duplicate.has(verdict.criteriaId));
60597
+ const acceptedIds = new Set(accepted.map((verdict) => verdict.criteriaId));
60598
+ const missing = [...expected].filter((id) => !acceptedIds.has(id) && !duplicate.has(id));
60599
+ const failures = [];
60600
+ if (duplicate.size) failures.push(`duplicate criterion id(s) in batch response: ${[...duplicate].join(", ")}`);
60601
+ if (unknown.length) failures.push(`unknown criterion id(s) in batch response: ${unknown.join(", ")}`);
60602
+ if (missing.length) failures.push(`missing criterion id(s) in batch response: ${missing.join(", ")}`);
60603
+ return { accepted, failures };
60554
60604
  }
60555
60605
  async function judgeAll(batches, opts) {
60556
60606
  const verdicts = [];
@@ -60564,8 +60614,10 @@ async function judgeAll(batches, opts) {
60564
60614
  for (let b = queue.shift(); b !== void 0; b = queue.shift()) {
60565
60615
  try {
60566
60616
  const landed = await backend(b.items, b.prompt, opts);
60567
- verdicts.push(...landed);
60568
- if (landed.length) opts.onVerdicts?.(landed);
60617
+ const checked = validateBatchVerdicts(b.items, landed);
60618
+ failures.push(...checked.failures);
60619
+ verdicts.push(...checked.accepted);
60620
+ if (checked.accepted.length) opts.onVerdicts?.(checked.accepted);
60569
60621
  } catch (e) {
60570
60622
  failures.push(e instanceof Error ? e.message : String(e));
60571
60623
  }
@@ -60576,7 +60628,9 @@ async function judgeAll(batches, opts) {
60576
60628
  return { verdicts, failures };
60577
60629
  }
60578
60630
  function applyRawVerdicts(items, verdicts) {
60579
- const byId2 = new Map(verdicts.map((v) => [v.criteriaId, v]));
60631
+ const counts = /* @__PURE__ */ new Map();
60632
+ for (const verdict of verdicts) counts.set(verdict.criteriaId, (counts.get(verdict.criteriaId) ?? 0) + 1);
60633
+ const byId2 = new Map(verdicts.filter((v) => counts.get(v.criteriaId) === 1).map((v) => [v.criteriaId, v]));
60580
60634
  let filled = 0;
60581
60635
  for (const item of items) {
60582
60636
  const v = byId2.get(item.criteriaId);
@@ -64249,7 +64303,9 @@ var S = {
64249
64303
  fr: {
64250
64304
  title: "Audit d'accessibilit\xE9 ultra11y",
64251
64305
  files: "fichiers",
64252
- rate: "r\xE9ussite automatique",
64306
+ coverage: (decided, total) => `${decided}/${total} crit\xE8res tranch\xE9s dans ce run`,
64307
+ remaining: (n) => `${n} \xE0 compl\xE9ter par scan ou adjudication`,
64308
+ provenance: { engine: "moteur", scan: "scan", agent: "agent" },
64253
64309
  none: "\u2705 Aucune non-conformit\xE9 d\xE9tect\xE9e par le moteur statique.",
64254
64310
  findings: "Non-conformit\xE9s",
64255
64311
  severity: "S\xE9v\xE9rit\xE9",
@@ -64317,7 +64373,9 @@ var S = {
64317
64373
  en: {
64318
64374
  title: "ultra11y accessibility audit",
64319
64375
  files: "files",
64320
- rate: "automatic pass rate",
64376
+ coverage: (decided, total) => `${decided}/${total} criteria decided in this run`,
64377
+ remaining: (n) => `${n} still to complete by scan or adjudication`,
64378
+ provenance: { engine: "engine", scan: "scan", agent: "agent" },
64321
64379
  none: "\u2705 No non-conformity detected by the static engine.",
64322
64380
  findings: "Non-conformities",
64323
64381
  severity: "Severity",
@@ -64439,11 +64497,24 @@ function groupByCriterion(groups) {
64439
64497
  }
64440
64498
  return [...byCriterion.values()].map(({ pageSet, ...c2 }) => ({ ...c2, pages: pageSet.size })).sort((a, b) => SEV_ORDER4.indexOf(a.severity) - SEV_ORDER4.indexOf(b.severity) || b.occurrences - a.occurrences || a.criterion.localeCompare(b.criterion));
64441
64499
  }
64442
- function runRate(result, standard, lang) {
64500
+ function runCoverage(result, standard, lang) {
64443
64501
  const groups = isCore(standard) ? reportGroups(result, lang) : packReportGroups(result, loadPack(standard), lang);
64444
64502
  const { decided, total } = reportCoverage(groups);
64503
+ const decidedRows = groups.flatMap((g) => g.rows).filter((r) => r.status === "C" || r.status === "NC");
64504
+ const by = {
64505
+ engine: decidedRows.filter((r) => !r.decidedBy || r.decidedBy === "engine").length,
64506
+ scan: decidedRows.filter((r) => r.decidedBy === "scan").length,
64507
+ agent: decidedRows.filter((r) => r.decidedBy === "agent").length
64508
+ };
64509
+ const s = S[lang];
64510
+ const provenance = ["engine", "scan", "agent"].filter((key2) => by[key2] > 0).map((key2) => `${by[key2]} ${s.provenance[key2]}`);
64511
+ const remaining = Math.max(0, total - decided);
64445
64512
  const agentRuled = groups.some((g) => g.rows.some((r) => r.decidedBy === "agent" && r.status === "C"));
64446
- return { text: `${formatRate(decided === 0 ? null : result.conformancePct, decided, total)}${agentRuled ? "*" : ""}`, agentRuled };
64513
+ return {
64514
+ text: s.coverage(decided, total),
64515
+ detail: [...provenance, ...remaining ? [s.remaining(remaining)] : []].join(" \xB7 "),
64516
+ agentRuled
64517
+ };
64447
64518
  }
64448
64519
  var cell = (v) => v.replace(/\|/g, "\\|");
64449
64520
  function criterionTableHead(s) {
@@ -64482,11 +64553,11 @@ function stepSummary(result, opts = {}) {
64482
64553
  const lang = opts.lang ?? "en";
64483
64554
  const s = S[lang];
64484
64555
  const stdLabel = isCore(standard) ? "WCAG 2.2 AA" : loadPack(standard).name;
64485
- const rate = runRate(result, standard, lang);
64556
+ const coverage = runCoverage(result, standard, lang);
64486
64557
  const out2 = [];
64487
64558
  out2.push(`## ${s.title} \u2014 ${stdLabel}`, "");
64488
- out2.push(`\`${result.date}\` \xB7 ${result.scope.files} ${s.files} \xB7 **${rate.text}** ${s.rate}`, "");
64489
- if (rate.agentRuled) out2.push(`> ${agentMarkNote(lang)}`, "");
64559
+ out2.push(`\`${result.date}\` \xB7 ${result.scope.files} ${s.files} \xB7 **${coverage.text}**${coverage.detail ? ` \xB7 ${coverage.detail}` : ""}`, "");
64560
+ if (coverage.agentRuled) out2.push(`> ${agentMarkNote(lang)}`, "");
64490
64561
  const baseDir = opts.baseDir ?? process.cwd();
64491
64562
  const all = findingsForStandard(result, standard);
64492
64563
  if (!all.length) {
@@ -64537,15 +64608,15 @@ function prComment(result, opts = {}) {
64537
64608
  const all = findingsForStandard(result, standard);
64538
64609
  const normative = all.filter((f) => !f.advisory);
64539
64610
  const blocking = normative.filter((f) => f.severity === "bloquant").length;
64540
- const rate = runRate(result, standard, lang);
64611
+ const coverage = runCoverage(result, standard, lang);
64541
64612
  const grouped = groupFindings(all, standard, lang, baseDir);
64542
64613
  const criteria = groupByCriterion(grouped);
64543
- const orphans = unattributedFindings(result).filter((f) => !f.advisory).length;
64614
+ const orphans = all.filter((f) => !f.advisory && !f.page).length;
64544
64615
  const head = [];
64545
64616
  head.push(`### ${s.title} \u2014 ${stdLabel}`, "");
64546
64617
  head.push(blocking ? s.verdictFail(blocking) : normative.length ? s.verdictWarn : s.verdictPass, "");
64547
- head.push(`\`${result.date}\` \xB7 ${result.scope.files} ${s.files} \xB7 **${rate.text}** ${s.rate}`, "");
64548
- if (rate.agentRuled) head.push(`> ${agentMarkNote(lang)}`, "");
64618
+ head.push(`\`${result.date}\` \xB7 ${result.scope.files} ${s.files} \xB7 **${coverage.text}**${coverage.detail ? ` \xB7 ${coverage.detail}` : ""}`, "");
64619
+ if (coverage.agentRuled) head.push(`> ${agentMarkNote(lang)}`, "");
64549
64620
  if (orphans) head.push(`> ${s.unattributed(orphans)}`, "");
64550
64621
  const tail = [];
64551
64622
  if (opts.artifactName) tail.push(s.artifact(opts.artifactName), "");
@@ -64581,7 +64652,7 @@ function perPageTable(result, standard = CORE2, lang = "en") {
64581
64652
  "",
64582
64653
  ...scoreboardTable(result, derived, standard, s, lang),
64583
64654
  "",
64584
- ...basisCaveats(result, derived, s, lang),
64655
+ ...basisCaveats(result, derived, standard, s, lang),
64585
64656
  ...fullGridBlock(result, derived, standard, s, lang),
64586
64657
  "",
64587
64658
  ...derived.flatMap((pg) => [...namedCriteriaBlock(result, pg, standard, s, lang), ""])
@@ -64613,7 +64684,8 @@ function scoreboardTable(result, derived, standard, s, lang) {
64613
64684
  "| --- | --- | ---: | ---: | ---: | ---: | ---: |"
64614
64685
  ];
64615
64686
  for (const pg of derived) {
64616
- const n = (sev) => severityCount(pg, sev);
64687
+ const pageFindings = findingsForStandard(pageView(result, pg), standard).filter((f) => !f.advisory);
64688
+ const n = (sev) => pageFindings.filter((f) => f.severity === sev).length;
64617
64689
  const t3 = pageTally(pageCriterionRows(result, pg, standard, lang));
64618
64690
  out2.push(
64619
64691
  `| ${pg.name}${pg.auth ? " \u{1F512}" : ""} \u2014 \`${pg.url}\` | ${basisLabel(pg.basis, lang)} | ${t3.c} | ${t3.nc} | ${n("bloquant")} | ${n("majeur")} | ${n("mineur")} |`
@@ -64637,12 +64709,10 @@ function undecidedBlock(result, derived, standard, s, lang) {
64637
64709
  out2.push("");
64638
64710
  return out2;
64639
64711
  }
64640
- function severityCount(pg, sev) {
64641
- return pg.findings.filter((f) => !f.advisory && f.severity === sev).length;
64642
- }
64643
- function basisCaveats(result, derived, s, lang) {
64712
+ function basisCaveats(result, derived, standard, s, lang) {
64644
64713
  const out2 = [`> ${s.scoreboardNote}`, ""];
64645
- const orphans = unattributedFindings(result).filter((f) => !f.advisory).length;
64714
+ const projected = new Set(findingsForStandard(result, standard));
64715
+ const orphans = unattributedFindings(result).filter((f) => projected.has(f) && !f.advisory).length;
64646
64716
  if (orphans) out2.push(`> ${s.unattributed(orphans)}`, "");
64647
64717
  if (derived.some((p) => p.basis === "attributed")) out2.push(`> ${s.sourceBasis}`, "");
64648
64718
  const notAudited = pageBasisWarning("not-audited", lang);
@@ -64654,9 +64724,11 @@ function pageBlock(result, page, standard, lang, baseDir) {
64654
64724
  const s = S[lang];
64655
64725
  const rows = pageCriterionRows(result, page, standard, lang);
64656
64726
  const nc = rows.filter((r) => r.status === "NC");
64657
- const occurrences = page.findings.filter((f) => !f.advisory).length;
64727
+ const pageFindings = findingsForStandard(pageView(result, page), standard).filter((f) => !f.advisory);
64728
+ const occurrences = pageFindings.length;
64658
64729
  if (!nc.length && !occurrences) return void 0;
64659
- const counts = `\u{1F534} ${severityCount(page, "bloquant")} \xB7 \u{1F7E0} ${severityCount(page, "majeur")} \xB7 \u{1F7E1} ${severityCount(page, "mineur")}`;
64730
+ const count = (severity) => pageFindings.filter((f) => f.severity === severity).length;
64731
+ const counts = `\u{1F534} ${count("bloquant")} \xB7 \u{1F7E0} ${count("majeur")} \xB7 \u{1F7E1} ${count("mineur")}`;
64660
64732
  const withTests = nc.some((r) => r.tests.length);
64661
64733
  const out2 = [
64662
64734
  "<details>",
@@ -64675,12 +64747,7 @@ function pageBlock(result, page, standard, lang, baseDir) {
64675
64747
  for (const r of nc) {
64676
64748
  out2.push(withTests ? `| ${cell(r.label)} | ${r.tests.map((t3) => `\`${t3}\``).join(" ")} |` : `| ${cell(r.label)} |`);
64677
64749
  }
64678
- const defects = groupFindings(
64679
- page.findings.filter((f) => !f.advisory),
64680
- standard,
64681
- lang,
64682
- baseDir
64683
- );
64750
+ const defects = groupFindings(pageFindings, standard, lang, baseDir);
64684
64751
  const blocking = groupByCriterion(defects.filter((g) => g.severity === "bloquant"));
64685
64752
  const rest = groupByCriterion(defects.filter((g) => g.severity !== "bloquant"));
64686
64753
  const shownBlocking = Math.min(blocking.length, PAGE_CRITERIA_SHOWN);
@@ -64717,7 +64784,8 @@ function fullGridBlock(result, derived, standard, s, lang) {
64717
64784
  return out2;
64718
64785
  }
64719
64786
  function orphansBlock(result, standard, s, lang, baseDir) {
64720
- const orphans = unattributedFindings(result).filter((f) => !f.advisory);
64787
+ const projected = new Set(findingsForStandard(result, standard));
64788
+ const orphans = unattributedFindings(result).filter((f) => projected.has(f) && !f.advisory);
64721
64789
  if (!orphans.length) return [];
64722
64790
  const criteria = groupByCriterion(groupFindings(orphans, standard, lang, baseDir));
64723
64791
  const counts = SEV_ORDER4.map((sev) => `${ICON5[sev]} ${orphans.filter((f) => f.severity === sev).length}`).join(" \xB7 ");
@@ -64774,17 +64842,18 @@ function pagesComment(result, opts = {}) {
64774
64842
  const derived = derivePages(result, scope);
64775
64843
  const normative = findingsForStandard(result, standard).filter((f) => !f.advisory);
64776
64844
  const blocking = normative.filter((f) => f.severity === "bloquant").length;
64777
- const rate = runRate(result, standard, lang);
64845
+ const coverage = runCoverage(result, standard, lang);
64778
64846
  head.push(blocking ? s.verdictFail(blocking) : normative.length ? s.verdictWarn : s.verdictPass, "");
64779
- head.push(`\`${result.date}\` \xB7 ${s.pagesCount(derived.length)} \xB7 **${rate.text}** ${s.rate}`, "");
64780
- if (rate.agentRuled) head.push(`> ${agentMarkNote(lang)}`, "");
64847
+ head.push(`\`${result.date}\` \xB7 ${s.pagesCount(derived.length)} \xB7 **${coverage.text}**${coverage.detail ? ` \xB7 ${coverage.detail}` : ""}`, "");
64848
+ if (coverage.agentRuled) head.push(`> ${agentMarkNote(lang)}`, "");
64849
+ const severity = (page, level) => findingsForStandard(pageView(result, page), standard).filter((f) => !f.advisory && f.severity === level).length;
64781
64850
  const blocks = [...derived].sort(
64782
- (a, b) => severityCount(b, "bloquant") - severityCount(a, "bloquant") || severityCount(b, "majeur") - severityCount(a, "majeur") || severityCount(b, "mineur") - severityCount(a, "mineur")
64851
+ (a, b) => severity(b, "bloquant") - severity(a, "bloquant") || severity(b, "majeur") - severity(a, "majeur") || severity(b, "mineur") - severity(a, "mineur")
64783
64852
  ).map((p) => pageBlock(result, p, standard, lang, baseDir)).filter((b) => b !== void 0);
64784
64853
  const assemble = (nBlocks2, nRows2, withGrid = true) => {
64785
64854
  const body3 = [...scoreboardTable(result, derived.slice(0, nRows2), standard, s, lang), ""];
64786
64855
  if (nRows2 < derived.length) body3.push(s.scoreboardClamped(derived.length - nRows2), "");
64787
- body3.push(...basisCaveats(result, derived, s, lang));
64856
+ body3.push(...basisCaveats(result, derived, standard, s, lang));
64788
64857
  body3.push(...undecidedBlock(result, derived, standard, s, lang));
64789
64858
  if (redirected.length) body3.push(...renderRedirected(redirected, lang), "");
64790
64859
  body3.push(...orphansBlock(result, standard, s, lang, baseDir), "");
@@ -71741,11 +71810,7 @@ async function cmdJudge(p) {
71741
71810
  if (truncated) items = items.slice(0, max);
71742
71811
  const size = grain === "criterion" ? 1 : BATCH_SIZE;
71743
71812
  const render2 = (slice) => formatAdjudication(slice, lang, standard, { preamble: false, contract: false });
71744
- const batches = [];
71745
- for (let i2 = 0; i2 < items.length; i2 += size) {
71746
- const slice = items.slice(i2, i2 + size);
71747
- batches.push({ items: slice, prompt: render2(slice) });
71748
- }
71813
+ const batches = batchWorklist(items, render2, size);
71749
71814
  const explicitModel = typeof p.flags.model === "string" && p.flags.model ? p.flags.model : void 0;
71750
71815
  const model = explicitModel ?? (runner === "claude" ? DEFAULT_CLI_MODEL : runner === "api" ? modelFromEnv() : void 0);
71751
71816
  const modelLabel = model ?? "Codex account default";
@@ -3,7 +3,7 @@ name: review-a11y
3
3
  description: "Use to REVIEW changed frontend code for accessibility: staged files, a working diff, branch, or PR; prompts such as 'review a11y', 'is this accessible?', or 'anything to fix before merge?'; and hook or CI findings on a change. Run the bundled install-free engine with cross-file JSX/TSX analysis, then adjudicate candidates and return a severity-ranked WCAG 2.2 AA review with file:line fixes, residual rendering risks, and a verdict. Use `ultra11y` instead for whole-repo audits, dated conformance reports, country standards, PRD backlogs, or authoring accessible markup."
4
4
  license: MIT
5
5
  metadata:
6
- version: 5.35.0
6
+ version: 5.35.1
7
7
  ---
8
8
 
9
9
  # review-a11y — accessibility review of changed code