Skip to content

fix(dashboard): Evaluierte-Notes-Quote serverseitig auf kpi_version-Basis — nie mehr >100 % (#224)#230

Merged
TillQuandel merged 1 commit into
masterfrom
fix/224-notes-pct-kontext
Jul 12, 2026
Merged

fix(dashboard): Evaluierte-Notes-Quote serverseitig auf kpi_version-Basis — nie mehr >100 % (#224)#230
TillQuandel merged 1 commit into
masterfrom
fix/224-notes-pct-kontext

Conversation

@TillQuandel

@TillQuandel TillQuandel commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Behebt #224. Closes #224.

Problem

Die Kachel „Evaluierte Notes" zeigte bei Pipeline-Versions-Filter „333,3 % der Notes" (Beleg: Playwright-Sweep 2026-07-12): Der Client rechnete 100*n_notes/total_generated — Zähler (distinct evaluierte Notes der KPI-Version, note_evals-DB, früh gefiltert) und Nenner (generierte Notes ALLER Versionen aus Logs/DB-Fallback, spät gefiltert, andere Versions-Normalisierung) stammten aus verschiedenen Kontexten. Der alte tgtHint dokumentierte die Mischung sogar selbst.

Fix

  • Server rechnet selbst: Neues KPI-Feld notes_eval_pct (+ Begleitfeld generated_kpi_ver) in _calc_kpis. Nenner = generierte Notes GENAU der kpi_version (identischer Anker wie der Zähler, kein Versions-Drift möglich) aus den bereits gefilterten Lauf-Zeilen — gleiche Basis auch im ungefilterten Zustand (behebt die dokumentierte Mischung gleich mit).
  • Guard statt Absurd-Wert: Bei Nenner 0 oder Zähler > Nenner (Datenlücke, z. B. Läufe vor fix(generative): pipeline_runs-Insert vom Inline-Eval entkoppeln + Test-Traces nach tmp (#198 P1+P2) #218 ohne DB-Zeile) → null → Kachel zeigt „–". Guard auf rohen Integer-Zählern (nicht dem gerundeten Prozentwert); Division nur im True-Zweig — strukturell nie >100 % serialisierbar, kein ZeroDivision möglich.
  • Client rechnet nicht mehr (_fmtDE(kpis.notes_eval_pct)); total_generated bleibt für seine Lifetime-Konsumenten (Strip „Notes generiert", Akzeptanz-%) unangetastet. tgtHint beschreibt die neue gemeinsame Basis + „–"-Fälle.

RED-Beweis (TDD)

4/4 neue Tests initial rot (alter Zustand: Client-Formel, kein Server-Feld): Repro 10-vs-3 → >100 %; ungefiltert nutzte Alle-Versionen-Nenner. Nach Fix: Repro → null; 5/20 → 25,0; Nenner 0 → null; ungefiltert 4/10 der KPI-Version → 40,0 (nicht 100*4/110).

Suite

5770 passed, 3 skipped, 4 deselected; ruff format+check sauber.

Playwright-Sichtverifikation (hell+dunkel)

Server aus Worktree auf Port 8063 (genau 1 Listener-PID), echte DB read-only: Versions-Filter v0.3.59 — vorher 333,3 % → jetzt „–"; ungefiltert 40 Notes → 62,5 %. Screenshots: C:/tmp/224-verify/*.png.

Reviews

  • Task-Review (Sonnet): Approved, 0 Critical/Important; Named-Risk-Checks (weitere total_generated-Konsumenten unangetastet; Zähler/Nenner-Anker identisch) bestanden. Minors (Backlog): kein expliziter ==100-%-Grenzfall-Test; generated_kpi_ver derzeit redundant zu kpi_version.
  • Cross-Model (Mistral magistral-medium): 1 Fund adjudiziert-verworfen: r["n_total"]-Direktzugriff als KeyError-Risiko — die neue Zeile folgt exakt dem Muster der vorbestehenden Nachbarn auf DERSELBEN Datenquelle (accept_generated Z. 546, total_generated Z. 562); eine Zeile ohne n_total würde heute schon an Z. 562 bei jedem Load crashen. Kein neues Risiko.

Umgebungs-Nebenfund (kein Code)

Playwright-MCP-Firefox-Profil war korrupt (Ghost-Prozesse); Profil gesichert als mcp-firefox-7d6a92c-bak-224, danach sauber. Friction-Log-Kandidat.

Kontrollrunde (2026-07-12, zweite unabhängige Review-Ebene)

  • Opus-Kontroll-Review (Fehlerfindung + Behauptungs-Drift, Selbstverifikationspflicht, Runtime-Proben gegen echte DB read-only): 0 Defekte. Guard-Invariante per Grenzwert-Probe belegt (1999/2000 → 100,0 — deckelt exakt, nie >100); beide Playwright-Werte nachgerechnet (ungefiltert 40/64 → 62,5 %; v0.3.59: 10 > 3 → null → „–"). 5 Kandidaten widerlegt, u. a.: die None-Versions-Kette ist in Produktion unerreichbar (Log-Pfad setzt ver="unknown", DB-Fallback überspringt versionslose Runs). Nebenbefund ohne PR-Bezug: 3 Collection-Errors bei Root-Sammlung von lib/decision_engine/tests (Package-Namen-Kollision tests) — vorbestehend, kanonischer Suite-Aufruf nicht betroffen.
  • Mistral-Schwerpunkt-Resample (Linse Versions-Anker-Kaskade): 1 HOCH-Kandidat (Versions-String-Format-Drift „v1.0" vs. „1.0" zwischen Zähler- und Nenner-Quelle) adjudiziert-verworfen: Bei Format-Mismatch bliebe der Nenner leer → sichere „–"-Anzeige (by design, kein Falschwert); in den echten Daten matchen die Strings (sonst existierte der 62,5-%-Wert nicht); die vorgeschlagene Normalisierung (v-Strip + lowercase) könnte unterschiedliche Versionen zusammenlegen — riskanter als der Status quo.

…Basis — nie mehr >100 % (#224)

Zaehler (n_notes aus note_evals) und Nenner der '% der Notes'-Anzeige
stammten aus verschiedenen Versions-/Filterkontexten: der Client rechnete
100*n_notes/total_generated, wobei total_generated ueber ALLE Versionen
poolt. Bei Versions-Filter auf alte Versionen kollabierte der Nenner
unter den Zaehler (10 Eval-Notes / 3 generierte -> '333,3 % der Notes').

- _calc_kpis: neues Feld notes_eval_pct (0-100 oder None) + Begleitfeld
  generated_kpi_ver; Nenner = n_total-Summe der all_log_runs exakt der
  kpi_version (derselbe Anker wie latest_qrows). Guard: Nenner 0 oder
  Zaehler > Nenner (Datenluecke) -> None.
- Client: tgt nutzt kpis.notes_eval_pct statt eigener Rechnung; None -> '–'.
  tgtHint beschreibt die gemeinsame Versions-/Filterbasis und die '–'-Faelle.
- total_generated bleibt unveraendert (Lifetime-Semantik, Strip 'Gesamt').

Tests: Issue-Repro (10/3 -> None), gesunder Fall (5/20 -> 25.0), Version
ohne Laeufe (-> None), ungefiltert kpi_version-Basis statt Alle-Versionen-
Mischung (40.0 statt 100*4/110).
@TillQuandel TillQuandel merged commit 073e525 into master Jul 12, 2026
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.

Dashboard: KPI "Evaluierte Notes" zeigt >100 % ("333,3 % der Notes") bei Pipeline-Versions-Filter

2 participants