Skip to content

fix(a11y): surface the WCAG 2.2.2 warnings the validator already computes - #18

Merged
MasterPlayspots merged 1 commit into
mainfrom
fix/surface-a11y-warnings
Aug 5, 2026
Merged

fix(a11y): surface the WCAG 2.2.2 warnings the validator already computes#18
MasterPlayspots merged 1 commit into
mainfrom
fix/surface-a11y-warnings

Conversation

@MasterPlayspots

Copy link
Copy Markdown
Owner

PR: die WCAG-2.2.2-Signale erreichen den Aufrufer

Branch-Vorschlag: fix/surface-a11y-warnings
Basis: e20d31a (main, 03.08.2026 21:59)
Patch: PR_weg-0.patch — 7 Dateien, +209 / −19


Warum

motion_validate ist das einzige öffentlich erreichbare Prüfwerkzeug. Es hat bis heute ok:true
zurückgegeben für ein Spec mit abgeschaltetem Reduced-Motion-Schutz, abgeschaltetem Pause-Pfad,
einem 120-Sekunden-Marquee und einem 60-Sekunden-Spin
— ohne ein einziges Signal.

Die Warnungen wurden dabei die ganze Zeit berechnet. validate.js erzeugt sie in Zeile 213
(MS-GLOBALS-RRM-OFF) und Zeile 324 (MS-GLOBALS-PAUSE-OFF); register-tools.js Zeile 99 baute
die Antwort ohne das Feld warnings. compile.js verwarf sie ebenso, weshalb auch der CLI-Pfad
blind war.

Am 04.08. dreimal unabhängig reproduziert, zuletzt gegen den Live-Endpunkt.

Was drin ist

1 · warnings[] wird durchgereichtregister-tools.js, compile.js
motion_validate und motion_compile geben warnings mit aus. ok bleibt unverändert (siehe
offene Frage unten). Die Werkzeugbeschreibung sagt jetzt ausdrücklich, dass ok:true bei
nicht-leerem warnings[] möglich ist.

2 · persistent steht im Katalogcatalog.js
motion_catalog liefert je Primitiv persistent: true|false. 18 der 40 Primitive sind
persistent. Vorher konnte ein Agent aus dem Katalog nicht ableiten, welche Primitive 2.2.2
auslösen. Dazu zwei neue Authoring-Regeln (7 und 8), die pauseControls überhaupt erst erwähnen —
der Schlüssel war bisher nur über die Fehlermeldung MS-GLOBALS-KEY auffindbar.

3 · respectReducedMotion wird typgeprüftvalidate.js
"nein danke" ergab ok:true und umging sogar die interne Warnung, weil die auf === false
prüft. Jetzt harter Fehler MS-GLOBALS-RRM-TYPE, wie bei pauseControls.

4 · ease bekommt ein Vokabularvalidate.js
Das Muster im Katalog war ein Zeichensatzfilter und damit invertiert: es nahm banana.out und
quantumBounce9000 an. Ein erfundener Wert lief wörtlich in die ausgelieferte Datei und GSAP fiel
still auf den Default zurück.

Die Vokabularprüfung sitzt jetzt im Validator, nicht im Katalogmuster. Das ist keine Stilfrage:
catalog.js deckelt jedes Muster bei 100 Zeichen (MAX_PATTERN_CHARS, ein ReDoS-Schutz, der in
test/forge-promote-gate.test.js:262 eigens festgeschrieben ist), und ein GSAP-Ease-Vokabular
braucht 166. Ein Vokabular im Muster hätte also entweder die Sicherheitsinvariante gebrochen oder
alle fünf Primitive auf MAJOR gehoben und die catalogVersion für jeden Konsumenten geändert.

Die Primitiv-Dateien bleiben unberührt. catalogVersion bleibt 8a9813a9b3c6c626.
npm run catalog-lock:check meldet „Catalog SemVer OK".

5 · hono 4.12.32 → 4.13.0 — nur package-lock.json, 6 Zeilen
Neues Prod-Advisory GHSA-8j4g-w8fx-2239 (ReDoS in der CORS-Middleware), Pfad
motionspec → @modelcontextprotocol/sdk@1.30.0 → hono. Das CI-Gate ist --audit-level=low und
fällt sonst durch. Die beiden Advisories von gestern (brace-expansion, fast-uri) sind mit
PR #17 erledigt.

Gates — alle lokal gefahren auf e20d31a

