ultra11y 5.0.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@
10
10
  "name": "ultra11y",
11
11
  "source": "./",
12
12
  "description": "Automatic accessibility review of the code under change before every commit, push and pull request, plus full WCAG 2.2 AA / RGAA audits and conformance deliverables on demand.",
13
- "version": "5.0.0",
13
+ "version": "5.0.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.0.0",
4
+ "version": "5.0.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.0.0",
4
+ "version": "5.0.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.0.0";
30
+ const ULTRA11Y_PLUGIN_VERSION = "5.0.1";
31
31
 
32
32
  const here = dirname(fileURLToPath(import.meta.url));
33
33
 
package/README.md CHANGED
@@ -125,7 +125,7 @@ claude mcp add ultra11y -- npx -y ultra11y mcp
125
125
  **As a GitHub Action** — audits the PR diff and, optionally, the served pages:
126
126
 
127
127
  ```yaml
128
- - uses: maxgfr/ultra11y@v4
128
+ - uses: maxgfr/ultra11y@v5
129
129
  with: { since: auto, standard: rgaa, fail-on: blocking }
130
130
  ```
131
131
 
@@ -383,7 +383,7 @@ a test). See [`CONTRIBUTING.md`](CONTRIBUTING.md) and `skills/ultra11y/reference
383
383
  block. It re-decides nothing and invents no format, so a page sheet and the compliance report
384
384
  cannot disagree; `check` gates it against invented criteria like any other report.
385
385
  See `references/pages.md`.
386
- - **A shipped GitHub Action** — `uses: maxgfr/ultra11y@v4` audits the **code** (PR diff) and,
386
+ - **A shipped GitHub Action** — `uses: maxgfr/ultra11y@v5` audits the **code** (PR diff) and,
387
387
  optionally, the **pages** (it can start your app, wait for it, then scan real URLs or your
388
388
  declared sample). The engine ships inside the action, so there is nothing to install and no
389
389
  `setup-node`. The gate runs **last**, after SARIF, annotations, the summary, the sticky PR
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultra11y",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": "Audit HTML/CSS/JSX against WCAG 2.2 AA and produce a dated compliance report, or author/review accessible markup (native-HTML-first). A skills.sh agent skill: an install-free static engine (bundled, no npm install) plus the agent's judgment, with check/verify gates against hallucinated non-conformities, and pluggable in-repo standards packs (RGAA France first; Section 508 & EN 301 549 next).",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.33.0",
@@ -6,7 +6,7 @@ import { join as join50, relative as relative5, resolve as resolve15, 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.0.0";
9
+ var VERSION = "5.0.1";
10
10
  var SCHEMA_VERSION = 2;
11
11
 
12
12
  // src/audit.ts
@@ -61923,6 +61923,20 @@ var ADJUDICATE_SCHEMA = {
61923
61923
  criteriaId: { type: "string" },
61924
61924
  verdict: { enum: ["C", "NC", "NA", "manual"] },
61925
61925
  justification: { type: "string", description: "REQUIRED for C and NA" },
61926
+ // REQUIRED by the fold alongside `justification`, for exactly the same reason
61927
+ // `normativeRef` is required on an NC: a cleared criterion has to name what it
61928
+ // cleared. Omitting it here (and from the adjudicator contract) made every
61929
+ // adjudication produce C/NA verdicts that `verify --apply` then refused wholesale —
61930
+ // 63 rejections out of 97 verdicts on the run that surfaced this.
61931
+ citations: {
61932
+ type: "array",
61933
+ description: "REQUIRED for C, and for NA when evidence was presented: the evidence items you cleared, `file`/`line` copied verbatim from this criterion's own evidence[]",
61934
+ items: {
61935
+ type: "object",
61936
+ required: ["file", "line"],
61937
+ properties: { file: { type: "string" }, line: { type: "number" }, selector: { type: "string" }, snippet: { type: "string" } }
61938
+ }
61939
+ },
61926
61940
  reason: { type: ["string", "null"], enum: ["needs-rendered-dom", "undecidable", null], description: "REQUIRED for a still-manual verdict" },
61927
61941
  findings: {
61928
61942
  type: "array",
@@ -62048,13 +62062,13 @@ For EACH of your criteria:
62048
62062
 
62049
62063
  1. Read its worklist entry. \`evidence[]\` holds source-anchored excerpts (\`file\`, \`line\`, \`selector\`, \`snippet\`) harvested from the audited code \u2014 open the cited files at the cited lines whenever the snippet alone cannot decide.
62050
62064
  2. Rule it (the apply gate is FAIL-CLOSED \u2014 a verdict missing its required field does not fold):
62051
- - \`C\` (conforming) \u2014 REQUIRES \`justification\` explaining why the evidence satisfies the criterion.
62065
+ - \`C\` (conforming) \u2014 REQUIRES \`justification\` explaining why the evidence satisfies the criterion, AND \`citations[]\` naming the evidence you cleared (\`file\`/\`line\` copied VERBATIM from this item's own \`evidence[]\`; an anchor that is not in that list is treated as fabricated). A criterion whose \`evidence[]\` is empty cannot be \`C\` at all \u2014 it is \`manual\` (\`undecidable\`), or \`NA\` if nothing in scope is concerned.
62052
62066
  - \`NC\` (non-conforming) \u2014 REQUIRES \`findings\`: at least one groundable \`{ file, line, selector?, message, snippet?, severity?, normativeRef }\` pointing at REAL source. The fold re-grounds every finding; an invented file:line is rejected. \`normativeRef\` MUST cite the precise failed test \u2014 under a country standard, one of the item's OWN tests, which the worklist lists for you under \xAB tests to rule on \xBB.
62053
- - \`NA\` (not applicable) \u2014 REQUIRES \`justification\`.
62067
+ - \`NA\` (not applicable) \u2014 REQUIRES \`justification\`, AND \`citations[]\` whenever evidence WAS presented, to say which of those items fall outside the criterion's scope.
62054
62068
  - \`manual\` (still undecidable) \u2014 REQUIRES \`reason\`: \`needs-rendered-dom\` (only a rendered DOM can decide, e.g. computed contrast) or \`undecidable\` (the evidence cannot settle it either way).
62055
62069
  3. Never guess. A criterion you cannot decide from real evidence stays \`manual\` with a reason \u2014 that is a valid, honest verdict; the scan tier or a human picks it up.
62056
62070
 
62057
- Return (structured output): \`{ "verdicts": [{ "criteriaId", "verdict", "justification", "reason", "findings" }] }\` \u2014 your ITEMS only, every field grounded in what you actually read, every NC finding carrying its \`normativeRef\`.
62071
+ Return (structured output): \`{ "verdicts": [{ "criteriaId", "verdict", "justification", "citations", "reason", "findings" }] }\` \u2014 your ITEMS only, every field grounded in what you actually read, every NC finding carrying its \`normativeRef\`, and every C (plus every evidenced NA) carrying its \`citations\`. A verdict that clears a criterion without naming what it cleared is refused by the fold, and one refusal discards the WHOLE adjudication \u2014 including every other verdict you got right.
62058
62072
  ${footer}`,
