fix(dashboard): DB-Fallback liefert echte Token-/Wall-Clock-Werte + ehrliche Agent-Stats-Meldung + Spark-Achsen-Praezision#292
Merged
Conversation
…hrliche Agent-Stats-Meldung + Spark-Achsen-Praezision Drei Bugs aus dem Multi-Perspektiven-Review 2026-07-15: Bug 1 (Datenintegritaet, D2): Der DB-only-Fallback fuer token_runs (eval_dashboard_server.build_data, Laeufe ohne .cache/runs/<run_id>.jsonl) schrieb tokens_in/out/cache hartkodiert auf 0, obwohl pipeline_runs die Spalten tokens_input/tokens_output/tokens_cache_read gefuellt hatte (v0.3.140: 12.863.095 tokens_total in der DB, Dashboard zeigte 0/"-"). duration_min/cost_usd/wall_clock_s wurden im selben Block bereits korrekt aus der DB gelesen -- nur die Token-Felder hatten das Muster nicht uebernommen. wall_clock_s war KEINE zusaetzliche Luecke (bereits in #239/#266 korrekt), Regressionstest ergaenzt. Bug 2 (UX, U1): Ohne JSONL-Traces liefert build_data agent_stats={} und die Agenten-Charts zeigten "Keine Daten fuer diese Filter-Kombination", obwohl kein Filter aktiv war. Agent-Statistiken kommen ausschliesslich aus lokalen Trace-JSONLs, es gibt keine Agent-Ebene in der DB. Fix: ehrliche Meldung wenn kein Filter aktiv ist, bisherige Meldung bleibt korrekt wenn ein Filter aktiv ist (dieselbe _globalFilters-Erkennung wie der bestehende Top-Level-Banner). Bug 3 (UX, U2): Spark-Trend-Achsenbeschriftung (_trendChart) rundete den Rohwert erst ueber _fmtDE() (DE-Format MIT Dezimalkomma) und parste das Ergebnis danach per parseFloat() zurueck -- parseFloat bricht am Komma ab ("0,03" -> 0), alle 3 Hilfslinien-Labels kollabierten auf denselben gerundeten Wert (API-Kosten-Sparkline zeigte 3x "0,00$"). Fix: Rohwert direkt an au.fmt, bei zu enger Spanne Nachkommastellen schrittweise erhoehen bis die Labels sich unterscheiden. Verifikation: pytest (5900 passed, 0 failed inkl. 9 neue Tests, davon 3 fuer Bug 3 echte Node-Ausfuehrung der extrahierten JS-Funktionen statt reiner Text-Assertion), ruff clean, Playwright (Firefox, hell+dunkel) gegen echte Produktions-DB-Kopie ohne JSONL-Traces im Worktree.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Quelle
Multi-Perspektiven-Review 2026-07-15.
Bug 1 — DB-Fallback hartkodiert Tokens auf 0 (Datenintegritäts-Fund D2)
Befund:
generative/eval_dashboard_server.py:507-528— der DB-only-Fallback fürtoken_runs(Läufe ohne.cache/runs/<run_id>.jsonl-Trace, z. B. extractive) schriebtokens_in/tokens_out/tokens_cachehartkodiert auf0, obwohlpipeline_runsdie Spaltentokens_input/tokens_output/tokens_cache_readgefüllt hatte.duration_min/cost_usd/wall_clock_swurden im selben Block bereits korrekt aus der DB gelesen — nur das Token-Feld-Muster fehlte.Beleg: v0.3.140 hatte 12.863.095
tokens_totalin der DB, Dashboard zeigte 0/„–" (Totals-Strip Tokens, KPI-Kacheln Billable/ohne-Cache,kpi_trend.tokens/cost, ch5).Fix: Token-Felder aus der DB-Zeile übernehmen (
tokens_input→tokens_in,tokens_output→tokens_out,tokens_cache_read→tokens_cache/tokens_cache_read).tokens_cache_createbleibt0(DB persistiert diese Spalte nicht, nur das Trace-JSONL —db.insert_run()-Docstring bestätigt).wall_clock_s-Klärung (Nebenbefund-Check): war keine zusätzliche Lücke — bereits in #239/#266 korrekt aus
pipeline_runs.wall_clock_sgelesen (git blame bestätigt). Regressionstest ergänzt statt Fix.Verifikation:
test_dashboard_db_only_fallback_tokens.py(RED vor Fix:assert 0 == 12863095-artige Fehlschläge; GREEN danach). Playwright gegen echte Produktions-DB-Kopie ohne JSONL-Traces: Totals-Strip zeigt „10,07M" statt „–",kpi-tokens/kpi-tokens-billablegefüllt (1,79M / 8,04M), ch5 rendert reale Balken.Bug 2 — agent_stats leer mit irreführender Meldung (UX-Fund U1)
Befund: Agent-Statistiken (ch7/ch8) kommen ausschließlich aus lokalen Trace-JSONLs — es gibt keine Agent-Ebene in der DB (
pipeline_runs/note_evalskennen nur Run-Summen, Schema-Check inshared/db_schema.pybestätigt: nurpipeline_runs,note_evals,calibration_labels). Ohne Traces lieferte_read_agent_stats(){}, das Frontend zeigte die generische Filter-Leer-Meldung „Keine Daten für diese Filter-Kombination" — irreführend, wenn gar kein Filter aktiv ist.Fix:
internal/dashboard/eval_dashboard.html, ch7/ch8-Else-Branch unterscheidet jetzt über dieselbe_globalFilters-Erkennung wie der bestehende Top-Level-Banner: kein Filter aktiv → ehrliche Meldung „Agent-Statistiken benötigen lokale Lauf-Traces (.cache/runs) — für ältere/rotierte Läufe nicht verfügbar"; Filter aktiv → bisherige (weiterhin korrekte) Meldung bleibt.Verifikation:
test_dashboard_agent_stats_empty_message.py. Playwright: ohne Filter (Worktree-DB-Kopie hat keine JSONL-Traces — idealer Testfall) zeigt beide Agent-Charts die neue Meldung; mit UI-Filter (Pipeline-Version-Dropdown) weiterhin die alte generische Meldung.Bug 3 — Spark-Trend-Achse zeigt „0,00$" dreifach (UX-Fund U2)
Befund:
internal/dashboard/eval_dashboard.html,_trendChart(~Z. 1592) — Achsenbeschriftung rundete den Rohwert erst über_fmtDE()(DE-Format mit Dezimalkomma, z. B."0,03") und parste das Ergebnis danach perparseFloat()zurück.parseFloat("0,03")bricht am Komma ab und liefert0— alle 3 Hilfslinien landeten beiau.fmt(0), sichtbar als 3× „0,00$" auf der API-Kosten-Sparkline. Tooltips daneben liefen nicht über diesen Roundtrip und waren korrekt (0,03–0,15$).Fix: Rohwert direkt an
au.fmt(das selbst rundet), kein_fmtDE→parseFloat-Umweg mehr. Zusatzhärtung: bei sehr kleinen Spannen (Standard-Nachkommastellen reichen nicht zum Unterscheiden) werden die Nachkommastellen schrittweise erhöht, bis alle 3 Labels sich unterscheiden (Cap 6 Nachkommastellen).Verifikation:
test_dashboard_spark_axis_precision.py— führt die echten JS-Funktionen (_fmtDE,_autoUnit,_trendChart) per Node aus dem HTML aus (Klammer-Balancer-Extraktion, keine Logik-Kopie), RED vor Fix (["0,00$","0,00$","0,00$"]), GREEN danach. Playwright: API-Kosten-Kachel angeklickt zeigt „0,18$" / „0,09$" / „0,01$" (real, unterscheidbar) statt 3× „0,00$".Verifikation gesamt
pytest generative lib/decision_engine/tests shared/tests -q: 5900 passed, 3 skipped, 8 deselected, 0 failed (inkl. 9 neuer Tests aus diesem PR)ruff check+ruff format --check: clean.cache/runs-Traces — alle drei Bugs live bestätigt, keine Page-Errorsinternal/dashboard/eval_dashboard.htmlbehält exakt 1 NUL-Byte (Drawer-Key-Separator, unverändert) vor/nach allen Edits