ultra11y 5.36.2 → 5.37.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.
@@ -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.36.2",
13
+ "version": "5.37.0",
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.36.2",
4
+ "version": "5.37.0",
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.36.2",
4
+ "version": "5.37.0",
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.36.2";
30
+ const ULTRA11Y_PLUGIN_VERSION = "5.37.0";
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.36.2",
3
+ "version": "5.37.0",
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.36.2";
9
+ var VERSION = "5.37.0";
10
10
  var SCHEMA_VERSION = 2;
11
11
  var INAPPLICABLE_STATUS = "C";
12
12
 
@@ -58231,12 +58231,17 @@ function automationOverview(standard) {
58231
58231
  const pack = loadPack(standard);
58232
58232
  const tests = { static: 0, rendered: 0, judgment: 0 };
58233
58233
  const criteria = { static: [], rendered: [], judgment: [] };
58234
+ const signals = { decisive: [], candidate: [], advisory: [] };
58234
58235
  for (const criterion of pack.criteria) {
58235
58236
  const tiers = Object.values(criterion.automation?.tests ?? {});
58236
58237
  for (const tier of tiers) tests[tier]++;
58237
58238
  for (const tier of ["static", "rendered", "judgment"]) if (tiers.includes(tier)) criteria[tier].push(criterion.id);
58239
+ const effects = new Set((criterion.automation?.rules ?? []).map((rule) => rule.effect));
58240
+ if (effects.has("decisive-nc")) signals.decisive.push(criterion.id);
58241
+ if (effects.has("candidate")) signals.candidate.push(criterion.id);
58242
+ if (effects.has("advisory")) signals.advisory.push(criterion.id);
58238
58243
  }
58239
- return { tests, criteria };
58244
+ return { tests, criteria, signals };
58240
58245
  }
58241
58246
  function automationCell(standard, id) {
58242
58247
  if (isCore(standard)) return "\u2014";
@@ -66404,9 +66409,11 @@ var S = {
66404
66409
  noCriterionForFindings: (n) => `${n} constat(s) sur cette page ne rendent aucun crit\xE8re du r\xE9f\xE9rentiel non conforme : leur r\xE8gle sort du p\xE9rim\xE8tre d'application de chacun. Ils comptent dans les colonnes ci-dessus, et sont d\xE9taill\xE9s dans l'artefact.`,
66405
66410
  runScope: "P\xE9rim\xE8tre de ce run",
66406
66411
  renderedActuallyTested: (n) => `${n} page(s) rendue(s) r\xE9ellement test\xE9e(s)`,
66412
+ testedPages: (pages, more) => `Pages test\xE9es : ${pages}${more ? ` \xB7 \u2026 +${more} dans l'artefact` : ""}`,
66407
66413
  noRenderedExecuted: "0 page rendue : aucun test rendered n'a \xE9t\xE9 ex\xE9cut\xE9",
66408
66414
  staticTested: (tests, ids) => `${tests} test(s) static \u2014 crit\xE8res : ${ids || "\u2014"}`,
66409
66415
  renderedContract: (tests, ids) => `${tests} test(s) rendered pr\xE9vus \u2014 crit\xE8res : ${ids || "\u2014"}`,
66416
+ deterministicSignals: (covered, decisive, candidate, advisory) => `Couverture moteur : ${covered} crit\xE8re(s) re\xE7oivent un signal normatif \u2014 ${decisive} crit\xE8re(s) peuvent produire un NC d\xE9cisif \xB7 ${candidate} re\xE7oivent des preuves candidates (avec chevauchement)${advisory ? ` \xB7 ${advisory} autre re\xE7oit une recommandation advisory` : ""}`,
66410
66417
  judgmentContract: (tests, criteria) => `${tests} test(s) judgment sur ${criteria} crit\xE8re(s), tous transmis \xE0 l'IA tant qu'ils ne sont pas tranch\xE9s`
66411
66418
  },
66412
66419
  en: {
@@ -66480,9 +66487,11 @@ var S = {
66480
66487
  noCriterionForFindings: (n) => `${n} finding(s) on this page make no criterion of the standard non-conforming: their rule falls outside every criterion's applicability. They are counted in the columns above, and detailed in the artifact.`,
66481
66488
  runScope: "Scope of this run",
66482
66489
  renderedActuallyTested: (n) => `${n} rendered page(s) actually tested`,
66490
+ testedPages: (pages, more) => `Pages tested: ${pages}${more ? ` \xB7 \u2026 +${more} in the artifact` : ""}`,
66483
66491
  noRenderedExecuted: "0 rendered pages: no rendered test was executed",
66484
66492
  staticTested: (tests, ids) => `${tests} static test(s) \u2014 criteria: ${ids || "\u2014"}`,
66485
66493
  renderedContract: (tests, ids) => `${tests} planned rendered test(s) \u2014 criteria: ${ids || "\u2014"}`,
66494
+ deterministicSignals: (covered, decisive, candidate, advisory) => `Engine coverage: ${covered} criterion(ia) receive a normative signal \u2014 ${decisive} criterion(ia) can produce a decisive NC \xB7 ${candidate} receive candidate evidence (with overlap)${advisory ? ` \xB7 ${advisory} other receives an advisory recommendation` : ""}`,
66486
66495
  judgmentContract: (tests, criteria) => `${tests} judgment test(s) across ${criteria} criterion(ia), all sent to AI while undecided`
66487
66496
  }
66488
66497
  };
@@ -66561,16 +66570,29 @@ function runCoverage(result, standard, lang) {
66561
66570
  agentRuled
66562
66571
  };
66563
66572
  }
