--- phase: quick-260921-jt4 plan: 01 type: execute wave: 1 depends_on: [] files_modified: - apps/web/src/app/(portal)/marketplace/components/MarketplaceCard.tsx - apps/web/src/app/(portal)/marketplace/components/MarketplaceCard.test.tsx - apps/web/src/components/dashboard/widget-catalog-modal.tsx - apps/web/src/components/dashboard/widget-catalog-modal.test.tsx - apps/web/src/components/settings/calendar-settings-panel.tsx - apps/web/src/components/settings/calendar-settings-panel.test.tsx - apps/web/src/components/dashboard/widgets/note-widget.tsx - apps/web/src/components/dashboard/widgets/note-widget.test.tsx - apps/web/src/components/dashboard/widgets/note-task-list.tsx - apps/web/src/components/dashboard/widgets/note-task-list.test.tsx - apps/web/src/components/dashboard/widgets/calendar-widget.tsx - apps/web/src/components/dashboard/widgets/calendar-widget.test.tsx - apps/web/src/components/dashboard/widgets/calculator-widget.tsx - apps/web/src/components/dashboard/widgets/favorites-widget.tsx - apps/web/src/components/layout/header.tsx - apps/web/src/components/settings/account-settings-form.tsx - apps/web/src/app/(auth)/login/page.tsx - apps/web/src/app/(auth)/reset-password/page.tsx - apps/web/src/app/(auth)/reset-password/[token]/page.tsx - apps/web/src/app/(portal)/change-password/page.tsx - apps/web/src/app/(portal)/modules/cert-manager/components/SplitTab.tsx - apps/web/src/app/(portal)/modules/cert-manager/zip-filename.ts - apps/web/src/app/(portal)/modules/cert-manager/zip-filename.test.ts - apps/web/src/lib/translations-identity.test.tsx - apps/web/src/messages/de.json - apps/web/src/messages/en.json - apps/api/src/tenders/tender-normalizer.service.ts autonomous: true requirements: [D-01, D-02, D-03, D-04, D-05, D-06, D-07] estimate: tokens: 150000 raw_tokens: 150000 tasks: 3 confidence: low must_haves: truths: - "Jede Stelle, die heute nur mit der Maus bedienbar ist, ist danach auch mit der Tastatur bedienbar und wird von einer Vorlesehilfe als Schaltflaeche angesagt — belegt durch Komponententests, die ein Tastaturereignis ausloesen, nicht durch Auszeichnungs-Behauptungen (D-01)." - "Das Erscheinungsbild ist an keiner der 13 Dateien ein anderes als vorher: kein neuer Rahmen, kein neuer Abstand, keine verschobene Kachel (D-04)." - "Biome meldet nach Abschluss genau 399 Befunde, 0 davon der Stufe error, und genau EINEN a11y-Befund — den bewusst stehengelassenen Tastatur-Handler des Taschenrechner-Rahmens. Keine einzige Unterdrueckung per biome-ignore (D-07)." - "Drei Druecke auf Weiter im Kalender-Widget holen die Quellenliste genau einmal statt dreimal, und zwei aufeinanderfolgende Termin-Abrufe tragen nie denselben from/to-Bereich — gemessen im Netzwerkprotokoll des Browsers, nicht per fetch aus der Seite." - "Der ZIP-Name des Zertifikat-Aufteilers kommt aus dem Uebersetzungskatalog und ist auf einer Windows-Freigabe garantiert gueltig, weil eine gepruefte Schutzfunktion jeden unzulaessigen Namen abfaengt — nicht, weil das deutsche Wort zufaellig harmlos ist." - "Jede neue Beschriftung steht in de.json UND en.json, deutsche Oberflaechentexte in der Sie-Form; beide Kataloge haben danach dieselbe Schluesselmenge (D-05)." - "Fuer jede der 30 Fundstellen steht in der SUMMARY, welcher der vier Wege gewaehlt wurde und — bei der Rueckfallvariante oder beim Stehenlassen — warum der gerade Weg dort nicht ging." artifacts: - apps/web/src/app/(portal)/modules/cert-manager/zip-filename.ts - apps/web/src/app/(portal)/modules/cert-manager/zip-filename.test.ts - apps/web/src/components/dashboard/widget-catalog-modal.test.tsx - apps/web/src/components/settings/calendar-settings-panel.test.tsx - apps/web/src/lib/translations-identity.test.tsx key_links: - "Hintergrundflaeche eines Dialogs -> echte Schaltflaeche -> onClose: beim Loeschen-Dialog MUSS dieser Weg abbrechen, niemals bestaetigen." - "note-widget -> previewOptions -> rehypeSanitize: die XSS-Schranke T-IEX-01 muss den Umbau des Kaestchen-Handlers unveraendert ueberleben." - "calendar-widget -> computeFetchWindow -> fetchEvents: der Sperrgriff darf den 5-Minuten-Auffrischer nicht mitsperren, sonst friert die Anzeige ein." --- Die 30 zurueckgestellten Barrierefreiheits-Befunde abarbeiten — mit den vom Orchestrator getroffenen Bedienentscheidungen D-01 bis D-04 — und die vier namentlich vermerkten Restposten aus den heutigen Vorgaengen bi2 und gof schliessen. Purpose: Heute sind mehrere Bedienelemente ausschliesslich mit der Maus erreichbar. Wer mit der Tastatur oder einer Vorlesehilfe arbeitet, kann sie nicht ausloesen — das ist der eigentliche Schaden hinter diesen Befunden, kein Schoenheitsfehler der Zaehlung. Output: 13 Oberflaechendateien mit echten Schaltflaechen statt klickbarer Bereiche, zwei Uebersetzungskataloge im Gleichstand, fuenf neue bzw. erweiterte Testdateien, ein gemessener Rueckgang von 429 auf 399 Befunde und zwei Kalender-Abrufe weniger pro Monatswechsel. @~/.claude/gsd-core/workflows/execute-plan.md @~/.claude/gsd-core/templates/summary.md @.planning/STATE.md @CLAUDE.md @.planning/quick/260921-bi2-lint-rueckstand-abbauen-mechanische-fixe/260921-bi2-SUMMARY.md @.planning/quick/260921-gof-effekt-abhaengigkeiten-in-react-21-befun/260921-gof-VERIFICATION.md Vom Planer am 2026-09-21 unmittelbar vor dem Schreiben dieses Plans gemessen, nicht uebernommen: ``` npx biome lint . --reporter=json -> total 429 real 350 test 79 errors 0 a11y 30 ``` Die Zahl 429 ist die **Gesamtzahl inklusive Testdateien** (350 echter Quelltext + 79 Testdateien), nicht der reine Quelltextanteil — die Auftragsbeschreibung bezeichnet sie als "real source only", das ist eine Fehlbeschriftung der sonst korrekten Zahl. Alle 30 a11y-Befunde liegen in echtem Quelltext. Die 30 Fundstellen, mit Zeilennummer zum Zeitpunkt der Planung (Zeilen verschieben sich beim Umbau — arbeite nach Element, nicht nach Zeilennummer): | Datei | Zeile | Regel | |---|---|---| | `app/(auth)/login/page.tsx` | 105 | noAutofocus | | `app/(auth)/reset-password/[token]/page.tsx` | 139 | noAutofocus | | `app/(auth)/reset-password/page.tsx` | 99 | noAutofocus | | `app/(portal)/change-password/page.tsx` | 86 | noAutofocus | | `marketplace/components/MarketplaceCard.tsx` | 116 | noNoninteractiveElementInteractions, noStaticElementInteractions, useKeyWithClickEvents | | `components/dashboard/widget-catalog-modal.tsx` | 56 | noNoninteractiveElementInteractions, noStaticElementInteractions, useKeyWithClickEvents | | `components/dashboard/widget-catalog-modal.tsx` | 64 | noNoninteractiveElementInteractions, useKeyWithClickEvents | | `dashboard/widgets/calculator-widget.tsx` | 323 | noNoninteractiveElementInteractions | | `dashboard/widgets/calculator-widget.tsx` | 345 | useAriaPropsSupportedByRole | | `dashboard/widgets/calendar-widget.tsx` | 253 | noNoninteractiveElementInteractions, noStaticElementInteractions | | `dashboard/widgets/favorites-widget.tsx` | 266 | useAriaPropsSupportedByRole | | `dashboard/widgets/favorites-widget.tsx` | 462 | noNoninteractiveElementInteractions | | `dashboard/widgets/favorites-widget.tsx` | 474 | noNoninteractiveElementInteractions | | `dashboard/widgets/note-widget.tsx` | 184 | noNoninteractiveElementInteractions, noStaticElementInteractions, useKeyWithClickEvents | | `components/layout/header.tsx` | 156 | noNoninteractiveElementInteractions | | `components/settings/account-settings-form.tsx` | 161 | noNoninteractiveElementInteractions | | `components/settings/calendar-settings-panel.tsx` | 159, 182, 199 | useAriaPropsSupportedByRole | | `components/settings/calendar-settings-panel.tsx` | 373 | noNoninteractiveElementInteractions, noStaticElementInteractions, useKeyWithClickEvents | **Zwei Befunde der Auftragsbeschreibung sind beim Nachlesen anders als angenommen** — der Plan folgt dem gelesenen Quelltext, nicht der Annahme: 1. **Vier der elf `noNoninteractiveElementInteractions` sind ueberhaupt keine Klicks**, sondern `onError`-Handler an ``-Elementen (Ersatzweg fuer nicht ladende Profilbilder und Favoriten-Symbole): `header.tsx:156`, `account-settings-form.tsx:161`, `favorites-widget.tsx:462` und `:474`. Ein Ladefehler ist keine Bedienung; hier gibt es nichts in eine Schaltflaeche zu verwandeln. 2. **Alle fuenf `useAriaPropsSupportedByRole` haben dieselbe Gestalt**: ein `aria-label` sitzt auf einem schlichten `
` bzw. `` ohne Rolle. Solche Elemente haben die Rolle `generic`, die gar keine ARIA-Merkmale traegt — die Beschriftung wird von jeder Vorlesehilfe **stillschweigend verworfen**. Das ist ein echter Mangel, kein Formfehler. Die folgenden Loesungswege wurden vom Planer **empirisch an Biome 2.5.0 mit der Projektkonfiguration geprueft** (Probedatei unter `apps/web/src/__probe__/`, danach geloescht). Das ist keine Vermutung — jede Zeile ist gemessen: | Probe | Ergebnis | |---|---| | `