62059
62073
  refuter: `# Contract: refuter
62060
62074
 
@@ -5,7 +5,7 @@ when_to_use: "Invoke WITHOUT being asked whenever changed front-end code should
5
5
  allowed-tools: Bash(node ${CLAUDE_SKILL_DIR}/scripts/ultra11y.mjs *), Read, Grep, Glob
6
6
  license: MIT
7
7
  metadata:
8
- version: 5.0.0
8
+ version: 5.0.1
9
9
  ---
10
10
 
11
11
  # review-a11y — accessibility review of changed code
@@ -6,7 +6,7 @@ import { join as join50, relative as relative5, resolve as resolve15, 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.0.0";
9
+ var VERSION = "5.0.1";
10
10
  var SCHEMA_VERSION = 2;
11
11
 
12
12
  // src/audit.ts
@@ -61923,6 +61923,20 @@ var ADJUDICATE_SCHEMA = {
61923
61923
  criteriaId: { type: "string" },
61924
61924
  verdict: { enum: ["C", "NC", "NA", "manual"] },
61925
61925
  justification: { type: "string", description: "REQUIRED for C and NA" },
61926
+ // REQUIRED by the fold alongside `justification`, for exactly the same reason
61927
+ // `normativeRef` is required on an NC: a cleared criterion has to name what it
61928
+ // cleared. Omitting it here (and from the adjudicator contract) made every
61929
+ // adjudication produce C/NA verdicts that `verify --apply` then refused wholesale —
61930
+ // 63 rejections out of 97 verdicts on the run that surfaced this.
61931
+ citations: {
61932
+ type: "array",
61933
+ description: "REQUIRED for C, and for NA when evidence was presented: the evidence items you cleared, `file`/`line` copied verbatim from this criterion's own evidence[]",
61934
+ items: {
61935
+ type: "object",
61936
+ required: ["file", "line"],
61937
+ properties: { file: { type: "string" }, line: { type: "number" }, selector: { type: "string" }, snippet: { type: "string" } }
61938
+ }
61939
+ },
61926
61940
  reason: { type: ["string", "null"], enum: ["needs-rendered-dom", "undecidable", null], description: "REQUIRED for a still-manual verdict" },
61927
61941
  findings: {
61928
61942
  type: "array",
@@ -62048,13 +62062,13 @@ For EACH of your criteria:
62048
62062
 
62049
62063
  1. Read its worklist entry. \`evidence[]\` holds source-anchored excerpts (\`file\`, \`line\`, \`selector\`, \`snippet\`) harvested from the audited code \u2014 open the cited files at the cited lines whenever the snippet alone cannot decide.
62050
62064
  2. Rule it (the apply gate is FAIL-CLOSED \u2014 a verdict missing its required field does not fold):
62051
- - \`C\` (conforming) \u2014 REQUIRES \`justification\` explaining why the evidence satisfies the criterion.
62065
+ - \`C\` (conforming) \u2014 REQUIRES \`justification\` explaining why the evidence satisfies the criterion, AND \`citations[]\` naming the evidence you cleared (\`file\`/\`line\` copied VERBATIM from this item's own \`evidence[]\`; an anchor that is not in that list is treated as fabricated). A criterion whose \`evidence[]\` is empty cannot be \`C\` at all \u2014 it is \`manual\` (\`undecidable\`), or \`NA\` if nothing in scope is concerned.
62052
62066
  - \`NC\` (non-conforming) \u2014 REQUIRES \`findings\`: at least one groundable \`{ file, line, selector?, message, snippet?, severity?, normativeRef }\` pointing at REAL source. The fold re-grounds every finding; an invented file:line is rejected. \`normativeRef\` MUST cite the precise failed test \u2014 under a country standard, one of the item's OWN tests, which the worklist lists for you under \xAB tests to rule on \xBB.
62053
- - \`NA\` (not applicable) \u2014 REQUIRES \`justification\`.
62067
+ - \`NA\` (not applicable) \u2014 REQUIRES \`justification\`, AND \`citations[]\` whenever evidence WAS presented, to say which of those items fall outside the criterion's scope.
62054
62068
  - \`manual\` (still undecidable) \u2014 REQUIRES \`reason\`: \`needs-rendered-dom\` (only a rendered DOM can decide, e.g. computed contrast) or \`undecidable\` (the evidence cannot settle it either way).
62055
62069
  3. Never guess. A criterion you cannot decide from real evidence stays \`manual\` with a reason \u2014 that is a valid, honest verdict; the scan tier or a human picks it up.
62056
62070
 
62057
- Return (structured output): \`{ "verdicts": [{ "criteriaId", "verdict", "justification", "reason", "findings" }] }\` \u2014 your ITEMS only, every field grounded in what you actually read, every NC finding carrying its \`normativeRef\`.
62071
+ Return (structured output): \`{ "verdicts": [{ "criteriaId", "verdict", "justification", "citations", "reason", "findings" }] }\` \u2014 your ITEMS only, every field grounded in what you actually read, every NC finding carrying its \`normativeRef\`, and every C (plus every evidenced NA) carrying its \`citations\`. A verdict that clears a criterion without naming what it cleared is refused by the fold, and one refusal discards the WHOLE adjudication \u2014 including every other verdict you got right.
62058
62072
  ${footer}`,
62059
62073
  refuter: `# Contract: refuter
62060
62074
 
@@ -4,7 +4,7 @@ description: "Use to AUDIT existing HTML/CSS/JSX against WCAG 2.2 AA accessibili
4
4
  when_to_use: "Invoke when the user asks for an accessibility AUDIT or a formal deliverable: audit a repo, site or page against WCAG 2.2 AA or a country standard (RGAA, Section 508, EN 301 549); produce a dated conformance report, a criterion grid, a PRD backlog, or tickets (GitHub/GitLab/Jira); author accessible markup from scratch; wire the repo gate (init --hook/--ci) or a rendered-DOM capture pipeline. For a review of the code UNDER CHANGE (diff, branch, PR), use the `review-a11y` skill instead."
5
5
  license: MIT
6
6
  metadata:
7
- version: 5.0.0
7
+ version: 5.0.1
8
8
  ---
9
9
 
10
10
  # ultra11y — audit WCAG 2.2 AA and write accessible markup
@@ -15,7 +15,7 @@ permissions:
15
15
  steps:
16
16
  - uses: actions/checkout@v4
17
17
  with: { fetch-depth: 0 } # the diff gate needs the base ref
18
- - uses: maxgfr/ultra11y@v4 # or pin the exact version, as `init --ci` does
18
+ - uses: maxgfr/ultra11y@v5 # or pin the exact version, as `init --ci` does
19
19
  with:
20
20
  since: auto # the PR's base branch
21
21
  standard: rgaa
@@ -27,7 +27,7 @@ steps:
27
27
  Page by page, with a real browser, in the same step:
28
28
 
29
29
  ```yaml