66564
- function runScopeLines(result, standard, lang) {
66573
+ function runScopeLines(result, standard, lang, includePageNames = false) {
66565
66574
  const s = S[lang];
66566
66575
  const pages = result.scope.pagesAudited?.length ?? 0;
66567
66576
  const out2 = [`> **${s.runScope}** \u2014 ${pages === 0 ? s.noRenderedExecuted : s.renderedActuallyTested(pages)}`];
66577
+ if (includePageNames && pages > 0) {
66578
+ const scope = pagesOf(result);
66579
+ const byId2 = new Map(scope.map((page) => [page.id, page]));
66580
+ const tested = (result.scope.pagesAudited ?? []).map((id) => byId2.get(id) ?? { id, name: id, url: "" });
66581
+ const shown = tested.slice(0, 12).map((page) => {
66582
+ const name2 = mdText(page.name || page.id);
66583
+ const url = page.url ? ` (\`${page.url.replace(/`/g, "%60")}\`)` : "";
66584
+ return `${name2}${url}`;
66585
+ });
66586
+ out2.push(`> ${s.testedPages(shown.join(" \xB7 "), tested.length - shown.length)}`);
66587
+ }
66568
66588
  const automation = automationOverview(standard);
66569
66589
  if (!automation) return out2;
66570
66590
  const ids = (values) => values.map((id) => `\`${id}\``).join(" \xB7 ");
66591
+ const normativeSignals = (/* @__PURE__ */ new Set([...automation.signals.decisive, ...automation.signals.candidate])).size;
66571
66592
  out2.push(
66572
66593
  `> ${s.staticTested(automation.tests.static, ids(automation.criteria.static))}`,
66573
66594
  `> ${s.renderedContract(automation.tests.rendered, ids(automation.criteria.rendered))}`,
66595
+ `> ${s.deterministicSignals(normativeSignals, automation.signals.decisive.length, automation.signals.candidate.length, automation.signals.advisory.length)}`,
66574
66596
  `> ${s.judgmentContract(automation.tests.judgment, automation.criteria.judgment.length)}`
66575
66597
  );
66576
66598
  return out2;
