Skip to content

feat(dashboard): KPI-Kacheln in zwei Gruppen + Wall-Clock-Tooltip korrigiert#274

Merged
TillQuandel merged 1 commit into
masterfrom
feat/kpi-gruppen-wallclock-tooltip
Jul 14, 2026
Merged

feat(dashboard): KPI-Kacheln in zwei Gruppen + Wall-Clock-Tooltip korrigiert#274
TillQuandel merged 1 commit into
masterfrom
feat/kpi-gruppen-wallclock-tooltip

Conversation

@TillQuandel

Copy link
Copy Markdown
Owner

Befund / Kontext

Zwei separate Nachbesserungen im selben Bereich (Dashboard-KPI-Kacheln), zusammengefasst in einem PR auf Tills Wunsch.

1) KPI-Layout (Till-Entscheid): Die 9 KPI-Kacheln im Übersicht-Abschnitt liefen bisher als eine flache Reihe (7-Spalten-Grid, 9 Kacheln => 7+2-Umbruch). Till wollte stattdessen zwei beschriftete Gruppen — explizit kein Slider/Karussell (Anti-Pattern).

2) Tooltip-Nit aus PR #266 (gh pr view 266, gh issue view 239 gelesen): Der Tooltip der Kachel „Wall-Clock (aktuell)" behauptete, bei deaktiviertem Inline-Eval sei die Wall-Clock „0,0h". Das ist fachlich falsch: insert_run() schreibt wall_clock_s beim Insert immer identisch zu duration_s (echter Messwert, orchestrator.py _wall_s = round(time.time() - _run_start, 1)). update_wall_clock_s() korrigiert die Zeile nur nach oben, wenn Stage-8 anschließend lief. Ohne Stage-8 bleibt wall_clock_s also ein echter, von 0 verschiedener Wert — 0,0h gilt nur für echte Alt-Zeilen von vor der #239-Spalte (Spalten-Default, kein Messwert).

Fix

Gruppierung (internal/dashboard/eval_dashboard.html):

  • Zwei Container #kpis-quality (4 Kacheln) und #kpis-perf (5 Kacheln) statt einem #kpis, je mit eigener Sub-Head-Beschriftung — „Kosten & Performance" wiederverwendet den bereits bestehenden Sektionsnamen (id="s-cost") statt einen neuen Begriff einzuführen (SSoT).
  • CSS: .kpis-quality/.kpis-perf bekommen eigene grid-template-columns (4 bzw. 5 Spalten — passt exakt in eine Zeile statt asymmetrisch umzubrechen wie vorher). Responsive Breakpoints (1200px/900px) neu und korrekt je Gruppe berechnet (die alten nth-child-Regeln waren auf die einzelne 9-Kachel-Reihe zugeschnitten und hätten bei blinder Wiederverwendung Doppel-Rahmen an der letzten Zeile erzeugt — deshalb sauber neu hergeleitet statt kopiert).
  • JS (renderKpis): kpiDefs bleibt EIN Array (unverändert in Reihenfolge/Inhalt bis auf den Tooltip-Fix) — die HTML-Strings werden per .slice(0, 4)/.slice(4) auf die zwei Container verteilt. _openKpiIdx bleibt ein Index ins ungeteilte Array, Sparkline-Klick-Verhalten unverändert.
  • renderSkeleton() befüllt jetzt beide Container mit passender Skeleton-Anzahl (4/5 statt vorher 7 in einem Container).
  • Alle 9 Kacheln, IDs, Tooltips, Sparklines, Tone-Farben unverändert — reine Gruppierung, kein Redesign. frontend-design-Skill vor dem Layout-Entwurf geladen und dezent angewendet (bestehende Designsprache respektiert: Struktur/Beschriftung kodiert die Bedeutung, keine neuen Farben/Fonts).

Gruppenzuordnung (alle 9 Kacheln passten exakt in die von Till genannten 2×4/5 — keine zusätzlichen Kacheln im HTML gefunden):

Gruppe Kacheln
Qualität Automatisch akzeptiert, Fehlerquote, Belegrate, Evaluierte Notes
Kosten & Performance Agent-Rechenzeit (Summe), Wall-Clock (aktuell), Billable Tokens, Tokens (ohne Cache), API-Kosten

Tooltip-Fix (Kachel kpi-wall, neuer Wortlaut):