30
- - uses: maxgfr/ultra11y@v4
30
+ - uses: maxgfr/ultra11y@v5
31
31
  with:
32
32
  standard: rgaa
33
33
  start: npm run start
@@ -37,7 +37,7 @@ Page by page, with a real browser, in the same step:
37
37
  ```
38
38
 
39
39
  `ultra11y init --ci` writes a workflow using it, **pinned to the exact engine version that
40
- generated the file** (`@v<that version>`) so a CI run stays reproducible. `@v<major>` — `@v3`
40
+ generated the file** (`@v<that version>`) so a CI run stays reproducible. `@v<major>` — `@v5`
41
41
  today — is a moving alias the release workflow repoints at each release, for teams who would
42
42
  rather take fixes automatically. It moves **within** a major only: when a breaking change cuts
43
43
  the next one, the old alias freezes where it is, so a pipeline pinned to it keeps working and
@@ -66,7 +66,7 @@ partial by construction. `adjudicate` closes that — opt-in, in two modes.
66
66
  env:
67
67
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} # the job's env, never an input
68
68
  steps:
69
- - uses: maxgfr/ultra11y@v4
69
+ - uses: maxgfr/ultra11y@v5
70
70
  with:
71
71
  standard: rgaa
72
72
  adjudicate: api # or `agent`
@@ -273,7 +273,7 @@ The action audits the **code** and, when you point it at a served app, the **pag
273
273
  list can come from three places, and none of them has to be written by hand:
274
274
 
275
275
  ```yaml
276
- - uses: maxgfr/ultra11y@v4
276
+ - uses: maxgfr/ultra11y@v5
277
277
  with:
278
278
  standard: rgaa
279
279
  start: npm run start
@@ -312,7 +312,7 @@ the setup project their E2E suite depends on — and hand the action its path:
312
312
 
313
313
  ```yaml
314
314
  - run: npx playwright test --project=setup # your existing login, writing the session file
315
- - uses: maxgfr/ultra11y@v4
315
+ - uses: maxgfr/ultra11y@v5
316
316
  with:
317
317
  standard: rgaa
318
318
  sample: 'true'
@@ -467,9 +467,9 @@ one job — the code diff, then the served pages — died on a `409 Conflict`, w
467
467
  written and never uploaded. Pass `artifact-name` on each invocation:
468
468
 
469
469
  ```yaml
470
- - uses: maxgfr/ultra11y@v4
470
+ - uses: maxgfr/ultra11y@v5
471
471
  with: { since: auto, artifact-name: a11y-code }
