Skip to content

fix(dashboard): DB-Fallback liefert echte Token-/Wall-Clock-Werte + ehrliche Agent-Stats-Meldung + Spark-Achsen-Praezision#292

Merged
TillQuandel merged 1 commit into
masterfrom
fix/db-fallback-tokens-agentstats-sparkaxis
Jul 15, 2026
Merged

fix(dashboard): DB-Fallback liefert echte Token-/Wall-Clock-Werte + ehrliche Agent-Stats-Meldung + Spark-Achsen-Praezision#292
TillQuandel merged 1 commit into
masterfrom
fix/db-fallback-tokens-agentstats-sparkaxis

Conversation

@TillQuandel

Copy link
Copy Markdown
Owner

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ür token_runs (Läufe ohne .cache/runs/<run_id>.jsonl-Trace, z. B. extractive) schrieb tokens_in/tokens_out/tokens_cache hartkodiert auf 0, obwohl pipeline_runs die Spalten tokens_input/tokens_output/tokens_cache_read gefüllt hatte. duration_min/cost_usd/wall_clock_s wurden im selben Block bereits korrekt aus der DB gelesen — nur das Token-Feld-Muster fehlte.

Beleg: v0.3.140 hatte 12.863.095 tokens_total in 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_inputtokens_in, tokens_outputtokens_out, tokens_cache_readtokens_cache/tokens_cache_read). tokens_cache_create bleibt 0 (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_s gelesen (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-billable gefü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_evals kennen nur Run-Summen, Schema-Check in shared/db_schema.py bestätigt: nur pipeline_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 per parseFloat() zurück. parseFloat("0,03") bricht am Komma ab und liefert 0 — alle 3 Hilfslinien landeten bei au.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 _fmtDEparseFloat-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
  • Playwright (Firefox, hell + dunkel) gegen Worktree-Server (Port 8069) mit echter Produktions-DB-Kopie ohne .cache/runs-Traces — alle drei Bugs live bestätigt, keine Page-Errors
  • NUL-Byte-Schutz: internal/dashboard/eval_dashboard.html behält exakt 1 NUL-Byte (Drawer-Key-Separator, unverändert) vor/nach allen Edits

…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.
@TillQuandel TillQuandel merged commit f3107af into master Jul 15, 2026
1 of 4 checks passed
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