@@ -66651,7 +66673,7 @@ function prComment(result, opts = {}) {
66651
66673
  head.push(`### ${s.title} \u2014 ${stdLabel}`, "");
66652
66674
  head.push(blocking ? s.verdictFail(blocking) : normative.length ? s.verdictWarn : s.verdictPass, "");
66653
66675
  head.push(`\`${result.date}\` \xB7 ${result.scope.files} ${s.files} \xB7 **${coverage.text}**${coverage.detail ? ` \xB7 ${coverage.detail}` : ""}`, "");
66654
- head.push(...runScopeLines(result, standard, lang), "");
66676
+ head.push(...runScopeLines(result, standard, lang, true), "");
66655
66677
  if (coverage.agentRuled) head.push(`> ${agentMarkNote(lang)}`, "");
66656
66678
  if (orphans) head.push(`> ${s.unattributed(orphans)}`, "");
66657
66679
  const tail = [];
@@ -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.36.2
6
+ version: 5.37.0
7
7
  ---
8
8
 
9
9
  # review-a11y — accessibility review of changed code
@@ -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.36.2";
9
+ var VERSION = "5.37.0";
10
10
  var SCHEMA_VERSION = 2;
11
11
  var INAPPLICABLE_STATUS = "C";
12
12
 
@@ -58231,12 +58231,17 @@ function automationOverview(standard) {
58231
58231
  const pack = loadPack(standard);
58232
58232
  const tests = { static: 0, rendered: 0, judgment: 0 };
58233
58233
  const criteria = { static: [], rendered: [], judgment: [] };
58234
+ const signals = { decisive: [], candidate: [], advisory: [] };
58234
58235
  for (const criterion of pack.criteria) {
58235
58236
  const tiers = Object.values(criterion.automation?.tests ?? {});
58236
58237
  for (const tier of tiers) tests[tier]++;
58237
58238
  for (const tier of ["static", "rendered", "judgment"]) if (tiers.includes(tier)) criteria[tier].push(criterion.id);
58239
+ const effects = new Set((criterion.automation?.rules ?? []).map((rule) => rule.effect));
58240
+ if (effects.has("decisive-nc")) signals.decisive.push(criterion.id);
58241
+ if (effects.has("candidate")) signals.candidate.push(criterion.id);
58242
+ if (effects.has("advisory")) signals.advisory.push(criterion.id);
58238
58243
  }
58239
- return { tests, criteria };
58244
+ return { tests, criteria, signals };
58240
58245
  }
58241
58246
  function automationCell(standard, id) {
58242
58247
  if (isCore(standard)) return "\u2014";
@@ -66404,9 +66409,11 @@ var S = {
66404
66409
  noCriterionForFindings: (n) => `${n} constat(s) sur cette page ne rendent aucun crit\xE8re du r\xE9f\xE9rentiel non conforme : leur r\xE8gle sort du p\xE9rim\xE8tre d'application de chacun. Ils comptent dans les colonnes ci-dessus, et sont d\xE9taill\xE9s dans l'artefact.`,
66405
66410
  runScope: "P\xE9rim\xE8tre de ce run",
66406
66411
  renderedActuallyTested: (n) => `${n} page(s) rendue(s) r\xE9ellement test\xE9e(s)`,
66412
+ testedPages: (pages, more) => `Pages test\xE9es : ${pages}${more ? ` \xB7 \u2026 +${more} dans l'artefact` : ""}`,
66407
66413
  noRenderedExecuted: "0 page rendue : aucun test rendered n'a \xE9t\xE9 ex\xE9cut\xE9",
66408
66414
  staticTested: (tests, ids) => `${tests} test(s) static \u2014 crit\xE8res : ${ids || "\u2014"}`,
66409
66415
  renderedContract: (tests, ids) => `${tests} test(s) rendered pr\xE9vus \u2014 crit\xE8res : ${ids || "\u2014"}`,
66416
+ deterministicSignals: (covered, decisive, candidate, advisory) => `Couverture moteur : ${covered} crit\xE8re(s) re\xE7oivent un signal normatif \u2014 ${decisive} crit\xE8re(s) peuvent produire un NC d\xE9cisif \xB7 ${candidate} re\xE7oivent des preuves candidates (avec chevauchement)${advisory ? ` \xB7 ${advisory} autre re\xE7oit une recommandation advisory` : ""}`,
66410
66417
  judgmentContract: (tests, criteria) => `${tests} test(s) judgment sur ${criteria} crit\xE8re(s), tous transmis \xE0 l'IA tant qu'ils ne sont pas tranch\xE9s`
66411
66418
  },
66412
66419
  en: {
@@ -66480,9 +66487,11 @@ var S = {
66480
66487
  noCriterionForFindings: (n) => `${n} finding(s) on this page make no criterion of the standard non-conforming: their rule falls outside every criterion's applicability. They are counted in the columns above, and detailed in the artifact.`,
66481
66488
  runScope: "Scope of this run",
66482
66489
  renderedActuallyTested: (n) => `${n} rendered page(s) actually tested`,
66490
+ testedPages: (pages, more) => `Pages tested: ${pages}${more ? ` \xB7 \u2026 +${more} in the artifact` : ""}`,
66483
66491
  noRenderedExecuted: "0 rendered pages: no rendered test was executed",
66484
66492
  staticTested: (tests, ids) => `${tests} static test(s) \u2014 criteria: ${ids || "\u2014"}`,
66485
66493
  renderedContract: (tests, ids) => `${tests} planned rendered test(s) \u2014 criteria: ${ids || "\u2014"}`,
66494
+ deterministicSignals: (covered, decisive, candidate, advisory) => `Engine coverage: ${covered} criterion(ia) receive a normative signal \u2014 ${decisive} criterion(ia) can produce a decisive NC \xB7 ${candidate} receive candidate evidence (with overlap)${advisory ? ` \xB7 ${advisory} other receives an advisory recommendation` : ""}`,
66486
66495
  judgmentContract: (tests, criteria) => `${tests} judgment test(s) across ${criteria} criterion(ia), all sent to AI while undecided`
66487
66496
  }
66488
66497
  };
@@ -66561,16 +66570,29 @@ function runCoverage(result, standard, lang) {
66561
66570
  agentRuled
66562
66571
  };
66563
66572
  }
66564
- function runScopeLines(result, standard, lang) {
66573
+ function runScopeLines(result, standard, lang, includePageNames = false) {
66565
66574
  const s = S[lang];
66566
66575
  const pages = result.scope.pagesAudited?.length ?? 0;
66567
66576
  const out2 = [`> **${s.runScope}** \u2014 ${pages === 0 ? s.noRenderedExecuted : s.renderedActuallyTested(pages)}`];
66577
+ if (includePageNames && pages > 0) {
66578
+ const scope = pagesOf(result);
66579
+ const byId2 = new Map(scope.map((page) => [page.id, page]));
66580
+ const tested = (result.scope.pagesAudited ?? []).map((id) => byId2.get(id) ?? { id, name: id, url: "" });
66581
+ const shown = tested.slice(0, 12).map((page) => {
66582
+ const name2 = mdText(page.name || page.id);
66583
+ const url = page.url ? ` (\`${page.url.replace(/`/g, "%60")}\`)` : "";
66584
+ return `${name2}${url}`;
66585
+ });
66586
+ out2.push(`> ${s.testedPages(shown.join(" \xB7 "), tested.length - shown.length)}`);
66587
+ }
66568
66588
  const automation = automationOverview(standard);
66569
66589
  if (!automation) return out2;
66570
66590
  const ids = (values) => values.map((id) => `\`${id}\``).join(" \xB7 ");
66591
+ const normativeSignals = (/* @__PURE__ */ new Set([...automation.signals.decisive, ...automation.signals.candidate])).size;
66571
66592
  out2.push(
66572
66593
  `> ${s.staticTested(automation.tests.static, ids(automation.criteria.static))}`,
66573
66594
  `> ${s.renderedContract(automation.tests.rendered, ids(automation.criteria.rendered))}`,
66595
+ `> ${s.deterministicSignals(normativeSignals, automation.signals.decisive.length, automation.signals.candidate.length, automation.signals.advisory.length)}`,
66574
66596
  `> ${s.judgmentContract(automation.tests.judgment, automation.criteria.judgment.length)}`
66575
66597
  );
66576
66598
  return out2;
@@ -66651,7 +66673,7 @@ function prComment(result, opts = {}) {
66651
66673
  head.push(`### ${s.title} \u2014 ${stdLabel}`, "");
66652
66674
  head.push(blocking ? s.verdictFail(blocking) : normative.length ? s.verdictWarn : s.verdictPass, "");
66653
66675
  head.push(`\`${result.date}\` \xB7 ${result.scope.files} ${s.files} \xB7 **${coverage.text}**${coverage.detail ? ` \xB7 ${coverage.detail}` : ""}`, "");
66654
- head.push(...runScopeLines(result, standard, lang), "");
66676
+ head.push(...runScopeLines(result, standard, lang, true), "");
66655
66677
  if (coverage.agentRuled) head.push(`> ${agentMarkNote(lang)}`, "");
66656
66678
  if (orphans) head.push(`> ${s.unattributed(orphans)}`, "");
66657
66679
  const tail = [];
@@ -3,7 +3,7 @@ name: ultra11y
3
3
  description: "Use to AUDIT a repository, site, or page against WCAG 2.2 AA or a country standard such as RGAA; produce a dated conformance report, criterion grid, PRD backlog, or tickets; AUTHOR accessible markup; fix accessibility; or wire a repo gate and rendered-DOM capture pipeline. The bundled install-free engine runs 81 static checks tied to success criteria, while the agent adjudicates judgment criteria and routes rendering criteria to browser scans; check/verify reject invented non-conformities. Use `review-a11y` instead for a review scoped only to a diff, branch, or PR."
4
4
  license: MIT
5
5
  metadata:
6
- version: 5.36.2
6
+ version: 5.37.0
7
7
  ---
8
8
 
9
9
  # ultra11y — audit WCAG 2.2 AA and write accessible markup
@@ -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.36.2";
9
+ var VERSION = "5.37.0";
10
10
  var SCHEMA_VERSION = 2;
11
11
  var INAPPLICABLE_STATUS = "C";
12
12
 
@@ -58231,12 +58231,17 @@ function automationOverview(standard) {
58231
58231
  const pack = loadPack(standard);
58232
58232
  const tests = { static: 0, rendered: 0, judgment: 0 };
58233
58233
  const criteria = { static: [], rendered: [], judgment: [] };
58234
+ const signals = { decisive: [], candidate: [], advisory: [] };
58234
58235
  for (const criterion of pack.criteria) {
58235
58236
  const tiers = Object.values(criterion.automation?.tests ?? {});
58236
58237
  for (const tier of tiers) tests[tier]++;
58237
58238
  for (const tier of ["static", "rendered", "judgment"]) if (tiers.includes(tier)) criteria[tier].push(criterion.id);
58239
+ const effects = new Set((criterion.automation?.rules ?? []).map((rule) => rule.effect));
58240
+ if (effects.has("decisive-nc")) signals.decisive.push(criterion.id);
58241
+ if (effects.has("candidate")) signals.candidate.push(criterion.id);
58242
+ if (effects.has("advisory")) signals.advisory.push(criterion.id);
58238
58243
  }
58239
- return { tests, criteria };
58244
+ return { tests, criteria, signals };
58240
58245
  }
58241
58246
  function automationCell(standard, id) {
58242
58247
  if (isCore(standard)) return "\u2014";
@@ -66404,9 +66409,11 @@ var S = {
66404
66409
  noCriterionForFindings: (n) => `${n} constat(s) sur cette page ne rendent aucun crit\xE8re du r\xE9f\xE9rentiel non conforme : leur r\xE8gle sort du p\xE9rim\xE8tre d'application de chacun. Ils comptent dans les colonnes ci-dessus, et sont d\xE9taill\xE9s dans l'artefact.`,
66405
66410
  runScope: "P\xE9rim\xE8tre de ce run",
66406
66411
  renderedActuallyTested: (n) => `${n} page(s) rendue(s) r\xE9ellement test\xE9e(s)`,
66412
+ testedPages: (pages, more) => `Pages test\xE9es : ${pages}${more ? ` \xB7 \u2026 +${more} dans l'artefact` : ""}`,
66407
66413
  noRenderedExecuted: "0 page rendue : aucun test rendered n'a \xE9t\xE9 ex\xE9cut\xE9",
66408
66414
  staticTested: (tests, ids) => `${tests} test(s) static \u2014 crit\xE8res : ${ids || "\u2014"}`,
66409
66415
  renderedContract: (tests, ids) => `${tests} test(s) rendered pr\xE9vus \u2014 crit\xE8res : ${ids || "\u2014"}`,
66416
+ deterministicSignals: (covered, decisive, candidate, advisory) => `Couverture moteur : ${covered} crit\xE8re(s) re\xE7oivent un signal normatif \u2014 ${decisive} crit\xE8re(s) peuvent produire un NC d\xE9cisif \xB7 ${candidate} re\xE7oivent des preuves candidates (avec chevauchement)${advisory ? ` \xB7 ${advisory} autre re\xE7oit une recommandation advisory` : ""}`,
66410
66417
  judgmentContract: (tests, criteria) => `${tests} test(s) judgment sur ${criteria} crit\xE8re(s), tous transmis \xE0 l'IA tant qu'ils ne sont pas tranch\xE9s`
66411
66418
  },
66412
66419
  en: {
@@ -66480,9 +66487,11 @@ var S = {
66480
66487
  noCriterionForFindings: (n) => `${n} finding(s) on this page make no criterion of the standard non-conforming: their rule falls outside every criterion's applicability. They are counted in the columns above, and detailed in the artifact.`,
66481
66488
  runScope: "Scope of this run",
66482
66489
  renderedActuallyTested: (n) => `${n} rendered page(s) actually tested`,
66490
+ testedPages: (pages, more) => `Pages tested: ${pages}${more ? ` \xB7 \u2026 +${more} in the artifact` : ""}`,
66483
66491
  noRenderedExecuted: "0 rendered pages: no rendered test was executed",
66484
66492
  staticTested: (tests, ids) => `${tests} static test(s) \u2014 criteria: ${ids || "\u2014"}`,
66485
66493
  renderedContract: (tests, ids) => `${tests} planned rendered test(s) \u2014 criteria: ${ids || "\u2014"}`,
66494
+ deterministicSignals: (covered, decisive, candidate, advisory) => `Engine coverage: ${covered} criterion(ia) receive a normative signal \u2014 ${decisive} criterion(ia) can produce a decisive NC \xB7 ${candidate} receive candidate evidence (with overlap)${advisory ? ` \xB7 ${advisory} other receives an advisory recommendation` : ""}`,
66486
66495
  judgmentContract: (tests, criteria) => `${tests} judgment test(s) across ${criteria} criterion(ia), all sent to AI while undecided`
66487
66496
  }
66488
66497
  };
@@ -66561,16 +66570,29 @@ function runCoverage(result, standard, lang) {
66561
66570
  agentRuled
66562
66571
  };
66563
66572
  }
66564
- function runScopeLines(result, standard, lang) {
66573
+ function runScopeLines(result, standard, lang, includePageNames = false) {
66565
66574
  const s = S[lang];
66566
66575
  const pages = result.scope.pagesAudited?.length ?? 0;
66567
66576
  const out2 = [`> **${s.runScope}** \u2014 ${pages === 0 ? s.noRenderedExecuted : s.renderedActuallyTested(pages)}`];
66577
+ if (includePageNames && pages > 0) {
66578
+ const scope = pagesOf(result);
66579
+ const byId2 = new Map(scope.map((page) => [page.id, page]));
66580
+ const tested = (result.scope.pagesAudited ?? []).map((id) => byId2.get(id) ?? { id, name: id, url: "" });
66581
+ const shown = tested.slice(0, 12).map((page) => {
66582
+ const name2 = mdText(page.name || page.id);
66583
+ const url = page.url ? ` (\`${page.url.replace(/`/g, "%60")}\`)` : "";
66584
+ return `${name2}${url}`;
66585
+ });
66586
+ out2.push(`> ${s.testedPages(shown.join(" \xB7 "), tested.length - shown.length)}`);
66587
+ }
66568
66588
  const automation = automationOverview(standard);
66569
66589
  if (!automation) return out2;
66570
66590
  const ids = (values) => values.map((id) => `\`${id}\``).join(" \xB7 ");
66591
+ const normativeSignals = (/* @__PURE__ */ new Set([...automation.signals.decisive, ...automation.signals.candidate])).size;
66571
66592
  out2.push(
66572
66593
  `> ${s.staticTested(automation.tests.static, ids(automation.criteria.static))}`,
66573
66594
  `> ${s.renderedContract(automation.tests.rendered, ids(automation.criteria.rendered))}`,
66595
+ `> ${s.deterministicSignals(normativeSignals, automation.signals.decisive.length, automation.signals.candidate.length, automation.signals.advisory.length)}`,
66574
66596
  `> ${s.judgmentContract(automation.tests.judgment, automation.criteria.judgment.length)}`
66575
66597
  );
66576
66598
  return out2;
@@ -66651,7 +66673,7 @@ function prComment(result, opts = {}) {
66651
66673
  head.push(`### ${s.title} \u2014 ${stdLabel}`, "");
66652
66674
  head.push(blocking ? s.verdictFail(blocking) : normative.length ? s.verdictWarn : s.verdictPass, "");
66653
66675
  head.push(`\`${result.date}\` \xB7 ${result.scope.files} ${s.files} \xB7 **${coverage.text}**${coverage.detail ? ` \xB7 ${coverage.detail}` : ""}`, "");
66654
- head.push(...runScopeLines(result, standard, lang), "");
66676
+ head.push(...runScopeLines(result, standard, lang, true), "");
66655
66677
  if (coverage.agentRuled) head.push(`> ${agentMarkNote(lang)}`, "");
66656
66678
  if (orphans) head.push(`> ${s.unattributed(orphans)}`, "");
66657
66679
  const tail = [];
package/src/annotate.ts CHANGED
@@ -188,9 +188,12 @@ const S = {
188
188
  `${n} constat(s) sur cette page ne rendent aucun critère du référentiel non conforme : leur règle sort du périmètre d'application de chacun. Ils comptent dans les colonnes ci-dessus, et sont détaillés dans l'artefact.`,
189
189
  runScope: "Périmètre de ce run",
190
190
  renderedActuallyTested: (n: number) => `${n} page(s) rendue(s) réellement testée(s)`,
191
+ testedPages: (pages: string, more: number) => `Pages testées : ${pages}${more ? ` · … +${more} dans l'artefact` : ""}`,
191
192
  noRenderedExecuted: "0 page rendue : aucun test rendered n'a été exécuté",
192
193
  staticTested: (tests: number, ids: string) => `${tests} test(s) static — critères : ${ids || "—"}`,
193
194
  renderedContract: (tests: number, ids: string) => `${tests} test(s) rendered prévus — critères : ${ids || "—"}`,
195
+ deterministicSignals: (covered: number, decisive: number, candidate: number, advisory: number) =>
196
+ `Couverture moteur : ${covered} critère(s) reçoivent un signal normatif — ${decisive} critère(s) peuvent produire un NC décisif · ${candidate} reçoivent des preuves candidates (avec chevauchement)${advisory ? ` · ${advisory} autre reçoit une recommandation advisory` : ""}`,
194
197
  judgmentContract: (tests: number, criteria: number) =>
195
198
  `${tests} test(s) judgment sur ${criteria} critère(s), tous transmis à l'IA tant qu'ils ne sont pas tranchés`,
196
199
  },
@@ -278,9 +281,12 @@ const S = {
278
281
  `${n} finding(s) on this page make no criterion of the standard non-conforming: their rule falls outside every criterion's applicability. They are counted in the columns above, and detailed in the artifact.`,
279
282
  runScope: "Scope of this run",
280
283
  renderedActuallyTested: (n: number) => `${n} rendered page(s) actually tested`,
284
+ testedPages: (pages: string, more: number) => `Pages tested: ${pages}${more ? ` · … +${more} in the artifact` : ""}`,
281
285
  noRenderedExecuted: "0 rendered pages: no rendered test was executed",
282
286
  staticTested: (tests: number, ids: string) => `${tests} static test(s) — criteria: ${ids || "—"}`,
283
287
  renderedContract: (tests: number, ids: string) => `${tests} planned rendered test(s) — criteria: ${ids || "—"}`,
288
+ deterministicSignals: (covered: number, decisive: number, candidate: number, advisory: number) =>
289
+ `Engine coverage: ${covered} criterion(ia) receive a normative signal — ${decisive} criterion(ia) can produce a decisive NC · ${candidate} receive candidate evidence (with overlap)${advisory ? ` · ${advisory} other receives an advisory recommendation` : ""}`,
284
290
  judgmentContract: (tests: number, criteria: number) => `${tests} judgment test(s) across ${criteria} criterion(ia), all sent to AI while undecided`,
285
291
  },
286
292
  } as const;
@@ -440,16 +446,29 @@ export function runCoverage(result: AuditResult, standard: StandardId, lang: Lan
440
446
  /** Compact and literal execution scope for GitHub surfaces. In particular, a source-only
441
447
  * action says “0 rendered pages” instead of deriving routes from source and implying that a
442
448
  * browser visited them. */
443
- function runScopeLines(result: AuditResult, standard: StandardId, lang: Lang): string[] {
449
+ function runScopeLines(result: AuditResult, standard: StandardId, lang: Lang, includePageNames = false): string[] {
444
450
  const s = S[lang];
445
451
  const pages = result.scope.pagesAudited?.length ?? 0;
446
452
  const out = [`> **${s.runScope}** — ${pages === 0 ? s.noRenderedExecuted : s.renderedActuallyTested(pages)}`];
453
+ if (includePageNames && pages > 0) {
454
+ const scope = pagesOf(result);
455
+ const byId = new Map(scope.map((page) => [page.id, page]));
456
+ const tested = (result.scope.pagesAudited ?? []).map((id) => byId.get(id) ?? { id, name: id, url: "" });
457
+ const shown = tested.slice(0, 12).map((page) => {
458
+ const name = mdText(page.name || page.id);
459
+ const url = page.url ? ` (\`${page.url.replace(/`/g, "%60")}\`)` : "";
460
+ return `${name}${url}`;
461
+ });
462
+ out.push(`> ${s.testedPages(shown.join(" · "), tested.length - shown.length)}`);
463
+ }
447
464
  const automation = automationOverview(standard);
448
465
  if (!automation) return out;
449
466
  const ids = (values: string[]) => values.map((id) => `\`${id}\``).join(" · ");
467
+ const normativeSignals = new Set([...automation.signals.decisive, ...automation.signals.candidate]).size;
450
468
  out.push(
451
469
  `> ${s.staticTested(automation.tests.static, ids(automation.criteria.static))}`,
452
470
  `> ${s.renderedContract(automation.tests.rendered, ids(automation.criteria.rendered))}`,
471
+ `> ${s.deterministicSignals(normativeSignals, automation.signals.decisive.length, automation.signals.candidate.length, automation.signals.advisory.length)}`,
453
472
  `> ${s.judgmentContract(automation.tests.judgment, automation.criteria.judgment.length)}`,
454
473
  );
455
474
  return out;
@@ -567,7 +586,7 @@ export function prComment(result: AuditResult, opts: AnnotateOptions & { runUrl?
567
586
  head.push(`### ${s.title} — ${stdLabel}`, "");
568
587
  head.push(blocking ? s.verdictFail(blocking) : normative.length ? s.verdictWarn : s.verdictPass, "");
569
588
  head.push(`\`${result.date}\` · ${result.scope.files} ${s.files} · **${coverage.text}**${coverage.detail ? ` · ${coverage.detail}` : ""}`, "");
570
- head.push(...runScopeLines(result, standard, lang), "");
589
+ head.push(...runScopeLines(result, standard, lang, true), "");
571
590
  if (coverage.agentRuled) head.push(`> ${agentMarkNote(lang)}`, "");
572
591
  if (orphans) head.push(`> ${s.unattributed(orphans)}`, "");
573
592
 
package/src/report.ts CHANGED
@@ -358,6 +358,7 @@ export function reportCoverage(groups: ReportGroup[]): { decided: number; total:
358
358
  export interface AutomationOverview {
359
359
  tests: { static: number; rendered: number; judgment: number };
360
360
  criteria: { static: string[]; rendered: string[]; judgment: string[] };
361
+ signals: { decisive: string[]; candidate: string[]; advisory: string[] };
361
362
  }
362
363
 
363
364
  /** The standard's declared test-level contract. This is a plan, not runtime coverage: the
@@ -368,12 +369,17 @@ export function automationOverview(standard: StandardId): AutomationOverview | u
368
369
  const pack = loadPack(standard);
369
370
  const tests = { static: 0, rendered: 0, judgment: 0 };
370
371
  const criteria = { static: [] as string[], rendered: [] as string[], judgment: [] as string[] };
372
+ const signals = { decisive: [] as string[], candidate: [] as string[], advisory: [] as string[] };
371
373
  for (const criterion of pack.criteria) {
372
374
  const tiers = Object.values(criterion.automation?.tests ?? {});
373
375
  for (const tier of tiers) tests[tier]++;
374
376
  for (const tier of ["static", "rendered", "judgment"] as const) if (tiers.includes(tier)) criteria[tier].push(criterion.id);
377
+ const effects = new Set((criterion.automation?.rules ?? []).map((rule) => rule.effect));
378
+ if (effects.has("decisive-nc")) signals.decisive.push(criterion.id);
379
+ if (effects.has("candidate")) signals.candidate.push(criterion.id);
380
+ if (effects.has("advisory")) signals.advisory.push(criterion.id);
375
381
  }
376
- return { tests, criteria };
382
+ return { tests, criteria, signals };
377
383
  }
378
384
 
379
385
  function automationCell(standard: StandardId, id: string): string {
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.36.2";
3
+ export const VERSION = "5.37.0";
4
4
  export const SCHEMA_VERSION = 2;
5
5
 
6
6
  // Lang = the UI FRAME's language — the `L` localization tables each module (report,