Gate Ergebnis
npm test 302 / 302, 0 Fehler (vorher 295; 7 neue Tests)
npm run lint sauber
npm run catalog-lock:check Catalog SemVer OK (added: none; removed: none)
npm run coverage 99,06 % Zeilen / 99,09 % Funktionen (Gate: 90 %)
npm audit --audit-level=low 0 vulnerabilities
npm run sbom + sbom:check + license-check 91 Komponenten vollständig, 95 permissiv
Compiler-Smoke (3 Kommandos) OK
Trust-Boundary-Smoke (blocked-demo muss scheitern) OK — fällt geschlossen
npm run e2e nicht fahrbar — Playwright-Chromium fehlt in der Sandbox (Build 1234 gefordert, 1194 vorhanden). Umgebungsgrenze, keine Aussage über den Code. CI / e2e war am 03.08. 13:57 UTC auf main rot; ob das noch gilt, muss GitHub zeigen

Der Beweis

BEWEIS_vorher-nachher.txt enthält die Antwort, die der Endpunkt nach dem Patch auf genau das
Spec gibt, das vorher ok:true ohne alles bekam — mit beiden Warnungen, persistent-Zählung,
Typprüfung und der ease-Tabelle.

Eine offene Frage, die ich nicht selbst entscheide

Soll ok bei einem 2.2.2-Verstoß weiterhin true sein?

Ich habe es so gelassen. Begründung: pauseControls: "off" ist ein dokumentierter Enum-Wert, und
ok beantwortet „kompiliert das Spec", nicht „ist es barrierefrei". Ein Umschalten auf ok:false
wäre ein Breaking Change für jeden, der off bewusst setzt.

Folge für die Außendarstellung: Auf den Flächen muss dann „meldet" stehen, nicht „verhindert".
Wenn dort „verhindert" oder „garantiert" stehen soll, ist ok:false der ehrliche Weg — dann aber
als eigener, angekündigter Major. Angesichts der FTC-Anordnung gegen accessiBe (1 Mio. USD,
03.01.2025, falsch dargestellte Konformitätsfähigkeit) ist das die teuerste Zeile im ganzen Haus.

Eine dritte Möglichkeit: ein eigenes Feld conformance: { "2.2.2": "violation" } neben ok.
Sag Bescheid, dann baue ich es nach.

Was NICHT drin ist

  • elastic.out(1,0.3) bleibt abgelehnt. Das Zeichensatzmuster in den Primitiv-Dateien verbietet
    das Komma; es zu weiten heißt MAJOR-Bump und neue catalogVersion. Der Fehler nennt jetzt
    wenigstens den wahren Grund (MS-PARAM-EASE-UNSUPPORTED) statt zu behaupten, der Wert sei
    unbekannt. Einargumentige Formen wie elastic.out(1) und back.out(1.7) laufen.
  • globals.defaultEase ist weiterhin ungeprüft (allowlisted, vom Compiler nicht ausgewertet).
    Gleiche Klasse, kleineres Risiko — bewusst außen vor gelassen, um den PR eng zu halten.
  • Kein Deploy. Der Patch berührt den Worker nicht; die MCP-Schicht muss nach dem Merge separat
    ausgerollt werden, sonst antwortet der Live-Endpunkt weiter wie bisher.

Commit-Vorschlag

fix(a11y): surface the WCAG 2.2.2 warnings the validator already computes

motion_validate and motion_compile dropped validateSpec().warnings, so the
only publicly reachable checker answered ok:true for a spec with
reduced-motion off, pause off, a 120s marquee and a 60s spin.

- register-tools.js/compile.js: pass warnings[] through
- catalog.js: expose a11y.persistent as `persistent` (18 of 40 primitives)
- validate.js: type-check globals.respectReducedMotion (MS-GLOBALS-RRM-TYPE)
- validate.js: gate `ease` against the GSAP vocabulary (MS-PARAM-EASE);
  kept out of the catalog pattern so the 100-char ReDoS screen and the
  catalogVersion both stay untouched
- lockfile: hono 4.12.32 -> 4.13.0 (GHSA-8j4g-w8fx-2239, prod tree)

catalogVersion unchanged (8a9813a9b3c6c626). 302/302 tests, coverage 99.06%.

\U0001F916 Generated with Claude Code

https://claude.ai/code/session_0149NhkePB1zzszxUyG1L5vW

…utes

motion_validate and motion_compile dropped validateSpec().warnings, so the
only publicly reachable checker answered ok:true for a spec with
reduced-motion off, pause off, a 120s marquee and a 60s spin.

