ultra11y 5.36.3 → 5.37.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.
- 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 +55 -19
- package/skills/review-a11y/SKILL.md +1 -1
- package/skills/review-a11y/scripts/ultra11y.mjs +55 -19
- package/skills/ultra11y/SKILL.md +1 -1
- package/skills/ultra11y/scripts/ultra11y.mjs +55 -19
- package/src/adjudicate.ts +2 -2
- package/src/annotate.ts +21 -2
- package/src/pages-report.ts +24 -10
- package/src/pages.ts +7 -2
- package/src/report.ts +26 -12
- package/src/standards/derive.ts +11 -0
- 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.
|
|
13
|
+
"version": "5.37.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.
|
|
4
|
+
"version": "5.37.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.
|
|
4
|
+
"version": "5.37.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.
|
|
30
|
+
const ULTRA11Y_PLUGIN_VERSION = "5.37.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.
|
|
3
|
+
"version": "5.37.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",
|
package/scripts/ultra11y.mjs
CHANGED
|
@@ -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.
|
|
9
|
+
var VERSION = "5.37.1";
|
|
10
10
|
var SCHEMA_VERSION = 2;
|
|
11
11
|
var INAPPLICABLE_STATUS = "C";
|
|
12
12
|
|
|
@@ -56362,6 +56362,10 @@ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
|
56362
56362
|
import { join as join31 } from "path";
|
|
56363
56363
|
|
|
56364
56364
|
// src/standards/derive.ts
|
|
56365
|
+
function isProvisionalJudgmentInapplicable(result, criterion) {
|
|
56366
|
+
if (result.status !== INAPPLICABLE_STATUS || result.inapplicable !== true || result.decidedBy === "agent") return false;
|
|
56367
|
+
return Object.values(criterion?.automation?.tests ?? {}).includes("judgment");
|
|
56368
|
+
}
|
|
56365
56369
|
function aggregate2(results) {
|
|
56366
56370
|
if (results.some((r) => r.status === "NC")) return "NC";
|
|
56367
56371
|
if (results.some((r) => r.status === "C" && !r.inapplicable)) return "C";
|
|
@@ -57687,7 +57691,12 @@ function pageGridModel(result, derived, standard, lang) {
|
|
|
57687
57691
|
}
|
|
57688
57692
|
const pack = loadPack(standard);
|
|
57689
57693
|
const rows = pack.criteria.map((pc) => ({ id: pc.id, label: pc.id, group: `${pc.theme}. ${themeName(pack, pc.theme, lang) ?? ""}`.trim() }));
|
|
57690
|
-
for (const p of derived)
|
|
57694
|
+
for (const p of derived) {
|
|
57695
|
+
for (const pc of derivePackResults(pageView(result, p), standard, p.id)) {
|
|
57696
|
+
const criterion = pack.criteria.find((row) => row.id === pc.id);
|
|
57697
|
+
put(pc.id, p.id, isProvisionalJudgmentInapplicable(pc, criterion) ? "manual" : pc.status);
|
|
57698
|
+
}
|
|
57699
|
+
}
|
|
57691
57700
|
return { rows, status };
|
|
57692
57701
|
}
|
|
57693
57702
|
function renderRedirected(redirected, lang = "en") {
|
|
@@ -57857,15 +57866,19 @@ function pageCriterionRows(result, page, standard, lang) {
|
|
|
57857
57866
|
}
|
|
57858
57867
|
const pack = loadPack(standard);
|
|
57859
57868
|
const byId2 = new Map(derivePackResults(pageView(result, page), standard, page.id).map((r) => [r.id, r]));
|
|
57860
|
-
return pack.criteria.map((pc) =>
|
|
57861
|
-
|
|
57862
|
-
|
|
57863
|
-
|
|
57864
|
-
|
|
57865
|
-
|
|
57866
|
-
|
|
57867
|
-
|
|
57868
|
-
|
|
57869
|
+
return pack.criteria.map((pc) => {
|
|
57870
|
+
const result2 = byId2.get(pc.id);
|
|
57871
|
+
const provisionalNa = result2 ? isProvisionalJudgmentInapplicable(result2, pc) : false;
|
|
57872
|
+
return {
|
|
57873
|
+
id: pc.id,
|
|
57874
|
+
label: `${pc.id} \u2014 ${titlePlain(pack, pc, lang)}`,
|
|
57875
|
+
group: `${pc.theme}. ${themeName(pack, pc.theme, lang) ?? ""}`.trim(),
|
|
57876
|
+
status: provisionalNa ? "manual" : result2?.status ?? "manual",
|
|
57877
|
+
tests: packTestIds(pack, pc.id),
|
|
57878
|
+
decidedBy: result2?.decidedBy,
|
|
57879
|
+
...result2?.inapplicable && !provisionalNa ? { inapplicable: true } : {}
|
|
57880
|
+
};
|
|
57881
|
+
});
|
|
57869
57882
|
}
|
|
57870
57883
|
function pagesForStandard(result, pages, standard, lang) {
|
|
57871
57884
|
if (isCore(standard)) return pages;
|
|
@@ -58231,12 +58244,17 @@ function automationOverview(standard) {
|
|
|
58231
58244
|
const pack = loadPack(standard);
|
|
58232
58245
|
const tests = { static: 0, rendered: 0, judgment: 0 };
|
|
58233
58246
|
const criteria = { static: [], rendered: [], judgment: [] };
|
|
58247
|
+
const signals = { decisive: [], candidate: [], advisory: [] };
|
|
58234
58248
|
for (const criterion of pack.criteria) {
|
|
58235
58249
|
const tiers = Object.values(criterion.automation?.tests ?? {});
|
|
58236
58250
|
for (const tier of tiers) tests[tier]++;
|
|
58237
58251
|
for (const tier of ["static", "rendered", "judgment"]) if (tiers.includes(tier)) criteria[tier].push(criterion.id);
|
|
58252
|
+
const effects = new Set((criterion.automation?.rules ?? []).map((rule) => rule.effect));
|
|
58253
|
+
if (effects.has("decisive-nc")) signals.decisive.push(criterion.id);
|
|
58254
|
+
if (effects.has("candidate")) signals.candidate.push(criterion.id);
|
|
58255
|
+
if (effects.has("advisory")) signals.advisory.push(criterion.id);
|
|
58238
58256
|
}
|
|
58239
|
-
return { tests, criteria };
|
|
58257
|
+
return { tests, criteria, signals };
|
|
58240
58258
|
}
|
|
58241
58259
|
function automationCell(standard, id) {
|
|
58242
58260
|
if (isCore(standard)) return "\u2014";
|
|
@@ -58441,19 +58459,21 @@ function packReportGroups(r, pack, lang = "en") {
|
|
|
58441
58459
|
const derived = derivePackResults(r, pack.key);
|
|
58442
58460
|
const s = L5[lang];
|
|
58443
58461
|
const naReason = lang === "fr" ? "Rien de la nature de ce crit\xE8re n'est pr\xE9sent dans le p\xE9rim\xE8tre." : "Nothing of this criterion's kind is present in scope.";
|
|
58462
|
+
const provisionalNaReason = lang === "fr" ? "Aucun sujet d\xE9tect\xE9 par le moteur ; l'IA doit confirmer la non-applicabilit\xE9 de ce crit\xE8re de jugement." : "The engine detected no subject; the AI must confirm that this judgment criterion is not applicable.";
|
|
58444
58463
|
const byTheme = /* @__PURE__ */ new Map();
|
|
58445
58464
|
for (const pr of derived) {
|
|
58446
58465
|
const pc = pack.criteria.find((c2) => c2.id === pr.id);
|
|
58466
|
+
const provisionalNa = isProvisionalJudgmentInapplicable(pr, pc);
|
|
58447
58467
|
const row = {
|
|
58448
58468
|
id: pr.id,
|
|
58449
58469
|
label: `${pack.name} ${pr.id} \u2014 ${title(pack, pc, lang)}`,
|
|
58450
|
-
status: pr.status,
|
|
58470
|
+
status: provisionalNa ? "manual" : pr.status,
|
|
58451
58471
|
findings: pr.findings,
|
|
58452
58472
|
...pr.decidedBy ? { decidedBy: pr.decidedBy } : {},
|
|
58453
|
-
...pr.inapplicable ? { inapplicable: true } : {},
|
|
58473
|
+
...pr.inapplicable && !provisionalNa ? { inapplicable: true } : {},
|
|
58454
58474
|
// outOfScope / scopedOut criteria are "manual" with their own dedicated justification —
|
|
58455
58475
|
// never mixed with the "nothing of that kind here" reason (see the manual section above).
|
|
58456
|
-
...pr.outOfScope ? { justification: s.outOfScope } : pr.scopedOut ? { justification: s.scopedOut } : pr.judgment ? { justification: s.judgment } : pr.inapplicable ? { justification: naReason } : {}
|
|
58476
|
+
...provisionalNa ? { justification: provisionalNaReason } : pr.outOfScope ? { justification: s.outOfScope } : pr.scopedOut ? { justification: s.scopedOut } : pr.judgment ? { justification: s.judgment } : pr.inapplicable ? { justification: naReason } : {}
|
|
58457
58477
|
};
|
|
58458
58478
|
(byTheme.get(pr.theme) ?? byTheme.set(pr.theme, []).get(pr.theme)).push(row);
|
|
58459
58479
|
}
|
|
@@ -61330,8 +61350,7 @@ function subjectsForPackCriterion2(standard, id, scs) {
|
|
|
61330
61350
|
}
|
|
61331
61351
|
function packResultNeedsAdjudication(pc, criterion) {
|
|
61332
61352
|
if (pc.status === "manual") return true;
|
|
61333
|
-
|
|
61334
|
-
return pc.status === INAPPLICABLE_STATUS && pc.inapplicable === true && pc.decidedBy !== "agent" && hasJudgmentTest;
|
|
61353
|
+
return isProvisionalJudgmentInapplicable(pc, criterion);
|
|
61335
61354
|
}
|
|
61336
61355
|
function buildAdjudicationWorklist(audit2, opts = {}) {
|
|
61337
61356
|
const docs = docsForAudit(audit2, opts.cwd);
|
|
@@ -66404,9 +66423,11 @@ var S = {
|
|
|
66404
66423
|
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
66424
|
runScope: "P\xE9rim\xE8tre de ce run",
|
|
66406
66425
|
renderedActuallyTested: (n) => `${n} page(s) rendue(s) r\xE9ellement test\xE9e(s)`,
|
|
66426
|
+
testedPages: (pages, more) => `Pages test\xE9es : ${pages}${more ? ` \xB7 \u2026 +${more} dans l'artefact` : ""}`,
|
|
66407
66427
|
noRenderedExecuted: "0 page rendue : aucun test rendered n'a \xE9t\xE9 ex\xE9cut\xE9",
|
|
66408
66428
|
staticTested: (tests, ids) => `${tests} test(s) static \u2014 crit\xE8res : ${ids || "\u2014"}`,
|
|
66409
66429
|
renderedContract: (tests, ids) => `${tests} test(s) rendered pr\xE9vus \u2014 crit\xE8res : ${ids || "\u2014"}`,
|
|
66430
|
+
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
66431
|
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
66432
|
},
|
|
66412
66433
|
en: {
|
|
@@ -66480,9 +66501,11 @@ var S = {
|
|
|
66480
66501
|
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
66502
|
runScope: "Scope of this run",
|
|
66482
66503
|
renderedActuallyTested: (n) => `${n} rendered page(s) actually tested`,
|
|
66504
|
+
testedPages: (pages, more) => `Pages tested: ${pages}${more ? ` \xB7 \u2026 +${more} in the artifact` : ""}`,
|
|
66483
66505
|
noRenderedExecuted: "0 rendered pages: no rendered test was executed",
|
|
66484
66506
|
staticTested: (tests, ids) => `${tests} static test(s) \u2014 criteria: ${ids || "\u2014"}`,
|
|
66485
66507
|
renderedContract: (tests, ids) => `${tests} planned rendered test(s) \u2014 criteria: ${ids || "\u2014"}`,
|
|
66508
|
+
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
66509
|
judgmentContract: (tests, criteria) => `${tests} judgment test(s) across ${criteria} criterion(ia), all sent to AI while undecided`
|
|
66487
66510
|
}
|
|
66488
66511
|
};
|
|
@@ -66561,16 +66584,29 @@ function runCoverage(result, standard, lang) {
|
|
|
66561
66584
|
agentRuled
|
|
66562
66585
|
};
|
|
66563
66586
|
}
|
|
66564
|
-
function runScopeLines(result, standard, lang) {
|
|
66587
|
+
function runScopeLines(result, standard, lang, includePageNames = false) {
|
|
66565
66588
|
const s = S[lang];
|
|
66566
66589
|
const pages = result.scope.pagesAudited?.length ?? 0;
|
|
66567
66590
|
const out2 = [`> **${s.runScope}** \u2014 ${pages === 0 ? s.noRenderedExecuted : s.renderedActuallyTested(pages)}`];
|
|
66591
|
+
if (includePageNames && pages > 0) {
|
|
66592
|
+
const scope = pagesOf(result);
|
|
66593
|
+
const byId2 = new Map(scope.map((page) => [page.id, page]));
|
|
66594
|
+
const tested = (result.scope.pagesAudited ?? []).map((id) => byId2.get(id) ?? { id, name: id, url: "" });
|
|
66595
|
+
const shown = tested.slice(0, 12).map((page) => {
|
|
66596
|
+
const name2 = mdText(page.name || page.id);
|
|
66597
|
+
const url = page.url ? ` (\`${page.url.replace(/`/g, "%60")}\`)` : "";
|
|
66598
|
+
return `${name2}${url}`;
|
|
66599
|
+
});
|
|
66600
|
+
out2.push(`> ${s.testedPages(shown.join(" \xB7 "), tested.length - shown.length)}`);
|
|
66601
|
+
}
|
|
66568
66602
|
const automation = automationOverview(standard);
|
|
66569
66603
|
if (!automation) return out2;
|
|
66570
66604
|
const ids = (values) => values.map((id) => `\`${id}\``).join(" \xB7 ");
|
|
66605
|
+
const normativeSignals = (/* @__PURE__ */ new Set([...automation.signals.decisive, ...automation.signals.candidate])).size;
|
|
66571
66606
|
out2.push(
|
|
66572
66607
|
`> ${s.staticTested(automation.tests.static, ids(automation.criteria.static))}`,
|
|
66573
66608
|
`> ${s.renderedContract(automation.tests.rendered, ids(automation.criteria.rendered))}`,
|
|
66609
|
+
`> ${s.deterministicSignals(normativeSignals, automation.signals.decisive.length, automation.signals.candidate.length, automation.signals.advisory.length)}`,
|
|
66574
66610
|
`> ${s.judgmentContract(automation.tests.judgment, automation.criteria.judgment.length)}`
|
|
66575
66611
|
);
|
|
66576
66612
|
return out2;
|
|
@@ -66651,7 +66687,7 @@ function prComment(result, opts = {}) {
|
|
|
66651
66687
|
head.push(`### ${s.title} \u2014 ${stdLabel}`, "");
|
|
66652
66688
|
head.push(blocking ? s.verdictFail(blocking) : normative.length ? s.verdictWarn : s.verdictPass, "");
|
|
66653
66689
|
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), "");
|
|
66690
|
+
head.push(...runScopeLines(result, standard, lang, true), "");
|
|
66655
66691
|
if (coverage.agentRuled) head.push(`> ${agentMarkNote(lang)}`, "");
|
|
66656
66692
|
if (orphans) head.push(`> ${s.unattributed(orphans)}`, "");
|
|
66657
66693
|
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.
|
|
6
|
+
version: 5.37.1
|
|
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.
|
|
9
|
+
var VERSION = "5.37.1";
|
|
10
10
|
var SCHEMA_VERSION = 2;
|
|
11
11
|
var INAPPLICABLE_STATUS = "C";
|
|
12
12
|
|
|
@@ -56362,6 +56362,10 @@ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
|
56362
56362
|
import { join as join31 } from "path";
|
|
56363
56363
|
|
|
56364
56364
|
// src/standards/derive.ts
|
|
56365
|
+
function isProvisionalJudgmentInapplicable(result, criterion) {
|
|
56366
|
+
if (result.status !== INAPPLICABLE_STATUS || result.inapplicable !== true || result.decidedBy === "agent") return false;
|
|
56367
|
+
return Object.values(criterion?.automation?.tests ?? {}).includes("judgment");
|
|
56368
|
+
}
|
|
56365
56369
|
function aggregate2(results) {
|
|
56366
56370
|
if (results.some((r) => r.status === "NC")) return "NC";
|
|
56367
56371
|
if (results.some((r) => r.status === "C" && !r.inapplicable)) return "C";
|
|
@@ -57687,7 +57691,12 @@ function pageGridModel(result, derived, standard, lang) {
|
|
|
57687
57691
|
}
|
|
57688
57692
|
const pack = loadPack(standard);
|
|
57689
57693
|
const rows = pack.criteria.map((pc) => ({ id: pc.id, label: pc.id, group: `${pc.theme}. ${themeName(pack, pc.theme, lang) ?? ""}`.trim() }));
|
|
57690
|
-
for (const p of derived)
|
|
57694
|
+
for (const p of derived) {
|
|
57695
|
+
for (const pc of derivePackResults(pageView(result, p), standard, p.id)) {
|
|
57696
|
+
const criterion = pack.criteria.find((row) => row.id === pc.id);
|
|
57697
|
+
put(pc.id, p.id, isProvisionalJudgmentInapplicable(pc, criterion) ? "manual" : pc.status);
|
|
57698
|
+
}
|
|
57699
|
+
}
|
|
57691
57700
|
return { rows, status };
|
|
57692
57701
|
}
|
|
57693
57702
|
function renderRedirected(redirected, lang = "en") {
|
|
@@ -57857,15 +57866,19 @@ function pageCriterionRows(result, page, standard, lang) {
|
|
|
57857
57866
|
}
|
|
57858
57867
|
const pack = loadPack(standard);
|
|
57859
57868
|
const byId2 = new Map(derivePackResults(pageView(result, page), standard, page.id).map((r) => [r.id, r]));
|
|
57860
|
-
return pack.criteria.map((pc) =>
|
|
57861
|
-
|
|
57862
|
-
|
|
57863
|
-
|
|
57864
|
-
|
|
57865
|
-
|
|
57866
|
-
|
|
57867
|
-
|
|
57868
|
-
|
|
57869
|
+
return pack.criteria.map((pc) => {
|
|
57870
|
+
const result2 = byId2.get(pc.id);
|
|
57871
|
+
const provisionalNa = result2 ? isProvisionalJudgmentInapplicable(result2, pc) : false;
|
|
57872
|
+
return {
|
|
57873
|
+
id: pc.id,
|
|
57874
|
+
label: `${pc.id} \u2014 ${titlePlain(pack, pc, lang)}`,
|
|
57875
|
+
group: `${pc.theme}. ${themeName(pack, pc.theme, lang) ?? ""}`.trim(),
|
|
57876
|
+
status: provisionalNa ? "manual" : result2?.status ?? "manual",
|
|
57877
|
+
tests: packTestIds(pack, pc.id),
|
|
57878
|
+
decidedBy: result2?.decidedBy,
|
|
57879
|
+
...result2?.inapplicable && !provisionalNa ? { inapplicable: true } : {}
|
|
57880
|
+
};
|
|
57881
|
+
});
|
|
57869
57882
|
}
|
|
57870
57883
|
function pagesForStandard(result, pages, standard, lang) {
|
|
57871
57884
|
if (isCore(standard)) return pages;
|
|
@@ -58231,12 +58244,17 @@ function automationOverview(standard) {
|
|
|
58231
58244
|
const pack = loadPack(standard);
|
|
58232
58245
|
const tests = { static: 0, rendered: 0, judgment: 0 };
|
|
58233
58246
|
const criteria = { static: [], rendered: [], judgment: [] };
|
|
58247
|
+
const signals = { decisive: [], candidate: [], advisory: [] };
|
|
58234
58248
|
for (const criterion of pack.criteria) {
|
|
58235
58249
|
const tiers = Object.values(criterion.automation?.tests ?? {});
|
|
58236
58250
|
for (const tier of tiers) tests[tier]++;
|
|
58237
58251
|
for (const tier of ["static", "rendered", "judgment"]) if (tiers.includes(tier)) criteria[tier].push(criterion.id);
|
|
58252
|
+
const effects = new Set((criterion.automation?.rules ?? []).map((rule) => rule.effect));
|
|
58253
|
+
if (effects.has("decisive-nc")) signals.decisive.push(criterion.id);
|
|
58254
|
+
if (effects.has("candidate")) signals.candidate.push(criterion.id);
|
|
58255
|
+
if (effects.has("advisory")) signals.advisory.push(criterion.id);
|
|
58238
58256
|
}
|
|
58239
|
-
return { tests, criteria };
|
|
58257
|
+
return { tests, criteria, signals };
|
|
58240
58258
|
}
|
|
58241
58259
|
function automationCell(standard, id) {
|
|
58242
58260
|
if (isCore(standard)) return "\u2014";
|
|
@@ -58441,19 +58459,21 @@ function packReportGroups(r, pack, lang = "en") {
|
|
|
58441
58459
|
const derived = derivePackResults(r, pack.key);
|
|
58442
58460
|
const s = L5[lang];
|
|
58443
58461
|
const naReason = lang === "fr" ? "Rien de la nature de ce crit\xE8re n'est pr\xE9sent dans le p\xE9rim\xE8tre." : "Nothing of this criterion's kind is present in scope.";
|
|
58462
|
+
const provisionalNaReason = lang === "fr" ? "Aucun sujet d\xE9tect\xE9 par le moteur ; l'IA doit confirmer la non-applicabilit\xE9 de ce crit\xE8re de jugement." : "The engine detected no subject; the AI must confirm that this judgment criterion is not applicable.";
|
|
58444
58463
|
const byTheme = /* @__PURE__ */ new Map();
|
|
58445
58464
|
for (const pr of derived) {
|
|
58446
58465
|
const pc = pack.criteria.find((c2) => c2.id === pr.id);
|
|
58466
|
+
const provisionalNa = isProvisionalJudgmentInapplicable(pr, pc);
|
|
58447
58467
|
const row = {
|
|
58448
58468
|
id: pr.id,
|
|
58449
58469
|
label: `${pack.name} ${pr.id} \u2014 ${title(pack, pc, lang)}`,
|
|
58450
|
-
status: pr.status,
|
|
58470
|
+
status: provisionalNa ? "manual" : pr.status,
|
|
58451
58471
|
findings: pr.findings,
|
|
58452
58472
|
...pr.decidedBy ? { decidedBy: pr.decidedBy } : {},
|
|
58453
|
-
...pr.inapplicable ? { inapplicable: true } : {},
|
|
58473
|
+
...pr.inapplicable && !provisionalNa ? { inapplicable: true } : {},
|
|
58454
58474
|
// outOfScope / scopedOut criteria are "manual" with their own dedicated justification —
|
|
58455
58475
|
// never mixed with the "nothing of that kind here" reason (see the manual section above).
|
|
58456
|
-
...pr.outOfScope ? { justification: s.outOfScope } : pr.scopedOut ? { justification: s.scopedOut } : pr.judgment ? { justification: s.judgment } : pr.inapplicable ? { justification: naReason } : {}
|
|
58476
|
+
...provisionalNa ? { justification: provisionalNaReason } : pr.outOfScope ? { justification: s.outOfScope } : pr.scopedOut ? { justification: s.scopedOut } : pr.judgment ? { justification: s.judgment } : pr.inapplicable ? { justification: naReason } : {}
|
|
58457
58477
|
};
|
|
58458
58478
|
(byTheme.get(pr.theme) ?? byTheme.set(pr.theme, []).get(pr.theme)).push(row);
|
|
58459
58479
|
}
|
|
@@ -61330,8 +61350,7 @@ function subjectsForPackCriterion2(standard, id, scs) {
|
|
|
61330
61350
|
}
|
|
61331
61351
|
function packResultNeedsAdjudication(pc, criterion) {
|
|
61332
61352
|
if (pc.status === "manual") return true;
|
|
61333
|
-
|
|
61334
|
-
return pc.status === INAPPLICABLE_STATUS && pc.inapplicable === true && pc.decidedBy !== "agent" && hasJudgmentTest;
|
|
61353
|
+
return isProvisionalJudgmentInapplicable(pc, criterion);
|
|
61335
61354
|
}
|
|
61336
61355
|
function buildAdjudicationWorklist(audit2, opts = {}) {
|
|
61337
61356
|
const docs = docsForAudit(audit2, opts.cwd);
|
|
@@ -66404,9 +66423,11 @@ var S = {
|
|
|
66404
66423
|
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
66424
|
runScope: "P\xE9rim\xE8tre de ce run",
|
|
66406
66425
|
renderedActuallyTested: (n) => `${n} page(s) rendue(s) r\xE9ellement test\xE9e(s)`,
|
|
66426
|
+
testedPages: (pages, more) => `Pages test\xE9es : ${pages}${more ? ` \xB7 \u2026 +${more} dans l'artefact` : ""}`,
|
|
66407
66427
|
noRenderedExecuted: "0 page rendue : aucun test rendered n'a \xE9t\xE9 ex\xE9cut\xE9",
|
|
66408
66428
|
staticTested: (tests, ids) => `${tests} test(s) static \u2014 crit\xE8res : ${ids || "\u2014"}`,
|
|
66409
66429
|
renderedContract: (tests, ids) => `${tests} test(s) rendered pr\xE9vus \u2014 crit\xE8res : ${ids || "\u2014"}`,
|
|
66430
|
+
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
66431
|
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
66432
|
},
|
|
66412
66433
|
en: {
|
|
@@ -66480,9 +66501,11 @@ var S = {
|
|
|
66480
66501
|
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
66502
|
runScope: "Scope of this run",
|
|
66482
66503
|
renderedActuallyTested: (n) => `${n} rendered page(s) actually tested`,
|
|
66504
|
+
testedPages: (pages, more) => `Pages tested: ${pages}${more ? ` \xB7 \u2026 +${more} in the artifact` : ""}`,
|
|
66483
66505
|
noRenderedExecuted: "0 rendered pages: no rendered test was executed",
|
|
66484
66506
|
staticTested: (tests, ids) => `${tests} static test(s) \u2014 criteria: ${ids || "\u2014"}`,
|
|
66485
66507
|
renderedContract: (tests, ids) => `${tests} planned rendered test(s) \u2014 criteria: ${ids || "\u2014"}`,
|
|
66508
|
+
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
66509
|
judgmentContract: (tests, criteria) => `${tests} judgment test(s) across ${criteria} criterion(ia), all sent to AI while undecided`
|
|
66487
66510
|
}
|
|
66488
66511
|
};
|
|
@@ -66561,16 +66584,29 @@ function runCoverage(result, standard, lang) {
|
|
|
66561
66584
|
agentRuled
|
|
66562
66585
|
};
|
|
66563
66586
|
}
|
|
66564
|
-
function runScopeLines(result, standard, lang) {
|
|
66587
|
+
function runScopeLines(result, standard, lang, includePageNames = false) {
|
|
66565
66588
|
const s = S[lang];
|
|
66566
66589
|
const pages = result.scope.pagesAudited?.length ?? 0;
|
|
66567
66590
|
const out2 = [`> **${s.runScope}** \u2014 ${pages === 0 ? s.noRenderedExecuted : s.renderedActuallyTested(pages)}`];
|
|
66591
|
+
if (includePageNames && pages > 0) {
|
|
66592
|
+
const scope = pagesOf(result);
|
|
66593
|
+
const byId2 = new Map(scope.map((page) => [page.id, page]));
|
|
66594
|
+
const tested = (result.scope.pagesAudited ?? []).map((id) => byId2.get(id) ?? { id, name: id, url: "" });
|
|
66595
|
+
const shown = tested.slice(0, 12).map((page) => {
|
|
66596
|
+
const name2 = mdText(page.name || page.id);
|
|
66597
|
+
const url = page.url ? ` (\`${page.url.replace(/`/g, "%60")}\`)` : "";
|
|
66598
|
+
return `${name2}${url}`;
|
|
66599
|
+
});
|
|
66600
|
+
out2.push(`> ${s.testedPages(shown.join(" \xB7 "), tested.length - shown.length)}`);
|
|
66601
|
+
}
|
|
66568
66602
|
const automation = automationOverview(standard);
|
|
66569
66603
|
if (!automation) return out2;
|
|
66570
66604
|
const ids = (values) => values.map((id) => `\`${id}\``).join(" \xB7 ");
|
|
66605
|
+
const normativeSignals = (/* @__PURE__ */ new Set([...automation.signals.decisive, ...automation.signals.candidate])).size;
|
|
66571
66606
|
out2.push(
|
|
66572
66607
|
`> ${s.staticTested(automation.tests.static, ids(automation.criteria.static))}`,
|
|
66573
66608
|
`> ${s.renderedContract(automation.tests.rendered, ids(automation.criteria.rendered))}`,
|
|
66609
|
+
`> ${s.deterministicSignals(normativeSignals, automation.signals.decisive.length, automation.signals.candidate.length, automation.signals.advisory.length)}`,
|
|
66574
66610
|
`> ${s.judgmentContract(automation.tests.judgment, automation.criteria.judgment.length)}`
|
|
66575
66611
|
);
|
|
66576
66612
|
return out2;
|
|
@@ -66651,7 +66687,7 @@ function prComment(result, opts = {}) {
|
|
|
66651
66687
|
head.push(`### ${s.title} \u2014 ${stdLabel}`, "");
|
|
66652
66688
|
head.push(blocking ? s.verdictFail(blocking) : normative.length ? s.verdictWarn : s.verdictPass, "");
|
|
66653
66689
|
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), "");
|
|
66690
|
+
head.push(...runScopeLines(result, standard, lang, true), "");
|
|
66655
66691
|
if (coverage.agentRuled) head.push(`> ${agentMarkNote(lang)}`, "");
|
|
66656
66692
|
if (orphans) head.push(`> ${s.unattributed(orphans)}`, "");
|
|
66657
66693
|
const tail = [];
|
package/skills/ultra11y/SKILL.md
CHANGED
|
@@ -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.
|
|
6
|
+
version: 5.37.1
|
|
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.
|
|
9
|
+
var VERSION = "5.37.1";
|
|
10
10
|
var SCHEMA_VERSION = 2;
|
|
11
11
|
var INAPPLICABLE_STATUS = "C";
|
|
12
12
|
|
|
@@ -56362,6 +56362,10 @@ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
|
56362
56362
|
import { join as join31 } from "path";
|
|
56363
56363
|
|
|
56364
56364
|
// src/standards/derive.ts
|
|
56365
|
+
function isProvisionalJudgmentInapplicable(result, criterion) {
|
|
56366
|
+
if (result.status !== INAPPLICABLE_STATUS || result.inapplicable !== true || result.decidedBy === "agent") return false;
|
|
56367
|
+
return Object.values(criterion?.automation?.tests ?? {}).includes("judgment");
|
|
56368
|
+
}
|
|
56365
56369
|
function aggregate2(results) {
|
|
56366
56370
|
if (results.some((r) => r.status === "NC")) return "NC";
|
|
56367
56371
|
if (results.some((r) => r.status === "C" && !r.inapplicable)) return "C";
|
|
@@ -57687,7 +57691,12 @@ function pageGridModel(result, derived, standard, lang) {
|
|
|
57687
57691
|
}
|
|
57688
57692
|
const pack = loadPack(standard);
|
|
57689
57693
|
const rows = pack.criteria.map((pc) => ({ id: pc.id, label: pc.id, group: `${pc.theme}. ${themeName(pack, pc.theme, lang) ?? ""}`.trim() }));
|
|
57690
|
-
for (const p of derived)
|
|
57694
|
+
for (const p of derived) {
|
|
57695
|
+
for (const pc of derivePackResults(pageView(result, p), standard, p.id)) {
|
|
57696
|
+
const criterion = pack.criteria.find((row) => row.id === pc.id);
|
|
57697
|
+
put(pc.id, p.id, isProvisionalJudgmentInapplicable(pc, criterion) ? "manual" : pc.status);
|
|
57698
|
+
}
|
|
57699
|
+
}
|
|
57691
57700
|
return { rows, status };
|
|
57692
57701
|
}
|
|
57693
57702
|
function renderRedirected(redirected, lang = "en") {
|
|
@@ -57857,15 +57866,19 @@ function pageCriterionRows(result, page, standard, lang) {
|
|
|
57857
57866
|
}
|
|
57858
57867
|
const pack = loadPack(standard);
|
|
57859
57868
|
const byId2 = new Map(derivePackResults(pageView(result, page), standard, page.id).map((r) => [r.id, r]));
|
|
57860
|
-
return pack.criteria.map((pc) =>
|
|
57861
|
-
|
|
57862
|
-
|
|
57863
|
-
|
|
57864
|
-
|
|
57865
|
-
|
|
57866
|
-
|
|
57867
|
-
|
|
57868
|
-
|
|
57869
|
+
return pack.criteria.map((pc) => {
|
|
57870
|
+
const result2 = byId2.get(pc.id);
|
|
57871
|
+
const provisionalNa = result2 ? isProvisionalJudgmentInapplicable(result2, pc) : false;
|
|
57872
|
+
return {
|
|
57873
|
+
id: pc.id,
|
|
57874
|
+
label: `${pc.id} \u2014 ${titlePlain(pack, pc, lang)}`,
|
|
57875
|
+
group: `${pc.theme}. ${themeName(pack, pc.theme, lang) ?? ""}`.trim(),
|
|
57876
|
+
status: provisionalNa ? "manual" : result2?.status ?? "manual",
|
|
57877
|
+
tests: packTestIds(pack, pc.id),
|
|
57878
|
+
decidedBy: result2?.decidedBy,
|
|
57879
|
+
...result2?.inapplicable && !provisionalNa ? { inapplicable: true } : {}
|
|
57880
|
+
};
|
|
57881
|
+
});
|
|
57869
57882
|
}
|
|
57870
57883
|
function pagesForStandard(result, pages, standard, lang) {
|
|
57871
57884
|
if (isCore(standard)) return pages;
|
|
@@ -58231,12 +58244,17 @@ function automationOverview(standard) {
|
|
|
58231
58244
|
const pack = loadPack(standard);
|
|
58232
58245
|
const tests = { static: 0, rendered: 0, judgment: 0 };
|
|
58233
58246
|
const criteria = { static: [], rendered: [], judgment: [] };
|
|
58247
|
+
const signals = { decisive: [], candidate: [], advisory: [] };
|
|
58234
58248
|
for (const criterion of pack.criteria) {
|
|
58235
58249
|
const tiers = Object.values(criterion.automation?.tests ?? {});
|
|
58236
58250
|
for (const tier of tiers) tests[tier]++;
|
|
58237
58251
|
for (const tier of ["static", "rendered", "judgment"]) if (tiers.includes(tier)) criteria[tier].push(criterion.id);
|
|
58252
|
+
const effects = new Set((criterion.automation?.rules ?? []).map((rule) => rule.effect));
|
|
58253
|
+
if (effects.has("decisive-nc")) signals.decisive.push(criterion.id);
|
|
58254
|
+
if (effects.has("candidate")) signals.candidate.push(criterion.id);
|
|
58255
|
+
if (effects.has("advisory")) signals.advisory.push(criterion.id);
|
|
58238
58256
|
}
|
|
58239
|
-
return { tests, criteria };
|
|
58257
|
+
return { tests, criteria, signals };
|
|
58240
58258
|
}
|
|
58241
58259
|
function automationCell(standard, id) {
|
|
58242
58260
|
if (isCore(standard)) return "\u2014";
|
|
@@ -58441,19 +58459,21 @@ function packReportGroups(r, pack, lang = "en") {
|
|
|
58441
58459
|
const derived = derivePackResults(r, pack.key);
|
|
58442
58460
|
const s = L5[lang];
|
|
58443
58461
|
const naReason = lang === "fr" ? "Rien de la nature de ce crit\xE8re n'est pr\xE9sent dans le p\xE9rim\xE8tre." : "Nothing of this criterion's kind is present in scope.";
|
|
58462
|
+
const provisionalNaReason = lang === "fr" ? "Aucun sujet d\xE9tect\xE9 par le moteur ; l'IA doit confirmer la non-applicabilit\xE9 de ce crit\xE8re de jugement." : "The engine detected no subject; the AI must confirm that this judgment criterion is not applicable.";
|
|
58444
58463
|
const byTheme = /* @__PURE__ */ new Map();
|
|
58445
58464
|
for (const pr of derived) {
|
|
58446
58465
|
const pc = pack.criteria.find((c2) => c2.id === pr.id);
|
|
58466
|
+
const provisionalNa = isProvisionalJudgmentInapplicable(pr, pc);
|
|
58447
58467
|
const row = {
|
|
58448
58468
|
id: pr.id,
|
|
58449
58469
|
label: `${pack.name} ${pr.id} \u2014 ${title(pack, pc, lang)}`,
|
|
58450
|
-
status: pr.status,
|
|
58470
|
+
status: provisionalNa ? "manual" : pr.status,
|
|
58451
58471
|
findings: pr.findings,
|
|
58452
58472
|
...pr.decidedBy ? { decidedBy: pr.decidedBy } : {},
|
|
58453
|
-
...pr.inapplicable ? { inapplicable: true } : {},
|
|
58473
|
+
...pr.inapplicable && !provisionalNa ? { inapplicable: true } : {},
|
|
58454
58474
|
// outOfScope / scopedOut criteria are "manual" with their own dedicated justification —
|
|
58455
58475
|
// never mixed with the "nothing of that kind here" reason (see the manual section above).
|
|
58456
|
-
...pr.outOfScope ? { justification: s.outOfScope } : pr.scopedOut ? { justification: s.scopedOut } : pr.judgment ? { justification: s.judgment } : pr.inapplicable ? { justification: naReason } : {}
|
|
58476
|
+
...provisionalNa ? { justification: provisionalNaReason } : pr.outOfScope ? { justification: s.outOfScope } : pr.scopedOut ? { justification: s.scopedOut } : pr.judgment ? { justification: s.judgment } : pr.inapplicable ? { justification: naReason } : {}
|
|
58457
58477
|
};
|
|
58458
58478
|
(byTheme.get(pr.theme) ?? byTheme.set(pr.theme, []).get(pr.theme)).push(row);
|
|
58459
58479
|
}
|
|
@@ -61330,8 +61350,7 @@ function subjectsForPackCriterion2(standard, id, scs) {
|
|
|
61330
61350
|
}
|
|
61331
61351
|
function packResultNeedsAdjudication(pc, criterion) {
|
|
61332
61352
|
if (pc.status === "manual") return true;
|
|
61333
|
-
|
|
61334
|
-
return pc.status === INAPPLICABLE_STATUS && pc.inapplicable === true && pc.decidedBy !== "agent" && hasJudgmentTest;
|
|
61353
|
+
return isProvisionalJudgmentInapplicable(pc, criterion);
|
|
61335
61354
|
}
|
|
61336
61355
|
function buildAdjudicationWorklist(audit2, opts = {}) {
|
|
61337
61356
|
const docs = docsForAudit(audit2, opts.cwd);
|
|
@@ -66404,9 +66423,11 @@ var S = {
|
|
|
66404
66423
|
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
66424
|
runScope: "P\xE9rim\xE8tre de ce run",
|
|
66406
66425
|
renderedActuallyTested: (n) => `${n} page(s) rendue(s) r\xE9ellement test\xE9e(s)`,
|
|
66426
|
+
testedPages: (pages, more) => `Pages test\xE9es : ${pages}${more ? ` \xB7 \u2026 +${more} dans l'artefact` : ""}`,
|
|
66407
66427
|
noRenderedExecuted: "0 page rendue : aucun test rendered n'a \xE9t\xE9 ex\xE9cut\xE9",
|
|
66408
66428
|
staticTested: (tests, ids) => `${tests} test(s) static \u2014 crit\xE8res : ${ids || "\u2014"}`,
|
|
66409
66429
|
renderedContract: (tests, ids) => `${tests} test(s) rendered pr\xE9vus \u2014 crit\xE8res : ${ids || "\u2014"}`,
|
|
66430
|
+
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
66431
|
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
66432
|
},
|
|
66412
66433
|
en: {
|
|
@@ -66480,9 +66501,11 @@ var S = {
|
|
|
66480
66501
|
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
66502
|
runScope: "Scope of this run",
|
|
66482
66503
|
renderedActuallyTested: (n) => `${n} rendered page(s) actually tested`,
|
|
66504
|
+
testedPages: (pages, more) => `Pages tested: ${pages}${more ? ` \xB7 \u2026 +${more} in the artifact` : ""}`,
|
|
66483
66505
|
noRenderedExecuted: "0 rendered pages: no rendered test was executed",
|
|
66484
66506
|
staticTested: (tests, ids) => `${tests} static test(s) \u2014 criteria: ${ids || "\u2014"}`,
|
|
66485
66507
|
renderedContract: (tests, ids) => `${tests} planned rendered test(s) \u2014 criteria: ${ids || "\u2014"}`,
|
|
66508
|
+
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
66509
|
judgmentContract: (tests, criteria) => `${tests} judgment test(s) across ${criteria} criterion(ia), all sent to AI while undecided`
|
|
66487
66510
|
}
|
|
66488
66511
|
};
|
|
@@ -66561,16 +66584,29 @@ function runCoverage(result, standard, lang) {
|
|
|
66561
66584
|
agentRuled
|
|
66562
66585
|
};
|
|
66563
66586
|
}
|
|
66564
|
-
function runScopeLines(result, standard, lang) {
|
|
66587
|
+
function runScopeLines(result, standard, lang, includePageNames = false) {
|
|
66565
66588
|
const s = S[lang];
|
|
66566
66589
|
const pages = result.scope.pagesAudited?.length ?? 0;
|
|
66567
66590
|
const out2 = [`> **${s.runScope}** \u2014 ${pages === 0 ? s.noRenderedExecuted : s.renderedActuallyTested(pages)}`];
|
|
66591
|
+
if (includePageNames && pages > 0) {
|
|
66592
|
+
const scope = pagesOf(result);
|
|
66593
|
+
const byId2 = new Map(scope.map((page) => [page.id, page]));
|
|
66594
|
+
const tested = (result.scope.pagesAudited ?? []).map((id) => byId2.get(id) ?? { id, name: id, url: "" });
|
|
66595
|
+
const shown = tested.slice(0, 12).map((page) => {
|
|
66596
|
+
const name2 = mdText(page.name || page.id);
|
|
66597
|
+
const url = page.url ? ` (\`${page.url.replace(/`/g, "%60")}\`)` : "";
|
|
66598
|
+
return `${name2}${url}`;
|
|
66599
|
+
});
|
|
66600
|
+
out2.push(`> ${s.testedPages(shown.join(" \xB7 "), tested.length - shown.length)}`);
|
|
66601
|
+
}
|
|
66568
66602
|
const automation = automationOverview(standard);
|
|
66569
66603
|
if (!automation) return out2;
|
|
66570
66604
|
const ids = (values) => values.map((id) => `\`${id}\``).join(" \xB7 ");
|
|
66605
|
+
const normativeSignals = (/* @__PURE__ */ new Set([...automation.signals.decisive, ...automation.signals.candidate])).size;
|
|
66571
66606
|
out2.push(
|
|
66572
66607
|
`> ${s.staticTested(automation.tests.static, ids(automation.criteria.static))}`,
|
|
66573
66608
|
`> ${s.renderedContract(automation.tests.rendered, ids(automation.criteria.rendered))}`,
|
|
66609
|
+
`> ${s.deterministicSignals(normativeSignals, automation.signals.decisive.length, automation.signals.candidate.length, automation.signals.advisory.length)}`,
|
|
66574
66610
|
`> ${s.judgmentContract(automation.tests.judgment, automation.criteria.judgment.length)}`
|
|
66575
66611
|
);
|
|
66576
66612
|
return out2;
|
|
@@ -66651,7 +66687,7 @@ function prComment(result, opts = {}) {
|
|
|
66651
66687
|
head.push(`### ${s.title} \u2014 ${stdLabel}`, "");
|
|
66652
66688
|
head.push(blocking ? s.verdictFail(blocking) : normative.length ? s.verdictWarn : s.verdictPass, "");
|
|
66653
66689
|
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), "");
|
|
66690
|
+
head.push(...runScopeLines(result, standard, lang, true), "");
|
|
66655
66691
|
if (coverage.agentRuled) head.push(`> ${agentMarkNote(lang)}`, "");
|
|
66656
66692
|
if (orphans) head.push(`> ${s.unattributed(orphans)}`, "");
|
|
66657
66693
|
const tail = [];
|
package/src/adjudicate.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
hasId,
|
|
32
32
|
getCriterion,
|
|
33
33
|
derivePackResults,
|
|
34
|
+
isProvisionalJudgmentInapplicable,
|
|
34
35
|
criterionUrl,
|
|
35
36
|
glossaryAnchorsOf,
|
|
36
37
|
localize,
|
|
@@ -408,8 +409,7 @@ function subjectsForPackCriterion(standard: StandardId, id: string, scs: string[
|
|
|
408
409
|
* particular cases. A prior agent decision is never reopened. */
|
|
409
410
|
function packResultNeedsAdjudication(pc: ReturnType<typeof derivePackResults>[number], criterion?: PackCriterion): boolean {
|
|
410
411
|
if (pc.status === "manual") return true;
|
|
411
|
-
|
|
412
|
-
return pc.status === INAPPLICABLE_STATUS && pc.inapplicable === true && pc.decidedBy !== "agent" && hasJudgmentTest;
|
|
412
|
+
return isProvisionalJudgmentInapplicable(pc, criterion);
|
|
413
413
|
}
|
|
414
414
|
|
|
415
415
|
/** Build the adjudication worklist.
|
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/pages-report.ts
CHANGED
|
@@ -26,7 +26,17 @@
|
|
|
26
26
|
import { prdUnits } from "./prd.js";
|
|
27
27
|
import { renderAuditorUnit, type AuditorCropLookup } from "./auditor.js";
|
|
28
28
|
import { agentMarkNote, basisLabel, formatRate, pageView, unattributedFindings } from "./pages.js";
|
|
29
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
CORE,
|
|
31
|
+
type StandardId,
|
|
32
|
+
derivePackResults,
|
|
33
|
+
isCore,
|
|
34
|
+
isProvisionalJudgmentInapplicable,
|
|
35
|
+
loadPack,
|
|
36
|
+
packTestIds,
|
|
37
|
+
themeName,
|
|
38
|
+
titlePlain,
|
|
39
|
+
} from "./standards/index.js";
|
|
30
40
|
import type { AuditResult, Lang, PageResult, Status } from "./types.js";
|
|
31
41
|
import { compareSC, scTitle } from "./wcag.js";
|
|
32
42
|
|
|
@@ -202,15 +212,19 @@ export function pageCriterionRows(result: AuditResult, page: PageResult, standar
|
|
|
202
212
|
}
|
|
203
213
|
const pack = loadPack(standard);
|
|
204
214
|
const byId = new Map(derivePackResults(pageView(result, page), standard, page.id).map((r) => [r.id, r]));
|
|
205
|
-
return pack.criteria.map((pc) =>
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
215
|
+
return pack.criteria.map((pc) => {
|
|
216
|
+
const result = byId.get(pc.id);
|
|
217
|
+
const provisionalNa = result ? isProvisionalJudgmentInapplicable(result, pc) : false;
|
|
218
|
+
return {
|
|
219
|
+
id: pc.id,
|
|
220
|
+
label: `${pc.id} — ${titlePlain(pack, pc, lang)}`,
|
|
221
|
+
group: `${pc.theme}. ${themeName(pack, pc.theme, lang) ?? ""}`.trim(),
|
|
222
|
+
status: provisionalNa ? ("manual" as const) : (result?.status ?? "manual"),
|
|
223
|
+
tests: packTestIds(pack, pc.id),
|
|
224
|
+
decidedBy: result?.decidedBy,
|
|
225
|
+
...(result?.inapplicable && !provisionalNa ? { inapplicable: true } : {}),
|
|
226
|
+
};
|
|
227
|
+
});
|
|
214
228
|
}
|
|
215
229
|
|
|
216
230
|
/** The pages, PROJECTED ONTO THE ACTIVE STANDARD — criteria, coverage and rate.
|
package/src/pages.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
// on that criterion. Reading it as `C` on every other page is how a page with no images
|
|
23
23
|
// scored 100% on "does each image have a relevant alternative?". See `pageStatus`.
|
|
24
24
|
import { snapshotPageId } from "./snapshot.js";
|
|
25
|
-
import { CORE, type StandardId, derivePackResults, isCore, loadPack, themeName } from "./standards/index.js";
|
|
25
|
+
import { CORE, type StandardId, derivePackResults, isCore, isProvisionalJudgmentInapplicable, loadPack, themeName } from "./standards/index.js";
|
|
26
26
|
import type { AuditResult, CriterionResult, Finding, Lang, PageCoverage, PageResult, PageScope, Status, ScanRedirect } from "./types.js";
|
|
27
27
|
import { renderedProvesOn } from "./coverage.js";
|
|
28
28
|
import { renderedRulesFor } from "./rules/rendered.js";
|
|
@@ -526,7 +526,12 @@ export function pageGridModel(result: AuditResult, derived: PageResult[], standa
|
|
|
526
526
|
|
|
527
527
|
const pack = loadPack(standard);
|
|
528
528
|
const rows = pack.criteria.map((pc) => ({ id: pc.id, label: pc.id, group: `${pc.theme}. ${themeName(pack, pc.theme, lang) ?? ""}`.trim() }));
|
|
529
|
-
for (const p of derived)
|
|
529
|
+
for (const p of derived) {
|
|
530
|
+
for (const pc of derivePackResults(pageView(result, p), standard, p.id)) {
|
|
531
|
+
const criterion = pack.criteria.find((row) => row.id === pc.id);
|
|
532
|
+
put(pc.id, p.id, isProvisionalJudgmentInapplicable(pc, criterion) ? "manual" : pc.status);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
530
535
|
return { rows, status };
|
|
531
536
|
}
|
|
532
537
|
|
package/src/report.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
isCore,
|
|
22
22
|
loadPack,
|
|
23
23
|
derivePackResults,
|
|
24
|
+
isProvisionalJudgmentInapplicable,
|
|
24
25
|
packCriteriaForFinding,
|
|
25
26
|
packConformancePct,
|
|
26
27
|
packTestIds,
|
|
@@ -358,6 +359,7 @@ export function reportCoverage(groups: ReportGroup[]): { decided: number; total:
|
|
|
358
359
|
export interface AutomationOverview {
|
|
359
360
|
tests: { static: number; rendered: number; judgment: number };
|
|
360
361
|
criteria: { static: string[]; rendered: string[]; judgment: string[] };
|
|
362
|
+
signals: { decisive: string[]; candidate: string[]; advisory: string[] };
|
|
361
363
|
}
|
|
362
364
|
|
|
363
365
|
/** The standard's declared test-level contract. This is a plan, not runtime coverage: the
|
|
@@ -368,12 +370,17 @@ export function automationOverview(standard: StandardId): AutomationOverview | u
|
|
|
368
370
|
const pack = loadPack(standard);
|
|
369
371
|
const tests = { static: 0, rendered: 0, judgment: 0 };
|
|
370
372
|
const criteria = { static: [] as string[], rendered: [] as string[], judgment: [] as string[] };
|
|
373
|
+
const signals = { decisive: [] as string[], candidate: [] as string[], advisory: [] as string[] };
|
|
371
374
|
for (const criterion of pack.criteria) {
|
|
372
375
|
const tiers = Object.values(criterion.automation?.tests ?? {});
|
|
373
376
|
for (const tier of tiers) tests[tier]++;
|
|
374
377
|
for (const tier of ["static", "rendered", "judgment"] as const) if (tiers.includes(tier)) criteria[tier].push(criterion.id);
|
|
378
|
+
const effects = new Set((criterion.automation?.rules ?? []).map((rule) => rule.effect));
|
|
379
|
+
if (effects.has("decisive-nc")) signals.decisive.push(criterion.id);
|
|
380
|
+
if (effects.has("candidate")) signals.candidate.push(criterion.id);
|
|
381
|
+
if (effects.has("advisory")) signals.advisory.push(criterion.id);
|
|
375
382
|
}
|
|
376
|
-
return { tests, criteria };
|
|
383
|
+
return { tests, criteria, signals };
|
|
377
384
|
}
|
|
378
385
|
|
|
379
386
|
function automationCell(standard: StandardId, id: string): string {
|
|
@@ -782,27 +789,34 @@ export function packReportGroups(r: AuditResult, pack: StandardPack, lang: Lang
|
|
|
782
789
|
const derived = derivePackResults(r, pack.key);
|
|
783
790
|
const s = L[lang];
|
|
784
791
|
const naReason = lang === "fr" ? "Rien de la nature de ce critère n'est présent dans le périmètre." : "Nothing of this criterion's kind is present in scope.";
|
|
792
|
+
const provisionalNaReason =
|
|
793
|
+
lang === "fr"
|
|
794
|
+
? "Aucun sujet détecté par le moteur ; l'IA doit confirmer la non-applicabilité de ce critère de jugement."
|
|
795
|
+
: "The engine detected no subject; the AI must confirm that this judgment criterion is not applicable.";
|
|
785
796
|
const byTheme = new Map<number, ReportRow[]>();
|
|
786
797
|
for (const pr of derived) {
|
|
787
798
|
const pc = pack.criteria.find((c) => c.id === pr.id)!;
|
|
799
|
+
const provisionalNa = isProvisionalJudgmentInapplicable(pr, pc);
|
|
788
800
|
const row: ReportRow = {
|
|
789
801
|
id: pr.id,
|
|
790
802
|
label: `${pack.name} ${pr.id} — ${packTitle(pack, pc, lang)}`,
|
|
791
|
-
status: pr.status,
|
|
803
|
+
status: provisionalNa ? "manual" : pr.status,
|
|
792
804
|
findings: pr.findings,
|
|
793
805
|
...(pr.decidedBy ? { decidedBy: pr.decidedBy } : {}),
|
|
794
|
-
...(pr.inapplicable ? { inapplicable: true } : {}),
|
|
806
|
+
...(pr.inapplicable && !provisionalNa ? { inapplicable: true } : {}),
|
|
795
807
|
// outOfScope / scopedOut criteria are "manual" with their own dedicated justification —
|
|
796
808
|
// never mixed with the "nothing of that kind here" reason (see the manual section above).
|
|
797
|
-
...(
|
|
798
|
-
? { justification:
|
|
799
|
-
: pr.
|
|
800
|
-
? { justification: s.
|
|
801
|
-
: pr.
|
|
802
|
-
? { justification: s.
|
|
803
|
-
: pr.
|
|
804
|
-
? { justification:
|
|
805
|
-
:
|
|
809
|
+
...(provisionalNa
|
|
810
|
+
? { justification: provisionalNaReason }
|
|
811
|
+
: pr.outOfScope
|
|
812
|
+
? { justification: s.outOfScope }
|
|
813
|
+
: pr.scopedOut
|
|
814
|
+
? { justification: s.scopedOut }
|
|
815
|
+
: pr.judgment
|
|
816
|
+
? { justification: s.judgment }
|
|
817
|
+
: pr.inapplicable
|
|
818
|
+
? { justification: naReason }
|
|
819
|
+
: {}),
|
|
806
820
|
};
|
|
807
821
|
(byTheme.get(pr.theme) ?? byTheme.set(pr.theme, []).get(pr.theme)!).push(row);
|
|
808
822
|
}
|
package/src/standards/derive.ts
CHANGED
|
@@ -45,6 +45,17 @@ export interface PackCriterionResult {
|
|
|
45
45
|
inapplicable?: boolean;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/** Whether subject harvesting only PROVISIONALLY closed a judgment criterion.
|
|
49
|
+
*
|
|
50
|
+
* The absence is useful evidence for the adjudicator, but it is not a published verdict:
|
|
51
|
+
* every official `judgment` test still has to pass through the agent. Keep the raw derived
|
|
52
|
+
* result intact for that worklist, while report/page projections use this predicate to show
|
|
53
|
+
* the row as open until an agent has confirmed `NA`. */
|
|
54
|
+
export function isProvisionalJudgmentInapplicable(result: PackCriterionResult, criterion?: PackCriterion): boolean {
|
|
55
|
+
if (result.status !== INAPPLICABLE_STATUS || result.inapplicable !== true || result.decidedBy === "agent") return false;
|
|
56
|
+
return Object.values(criterion?.automation?.tests ?? {}).includes("judgment");
|
|
57
|
+
}
|
|
58
|
+
|
|
48
59
|
// NC dominates (a real failure anywhere fails the criterion); then a decided C; then
|
|
49
60
|
// manual (residual); else nothing of that kind exists here. Mirrors the core's aggregation.
|
|
50
61
|
//
|
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.
|
|
3
|
+
export const VERSION = "5.37.1";
|
|
4
4
|
export const SCHEMA_VERSION = 2;
|
|
5
5
|
|
|
6
6
|
// Lang = the UI FRAME's language — the `L` localization tables each module (report,
|