Summe der ECHTEN Wall-Clock-Zeit (Beginn bis Ende) aller Läufe der aktuellen Version, in Stunden — im Gegensatz zur Kachel „Agent-Rechenzeit" daneben (Summe der Call-Dauern, mit Overlap bei Parallelität). Inklusive Stage-8-Qualitäts-Eval, sofern er lief. Bei deaktiviertem Inline-Eval (kein Stage-8) ist der Wert trotzdem echt und NICHT 0,0 h: er entspricht der real gemessenen Laufzeit bis zum Pipeline-Ende, weil dort keine separate Eval-Phase fehlt, die noch dazukäme. 0,0 h nur bei Läufen, deren Daten vor der Wall-Clock-Persistierung entstanden (#239) — dort fehlt die Spalte schlicht, kein Messwert.

TDD / RED-Beleg

RED vor der Implementierung (5 neue Tests schlugen erwartungsgemäß fehl, 6 bestehende PR-#266-Tests blieben grün):

FAILED generative/tests/test_dashboard_kpi_groups.py::test_html_has_two_labeled_kpi_group_containers
FAILED generative/tests/test_dashboard_kpi_groups.py::test_kpi_group_containers_appear_in_document_order_quality_then_perf
FAILED generative/tests/test_dashboard_kpi_groups.py::test_kpi_defs_order_matches_group_split_quality_first_four_perf_last_five
FAILED generative/tests/test_dashboard_wall_clock_kpi.py::test_wall_clock_tooltip_does_not_claim_zero_for_disabled_inline_eval
FAILED generative/tests/test_dashboard_wall_clock_kpi.py::test_wall_clock_tooltip_explains_disabled_inline_eval_as_real_nonzero_value
5 failed, 6 passed

Neue Tests (11 gesamt, alle grün nach Fix):

  • generative/tests/test_dashboard_kpi_groups.py (neu, 4 Tests): zwei Container-IDs vorhanden, kein Slider/Karussell-Pattern, Container-Reihenfolge Qualität→Kosten&Performance, kpiDefs-Label-Reihenfolge + Slice-Grenze bei Index 4 verankert.
  • generative/tests/test_dashboard_wall_clock_kpi.py (erweitert, 2 Tests): alte falsche Formulierung nicht mehr im HTML, neue korrekte Formulierung vorhanden.

Suite / Lint

  • pytest generative lib/decision_engine/tests shared/tests -q: 5863 passed, 3 skipped, 8 deselected.
  • ruff check .: sauber. ruff format --check .: 273 files already formatted.

Playwright-Sichtverifikation

Server (Port 8062, ATOMIC_DB_PATH auf Kopie der Live-DB in C:/tmp/kpi-db.db, read-only) lief korrekt, /data.json erreichbar (Status 200). Browser-Screenshot (Firefox/Playwright-MCP) ließ sich in dieser Session nicht durchführen — Launch scheiterte zweimal mit Failed to launch the browser process bei ~3,9 GB freiem RAM von 16 GB (dasselbe bekannte Ressourcenproblem wie in PR #266 dokumentiert).

Ersatzverifikation (manuelle Nachsicht im Browser empfohlen): den tatsächlich vom laufenden Server ausgelieferten HTML-Response direkt per Invoke-WebRequest abgefragt und alle neuen Marker bestätigt — id="kpis-quality", id="kpis-perf", Kosten & Performance, beide Kachel-Labels, neuer Tooltip-Wortlaut, beide Slice-Grenzen (.slice(0, 4)/.slice(4)) — alle vorhanden. Zusätzlich /data.json gegen die Live-DB-Kopie geprüft: cur_dur_h=5,2, cur_wall_h=0 (auf diesem Datenstand plausibel — Altdaten ohne persistierte Wall-Clock, exakt der im korrigierten Tooltip beschriebene Fall, kein Bug).

Scope

Nur internal/dashboard/eval_dashboard.html + neue/angepasste Tests. Keine Python-Logik-Änderungen (_calc_kpis etc. unangetastet).

@TillQuandel TillQuandel merged commit 6bb6216 into master Jul 14, 2026
1 of 4 checks passed
TillQuandel added a commit that referenced this pull request Jul 15, 2026
#274-Nachbesserung) (#290)

* fix(dashboard): Spark-Trend-Row öffnet unter der Gruppe der angeklickten Kachel (#274-Nachbesserung)

Till-Live-Fund: Nach dem KPI-Gruppen-Umbau (#274) sitzt die einzige
#spark-row fix im HTML nach #kpis-perf. Klick auf eine Kachel der oberen
Gruppe "Qualität" oeffnete die Versions-Trend-Row deshalb unter der
FALSCHEN (unteren) Gruppe statt direkt darunter.

_openKpiSpark haengt die Row jetzt per insertAdjacentElement('afterend', ...)
dynamisch unter die Gruppe der angeklickten Kachel (idx<4 = Qualitaet,
dieselbe Slice-Grenze wie kpiDefs.slice(0,4)/.slice(4) in renderKpis).
Reposition laeuft in beiden Faellen (Frisch-Oeffnen UND Umschalten zwischen
den Gruppen bei bereits offener Row) — renderKpis selbst fasst die Row nicht
an (nur die innerHTML der beiden Kacheln-Container), sie springt also
zwischen periodischen Re-Renders nicht zurueck.

* fix(dashboard): Accept-Kachel wieder klickbar — #221 hatte sie versehentlich stillgelegt (Till-Live-Fund)

#221 (#204 P8g) hatte der Kachel "Automatisch akzeptiert" sparkless:true
gegeben mit der Begruendung, ch4 "Akzeptanzrate über Versionen" zeige den
Trend bereits — die Klick-Sparkline sei ein reines Duplikat.

Till stuft das als Regression ein: ch4 zeigt die Rate JE PDF (mehrere
Linien pro Version, Median), die Kachel-Sparkline dagegen die GEPOOLTE
Rate ueber alle PDFs — dieselbe Semantik wie die Klick-Sparklines von
Fehlerquote/Belegrate daneben. Kein Duplikat, also wieder klickbar.

sparkless:true entfernt + veralteten Kommentar korrigiert. Trend-Datenkette
geprueft: kpiTrend.accept (eval_dashboard_server.py, _pooled_accept aus
all_log_runs, gepoolt n_vault/n_total je Version) war bereits vollstaendig
verdrahtet und unveraendert seit vor #221#221 hat nur den Klick-Handler
im Frontend entfernt, die Datenkette nie angefasst. n-Guard (n<20) und
Null-Handling in _trendChart greifen fuer 'accept' bereits generisch wie
bei hall/cov/dur/tokens, keine Sonderbehandlung noetig.

---------

Co-authored-by: TillQuandel <tillq@live.de>
TillQuandel added a commit that referenced this pull request Jul 15, 2026
…s verwaist gecappt + Versions-Label an beiden KPI-Gruppen (Till-Befund) (#291)

Befund: "Qualität" und "Kosten & Performance" zeigten v0.3.140 als
aktuelle Version, obwohl die DB Läufe bis v0.3.143 hat, und es war nicht
erkennbar, dass beide Gruppen zur gleichen Version gehören.

Ursachen:
- config.AGENT_VERSION stand committed auf v0.3.140; _capped_latest_version
  (#191/#193-Schutz) blendet Versionen > Code-Version aus. Die v0.3.143-
  Läufe existieren, weil Till den Bump lokal (uncommitted) gesetzt hatte.
- Der #274-Gruppen-Umbau zeigt das Versions-Label (kpi-ver-label) nur am
  "Qualität"-Header; "Kosten & Performance" hatte gar keins.

Fix:
- generative/config.py: AGENT_VERSION auf v0.3.144 gebumpt. Cap zeigt
  jetzt v0.3.143 (jüngste Version mit Daten <= 144) als aktuell.
- internal/dashboard/eval_dashboard.html: zweites Label
  id="kpi-ver-label-perf" am "Kosten & Performance"-Header, von derselben
  JS-Zuweisung befüllt wie das bestehende "Qualität"-Label (SSoT).

Tests: neuer test_dashboard_kpi_group_version_labels.py (RED vor Fix,
GREEN danach). Volle Suite (generative + lib/decision_engine/tests +
shared/tests) 5893 passed, 3 skipped, 0 failed. ruff check + format clean
für die geänderten Dateien.

Playwright-Sichtprüfung (Firefox, Kopie der KPI-DB mit v0.3.143-Läufen):
Warn-Banner "Eval-Daten mit Version über der Code-Version" ist weg, beide
Header zeigen "— v0.3.143".

Hinweis: Tills lokale uncommitted config.py-Änderung (140→143) wird nach
diesem Merge obsolet und kann per `git checkout -- generative/config.py`
verworfen werden.

Co-authored-by: TillQuandel <tillq@live.de>
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.

2 participants