- register-tools.js/compile.js: pass warnings[] through
- catalog.js: expose a11y.persistent as `persistent` (18 of 40 primitives)
- validate.js: type-check globals.respectReducedMotion (MS-GLOBALS-RRM-TYPE)
- validate.js: gate `ease` against the GSAP vocabulary (MS-PARAM-EASE);
  kept out of the catalog pattern so the 100-char ReDoS screen and the
  catalogVersion both stay untouched
- lockfile: hono 4.12.32 -> 4.13.0 (GHSA-8j4g-w8fx-2239, prod tree)

catalogVersion unchanged (8a9813a9b3c6c626). 302/302 tests, coverage 99.06%.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149NhkePB1zzszxUyG1L5vW
@netlify

netlify Bot commented Aug 5, 2026

Copy link
Copy Markdown

Deploy Preview for strong-fudge-f04a16 ready!

Name Link
🔨 Latest commit 62fde3e
🔍 Latest deploy log https://app.netlify.com/projects/strong-fudge-f04a16/deploys/6a732269107c0800084e31ac
😎 Deploy Preview https://deploy-preview-18--strong-fudge-f04a16.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@MasterPlayspots
MasterPlayspots merged commit 3c3bd66 into main Aug 5, 2026
10 of 11 checks passed
MasterPlayspots added a commit that referenced this pull request Aug 17, 2026
…caught it (#24)

* docs(changelog): 1.2.5 through 1.2.7, plus the gate that should have caught it

THE MEASURED GAPS
  1. Five tags exist (v1.2.3 ... v1.2.7). One GitHub release does (v1.2.5).
  2. CHANGELOG ended at 1.2.4 while npm served 1.2.7 — three releases with
     no entry.
  3. Unreleased commits sit on main after v1.2.7.

WHAT CHANGED
  CHANGELOG: 1.2.5, 1.2.6 and 1.2.7 written from the commit log, not from
  memory. Tone follows 1.2.7's own name — "honest short descriptions".

  bin/changelog-gate.js: the previous prepublishOnly check only asked whether
  CHANGELOG.md EXISTED. It did, continuously, while three versions shipped
  without an entry. A file-exists check cannot catch that; it was green the
  whole time. The new gate requires a NON-EMPTY "## [<version>]" section.

  .github/workflows/release.yml: a tag now creates its GitHub release, with the
  changelog section as the release notes. Writing release notes twice means
  writing them differently, and then neither is authoritative.

PROVEN, not asserted:
  version present + section filled  -> exit 0
  version absent from CHANGELOG     -> exit 1
  section present but empty         -> exit 1
  npm test green, npm audit: 0 vulnerabilities

CORRECTIONS to the task description:
  · It claims TWO unreleased commits after v1.2.7. There are THREE — the extra
    one is 4d6fb59 "fix: resolve high severity npm vulnerability". A security
    fix is sitting on main, unpublished; npm still serves 1.2.7 without it.
    Recorded under [Unreleased].
  · plugin.json does not exist on main, so it cannot be at 1.2.7 as claimed.
    package.json and server.json are both 1.2.7 — no drift between those two.
  · The six "orphan" branches are all genuinely merged (PRs #4, #15, #17, #18,
    #19, #20); only the refs remain. Deleting them is K4 — listed, not done.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(deps): regenerate package-lock.json — it pinned nothing

CI was red on this PR. It is red on `main` too, for the same reason and
independently of anything in this branch: a clean `main` worktree fails
`npm ci` identically.

  npm error `npm ci` can only install packages when your package.json and
  npm error package-lock.json are in sync.
  npm error Missing: @commitlint/cli@21.2.2 from lock file
  npm error Missing: @modelcontextprotocol/sdk@1.30.0 from lock file
  npm error Missing: zod@4.4.3 from lock file
  ... 20 more

The lock file was not merely stale. It carried NO ENTRY for either runtime
dependency — @modelcontextprotocol/sdk and zod — and none for the devDependency
tree at all. It pinned nothing. Every CI job died at `npm ci` before running a
single test, which is why coverage, e2e, lint, security and all three test
matrix legs failed within 17 seconds.

Regenerated with `npm install --package-lock-only`. The resulting versions match
exactly what package.json already specifies (sdk 1.30.0, zod 4.4.3), so this
changes no dependency — it records the ones that were already chosen.

  npm ci --dry-run   passes
  npm test           green
  npm audit          0 vulnerabilities

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant