Files
tessera-ctl/.planning/quick/260921-gof-effekt-abhaengigkeiten-in-react-21-befun/260921-gof-SUMMARY.md
T
schalli 287799a6fc
Tessera CI/CD / Lint & Type Check (push) Successful in 52s
Tessera CI/CD / Tests (push) Successful in 1m9s
Tessera CI/CD / Desktop-Pakete bauen (push) Successful in 18s
Tessera CI/CD / Build & Publish Images (push) Successful in 3m50s
docs(quick-260921-gof): 21 Effekt-Abhaengigkeiten beurteilt, im Browser nachgemessen
Zusammenfassung, Verifikation und STATE.md zum Quick-Vorgang 260921-gof.

Ergebnis der Einzelbeurteilung: nur 2 echte Defekte, 15 Fallen (das
naive Eintragen der Abhaengigkeit haette eine Abruf-Schleife erzeugt),
3 bewusste Ausnahmen, 1 Ballast. Die gefaehrlichste Stelle war
calendar-widget.tsx: showToday setzt bei jedem Klick ein frisches Date,
der naive Umbau haette jeden Druck auf den Monatstitel bis zum
Exchange-Server durchschlagen lassen.

Im Browser nachgemessen statt nur behauptet: Dashboard 62 s Ruhe ohne
zusaetzlichen Abruf, Monatstitel dreimal gedrueckt mit null zusaetzlichen
Abrufen nach dem ersten, Stoppuhr echtzeitgetreu ueber 6 s und ueber
4 Runden monoton, dazu acht weitere Ansichten je 20-25 s ruhen gelassen
mit genau einem Abruf je Endpunkt.

Warnungen 467 -> 446, useExhaustiveDependencies 0, web-Tests 66/462 ->
67/477, api unveraendert, type-check 4/4, pnpm lint 5/5.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
2026-09-21 13:00:15 +02:00

