ultra11y 5.43.4 → 5.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.opencode/plugins/ultra11y.js +1 -1
- package/README.md +1 -1
- package/package.json +1 -1
- package/scripts/ultra11y.mjs +23 -13
- package/skills/review-a11y/SKILL.md +1 -1
- package/skills/review-a11y/scripts/ultra11y.mjs +23 -13
- package/skills/ultra11y/SKILL.md +1 -1
- package/skills/ultra11y/references/dynamic.md +2 -1
- package/skills/ultra11y/references/orchestrators.md +4 -3
- package/skills/ultra11y/references/verify.md +3 -0
- package/skills/ultra11y/scripts/ultra11y.mjs +23 -13
- package/skills/ultra11y/templates/gitlab-ci.yml +1 -1
- package/src/cli.ts +16 -5
- package/src/pages-report.ts +3 -2
- package/src/report.ts +6 -3
- package/src/standards/derive.ts +7 -1
- package/src/standards/document.ts +1 -1
- package/src/types.ts +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"name": "ultra11y",
|
|
11
11
|
"source": "./",
|
|
12
12
|
"description": "Automatic accessibility review before commit, push and pull request, plus detailed evidenced Markdown, HTML and per-page WCAG 2.2 AA / RGAA reports in Claude Code.",
|
|
13
|
-
"version": "5.
|
|
13
|
+
"version": "5.44.0",
|
|
14
14
|
"author": { "name": "maxgfr" },
|
|
15
15
|
"homepage": "https://github.com/SocialGouv/ultra11y",
|
|
16
16
|
"repository": "https://github.com/SocialGouv/ultra11y",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra11y",
|
|
3
3
|
"description": "Accessibility for WCAG 2.2 AA and country standards (RGAA…): automatic review before commit, push and pull request, plus detailed evidenced Markdown, HTML and per-page conformance reports in interactive agent sessions.",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.44.0",
|
|
5
5
|
"author": { "name": "maxgfr" },
|
|
6
6
|
"homepage": "https://github.com/SocialGouv/ultra11y",
|
|
7
7
|
"repository": "https://github.com/SocialGouv/ultra11y",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra11y",
|
|
3
3
|
"description": "Accessibility for WCAG 2.2 AA and country standards (RGAA…): automatic review before commit, push and pull request, plus detailed evidenced Markdown, HTML and per-page conformance reports in interactive agent sessions.",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.44.0",
|
|
5
5
|
"author": { "name": "maxgfr", "url": "https://github.com/maxgfr" },
|
|
6
6
|
"homepage": "https://github.com/SocialGouv/ultra11y",
|
|
7
7
|
"repository": "https://github.com/SocialGouv/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.44.0";
|
|
31
31
|
|
|
32
32
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
33
33
|
|
package/README.md
CHANGED
|
@@ -160,7 +160,7 @@ ultra11y verify --report <md> [--conformities <ledger|adjudication.json> | --n
|
|
|
160
160
|
ultra11y fix <globs… | -> [--write] [--iterate] [--changed | --since <ref> | --staged] [--safe] [--only <ids>] [--jsx] [--json]
|
|
161
161
|
ultra11y init [--hook] [--ci] [--baseline] [--fail-on blocking|major|minor]
|
|
162
162
|
ultra11y pack check <pack.json> [--guidance <g.json>] | scaffold # gate an (AI-)authored standards pack
|
|
163
|
-
ultra11y scan <url|file…> [--runtime auto|local|docker] [--cwd <dir>] [--storage-state <file>] [--merge <audit.json>] [--out <dir>] [--json]
|
|
163
|
+
ultra11y scan <url|file…> [--runtime auto|local|docker] [--cwd <dir>] [--root <dir>] [--storage-state <file>] [--merge <audit.json>] [--out <dir>] [--json]
|
|
164
164
|
ultra11y scan --sitemap <url> | --crawl <url> [--depth <n>] [--max <n>] [--runtime …] [--merge <audit.json>] [--json]
|
|
165
165
|
ultra11y mcp [--transport stdio|http] [--cwd <dir>] [--allow-write] [--port <n>] [--bind <addr>] [--allow-remote]
|
|
166
166
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra11y",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.44.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",
|
package/scripts/ultra11y.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { join as join52, relative as relative6, resolve as resolve17, 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.44.0";
|
|
10
10
|
var SCHEMA_VERSION = 2;
|
|
11
11
|
var INAPPLICABLE_STATUS = "C";
|
|
12
12
|
|
|
@@ -58325,8 +58325,9 @@ function derivePackResults(audit2, packKey, pageId) {
|
|
|
58325
58325
|
const measured = measuredRescue(derived, pc, cov, ran, pageId);
|
|
58326
58326
|
const decided = adjudicated?.get(pc.id);
|
|
58327
58327
|
if (decided?.status === "manual") {
|
|
58328
|
+
const { inapplicable: _absence, ...open } = measured;
|
|
58328
58329
|
return {
|
|
58329
|
-
...
|
|
58330
|
+
...open,
|
|
58330
58331
|
status: measured.status === "NC" ? "NC" : "manual",
|
|
58331
58332
|
...decided.justification ? { justification: decided.justification } : {},
|
|
58332
58333
|
decidedBy: "agent"
|
|
@@ -59853,8 +59854,9 @@ function pageTally(rows) {
|
|
|
59853
59854
|
c: rows.filter((r) => r.status === "C").length,
|
|
59854
59855
|
nc: rows.filter((r) => r.status === "NC").length,
|
|
59855
59856
|
// No row carries `NA` any more (INAPPLICABLE_STATUS); this counts the conformities
|
|
59856
|
-
// reached for want of a subject, and it is a SUBSET of `c` rather than a fourth bucket
|
|
59857
|
-
|
|
59857
|
+
// reached for want of a subject, and it is a SUBSET of `c` rather than a fourth bucket
|
|
59858
|
+
// (same predicate as src/report.ts tallyRows).
|
|
59859
|
+
na: rows.filter((r) => r.status === "C" && r.inapplicable).length,
|
|
59858
59860
|
manual: rows.filter((r) => r.status === "manual").length
|
|
59859
59861
|
};
|
|
59860
59862
|
}
|
|
@@ -60402,7 +60404,9 @@ function tallyRows(rows) {
|
|
|
60402
60404
|
return {
|
|
60403
60405
|
c: rows.filter((x) => x.status === "C").length,
|
|
60404
60406
|
nc: rows.filter((x) => x.status === "NC").length,
|
|
60405
|
-
|
|
60407
|
+
// NA within C, structurally: a row that carried `inapplicable` under another status (a
|
|
60408
|
+
// criterion that stayed open, say) must not be counted in both columns.
|
|
60409
|
+
na: rows.filter((x) => x.status === "C" && x.inapplicable).length,
|
|
60406
60410
|
manual: rows.filter((x) => x.status === "manual").length
|
|
60407
60411
|
};
|
|
60408
60412
|
}
|
|
@@ -60905,7 +60909,7 @@ function render(r, lang, opts) {
|
|
|
60905
60909
|
}
|
|
60906
60910
|
}
|
|
60907
60911
|
out2.push(`## ${s.naTitle}`, "");
|
|
60908
|
-
const na = rows.filter((x) => x.inapplicable);
|
|
60912
|
+
const na = rows.filter((x) => x.status === "C" && x.inapplicable);
|
|
60909
60913
|
if (!na.length) out2.push(s.nothing, "");
|
|
60910
60914
|
else {
|
|
60911
60915
|
out2.push(`> ${s.naNote}`, "");
|
|
@@ -68865,7 +68869,7 @@ function packAuditDocument(input, packKey, lang) {
|
|
|
68865
68869
|
// worse than either being wrong.
|
|
68866
68870
|
c: rows.filter((r) => r.status === "C").length,
|
|
68867
68871
|
nc: rows.filter((r) => r.status === "NC").length,
|
|
68868
|
-
na: rows.filter((r) => r.inapplicable).length,
|
|
68872
|
+
na: rows.filter((r) => r.status === "C" && r.inapplicable).length,
|
|
68869
68873
|
manual: rows.filter((r) => r.status === "manual").length
|
|
68870
68874
|
};
|
|
68871
68875
|
});
|
|
@@ -74156,9 +74160,9 @@ Usage:
|
|
|
74156
74160
|
ultra11y init [--hook] [--ci] [--baseline] [--fail-on blocking|major|minor]
|
|
74157
74161
|
ultra11y judge --in <audit.json> [--standard <pack>] [--runner api|claude|codex] [--grain batch|criterion] [--max <n>] [--model <id>] [--effort <level>] [--max-budget-usd <n>] [--timeout <s>] [--out <dir>] [--apply] (adjudicate manual criteria \u2014 api needs ANTHROPIC_API_KEY; claude/codex reuse their CLI login; cli aliases claude)
|
|
74158
74162
|
ultra11y pack check <pack.json> [--guidance <g.json>] [--json] | pack scaffold
|
|
74159
|
-
ultra11y scan <url|file\u2026> [--runtime auto|local|docker] [--cwd <dir>] [--storage-state <file>] [--no-interact] [--interact-clicks] [--no-snapshot] [--merge <audit.json>] [--out <dir>] [--json]
|
|
74160
|
-
ultra11y scan --sample [--runtime \u2026] [--cwd <dir>] [--storage-state <file>] [--merge <audit.json>] [--json] (scan the .ultra11yrc.json page sample)
|
|
74161
|
-
ultra11y scan --sitemap <url> | --crawl <url> [--depth <n>] [--max <n>] [--runtime \u2026] [--cwd <dir>] [--merge <audit.json>] [--json]
|
|
74163
|
+
ultra11y scan <url|file\u2026> [--runtime auto|local|docker] [--cwd <dir>] [--root <dir>] [--storage-state <file>] [--no-interact] [--interact-clicks] [--no-snapshot] [--merge <audit.json>] [--out <dir>] [--json]
|
|
74164
|
+
ultra11y scan --sample [--runtime \u2026] [--cwd <dir>] [--root <dir>] [--storage-state <file>] [--merge <audit.json>] [--json] (scan the .ultra11yrc.json page sample)
|
|
74165
|
+
ultra11y scan --sitemap <url> | --crawl <url> [--depth <n>] [--max <n>] [--runtime \u2026] [--cwd <dir>] [--root <dir>] [--merge <audit.json>] [--json]
|
|
74162
74166
|
ultra11y scan --clean (remove the dynamic-tier Docker image + temp contexts)
|
|
74163
74167
|
ultra11y sample check [--standard <pack>] [--json] (lint the .ultra11yrc.json page sample vs the standard's required page kinds)
|
|
74164
74168
|
ultra11y snapshot write [--root <dir>] [--fail-on blocking|major|minor] [--json] (payload on stdin \u2192 .ultra11y/pages/<id>/ + audit it)
|
|
@@ -74402,7 +74406,8 @@ Options:
|
|
|
74402
74406
|
--no-captures audit: do NOT auto-detect/ingest .ultra11y/captures nor .ultra11y/pages
|
|
74403
74407
|
--e2e render: write the Playwright/Cypress fixtures into .ultra11y/e2e/
|
|
74404
74408
|
--runner <name> render --e2e: force playwright|cypress instead of auto-detecting
|
|
74405
|
-
--root <dir> snapshot: project root holding .ultra11y/pages (default: .
|
|
74409
|
+
--root <dir> snapshot, scan: project root holding .ultra11y/pages (default: . \u2014
|
|
74410
|
+
scan writes the snapshots it collects under it)
|
|
74406
74411
|
--port <n> dev: port for the side-car (default: 4111); mcp: HTTP transport port
|
|
74407
74412
|
--transport <k> mcp: stdio (default) or http
|
|
74408
74413
|
--bind <addr> mcp --transport http: address to bind (default 127.0.0.1)
|
|
@@ -77027,6 +77032,10 @@ Iterated over ${rounds} round(s) to a fixpoint \u2014 ${totalWritten} file(s) wr
|
|
|
77027
77032
|
}
|
|
77028
77033
|
return 0;
|
|
77029
77034
|
}
|
|
77035
|
+
function scanSnapshotRoot(flags2) {
|
|
77036
|
+
if (flags2["no-snapshot"] === true) return void 0;
|
|
77037
|
+
return typeof flags2.root === "string" && flags2.root ? resolve17(flags2.root) : process.cwd();
|
|
77038
|
+
}
|
|
77030
77039
|
async function cmdScan(p) {
|
|
77031
77040
|
const standard = stdOf(p, "scan");
|
|
77032
77041
|
if (standard === null) return 2;
|
|
@@ -77079,7 +77088,7 @@ async function cmdScan(p) {
|
|
|
77079
77088
|
const interactClicks = p.flags["interact-clicks"] === true;
|
|
77080
77089
|
const sitemap = typeof p.flags.sitemap === "string" ? p.flags.sitemap : void 0;
|
|
77081
77090
|
const crawl = typeof p.flags.crawl === "string" ? p.flags.crawl : void 0;
|
|
77082
|
-
const snapshotRoot = p.flags
|
|
77091
|
+
const snapshotRoot = scanSnapshotRoot(p.flags);
|
|
77083
77092
|
const useSample = p.flags.sample === true;
|
|
77084
77093
|
let sampleConfig;
|
|
77085
77094
|
if (useSample) {
|
|
@@ -77764,6 +77773,7 @@ export {
|
|
|
77764
77773
|
COMMANDS,
|
|
77765
77774
|
REMOVED_FLAGS,
|
|
77766
77775
|
main,
|
|
77767
|
-
parseArgs
|
|
77776
|
+
parseArgs,
|
|
77777
|
+
scanSnapshotRoot
|
|
77768
77778
|
};
|
|
77769
77779
|
// "Copyright" and "@license" are already caught by DIRECTIVE_RE.
|
|
@@ -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.44.0
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# review-a11y — accessibility review of changed code
|
|
@@ -6,7 +6,7 @@ import { join as join52, relative as relative6, resolve as resolve17, 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.44.0";
|
|
10
10
|
var SCHEMA_VERSION = 2;
|
|
11
11
|
var INAPPLICABLE_STATUS = "C";
|
|
12
12
|
|
|
@@ -58325,8 +58325,9 @@ function derivePackResults(audit2, packKey, pageId) {
|
|
|
58325
58325
|
const measured = measuredRescue(derived, pc, cov, ran, pageId);
|
|
58326
58326
|
const decided = adjudicated?.get(pc.id);
|
|
58327
58327
|
if (decided?.status === "manual") {
|
|
58328
|
+
const { inapplicable: _absence, ...open } = measured;
|
|
58328
58329
|
return {
|
|
58329
|
-
...
|
|
58330
|
+
...open,
|
|
58330
58331
|
status: measured.status === "NC" ? "NC" : "manual",
|
|
58331
58332
|
...decided.justification ? { justification: decided.justification } : {},
|
|
58332
58333
|
decidedBy: "agent"
|
|
@@ -59853,8 +59854,9 @@ function pageTally(rows) {
|
|
|
59853
59854
|
c: rows.filter((r) => r.status === "C").length,
|
|
59854
59855
|
nc: rows.filter((r) => r.status === "NC").length,
|
|
59855
59856
|
// No row carries `NA` any more (INAPPLICABLE_STATUS); this counts the conformities
|
|
59856
|
-
// reached for want of a subject, and it is a SUBSET of `c` rather than a fourth bucket
|
|
59857
|
-
|
|
59857
|
+
// reached for want of a subject, and it is a SUBSET of `c` rather than a fourth bucket
|
|
59858
|
+
// (same predicate as src/report.ts tallyRows).
|
|
59859
|
+
na: rows.filter((r) => r.status === "C" && r.inapplicable).length,
|
|
59858
59860
|
manual: rows.filter((r) => r.status === "manual").length
|
|
59859
59861
|
};
|
|
59860
59862
|
}
|
|
@@ -60402,7 +60404,9 @@ function tallyRows(rows) {
|
|
|
60402
60404
|
return {
|
|
60403
60405
|
c: rows.filter((x) => x.status === "C").length,
|
|
60404
60406
|
nc: rows.filter((x) => x.status === "NC").length,
|
|
60405
|
-
|
|
60407
|
+
// NA within C, structurally: a row that carried `inapplicable` under another status (a
|
|
60408
|
+
// criterion that stayed open, say) must not be counted in both columns.
|
|
60409
|
+
na: rows.filter((x) => x.status === "C" && x.inapplicable).length,
|
|
60406
60410
|
manual: rows.filter((x) => x.status === "manual").length
|
|
60407
60411
|
};
|
|
60408
60412
|
}
|
|
@@ -60905,7 +60909,7 @@ function render(r, lang, opts) {
|
|
|
60905
60909
|
}
|
|
60906
60910
|
}
|
|
60907
60911
|
out2.push(`## ${s.naTitle}`, "");
|
|
60908
|
-
const na = rows.filter((x) => x.inapplicable);
|
|
60912
|
+
const na = rows.filter((x) => x.status === "C" && x.inapplicable);
|
|
60909
60913
|
if (!na.length) out2.push(s.nothing, "");
|
|
60910
60914
|
else {
|
|
60911
60915
|
out2.push(`> ${s.naNote}`, "");
|
|
@@ -68865,7 +68869,7 @@ function packAuditDocument(input, packKey, lang) {
|
|
|
68865
68869
|
// worse than either being wrong.
|
|
68866
68870
|
c: rows.filter((r) => r.status === "C").length,
|
|
68867
68871
|
nc: rows.filter((r) => r.status === "NC").length,
|
|
68868
|
-
na: rows.filter((r) => r.inapplicable).length,
|
|
68872
|
+
na: rows.filter((r) => r.status === "C" && r.inapplicable).length,
|
|
68869
68873
|
manual: rows.filter((r) => r.status === "manual").length
|
|
68870
68874
|
};
|
|
68871
68875
|
});
|
|
@@ -74156,9 +74160,9 @@ Usage:
|
|
|
74156
74160
|
ultra11y init [--hook] [--ci] [--baseline] [--fail-on blocking|major|minor]
|
|
74157
74161
|
ultra11y judge --in <audit.json> [--standard <pack>] [--runner api|claude|codex] [--grain batch|criterion] [--max <n>] [--model <id>] [--effort <level>] [--max-budget-usd <n>] [--timeout <s>] [--out <dir>] [--apply] (adjudicate manual criteria \u2014 api needs ANTHROPIC_API_KEY; claude/codex reuse their CLI login; cli aliases claude)
|
|
74158
74162
|
ultra11y pack check <pack.json> [--guidance <g.json>] [--json] | pack scaffold
|
|
74159
|
-
ultra11y scan <url|file\u2026> [--runtime auto|local|docker] [--cwd <dir>] [--storage-state <file>] [--no-interact] [--interact-clicks] [--no-snapshot] [--merge <audit.json>] [--out <dir>] [--json]
|
|
74160
|
-
ultra11y scan --sample [--runtime \u2026] [--cwd <dir>] [--storage-state <file>] [--merge <audit.json>] [--json] (scan the .ultra11yrc.json page sample)
|
|
74161
|
-
ultra11y scan --sitemap <url> | --crawl <url> [--depth <n>] [--max <n>] [--runtime \u2026] [--cwd <dir>] [--merge <audit.json>] [--json]
|
|
74163
|
+
ultra11y scan <url|file\u2026> [--runtime auto|local|docker] [--cwd <dir>] [--root <dir>] [--storage-state <file>] [--no-interact] [--interact-clicks] [--no-snapshot] [--merge <audit.json>] [--out <dir>] [--json]
|
|
74164
|
+
ultra11y scan --sample [--runtime \u2026] [--cwd <dir>] [--root <dir>] [--storage-state <file>] [--merge <audit.json>] [--json] (scan the .ultra11yrc.json page sample)
|
|
74165
|
+
ultra11y scan --sitemap <url> | --crawl <url> [--depth <n>] [--max <n>] [--runtime \u2026] [--cwd <dir>] [--root <dir>] [--merge <audit.json>] [--json]
|
|
74162
74166
|
ultra11y scan --clean (remove the dynamic-tier Docker image + temp contexts)
|
|
74163
74167
|
ultra11y sample check [--standard <pack>] [--json] (lint the .ultra11yrc.json page sample vs the standard's required page kinds)
|
|
74164
74168
|
ultra11y snapshot write [--root <dir>] [--fail-on blocking|major|minor] [--json] (payload on stdin \u2192 .ultra11y/pages/<id>/ + audit it)
|
|
@@ -74402,7 +74406,8 @@ Options:
|
|
|
74402
74406
|
--no-captures audit: do NOT auto-detect/ingest .ultra11y/captures nor .ultra11y/pages
|
|
74403
74407
|
--e2e render: write the Playwright/Cypress fixtures into .ultra11y/e2e/
|
|
74404
74408
|
--runner <name> render --e2e: force playwright|cypress instead of auto-detecting
|
|
74405
|
-
--root <dir> snapshot: project root holding .ultra11y/pages (default: .
|
|
74409
|
+
--root <dir> snapshot, scan: project root holding .ultra11y/pages (default: . \u2014
|
|
74410
|
+
scan writes the snapshots it collects under it)
|
|
74406
74411
|
--port <n> dev: port for the side-car (default: 4111); mcp: HTTP transport port
|
|
74407
74412
|
--transport <k> mcp: stdio (default) or http
|
|
74408
74413
|
--bind <addr> mcp --transport http: address to bind (default 127.0.0.1)
|
|
@@ -77027,6 +77032,10 @@ Iterated over ${rounds} round(s) to a fixpoint \u2014 ${totalWritten} file(s) wr
|
|
|
77027
77032
|
}
|
|
77028
77033
|
return 0;
|
|
77029
77034
|
}
|
|
77035
|
+
function scanSnapshotRoot(flags2) {
|
|
77036
|
+
if (flags2["no-snapshot"] === true) return void 0;
|
|
77037
|
+
return typeof flags2.root === "string" && flags2.root ? resolve17(flags2.root) : process.cwd();
|
|
77038
|
+
}
|
|
77030
77039
|
async function cmdScan(p) {
|
|
77031
77040
|
const standard = stdOf(p, "scan");
|
|
77032
77041
|
if (standard === null) return 2;
|
|
@@ -77079,7 +77088,7 @@ async function cmdScan(p) {
|
|
|
77079
77088
|
const interactClicks = p.flags["interact-clicks"] === true;
|
|
77080
77089
|
const sitemap = typeof p.flags.sitemap === "string" ? p.flags.sitemap : void 0;
|
|
77081
77090
|
const crawl = typeof p.flags.crawl === "string" ? p.flags.crawl : void 0;
|
|
77082
|
-
const snapshotRoot = p.flags
|
|
77091
|
+
const snapshotRoot = scanSnapshotRoot(p.flags);
|
|
77083
77092
|
const useSample = p.flags.sample === true;
|
|
77084
77093
|
let sampleConfig;
|
|
77085
77094
|
if (useSample) {
|
|
@@ -77764,6 +77773,7 @@ export {
|
|
|
77764
77773
|
COMMANDS,
|
|
77765
77774
|
REMOVED_FLAGS,
|
|
77766
77775
|
main,
|
|
77767
|
-
parseArgs
|
|
77776
|
+
parseArgs,
|
|
77777
|
+
scanSnapshotRoot
|
|
77768
77778
|
};
|
|
77769
77779
|
// "Copyright" and "@license" are already caught by DIRECTIVE_RE.
|
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 93 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.44.0
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# ultra11y — audit WCAG 2.2 AA and write accessible markup
|
|
@@ -233,7 +233,8 @@ and the scan stops there. Point `--crawl` at a real entry page, or pass the URLs
|
|
|
233
233
|
`scan` does not only keep findings: each page it visits is persisted to
|
|
234
234
|
`.ultra11y/pages/<id>/` (DOM + computed styles + boxes + stylesheets + a viewport
|
|
235
235
|
screenshot). The browser is already on the page, so this costs one `evaluate`. `--no-snapshot`
|
|
236
|
-
opts out
|
|
236
|
+
opts out; `--root <dir>` relocates the tree (default: the working directory — `--cwd` is
|
|
237
|
+
where Playwright resolves from, not where snapshots land).
|
|
237
238
|
|
|
238
239
|
### …and what it MEASURED, not only what it saw
|
|
239
240
|
|
|
@@ -166,9 +166,10 @@ repo it does not own — write the run's intermediates out-of-tree and let only
|
|
|
166
166
|
dated report land in the project, if at all.
|
|
167
167
|
|
|
168
168
|
`.ultra11y/pages/` is written only by the page-snapshot commands (`scan`, `snapshot`,
|
|
169
|
-
`dev`).
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
`dev`). All of them take `--root` to relocate it — for `scan`, where the snapshots it
|
|
170
|
+
collects are written (`--cwd` stays where Playwright resolves from), so an orchestrator can
|
|
171
|
+
run from the audited checkout without dirtying it. `audit`, `report`, `prd`, `tickets`,
|
|
172
|
+
`verify` and `check` never touch it.
|
|
172
173
|
|
|
173
174
|
## Exit codes
|
|
174
175
|
|
|
@@ -93,6 +93,9 @@ name (« not open for adjudication »), never re-applied: re-folding the same fi
|
|
|
93
93
|
written-back audit answers `ok: false` with that criterion in `rejectedCriteria[]`. Agent `NC`s become
|
|
94
94
|
real `agent:<sc>` findings that re-render in the report's §2 and re-enter the verify worklist;
|
|
95
95
|
`report`/`prd` re-render with the adjudicated statuses; §5 shrinks to only still-`manual` items.
|
|
96
|
+
A `manual` verdict — or a coverage gap — on a criterion the engine had provisionally closed for
|
|
97
|
+
want of a subject stays in §5 only: it is never counted in the NA column, which remains a subset
|
|
98
|
+
of §3's C.
|
|
96
99
|
|
|
97
100
|
## Residual risk
|
|
98
101
|
|
|
@@ -6,7 +6,7 @@ import { join as join52, relative as relative6, resolve as resolve17, 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.44.0";
|
|
10
10
|
var SCHEMA_VERSION = 2;
|
|
11
11
|
var INAPPLICABLE_STATUS = "C";
|
|
12
12
|
|
|
@@ -58325,8 +58325,9 @@ function derivePackResults(audit2, packKey, pageId) {
|
|
|
58325
58325
|
const measured = measuredRescue(derived, pc, cov, ran, pageId);
|
|
58326
58326
|
const decided = adjudicated?.get(pc.id);
|
|
58327
58327
|
if (decided?.status === "manual") {
|
|
58328
|
+
const { inapplicable: _absence, ...open } = measured;
|
|
58328
58329
|
return {
|
|
58329
|
-
...
|
|
58330
|
+
...open,
|
|
58330
58331
|
status: measured.status === "NC" ? "NC" : "manual",
|
|
58331
58332
|
...decided.justification ? { justification: decided.justification } : {},
|
|
58332
58333
|
decidedBy: "agent"
|
|
@@ -59853,8 +59854,9 @@ function pageTally(rows) {
|
|
|
59853
59854
|
c: rows.filter((r) => r.status === "C").length,
|
|
59854
59855
|
nc: rows.filter((r) => r.status === "NC").length,
|
|
59855
59856
|
// No row carries `NA` any more (INAPPLICABLE_STATUS); this counts the conformities
|
|
59856
|
-
// reached for want of a subject, and it is a SUBSET of `c` rather than a fourth bucket
|
|
59857
|
-
|
|
59857
|
+
// reached for want of a subject, and it is a SUBSET of `c` rather than a fourth bucket
|
|
59858
|
+
// (same predicate as src/report.ts tallyRows).
|
|
59859
|
+
na: rows.filter((r) => r.status === "C" && r.inapplicable).length,
|
|
59858
59860
|
manual: rows.filter((r) => r.status === "manual").length
|
|
59859
59861
|
};
|
|
59860
59862
|
}
|
|
@@ -60402,7 +60404,9 @@ function tallyRows(rows) {
|
|
|
60402
60404
|
return {
|
|
60403
60405
|
c: rows.filter((x) => x.status === "C").length,
|
|
60404
60406
|
nc: rows.filter((x) => x.status === "NC").length,
|
|
60405
|
-
|
|
60407
|
+
// NA within C, structurally: a row that carried `inapplicable` under another status (a
|
|
60408
|
+
// criterion that stayed open, say) must not be counted in both columns.
|
|
60409
|
+
na: rows.filter((x) => x.status === "C" && x.inapplicable).length,
|
|
60406
60410
|
manual: rows.filter((x) => x.status === "manual").length
|
|
60407
60411
|
};
|
|
60408
60412
|
}
|
|
@@ -60905,7 +60909,7 @@ function render(r, lang, opts) {
|
|
|
60905
60909
|
}
|
|
60906
60910
|
}
|
|
60907
60911
|
out2.push(`## ${s.naTitle}`, "");
|
|
60908
|
-
const na = rows.filter((x) => x.inapplicable);
|
|
60912
|
+
const na = rows.filter((x) => x.status === "C" && x.inapplicable);
|
|
60909
60913
|
if (!na.length) out2.push(s.nothing, "");
|
|
60910
60914
|
else {
|
|
60911
60915
|
out2.push(`> ${s.naNote}`, "");
|
|
@@ -68865,7 +68869,7 @@ function packAuditDocument(input, packKey, lang) {
|
|
|
68865
68869
|
// worse than either being wrong.
|
|
68866
68870
|
c: rows.filter((r) => r.status === "C").length,
|
|
68867
68871
|
nc: rows.filter((r) => r.status === "NC").length,
|
|
68868
|
-
na: rows.filter((r) => r.inapplicable).length,
|
|
68872
|
+
na: rows.filter((r) => r.status === "C" && r.inapplicable).length,
|
|
68869
68873
|
manual: rows.filter((r) => r.status === "manual").length
|
|
68870
68874
|
};
|
|
68871
68875
|
});
|
|
@@ -74156,9 +74160,9 @@ Usage:
|
|
|
74156
74160
|
ultra11y init [--hook] [--ci] [--baseline] [--fail-on blocking|major|minor]
|
|
74157
74161
|
ultra11y judge --in <audit.json> [--standard <pack>] [--runner api|claude|codex] [--grain batch|criterion] [--max <n>] [--model <id>] [--effort <level>] [--max-budget-usd <n>] [--timeout <s>] [--out <dir>] [--apply] (adjudicate manual criteria \u2014 api needs ANTHROPIC_API_KEY; claude/codex reuse their CLI login; cli aliases claude)
|
|
74158
74162
|
ultra11y pack check <pack.json> [--guidance <g.json>] [--json] | pack scaffold
|
|
74159
|
-
ultra11y scan <url|file\u2026> [--runtime auto|local|docker] [--cwd <dir>] [--storage-state <file>] [--no-interact] [--interact-clicks] [--no-snapshot] [--merge <audit.json>] [--out <dir>] [--json]
|
|
74160
|
-
ultra11y scan --sample [--runtime \u2026] [--cwd <dir>] [--storage-state <file>] [--merge <audit.json>] [--json] (scan the .ultra11yrc.json page sample)
|
|
74161
|
-
ultra11y scan --sitemap <url> | --crawl <url> [--depth <n>] [--max <n>] [--runtime \u2026] [--cwd <dir>] [--merge <audit.json>] [--json]
|
|
74163
|
+
ultra11y scan <url|file\u2026> [--runtime auto|local|docker] [--cwd <dir>] [--root <dir>] [--storage-state <file>] [--no-interact] [--interact-clicks] [--no-snapshot] [--merge <audit.json>] [--out <dir>] [--json]
|
|
74164
|
+
ultra11y scan --sample [--runtime \u2026] [--cwd <dir>] [--root <dir>] [--storage-state <file>] [--merge <audit.json>] [--json] (scan the .ultra11yrc.json page sample)
|
|
74165
|
+
ultra11y scan --sitemap <url> | --crawl <url> [--depth <n>] [--max <n>] [--runtime \u2026] [--cwd <dir>] [--root <dir>] [--merge <audit.json>] [--json]
|
|
74162
74166
|
ultra11y scan --clean (remove the dynamic-tier Docker image + temp contexts)
|
|
74163
74167
|
ultra11y sample check [--standard <pack>] [--json] (lint the .ultra11yrc.json page sample vs the standard's required page kinds)
|
|
74164
74168
|
ultra11y snapshot write [--root <dir>] [--fail-on blocking|major|minor] [--json] (payload on stdin \u2192 .ultra11y/pages/<id>/ + audit it)
|
|
@@ -74402,7 +74406,8 @@ Options:
|
|
|
74402
74406
|
--no-captures audit: do NOT auto-detect/ingest .ultra11y/captures nor .ultra11y/pages
|
|
74403
74407
|
--e2e render: write the Playwright/Cypress fixtures into .ultra11y/e2e/
|
|
74404
74408
|
--runner <name> render --e2e: force playwright|cypress instead of auto-detecting
|
|
74405
|
-
--root <dir> snapshot: project root holding .ultra11y/pages (default: .
|
|
74409
|
+
--root <dir> snapshot, scan: project root holding .ultra11y/pages (default: . \u2014
|
|
74410
|
+
scan writes the snapshots it collects under it)
|
|
74406
74411
|
--port <n> dev: port for the side-car (default: 4111); mcp: HTTP transport port
|
|
74407
74412
|
--transport <k> mcp: stdio (default) or http
|
|
74408
74413
|
--bind <addr> mcp --transport http: address to bind (default 127.0.0.1)
|
|
@@ -77027,6 +77032,10 @@ Iterated over ${rounds} round(s) to a fixpoint \u2014 ${totalWritten} file(s) wr
|
|
|
77027
77032
|
}
|
|
77028
77033
|
return 0;
|
|
77029
77034
|
}
|
|
77035
|
+
function scanSnapshotRoot(flags2) {
|
|
77036
|
+
if (flags2["no-snapshot"] === true) return void 0;
|
|
77037
|
+
return typeof flags2.root === "string" && flags2.root ? resolve17(flags2.root) : process.cwd();
|
|
77038
|
+
}
|
|
77030
77039
|
async function cmdScan(p) {
|
|
77031
77040
|
const standard = stdOf(p, "scan");
|
|
77032
77041
|
if (standard === null) return 2;
|
|
@@ -77079,7 +77088,7 @@ async function cmdScan(p) {
|
|
|
77079
77088
|
const interactClicks = p.flags["interact-clicks"] === true;
|
|
77080
77089
|
const sitemap = typeof p.flags.sitemap === "string" ? p.flags.sitemap : void 0;
|
|
77081
77090
|
const crawl = typeof p.flags.crawl === "string" ? p.flags.crawl : void 0;
|
|
77082
|
-
const snapshotRoot = p.flags
|
|
77091
|
+
const snapshotRoot = scanSnapshotRoot(p.flags);
|
|
77083
77092
|
const useSample = p.flags.sample === true;
|
|
77084
77093
|
let sampleConfig;
|
|
77085
77094
|
if (useSample) {
|
|
@@ -77764,6 +77773,7 @@ export {
|
|
|
77764
77773
|
COMMANDS,
|
|
77765
77774
|
REMOVED_FLAGS,
|
|
77766
77775
|
main,
|
|
77767
|
-
parseArgs
|
|
77776
|
+
parseArgs,
|
|
77777
|
+
scanSnapshotRoot
|
|
77768
77778
|
};
|
|
77769
77779
|
// "Copyright" and "@license" are already caught by DIRECTIVE_RE.
|
|
@@ -27,7 +27,7 @@ variables:
|
|
|
27
27
|
ULTRA11Y_LANG: en
|
|
28
28
|
# Exact by default: a CI report must say which engine produced it. The release script keeps
|
|
29
29
|
# this pin aligned with the package version; override only for a deliberate upgrade test.
|
|
30
|
-
ULTRA11Y_VERSION: '5.
|
|
30
|
+
ULTRA11Y_VERSION: '5.44.0'
|
|
31
31
|
# Batches of 8 amortise the prompt; each accepted verdict is checkpointed before the next
|
|
32
32
|
# batch, and later passes receive only the residue.
|
|
33
33
|
ULTRA11Y_GRAIN: batch
|
package/src/cli.ts
CHANGED
|
@@ -160,9 +160,9 @@ Usage:
|
|
|
160
160
|
ultra11y init [--hook] [--ci] [--baseline] [--fail-on blocking|major|minor]
|
|
161
161
|
ultra11y judge --in <audit.json> [--standard <pack>] [--runner api|claude|codex] [--grain batch|criterion] [--max <n>] [--model <id>] [--effort <level>] [--max-budget-usd <n>] [--timeout <s>] [--out <dir>] [--apply] (adjudicate manual criteria — api needs ANTHROPIC_API_KEY; claude/codex reuse their CLI login; cli aliases claude)
|
|
162
162
|
ultra11y pack check <pack.json> [--guidance <g.json>] [--json] | pack scaffold
|
|
163
|
-
ultra11y scan <url|file…> [--runtime auto|local|docker] [--cwd <dir>] [--storage-state <file>] [--no-interact] [--interact-clicks] [--no-snapshot] [--merge <audit.json>] [--out <dir>] [--json]
|
|
164
|
-
ultra11y scan --sample [--runtime …] [--cwd <dir>] [--storage-state <file>] [--merge <audit.json>] [--json] (scan the .ultra11yrc.json page sample)
|
|
165
|
-
ultra11y scan --sitemap <url> | --crawl <url> [--depth <n>] [--max <n>] [--runtime …] [--cwd <dir>] [--merge <audit.json>] [--json]
|
|
163
|
+
ultra11y scan <url|file…> [--runtime auto|local|docker] [--cwd <dir>] [--root <dir>] [--storage-state <file>] [--no-interact] [--interact-clicks] [--no-snapshot] [--merge <audit.json>] [--out <dir>] [--json]
|
|
164
|
+
ultra11y scan --sample [--runtime …] [--cwd <dir>] [--root <dir>] [--storage-state <file>] [--merge <audit.json>] [--json] (scan the .ultra11yrc.json page sample)
|
|
165
|
+
ultra11y scan --sitemap <url> | --crawl <url> [--depth <n>] [--max <n>] [--runtime …] [--cwd <dir>] [--root <dir>] [--merge <audit.json>] [--json]
|
|
166
166
|
ultra11y scan --clean (remove the dynamic-tier Docker image + temp contexts)
|
|
167
167
|
ultra11y sample check [--standard <pack>] [--json] (lint the .ultra11yrc.json page sample vs the standard's required page kinds)
|
|
168
168
|
ultra11y snapshot write [--root <dir>] [--fail-on blocking|major|minor] [--json] (payload on stdin → .ultra11y/pages/<id>/ + audit it)
|
|
@@ -406,7 +406,8 @@ Options:
|
|
|
406
406
|
--no-captures audit: do NOT auto-detect/ingest .ultra11y/captures nor .ultra11y/pages
|
|
407
407
|
--e2e render: write the Playwright/Cypress fixtures into .ultra11y/e2e/
|
|
408
408
|
--runner <name> render --e2e: force playwright|cypress instead of auto-detecting
|
|
409
|
-
--root <dir> snapshot: project root holding .ultra11y/pages (default: .
|
|
409
|
+
--root <dir> snapshot, scan: project root holding .ultra11y/pages (default: . —
|
|
410
|
+
scan writes the snapshots it collects under it)
|
|
410
411
|
--port <n> dev: port for the side-car (default: 4111); mcp: HTTP transport port
|
|
411
412
|
--transport <k> mcp: stdio (default) or http
|
|
412
413
|
--bind <addr> mcp --transport http: address to bind (default 127.0.0.1)
|
|
@@ -4028,6 +4029,16 @@ async function cmdFix(p: ParsedArgs): Promise<number> {
|
|
|
4028
4029
|
return 0;
|
|
4029
4030
|
}
|
|
4030
4031
|
|
|
4032
|
+
/** Where `scan` writes the page snapshots it collects: `--root <dir>` when given — the same
|
|
4033
|
+
* contract as `snapshot write`, `dev` and `pages discover --from-snapshots` — else the
|
|
4034
|
+
* working directory. Absolute either way, as it always was: the merge audits the snapshot
|
|
4035
|
+
* DOMs by this path. Undefined under `--no-snapshot`: nothing is persisted. `--cwd` plays
|
|
4036
|
+
* no part here: it keeps its own meaning, where Playwright resolves from. */
|
|
4037
|
+
export function scanSnapshotRoot(flags: ParsedArgs["flags"]): string | undefined {
|
|
4038
|
+
if (flags["no-snapshot"] === true) return undefined;
|
|
4039
|
+
return typeof flags.root === "string" && flags.root ? resolve(flags.root) : process.cwd();
|
|
4040
|
+
}
|
|
4041
|
+
|
|
4031
4042
|
async function cmdScan(p: ParsedArgs): Promise<number> {
|
|
4032
4043
|
// `scan` takes `--standard` for the same reason `audit` now does: it REWRITES
|
|
4033
4044
|
// audit-latest.json mid-chain, and a merge that silently re-keyed an RGAA document back to
|
|
@@ -4135,7 +4146,7 @@ async function cmdScan(p: ParsedArgs): Promise<number> {
|
|
|
4135
4146
|
// is already on the page, so this costs one `evaluate` — and it is what lets the page be
|
|
4136
4147
|
// re-audited offline and earn a real per-page verdict instead of staying "to assess"
|
|
4137
4148
|
// forever (src/pages.ts). `--no-snapshot` opts out.
|
|
4138
|
-
const snapshotRoot = p.flags
|
|
4149
|
+
const snapshotRoot = scanSnapshotRoot(p.flags);
|
|
4139
4150
|
|
|
4140
4151
|
// --sample: iterate the NORMATIVE page sample from `.ultra11yrc.json` (per-page
|
|
4141
4152
|
// storageState overrides --storage-state). Loaded + validated here (hard error on a
|
package/src/pages-report.ts
CHANGED
|
@@ -262,8 +262,9 @@ export function pageTally(rows: PageCriterionRow[]): { c: number; nc: number; na
|
|
|
262
262
|
c: rows.filter((r) => r.status === "C").length,
|
|
263
263
|
nc: rows.filter((r) => r.status === "NC").length,
|
|
264
264
|
// No row carries `NA` any more (INAPPLICABLE_STATUS); this counts the conformities
|
|
265
|
-
// reached for want of a subject, and it is a SUBSET of `c` rather than a fourth bucket
|
|
266
|
-
|
|
265
|
+
// reached for want of a subject, and it is a SUBSET of `c` rather than a fourth bucket
|
|
266
|
+
// (same predicate as src/report.ts tallyRows).
|
|
267
|
+
na: rows.filter((r) => r.status === "C" && r.inapplicable).length,
|
|
267
268
|
manual: rows.filter((r) => r.status === "manual").length,
|
|
268
269
|
};
|
|
269
270
|
}
|
package/src/report.ts
CHANGED
|
@@ -627,7 +627,9 @@ export function tallyRows(rows: ReportRow[]): ReportTally {
|
|
|
627
627
|
return {
|
|
628
628
|
c: rows.filter((x) => x.status === "C").length,
|
|
629
629
|
nc: rows.filter((x) => x.status === "NC").length,
|
|
630
|
-
|
|
630
|
+
// NA within C, structurally: a row that carried `inapplicable` under another status (a
|
|
631
|
+
// criterion that stayed open, say) must not be counted in both columns.
|
|
632
|
+
na: rows.filter((x) => x.status === "C" && x.inapplicable).length,
|
|
631
633
|
manual: rows.filter((x) => x.status === "manual").length,
|
|
632
634
|
};
|
|
633
635
|
}
|
|
@@ -1522,9 +1524,10 @@ function render(r: AuditResult, lang: Lang, opts: RenderOpts): ReportDocuments {
|
|
|
1522
1524
|
}
|
|
1523
1525
|
|
|
1524
1526
|
// 4. conforming for want of a subject — each with what was looked for, so the claim stays
|
|
1525
|
-
// falsifiable rather than merely asserted.
|
|
1527
|
+
// falsifiable rather than merely asserted. Same predicate as tallyRows: the section lists
|
|
1528
|
+
// exactly the criteria the synthesis counts as NA.
|
|
1526
1529
|
out.push(`## ${s.naTitle}`, "");
|
|
1527
|
-
const na = rows.filter((x) => x.inapplicable);
|
|
1530
|
+
const na = rows.filter((x) => x.status === "C" && x.inapplicable);
|
|
1528
1531
|
if (!na.length) out.push(s.nothing, "");
|
|
1529
1532
|
else {
|
|
1530
1533
|
out.push(`> ${s.naNote}`, "");
|
package/src/standards/derive.ts
CHANGED
|
@@ -469,8 +469,14 @@ export function derivePackResults(audit: AuditResult, packKey: string, pageId?:
|
|
|
469
469
|
const measured = measuredRescue(derived, pc, cov, ran, pageId);
|
|
470
470
|
const decided = adjudicated?.get(pc.id);
|
|
471
471
|
if (decided?.status === "manual") {
|
|
472
|
+
// An abstention keeps the criterion OPEN, so the absence-derived `inapplicable` must not
|
|
473
|
+
// ride along: the report counts NA inside C (src/report.ts tallyRows), and a row that is
|
|
474
|
+
// both « à évaluer » and « conforme faute de sujet » lands in both columns — NA then
|
|
475
|
+
// overtakes C in the synthesis and `check --report` refuses the document this engine
|
|
476
|
+
// itself wrote.
|
|
477
|
+
const { inapplicable: _absence, ...open } = measured;
|
|
472
478
|
return {
|
|
473
|
-
...
|
|
479
|
+
...open,
|
|
474
480
|
status: measured.status === "NC" ? "NC" : "manual",
|
|
475
481
|
...(decided.justification ? { justification: decided.justification } : {}),
|
|
476
482
|
decidedBy: "agent" as const,
|
|
@@ -174,7 +174,7 @@ export function packAuditDocument(input: AuditResult | PackAuditResult, packKey:
|
|
|
174
174
|
// worse than either being wrong.
|
|
175
175
|
c: rows.filter((r) => r.status === "C").length,
|
|
176
176
|
nc: rows.filter((r) => r.status === "NC").length,
|
|
177
|
-
na: rows.filter((r) => r.inapplicable).length,
|
|
177
|
+
na: rows.filter((r) => r.status === "C" && r.inapplicable).length,
|
|
178
178
|
manual: rows.filter((r) => r.status === "manual").length,
|
|
179
179
|
};
|
|
180
180
|
});
|
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.44.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,
|