472
- - uses: maxgfr/ultra11y@v4
472
+ - uses: maxgfr/ultra11y@v5
473
473
  with: { crawl: http://localhost:3000, artifact-name: a11y-pages }
474
474
  ```
475
475
 
@@ -6,7 +6,7 @@ import { join as join50, relative as relative5, resolve as resolve15, 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.0.0";
9
+ var VERSION = "5.0.1";
10
10
  var SCHEMA_VERSION = 2;
11
11
 
12
12
  // src/audit.ts
@@ -61923,6 +61923,20 @@ var ADJUDICATE_SCHEMA = {
61923
61923
  criteriaId: { type: "string" },
61924
61924
  verdict: { enum: ["C", "NC", "NA", "manual"] },
61925
61925
  justification: { type: "string", description: "REQUIRED for C and NA" },
61926
+ // REQUIRED by the fold alongside `justification`, for exactly the same reason
61927
+ // `normativeRef` is required on an NC: a cleared criterion has to name what it
61928
+ // cleared. Omitting it here (and from the adjudicator contract) made every
61929
+ // adjudication produce C/NA verdicts that `verify --apply` then refused wholesale —
61930
+ // 63 rejections out of 97 verdicts on the run that surfaced this.
61931
+ citations: {
61932
+ type: "array",
61933
+ description: "REQUIRED for C, and for NA when evidence was presented: the evidence items you cleared, `file`/`line` copied verbatim from this criterion's own evidence[]",
61934
+ items: {
61935
+ type: "object",
61936
+ required: ["file", "line"],
61937
+ properties: { file: { type: "string" }, line: { type: "number" }, selector: { type: "string" }, snippet: { type: "string" } }
61938
+ }
61939
+ },
61926
61940
  reason: { type: ["string", "null"], enum: ["needs-rendered-dom", "undecidable", null], description: "REQUIRED for a still-manual verdict" },
61927
61941
  findings: {
61928
61942
  type: "array",
@@ -62048,13 +62062,13 @@ For EACH of your criteria:
62048
62062
 
62049
62063
  1. Read its worklist entry. \`evidence[]\` holds source-anchored excerpts (\`file\`, \`line\`, \`selector\`, \`snippet\`) harvested from the audited code \u2014 open the cited files at the cited lines whenever the snippet alone cannot decide.
62050
62064
  2. Rule it (the apply gate is FAIL-CLOSED \u2014 a verdict missing its required field does not fold):
62051
- - \`C\` (conforming) \u2014 REQUIRES \`justification\` explaining why the evidence satisfies the criterion.
62065
+ - \`C\` (conforming) \u2014 REQUIRES \`justification\` explaining why the evidence satisfies the criterion, AND \`citations[]\` naming the evidence you cleared (\`file\`/\`line\` copied VERBATIM from this item's own \`evidence[]\`; an anchor that is not in that list is treated as fabricated). A criterion whose \`evidence[]\` is empty cannot be \`C\` at all \u2014 it is \`manual\` (\`undecidable\`), or \`NA\` if nothing in scope is concerned.
62052
62066
  - \`NC\` (non-conforming) \u2014 REQUIRES \`findings\`: at least one groundable \`{ file, line, selector?, message, snippet?, severity?, normativeRef }\` pointing at REAL source. The fold re-grounds every finding; an invented file:line is rejected. \`normativeRef\` MUST cite the precise failed test \u2014 under a country standard, one of the item's OWN tests, which the worklist lists for you under \xAB tests to rule on \xBB.
62053
- - \`NA\` (not applicable) \u2014 REQUIRES \`justification\`.
62067
+ - \`NA\` (not applicable) \u2014 REQUIRES \`justification\`, AND \`citations[]\` whenever evidence WAS presented, to say which of those items fall outside the criterion's scope.
62054
62068
  - \`manual\` (still undecidable) \u2014 REQUIRES \`reason\`: \`needs-rendered-dom\` (only a rendered DOM can decide, e.g. computed contrast) or \`undecidable\` (the evidence cannot settle it either way).
62055
62069
  3. Never guess. A criterion you cannot decide from real evidence stays \`manual\` with a reason \u2014 that is a valid, honest verdict; the scan tier or a human picks it up.
62056
62070
 
62057
- Return (structured output): \`{ "verdicts": [{ "criteriaId", "verdict", "justification", "reason", "findings" }] }\` \u2014 your ITEMS only, every field grounded in what you actually read, every NC finding carrying its \`normativeRef\`.
62071
+ Return (structured output): \`{ "verdicts": [{ "criteriaId", "verdict", "justification", "citations", "reason", "findings" }] }\` \u2014 your ITEMS only, every field grounded in what you actually read, every NC finding carrying its \`normativeRef\`, and every C (plus every evidenced NA) carrying its \`citations\`. A verdict that clears a criterion without naming what it cleared is refused by the fold, and one refusal discards the WHOLE adjudication \u2014 including every other verdict you got right.
62058
62072
  ${footer}`,
62059
62073
  refuter: `# Contract: refuter
62060
62074
 
@@ -34,6 +34,21 @@ const ADJUDICATE_SCHEMA = {
34
34
  criteriaId: { type: "string" },
35
35
  verdict: { enum: ["C", "NC", "NA", "manual"] },
36
36
  justification: { type: "string", description: "REQUIRED for C and NA" },
37
+ // REQUIRED by the fold alongside `justification`, for exactly the same reason
38
+ // `normativeRef` is required on an NC: a cleared criterion has to name what it
39
+ // cleared. Omitting it here (and from the adjudicator contract) made every
40
+ // adjudication produce C/NA verdicts that `verify --apply` then refused wholesale —
41
+ // 63 rejections out of 97 verdicts on the run that surfaced this.
42
+ citations: {
43
+ type: "array",
44
+ description:
45
+ "REQUIRED for C, and for NA when evidence was presented: the evidence items you cleared, `file`/`line` copied verbatim from this criterion's own evidence[]",
46
+ items: {
47
+ type: "object",
48
+ required: ["file", "line"],
49
+ properties: { file: { type: "string" }, line: { type: "number" }, selector: { type: "string" }, snippet: { type: "string" } },
50
+ },
51
+ },
37
52
  reason: { type: ["string", "null"], enum: ["needs-rendered-dom", "undecidable", null], description: "REQUIRED for a still-manual verdict" },
38
53
  findings: {
39
54
  type: "array",
@@ -176,13 +191,13 @@ For EACH of your criteria:
176
191
 
177
192
  1. Read its worklist entry. \`evidence[]\` holds source-anchored excerpts (\`file\`, \`line\`, \`selector\`, \`snippet\`) harvested from the audited code — open the cited files at the cited lines whenever the snippet alone cannot decide.
178
193
  2. Rule it (the apply gate is FAIL-CLOSED — a verdict missing its required field does not fold):
179
- - \`C\` (conforming) — REQUIRES \`justification\` explaining why the evidence satisfies the criterion.
194
+ - \`C\` (conforming) — REQUIRES \`justification\` explaining why the evidence satisfies the criterion, AND \`citations[]\` naming the evidence you cleared (\`file\`/\`line\` copied VERBATIM from this item's own \`evidence[]\`; an anchor that is not in that list is treated as fabricated). A criterion whose \`evidence[]\` is empty cannot be \`C\` at all — it is \`manual\` (\`undecidable\`), or \`NA\` if nothing in scope is concerned.
180
195
  - \`NC\` (non-conforming) — REQUIRES \`findings\`: at least one groundable \`{ file, line, selector?, message, snippet?, severity?, normativeRef }\` pointing at REAL source. The fold re-grounds every finding; an invented file:line is rejected. \`normativeRef\` MUST cite the precise failed test — under a country standard, one of the item's OWN tests, which the worklist lists for you under « tests to rule on ».
181
- - \`NA\` (not applicable) — REQUIRES \`justification\`.
196
+ - \`NA\` (not applicable) — REQUIRES \`justification\`, AND \`citations[]\` whenever evidence WAS presented, to say which of those items fall outside the criterion's scope.
182
197
  - \`manual\` (still undecidable) — REQUIRES \`reason\`: \`needs-rendered-dom\` (only a rendered DOM can decide, e.g. computed contrast) or \`undecidable\` (the evidence cannot settle it either way).
183
198
  3. Never guess. A criterion you cannot decide from real evidence stays \`manual\` with a reason — that is a valid, honest verdict; the scan tier or a human picks it up.
184
199
 
185
- Return (structured output): \`{ "verdicts": [{ "criteriaId", "verdict", "justification", "reason", "findings" }] }\` — your ITEMS only, every field grounded in what you actually read, every NC finding carrying its \`normativeRef\`.
200
+ Return (structured output): \`{ "verdicts": [{ "criteriaId", "verdict", "justification", "citations", "reason", "findings" }] }\` — your ITEMS only, every field grounded in what you actually read, every NC finding carrying its \`normativeRef\`, and every C (plus every evidenced NA) carrying its \`citations\`. A verdict that clears a criterion without naming what it cleared is refused by the fold, and one refusal discards the WHOLE adjudication — including every other verdict you got right.
186
201
  ${footer}`,
187
202
  refuter: `# Contract: refuter
188
203
 
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.0.0";
3
+ export const VERSION = "5.0.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,