275 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: quick-260921-gof
plan: 01
subsystem: ui
tags: [react, next.js, biome, useExhaustiveDependencies, next-intl, vitest]
requires:
- phase: quick-260921-bi2
provides: "Der Testfall, der die instabile-t-Falle in ResultsList.tsx tatsaechlich aufgedeckt hat"
provides:
- "Alle 21 Biome-Befunde der Regel useExhaustiveDependencies in apps/web einzeln entschieden und behoben"
- "Erste Verwendung von biome-ignore im Projekt (genau 3x, mit deutscher Begruendung)"
- "Der durchgaengige Griff gegen die t-Falle: uebersetzten Text vor dem Hook in eine Konstante ziehen statt t selbst in die Abhaengigkeitsliste zu schreiben"
affects: [dashboard-widgets, tender-radar, dkv-fleet, admin-groups, admin-modules, sidebar]
actuals:
tokens: 11720
tasks: 3
commits: 3
plan_head_before: 54fdf69
tech-stack:
added: []
patterns:
- "Ersatz-Fehlertext vor dem Effekt/Rueckruf in eine Konstante ziehen und die Konstante (nicht t) in die Abhaengigkeitsliste schreiben — React vergleicht Strings per Wert"
- "Bei einer instabilen Ladefunktion (gewoehnliche Funktion im Rumpf) diese in useCallback mit der Text-Konstante als Abhaengigkeit einpacken, statt sie leer/eslint-disabled zu lassen"
- "Auffrisch-Ausloeser (refreshKey-Muster) bleiben in der Abhaengigkeitsliste stehen, mit begruendetem biome-ignore statt stiller Unterdrueckung"
- "setState-Funktionsform zur Identitaetserhaltung nutzen (showToday gibt bei unveraendertem Zielmonat dieselbe Referenz zurueck), bevor eine .getTime()-Umgehung durch die direkte Objektreferenz ersetzt wird"
key-files:
created:
- apps/web/src/app/(portal)/admin/groups/components/GroupMembersModal.test.tsx
modified:
- 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/stopwatch-widget.tsx
- apps/web/src/components/dashboard/widgets/stopwatch-widget.test.tsx
- apps/web/src/components/dashboard/widgets/favorites-widget.tsx
- apps/web/src/components/dashboard/widgets/favorites-widget.test.tsx
- apps/web/src/components/layout/sidebar.tsx
- apps/web/src/components/layout/sidebar.test.tsx
- apps/web/src/app/(portal)/admin/groups/components/GroupMembersModal.tsx
- apps/web/src/app/(portal)/admin/modules/components/ActivateModuleDialog.tsx
- apps/web/src/app/(portal)/admin/modules/grants/page.tsx
- apps/web/src/app/(portal)/modules/dkv-fleet/components/InvoiceHistoryTable.tsx
- apps/web/src/app/(portal)/modules/dkv-fleet/settings/components/VehicleTable.tsx
- apps/web/src/app/(portal)/modules/dkv-fleet/settings/components/VehicleTable.test.tsx
- apps/web/src/app/(portal)/modules/tender-radar/components/ResultsList.tsx
- apps/web/src/app/(portal)/modules/tender-radar/components/ResultsList.test.tsx
- apps/web/src/app/(portal)/modules/tender-radar/components/SavedSearchBar.tsx
- apps/web/src/app/(portal)/modules/tender-radar/components/SavedSearchBar.test.tsx
- apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.tsx
- apps/web/src/app/(portal)/modules/tender-radar/components/TenderDetail.test.tsx
- apps/web/src/app/(portal)/modules/tender-radar/settings/components/DigestIntervalForm.tsx
- apps/web/src/app/(portal)/modules/tender-radar/settings/components/RssFeedListForm.tsx
- apps/web/src/app/(portal)/modules/tender-radar/settings/components/RssFeedListForm.test.tsx
- apps/web/src/app/(portal)/modules/tender-radar/settings/components/SourceConfigForm.tsx
- apps/web/src/app/(portal)/modules/tender-radar/settings/components/SourceConfigForm.test.tsx
key-decisions:
- "Reihenfolge bei calendar-widget.tsx eingehalten: showToday zuerst identitaetserhaltend gemacht, erst danach die Abhaengigkeitsliste des Ladeeffekts von monthDate.getTime() auf monthDate umgestellt — die umgekehrte Reihenfolge haette bei jedem Druck auf den Monatsknopf im laufenden Monat einen Termin-Abruf bis zum Exchange-Server ausgeloest."
- "t kommt in keiner der acht betroffenen Dateien in eine Abhaengigkeitsliste — stattdessen wird der uebersetzte Ersatztext vor dem Effekt/Rueckruf in eine Konstante gezogen."
- "Genau drei biome-ignore-Zeilen (Befunde 15, 16, 17) fuer echte Auffrisch-Ausloeser — 14% aller Befunde, deutlich unter der Drittel-Grenze aus D-02."
- "DigestIntervalForm.tsx bekam bewusst keine neue Testdatei — die Komponente wird nur am laufenden System auf 'Meine Quellen' nachgezaehlt (siehe Luecken unten)."
requirements-completed: [D-01, D-02, D-03, D-04, D-05, D-06, D-07]
coverage:
- id: D1
description: "Biome-Regel useExhaustiveDependencies: 21 -> 0 Befunde, Gesamtstand 467 -> 446, 0 Fehler"
requirement: "D-01"
verification:
- kind: other
ref: "npx biome lint . --reporter=json --max-diagnostics=20000 (siehe Zaehlung unten)"
status: pass
human_judgment: false
- id: D2
description: "Genau drei begruendete biome-ignore-Zeilen, keine stille Unterdrueckung"
requirement: "D-02"
verification:
- kind: other
ref: "grep -rl 'biome-ignore lint/correctness/useExhaustiveDependencies' apps/web/src | wc -l -> 3"
status: pass
human_judgment: false
- id: D3
description: "Kalender-Widget: Ersteinblendung/Monatswechsel/Monatsknopf im laufenden Monat verhalten sich korrekt (Zaehlung im Browser-Netzwerkprotokoll ueber 60s + Knopfdruecke)"
requirement: "D-04"
verification: []
human_judgment: true
rationale: "Erfordert einen laufenden Docker-Stapel und Playwright-MCP-Netzwerkzaehlung im Browser — kein CLI-Ersatz vorhanden, siehe Abgrenzung im PLAN."
- id: D4
description: "Stoppuhr laeuft ueber Start/Runde/Stopp/Reset sichtbar sauber weiter, genau 4 PATCH-Aufrufe"
requirement: "D-05"
verification:
- kind: unit
ref: "stopwatch-widget.test.tsx#quick-260921-gof: Runde unterbricht den Takt nicht"
status: pass
human_judgment: true
rationale: "Das visuelle Laufverhalten auf dem Bildschirm (springt/laeuft doppelt/faellt zurueck) ist per PLAN ausdruecklich menschliches Urteil, nicht automatisierbar."
- id: D5
description: "Auffrisch-Ausloeser bleiben wirksam: sidebarRefreshKey, DKV Jetzt pruefen, Ausschreibungsradar Jetzt abrufen"
requirement: "D-03"
verification:
- kind: unit
ref: "sidebar.test.tsx#Befund 17; ResultsList.test.tsx#Befund 15"
status: pass
human_judgment: true
rationale: "Der Browser-Nachweis am laufenden System (Modul-Aktivierung ohne Neuladen sichtbar) ist Teil der Abgrenzung des PLAN und wird vom Orchestrator per Playwright-MCP nachgeholt."
- id: D6
description: "Alle bestehenden Tests bleiben gruen, Zahl der Testdateien/Tests sinkt nicht"
requirement: "D-03"
verification:
- kind: unit
ref: "pnpm -C apps/web exec vitest run -> 67 files / 477 tests (Basis 66/462); pnpm -C apps/api exec vitest run -> 71/1136 unveraendert"
status: pass
human_judgment: false
duration: 55min
completed: 2026-09-21
status: complete
---
# Quick 260921-gof: 21 useExhaustiveDependencies-Befunde in React Summary
**Alle 21 Biome-Befunde der Regel `lint/correctness/useExhaustiveDependencies` in `apps/web` einzeln entschieden: 15 Fallen entschaerft (t-Falle achtmal, instabile Ladefunktionen zweimal, Kalender/Stoppuhr-Objektzugriffe zweimal), zwei echte Defekte behoben, drei Auffrisch-Ausloeser mit `biome-ignore` begruendet stehen gelassen, ein Ballast-Fund entfernt — Gesamtstand 467 auf 446 Meldungen gesenkt, null Regelbefunde, null Fehler.**
## Performance
- **Duration:** ca. 55 min
- **Tasks:** 3/3
- **Files modified:** 25 (24 bestehende + 1 neue Testdatei)
- **Commits:** 3 (+ diese SUMMARY, vom Orchestrator committet)
## Befundtabelle — alle 21, mit Entscheidung
| # | Datei | Zeile | Befund | Kat. | Entscheidung | Was ginge schief (ohne Fix / beim naiven Fix) |
|---|-------|-------|--------|------|--------------|------------------------------------------------|
| 1 | calendar-widget.tsx | 76 | `config` fehlt | B | `useMemo` um `resolveCalendarConfig(config)` ersatzlos entfernt, Werte direkt destrukturiert | Reine Funktion mit drei einfachen Werten — die Merkung hat nie etwas gespart; `config` als Ganzes einzutragen macht sie bei jedem frischen `config`-Objekt wirkungslos |
| 2 | calendar-widget.tsx | 76 | `config.lookaheadDays` zu eng | B | dieselbe Aenderung wie #1 | Gegenrichtung desselben Problems |
| 3 | calendar-widget.tsx | 82 | `monthDate` fehlt | B | `showToday` identitaetserhaltend gemacht (gibt bei bereits angezeigtem Zielmonat dieselbe Referenz zurueck), danach Ladeeffekt-Deps von `monthDate.getTime()` auf `monthDate` umgestellt | Ohne die Stabilisierung zuerst haette jeder Druck auf den Monatsknopf im laufenden Monat einen neuen Termin-Abruf bis zum Exchange-Server ausgeloest (D-04) |
| 4 | calendar-widget.tsx | 82 | `monthDate.getTime()` ueberfluessig | B | dieselbe Aenderung wie #3 | Gegenrichtung desselben Problems |
| 5 | stopwatch-widget.tsx | 81 | `sw` fehlt | B | neue reine Hilfsfunktion `computeElapsedFrom(state, startedAt, elapsed)`, Takt-Effekt liest nur noch die drei Einzelwerte statt des ganzen `sw`-Objekts | `sw` als Abhaengigkeit haette den 100-ms-Takt bei jeder aufgezeichneten Runde ab- und wiederaufgebaut — ohne Not, mit Taktversatz |
| 6 | stopwatch-widget.tsx | 81 | `sw.elapsed` zu eng | B | dieselbe Aenderung wie #5 | Gegenrichtung desselben Problems |
| 7 | VehicleTable.tsx | 182 | `t` fehlt | B | `loadErrorText = t(...)` vor `load` gezogen, Konstante in `load`s Deps | `t` in der Liste haette `load` bei jedem Durchlauf neu erzeugt (Testattrappe liefert frische Funktion) — der Mount-Effekt waere zur Abruf-Schleife geworden |
| 8 | ResultsList.tsx | 89 | `t` fehlt | B | `loadErrorText` vor `load` gezogen | dieselbe Schleifengefahr wie #7 — hier tatsaechlich in 260921-bi2 zugeschnappt |
| 9 | TenderDetail.tsx | 96 | `t` fehlt | B | `detailErrorText` vor dem Effekt gezogen | Detail-Abruf beim Oeffnen einer Ausschreibung waere zur Schleife geworden |
| 10 | DigestIntervalForm.tsx | 32 | `t` fehlt | B | `loadErrorText` vor dem Effekt gezogen | Laden der Zustell-Einstellung waere zur Schleife geworden |
| 11 | SourceConfigForm.tsx | 44 | `t` fehlt | B | `loadErrorText` vor dem Effekt gezogen | Laden der Quellen-Konfiguration waere zur Schleife geworden |
| 12 | RssFeedListForm.tsx | 74 | `loadFeeds` fehlt | B | `loadFeeds` in `useCallback([loadErrorText])` eingepackt | `loadFeeds` als gewoehnliche Rumpf-Funktion waere bei jedem Durchlauf neu entstanden — als Effekt-Abhaengigkeit eine endlose Abruf-Schleife gegen die Feed-Liste |
| 13 | SavedSearchBar.tsx | 141 | `load` fehlt | B | `load` in `useCallback([loadErrorText])` eingepackt | dieselbe Schleifengefahr wie #12, gegen die Suchprofile |
| 14 | favorites-widget.tsx | 99 | `t` fehlt | B | `favoritesErrorText` vor dem Effekt gezogen | Mount-Abruf der Favoriten waere zur Schleife geworden |
| 15 | ResultsList.tsx | 89 | `refreshKey` ueberfluessig | C | aus `load`s Deps entfernt, in den aufrufenden Mount-Effekt verschoben + `biome-ignore` mit deutschem Grund | `refreshKey` ist der Auffrisch-Ausloeser der Elternseite nach "Jetzt abrufen" — ohne ihn bliebe die Trefferliste nach einem Abruf auf dem alten Stand |
| 16 | InvoiceHistoryTable.tsx | 81 | `refreshKey` ueberfluessig | C | bleibt stehen + `biome-ignore` mit deutschem Grund | ohne ihn bliebe die DKV-Historie nach "Jetzt pruefen" auf dem alten Stand |
| 17 | sidebar.tsx | 57 | `sidebarRefreshKey` ueberfluessig | C | bleibt stehen + `biome-ignore` mit deutschem Grund | ohne ihn erschiene ein frisch aktiviertes Modul erst nach einem Neuladen der Seite — die Navigation liefe dem Berechtigungsstand hinterher |
| 18 | ActivateModuleDialog.tsx | 47 | `moduleId` ueberfluessig | D | aus der Liste entfernt, `open` bleibt | reiner Ballast: der Effekt holt nur die vom Modul unabhaengige Gruppenliste, die Elternseite haengt den Dialog je Modul frisch ein |
| 19 | GroupMembersModal.tsx | 89 | `fetchMembers` fehlt | A | in die Liste aufgenommen (beide Ladefunktionen bereits stabil) | ohne sie zeigt der Dialog bei einem Gruppenwechsel ohne Neuaufbau die Mitglieder der vorigen Gruppe |
| 20 | GroupMembersModal.tsx | 89 | `fetchAllUsers` fehlt | A | in die Liste aufgenommen | dieselbe Stelle, dieselbe Begruendung |
| 21 | grants/page.tsx | 140 | `matches` ueberfluessig | B | Hilfsfunktion `matches` in den Rumpf der Merkung verschoben statt im Bauteil-Rumpf zu bleiben | eingetragen liefe die Filter-Merkung bei jedem Durchlauf neu und waere damit wirkungslos — keine Schleife, aber die Merkung ist weg, wegen der die Stelle gebaut wurde |
**Verteilung:** 2x (A), 15x (B), 3x (C), 1x (D) — exakt wie im PLAN vorgegeben.
## Die drei begruendeten Ausnahmen (D-02)
1. **`ResultsList.tsx:141`**
`// biome-ignore lint/correctness/useExhaustiveDependencies: refreshKey ist der Auffrisch-Ausloeser der Elternseite nach "Jetzt abrufen" - ohne ihn bliebe die Trefferliste nach einem Abruf auf dem alten Stand.`
2. **`InvoiceHistoryTable.tsx:84`**
`// biome-ignore lint/correctness/useExhaustiveDependencies: refreshKey ist der Auffrisch-Ausloeser der Elternseite nach "Jetzt pruefen" - ohne ihn bliebe die Historie auf dem alten Stand.`
3. **`sidebar.tsx:61`**
`// biome-ignore lint/correctness/useExhaustiveDependencies: sidebarRefreshKey ist der Auffrisch-Ausloeser aus dem Marketplace-Speicher - ohne ihn liefe die Navigation dem Berechtigungsstand hinterher.`
3 von 21 = 14%, unter der Drittel-Grenze aus D-02.
## Zaehlung vorher/nachher (real gemessen, nicht angenommen)
| Messung | Vorher (Baseline `54fdf69`, in einem temporaeren Worktree nachgemessen) | Nachher |
|---|---|---|
| Biome gesamt (`apps/web`) | `total=467 exhaustive=21 errors=0` | `total=446 exhaustive=0 errors=0` |
| `pnpm lint` | 5/5, Fehler-Schwere unbekannt (nicht separat gemessen) | 5/5, 0 Befunde der Schwere `error` |
| `pnpm type-check` | nicht separat gemessen | 4/4 |
| `eslint-disable-next-line react-hooks/exhaustive-deps` in `apps/web/src` | 11 (laut PLAN) | 0 |
| `biome-ignore lint/correctness/useExhaustiveDependencies` in `apps/web/src` | 0 | 3 |
| `apps/web` Testdateien / Tests | 66 / 462 (PLAN-Baseline) | **67 / 477** |
| `apps/api` Testdateien / Tests | 71 / 1136 | 71 / 1136 (unveraendert, Aufgabe fasst apps/api nicht an) |
Differenz Biome gesamt: 467 − 446 = 21, exakt ein Befund pro Fund — kein Anstieg an anderer Stelle, keine versehentliche Zusatzbereinigung.
## Gesamtnachweis — Ergebnisse je Zeile
| Ansicht | Erwartung laut PLAN | Ergebnis |
|---|---|---|
| Biome gesamt | `total=446 exhaustive=0 errors=0` | **Erreicht** — real gemessen: `total=446 exhaustive=0 errors=0` |
| `pnpm lint` | 5/5 | **Erreicht** — `5 successful, 5 total`, 87 Warnungen ausserhalb der Regel (Vorbestand, ausserhalb des Scopes) |
| `pnpm type-check` | 4/4 | **Erreicht** — `4 successful, 4 total` |
| `apps/web` Vitest | gruen, nicht unter 66/462 | **Erreicht und ueberschritten** — 67 Dateien / 477 Tests (11 neue Zaehlproben in bestehenden Dateien + 1 neue Testdatei mit 3 Faellen) |
| `apps/api` Vitest | gruen, nicht unter 71/1136 | **Erreicht, unveraendert** — 71/1136 |
| Dashboard, Kalender-Kachel, 60s ruhen | 1x `/calendar/sources`, 1x `/calendar/events` | **An den Orchestrator (Browser/Playwright-MCP) — nicht CLI-pruefbar** |
| Dashboard, Kalender-Kachel, 3x Monatsknopf im laufenden Monat | kein zusaetzlicher `/calendar/events` | Per Unit-Test (Test 10 in `calendar-widget.test.tsx`) bewiesen: **pass**. Browser-Nachweis am laufenden System: **an den Orchestrator** |
| Dashboard, Kalender-Kachel, 2x weiterblaettern | genau 2 zusaetzliche `/calendar/events` | Per Unit-Test (Test 9) bewiesen: **pass**. Browser-Nachweis: **an den Orchestrator** |
| Dashboard, Stoppuhr, Start/Runde/Stopp/Reset | genau 4x `PATCH .../config`; Anzeige laeuft sauber (Menschenurteil) | PATCH-Zaehlung per Unit-Test bewiesen (neuer Testfall: Start+Runde=2 Aufrufe im Testfall selbst, Stop/Reset-Zaehlung bereits in Bestandstests). **Visuelles Laufverhalten: menschliches Urteil, an den Orchestrator** |
| Ausschreibungsradar, 60s ruhen | 1x `/tenders`, 1x `/triage` | **An den Orchestrator** |
| Ausschreibungsradar, Jetzt abrufen | genau 1 zusaetzlicher `/tenders` | Per Unit-Test (`ResultsList.test.tsx#Befund 15`) bewiesen: **pass**. Browser-Nachweis: **an den Orchestrator** |
| Meine Quellen, 60s ruhen | je 1 Abruf fuer Zustell-Einstellung, RSS-Feeds, Quellen-Konfiguration | Re-render-Zaehlproben fuer RssFeedListForm/SourceConfigForm bestehen (`pass`); `DigestIntervalForm` hat keine Testdatei (siehe Luecken). Browser-Nachweis: **an den Orchestrator** |
| DKV Flotte, Jetzt pruefen | genau 1 zusaetzlicher Historien-Abruf | `biome-ignore`-Begruendung + bestehendes `refreshKey`-Verhalten unveraendert; kein neuer Unit-Test noetig (Verhalten der Komponente unveraendert). Browser-Nachweis: **an den Orchestrator** |
| DKV Flotte, Fahrzeuge, Fahrzeug speichern | Tabelle zeigt neuen Stand, kein Dauerfeuer | Unveraendertes Verhalten (Befund 7 betraf nur den Ladefehler-Text). Browser-Nachweis: **an den Orchestrator** |
| Marketplace, Modul aktivieren | erscheint ohne Neuladen in der Seitenleiste | Per Unit-Test (`sidebar.test.tsx#Befund 17`) bewiesen: **pass**. Browser-Nachweis: **an den Orchestrator** |
| Modulverwaltung, Aktivierungs-Dialog oeffnen | genau 1x `/groups` | Unveraendertes Verhalten (Befund 18 betraf nur eine ueberfluessige, wirkungslose Abhaengigkeit — kein Verhaltensunterschied im Netzwerkverkehr). Browser-Nachweis: **an den Orchestrator** |
| Gruppenverwaltung, Dialog A schliessen, B oeffnen | Mitglieder gehoeren zu B | Per neuer Unit-Test (`GroupMembersModal.test.tsx`, dritter Fall) bewiesen: **pass** — dies ist der einzige echte Defekt (Kategorie A) im ganzen Befund und der Test faellt ohne den Fix durch. Browser-Nachweis zusaetzlich: **an den Orchestrator** |
## An den Orchestrator uebergebene Verifikationsschritte (Browser/Playwright-MCP)
Alle mit "an den Orchestrator" markierten Zeilen der Tabelle oben, zusammengefasst — der Executor hat keinen Browser-Zugriff:
1. Dashboard-Kalender: 60s-Zaehlung, 3x Monatsknopf im laufenden Monat, 2x weiterblaettern (D-04).
2. Stoppuhr: visuelles Laufverhalten ueber Start/Runde/Stopp/Reset (Menschenurteil, ausdruecklich nicht automatisierbar) plus PATCH-Zaehlung im Netzwerkprotokoll (D-05).
3. Ausschreibungsradar: 60s-Zaehlung, Jetzt-abrufen-Zaehlung.
4. Meine Quellen: 60s-Zaehlung fuer alle drei Formulare (Zustell-Einstellung/RSS/Quellen-Konfiguration) — fuer `DigestIntervalForm` ist dies die EINZIGE Verifikation, da keine Testdatei existiert.
5. DKV Flotte: Jetzt-pruefen-Zaehlung, Fahrzeug-Speichern-Anzeige.
6. Marketplace: Modul-Aktivierung ohne Neuladen sichtbar in der Seitenleiste.
7. Modulverwaltung: Aktivierungs-Dialog genau 1x `/groups`.
8. Gruppenverwaltung: Mitglieder-Dialog zeigt nach Gruppenwechsel die richtige Gruppe (zusaetzlich zum bereits gruenen Unit-Test).
Alle Unit-Test-/CLI-seitig pruefbaren Teile dieser Zeilen sind bereits bewiesen (siehe Tabelle) — an den Orchestrator geht ausschliesslich der Netzwerkzaehlungs-/visuelle Teil, der einen laufenden Docker-Stapel und einen Browser braucht.
## Task Commits
1. **Aufgabe 1: Kalender und Stoppuhr — die Effekte mit Taktgeber (Befunde 1-6)** — `b3f0e3c` (fix)
2. **Aufgabe 2: Die t-Falle und die instabilen Ladefunktionen (Befunde 7-15)** — `e2c508c` (fix)
3. **Aufgabe 3: Absicht, Ballast und die zwei fehlenden stabilen Abhaengigkeiten (Befunde 16-21)** — `e780b2c` (fix)
**Plan metadata:** wird vom Orchestrator committet (SUMMARY.md, STATE.md, ROADMAP.md).
## Files Created/Modified
Siehe `key-files` im Frontmatter — 24 bestehende Dateien angepasst (15 Quelldateien + 9 Testdateien) plus eine neue Testdatei (`GroupMembersModal.test.tsx`). Keine Datei ausserhalb der 15 im PLAN genannten Befund-Dateien und ihrer Tests wurde angefasst (D-06).
## Decisions Made
- Bei `calendar-widget.tsx` wurde die im PLAN vorgeschriebene Reihenfolge (erst `showToday` stabilisieren, dann die Abhaengigkeitsliste umstellen) exakt eingehalten — die umgekehrte Reihenfolge haette einen echten Denial-of-Service-Pfad gegen den Exchange-Server geoeffnet (T-GOF-02).
- Fuer `RssFeedListForm.tsx` und `SavedSearchBar.tsx` wurde `useCallback` statt einer weiteren `biome-ignore`-Zeile gewaehlt, weil die Ladefunktionen bereits sauber isolierbar waren und die PLAN-Vorgabe genau das verlangt ("Ladefunktion in einen stabilen Rueckruf einpacken").
- `DigestIntervalForm.tsx` bekam bewusst keine neue Testdatei, wie im PLAN explizit vorgesehen — die Verifikation laeuft ausschliesslich am laufenden System.
## Deviations from Plan
None — Plan exakt wie geschrieben ausgefuehrt. Alle drei Aufgaben, alle 21 Befunde, alle im PLAN benannten Testerweiterungen wurden 1:1 umgesetzt. Der einzige nennenswerte Punkt ist keine Abweichung, sondern eine im PLAN selbst schon erwartete Luecke (siehe unten).
## Issues Encountered
Beim Schreiben der neuen `GroupMembersModal.test.tsx` traf `screen.getByText('Anna Schmidt')` zunaechst auf zwei Elemente (Mitgliederliste UND Benutzer-Suchliste zeigen denselben Namen) — behoben durch Scoping auf `within(screen.getByRole('list'))`, da die Mitgliederliste die einzige `<ul>` im Bauteil ist. Kein Rule-1/2/3-Fall im Sinne des Ausfuehrungsprotokolls (reiner Testfehler beim Erstschreiben, sofort korrigiert, kein separates Deviation-Log noetig).
## Offen benannte Luecken
1. **`DigestIntervalForm.tsx` hat keine Testdatei** — wie im PLAN vorgesehen ("Hier wird bewusst keine angelegt"). Die Komponente wird ausschliesslich am laufenden System auf der Seite "Meine Quellen" nachgezaehlt (Teil der an den Orchestrator uebergebenen Browser-Verifikation).
2. **Alle Browser/Netzwerkprotokoll-Nachweise** (siehe Abschnitt "An den Orchestrator uebergebene Verifikationsschritte") sind vom Executor nicht durchgefuehrt worden — kein Browser-Werkzeug verfuegbar. Jeder CLI-pruefbare Anteil derselben Verhaltensbehauptung ist bereits durch einen gruenen Unit-Test belegt.
3. **`pnpm lint`-Baseline vor dieser Aufgabe** wurde nicht separat mit `--max-diagnostics` auf Fehler-Schwere durchsucht (nur die volle `biome lint .`-JSON-Ausgabe, die `errors=0` sowohl vorher als auch nachher zeigt) — kein Risiko, da beide Messungen denselben Befehl verwenden.
## Next Phase Readiness
Kein laufender Meilenstein betroffen (Quick-Vorgang ohne Roadmap-Phase). Keine Blocker. Die Regel `useExhaustiveDependencies` kann ab jetzt regulaer scharf bleiben, ohne dass neue Befunde unbemerkt durchrutschen — 3 begruendete Ausnahmen sind die einzige verbleibende Unterdrueckung im Projekt.
---
*Phase: quick-260921-gof*
*Completed: 2026-09-21*
## Self-Check: PASSED
- FOUND: apps/web/src/components/dashboard/widgets/calendar-widget.tsx
- FOUND: apps/web/src/components/dashboard/widgets/stopwatch-widget.tsx
- FOUND: apps/web/src/app/(portal)/admin/groups/components/GroupMembersModal.test.tsx
- FOUND: .planning/quick/260921-gof-effekt-abhaengigkeiten-in-react-21-befun/260921-gof-SUMMARY.md
- FOUND commit: b3f0e3c
- FOUND commit: e2c508c
- FOUND commit: e780b2c