---
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 |
|---|---|
| `