Skip to content

fix(dashboard): UI-Politur-Buendel A (#320-#324) - #341

Merged
TillQuandel merged 6 commits into
masterfrom
fix/bundle-a-dashboard-ui
Jul 17, 2026
Merged

fix(dashboard): UI-Politur-Buendel A (#320-#324)#341
TillQuandel merged 6 commits into
masterfrom
fix/bundle-a-dashboard-ui

Conversation

@TillQuandel

Copy link
Copy Markdown
Owner

Zusammenfassung

Sammel-PR "Bündel A Dashboard-UI" — 5 kleine, unabhängige UI-Fixes aus dem UX-Review zu PR #312 (2026-07-16), je Issue ein Commit. Alle 5 Punkte umgesetzt, keine ausgelassen.

#320 — Badge-Hinweis für modellose Eval-Zeilen im Modell-Dropdown

Änderung: Server zählt jetzt im selben Durchlauf wie n_valid je Modell mit, wie viele valide Eval-Zeilen KEIN run_id-Match zu einem Pipeline-Lauf haben (models_unmatched_n, generative/eval_dashboard_server.py). Frontend zeigt das als kompakten *-Hint-Marker (bestehendes .hint/.hint-pop-Muster) neben dem "Modell"-Label — nur sichtbar, wenn die Zahl > 0 ist.

Sichtprüfung: Repro mit echten Produktionsdaten via ?eval_version=1.3 (dort sind laut Issue alle 87 Zeilen modellos — bestätigt: models_unmatched_n: 87). Screenshots 320-*-vor/nach.png zeigen den *-Marker neben "MODELL" nur in der Nach-Version; 320-*-nach-hover.png zeigt den Tooltip-Text ("87 Zeilen ohne Modell-Zuordnung …"). Auch im Default-View (eval_version 4.3) taucht der Marker auf (sichtbar in den #324-Screenshots) — die Lücke betrifft nicht nur den Sonderfall 1.3. Kleine Auffälligkeit: der Tooltip-Popup wird oben leicht vom Viewport-Rand abgeschnitten, wenn die Filterbar ganz oben pinnt (gleiches Verhalten wie alle anderen .hint-Elemente dort, kein Regressionseffekt meines Fixes).

Tests: generative/tests/test_dashboard_model_filter_n_valid.py (+4 neue Fälle: Zählung, Sentinel-Ausschluss, Null-Fall, HTML-Anker).

#321 — Zebra-/Hover-Naht an der sticky PDF-Spalte der Matrix

Änderung: Statt die Sticky-Spalte bei Zebra/Hover deckend auf den generischen var(--bg-card) zurückzusetzen, jetzt vorberechnete opake Misch­farben (--bg-card-zebra/--bg-card-hover, je Theme in :root/body.light) — reproduziert denselben 1,5/3,5-%-Tint wie die rgba-Overlays der übrigen Spalten, bleibt aber deckend für den Sticky-Scroll-Effekt.

Sichtprüfung: Der Farbunterschied ist bewusst sehr subtil (1,5–3,5 % Opazität) und in Screenshots kaum sichtbar — daher zusätzlich per Playwright getComputedStyle verifiziert:

  • Hell, vorher: sticky-Zelle rgb(255,255,255) vs. Rest der Zebra-Zeile rgba(0,0,0,0.015) (auf Weiß ≈ #fbfbfb) → sichtbarer Bruch.
  • Hell, nachher: sticky-Zelle rgb(251,251,251) = exakt #fbfbfb → deckungsgleich mit dem Rest der Zeile.
  • Dunkel, vorher: sticky rgb(20,30,46) vs. Rest rgba(255,255,255,0.015) (≈ #182131 komposit) → Bruch.
  • Dunkel, nachher: sticky rgb(24,33,49) → deckungsgleich.

Screenshots 321-*-vor/nach.png (Matrix nach 400px Horizontal-Scroll, Hover auf Zebra-Zeile) zeigen keine Regression, keinen Layout-Bruch.

Tests: rein CSS/Wortlaut-Punkt, keine neuen pytest-Tests — Farbverifikation wie oben beschrieben.

#322 — n=0-Banner-Wortlaut widerspricht Matrix-Verhalten

Änderung: Beide Banner-Textvarianten (mit/ohne Betriebskennzahlen) sowie der statische Default-Text ergänzen jetzt den Hinweis, dass die Versions×PDF-Matrix filterunabhängig weiter den vollen Corpus zeigt (bestätigt: die Matrix ignoriert laut Code-Kommentar in build_data() JEDEN Filter — PDF/Version/Modell/Sprache/Lauf —, nicht nur PDF/Version wie im Issue-Testname genannt).

Sichtprüfung: Repro mit echten Produktionsdaten über den Lauf-Filter auf den bekannten Merge-only-Run 20260713-084724 (0 Notes evaluiert, Betriebskennzahlen vorhanden — derselbe Run aus dem #237-Fix). Screenshots 322-*-vor/nach.png zeigen den alten vs. neuen Bannertext im direkten Vergleich, hell und dunkel.

Tests: generative/tests/test_dashboard_null_eval_honesty.py (+1 neuer Fall: prüft den Zusatzhinweis im statischen Default-Text UND in beiden dynamischen JS-Varianten).

#323 — Scatter-Legende zeigt Roh-PDF-Keys statt kanonisierter Labels

Änderung: _chart_scatter_versioned (generative/eval_dashboard_server.py) bildet den Legenden-Dict-Key jetzt über D._pdf_group_key(pdf) statt über den Rohstring — derselbe Kanonisierungs-Pfad wie _calc_pdf_table/#311. Label weiterhin aus D._PDF_LABELS/_pdf_short_name. points[].pdf trägt jetzt ebenfalls den kanonischen Key (nötig, damit das Frontend Punkte weiterhin korrekt ihrer Legenden-Gruppe zuordnet, pt.pdf === legendEntry.raw).

Sichtprüfung: stärkster Vor/Nach-Unterschied im gesamten Bündel — mit echten Produktionsdaten (?eval_version=4.1) zeigte die Legende vorher drei separate Bates-Einträge ("Bates (2017)", "bates-2017", "Bates") in unterschiedlichen Farben, nachher einen ("Bates (2017)"). Screenshots 323-*-vor/nach.png zeigen das direkt in der Legendenzeile.

Tests: generative/tests/test_dashboard_scatter_pdf_canonicalization.py (neu, 3 Fälle: Kollaps von Drift-Varianten, Punkt/Legenden-Key-Konsistenz, Regressionswächter gegen versehentliches Zusammenlegen unterschiedlicher Quellen).

#324 — Filterbar zweizeilig im Band 1201–~1430px

Änderung: Die Kompakt-Styles der Filterbar (.filter-group Padding, .fselect max-width) in eine eigene @media (max-width: 1440px) verschoben, statt die bisherige 1200px-Schwelle der unbeteiligten KPI-Grid-Regeln (kpis-perf) mit anzuheben (Fernwirkungs-Vermeidung auf eine unbeteiligte Ansicht).

Sichtprüfung: bei 1300px (im vormals betroffenen Band) bricht "Modell" vorher sichtbar in eine zweite Zeile um, nachher passt die gesamte Filterbar in eine Zeile — Screenshots 324-1300-*-vor/nach.png. Keine Regression bei 1536px/1100px (außerhalb des Bands, 324-1536-*/324-1100-*).

Tests: generative/tests/test_dashboard_responsive_1100px.py (2 Tests auf den neuen 1440px-Breakpoint umgestellt, 1 neuer Regressionswächter: Kompakt-Regeln dürfen NICHT mehr im 1200px-Block stehen).

Zusätzlicher Fix-Commit

test_html_header_updated_icon_removed (test_dashboard_updated_icon_sidebar_only.py) prüfte pauschal "kein hint-pop im Filterbar-Abschnitt" als Proxy für das entfernte alte ↻-Updated-Icon — kollidierte mit dem neuen, legitimen #320-Hint-Marker. Assertion auf den eigentlich relevanten Anker verengt.

Sichtprüfungs-Setup

Testserver aus dem Worktree, read-only DB-Kopie (sqlite3-Backup-API von .cache/atomic_analytics.db), NIE Port 8051 (Live-Server). Vor/Nach-Vergleich über eine separate git worktree am Basis-Commit (1afbed0, Port 8069) neben dem Fix-Stand (Port 8070) — Playwright (playwright-core + firefox-1532), je Punkt hell+dunkel, Viewports 1536×864 + 1100px, für #324 zusätzlich 1300×864 (Band-Mitte). Screenshots unter C:\tmp\bundleA-shots\, DB-Kopie unter C:\tmp\bundleA-db.sqlite.

Verifikation

  • uv run pytest generative lib/decision_engine/tests shared/tests -q6220 passed, 3 skipped, 8 deselected (0 failed)
  • uv run ruff check . → All checks passed
  • uv run ruff format --check . → 306 files already formatted
  • NUL-Byte-Count internal/dashboard/eval_dashboard.html1 (unverändert, vor jedem Edit verifiziert)

Closes #320
Closes #321
Closes #322
Closes #323
Closes #324

Nicht mergen.

Tilltime added 6 commits July 17, 2026 14:16
…#323)

_chart_scatter_versioned baute die PDF-Legende des Qualitaets-Scatters aus
dem rohen pdf-String als Dict-Key -- ohne die Kanonisierung ueber
D._pdf_group_key(), die #311 fuer die anderen Charts eingefuehrt hat. Zwei
Rohvarianten derselben Quelle (z.B. "Bates - 2017 - Information Behavior.pdf"
vs. "bates-2017") landeten dadurch als zwei separate Legenden-Eintraege in
zwei Farben.

Dict-Key jetzt ueber D._pdf_group_key(pdf), Label weiter aus
D._PDF_LABELS/_pdf_short_name (derselbe Pfad wie _calc_pdf_table). points[].pdf
traegt jetzt ebenfalls den kanonischen Key, nicht mehr den Rohstring -- noetig,
damit das Frontend (renderScatter: pt.pdf === legendEntry.raw) Punkte weiter
korrekt ihrer Legenden-Gruppe zuordnet.
…opdown (#320)

Valide Eval-Zeilen ohne run_id-Match zu einem Pipeline-Lauf zaehlen in KEINER
Modell-Dropdown-Option -- das Dropdown machte diese Luecke bisher nicht
kenntlich (Statistiker-Review-Bilanz: 479 valide 4.1-Zeilen = 442 mit
Modell-Zuordnung + 37 ohne). Server zaehlt die Luecke jetzt im selben
Durchlauf wie n_valid je Modell mit (models_unmatched_n, keine separate
Neuberechnung), Frontend zeigt sie als Hint-Marker (bestehendes .hint/
.hint-pop-Muster) neben dem Modell-Label -- nur sichtbar, wenn N > 0.
…#321)

Die sticky erste Spalte der Versions×PDF-Matrix setzte Zebra- und Hover-
Zeilen bislang deckend auf den generischen var(--bg-card) zurueck (noetig,
damit darunter gescrollte Zellen nicht durchscheinen) -- dadurch fehlte der
Zebra-/Hover-Tint sichtbar genau in dieser einen Spalte: eine Naht zur
restlichen Zeile, Row-Hover erfasste die PDF-Zelle nie.

Fix: vorberechnete opake Zebra-/Hover-Mischfarben (--bg-card-zebra/
--bg-card-hover, je Theme in :root/body.light) statt des generischen
Card-Hintergrunds -- reproduziert denselben 1,5/3,5-Prozent-Tint wie die
rgba-Overlays der uebrigen Spalten, bleibt aber deckend fuer den Sticky-
Scroll-Effekt.
Bei einer Filterkombination mit 0 evaluierten Notes behauptete das Empty-
Banner unbedingt "Kennzahlen und Charts sind leer" -- die Versions×PDF-
Matrix ignoriert aber bewusst JEDEN aktiven Filter (PDF/Version/Modell/
Sprache/Lauf, s. _matrix_base_rows in build_data()) und bleibt gefuellt.
Beide Banner-Textvarianten (mit/ohne Betriebskennzahlen) sowie der
statische Default-Text ergaenzen jetzt den Hinweis, dass die Matrix
filterunabhaengig weiter den vollen Corpus zeigt.
)

Die Kompakt-Styles der Filterbar (.filter-group Padding, .fselect
max-width) griffen nur innerhalb @media (max-width: 1200px); der naechste
Breakpoint war @media (min-width: 1201px) fuer die Matrix-Sticky-Regel
(andere Zustaendigkeit). Dazwischen (1201-~1430px) blieb die volle,
unkompaktierte Breite aktiv -- bei 1280px brach "Modell" als letzte
Filter-Group allein in eine zweite Zeile um.

Fix: die beiden Kompakt-Regeln in eine eigene @media (max-width: 1440px)
verschoben, statt die 1200px-Schwelle der unbeteiligten KPI-Grid-Regeln
(kpis-perf) mit anzuheben. Bestehende Regressionswaechter-Tests
(test_dashboard_responsive_1100px.py) auf den neuen Breakpoint umgestellt,
neuer Test sichert, dass die Regeln NICHT mehr im 1200px-Block stehen.
…s updated-Icon)

test_html_header_updated_icon_removed pruefte bislang pauschal "kein
hint-pop ueberhaupt im Filterbar-Abschnitt" als Proxy dafuer, dass das
alte ↻-Updated-Icon dort weg ist. #320 fuegt der Filterbar legitim einen
ANDEREN, eigenstaendigen Hint-Marker hinzu (#model-unmatched-hint) --
die pauschale Assertion kollidierte damit. Auf den eigentlich relevanten
Anker verengt (kein '<span class="updated' mehr im Abschnitt); die
bereits vorhandenen id/class-Assertions auf Dokumentebene decken den
Rest weiterhin ab.
@TillQuandel
TillQuandel merged commit 90676b8 into master Jul 17, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment