Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions generative/tests/test_dashboard_kpi_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,34 @@ def test_kpi_defs_order_matches_group_split_quality_first_four_perf_last_five():
# Slice-Grenze bei Index 4 im tatsaechlichen Render-Code verankert.
assert ".slice(0, 4)" in html
assert ".slice(4)" in html


def test_spark_row_relocates_to_clicked_kpi_group_on_open():
"""#274-Nachbesserung (Till-Live-Fund): die EINE #spark-row saß nach dem
Gruppen-Umbau (#274) fix im HTML nach #kpis-perf — ein Klick auf eine
Qualitäts-Kachel (idx<4) öffnete die Trend-Row also unter der FALSCHEN
(unteren) Gruppe statt direkt unter der eigenen. Fix: _openKpiSpark hängt
die Row per insertAdjacentElement('afterend', ...) dynamisch unter die
Gruppe der angeklickten Kachel — dieselbe idx<4-Grenze wie der
kpiDefs-Slice-Split oben.
"""
html = _build_live_html()
open_fn = html.split("window._openKpiSpark = function(idx) {")[1].split("window.closeKpiSpark = function()")[0]
assert "insertAdjacentElement('afterend', row)" in open_fn
assert "kpis-quality" in open_fn and "kpis-perf" in open_fn
assert "idx < 4" in open_fn


def test_kpi_accept_tile_is_clickable_again():
"""#221 (#204 P8g) hatte der Accept-Kachel `sparkless:true` gegeben (kein
onclick mehr) mit der Begründung, ch4 "Akzeptanzrate über Versionen"
zeige denselben Trend bereits. Till-Live-Fund/Regression: ch4 zeigt die
Rate JE PDF (mehrere Linien je Version), die Kachel-Sparkline dagegen die
GEPOOLTE Rate über alle PDFs — analog zu Fehlerquote/Belegrate daneben,
kein reines Duplikat. sparkless entfernt, Kachel wieder klickbar.
Isoliert auf den kpi-accept-Eintrag: kpi-wall/kpi-tokens-billable bleiben
sparkless (dafür fehlt serverseitig weiterhin eine Zeitreihe je Version).
"""
html = _build_live_html()
accept_def = html.split("id:'kpi-accept'")[1].split("id:'kpi-hall'")[0]
assert "sparkless" not in accept_def
30 changes: 25 additions & 5 deletions internal/dashboard/eval_dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -1296,16 +1296,22 @@
// #187: hint = Begriffserklärung für Nicht-Techniker, je Kachel via
// Code-Herleitung (siehe PR-Beschreibung für Begriff→Text→Quelle-Tabelle).
const kpiDefs = [
// #204 P8g: kein onclick-Sparkline mehr — "Automatisch akzeptiert" hat
// bereits einen eigenen Versions-Trend-Chart (ch4 "Akzeptanzrate je
// Version" in der Trade-off-Sektion); die Klick-Sparkline duplizierte
// dieselbe Aussage in einer zweiten, kleineren Darstellung.
// #221-Nachbesserung (#204 P8g, Till-Live-Fund): hier stand vormals
// sparkless:true mit der Begruendung, "Automatisch akzeptiert" habe
// bereits einen eigenen Versions-Trend-Chart (ch4 "Akzeptanzrate über
// Versionen" in der Trade-off-Sektion) — 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 (kpiTrend.accept liefert bereits echte Werte, siehe
// eval_dashboard_server.py _pooled_accept — unveraendert seit vor #221).
{ id:'kpi-accept', key:'accept', label:'Automatisch akzeptiert',
// #237: bei 0 evaluierten Notes (Merge-only-/Eval-Stage-ausgefallener Lauf)
// ist die Akzeptanzrate zwar rechnerisch gültig (Basis: generierte/
// Vault-Notes, nicht Evals), aber ohne Eval-Abdeckung nicht als
// Qualitätsampel aussagekräftig — Kachel neutralisiert statt grün.
val: kpis.n_notes===0 ? null : kpis.avg_accept, u:'%', digits:1, sparkless:true,
val: kpis.n_notes===0 ? null : kpis.avg_accept, u:'%', digits:1,
hint:'Anteil der von der Pipeline erzeugten Notes, die ohne manuelles Zusammenführen direkt in den Vault übernommen wurden. Gepoolt über alle Läufe der aktuellen Pipeline-Version (Summe akzeptiert / Summe generiert), nicht der Schnitt einzelner PDFs.',
tone: kpis.n_notes===0 ? 'neutral' : (kpis.avg_accept!=null?(kpis.avg_accept>=T.accept[0]?'good':kpis.avg_accept<=T.accept[1]?'bad':'warn'):'neutral'),
tgt: kpis.n_notes===0 ? '–' : (kpis.avg_accept!=null?(kpis.avg_accept>=T.accept[0]?'Ziel erreicht':`Ziel ≥ ${T.accept[0]} %`):'–'),
Expand Down Expand Up @@ -1639,6 +1645,20 @@
row.style.setProperty('--spark-border-color', _toneColor(tone));
}

// #274-Nachbesserung (Till-Live-Fund): es gibt nur EINE #spark-row im DOM
// (kein Duplikat je Gruppe) — sie muss beim Oeffnen/Umschalten direkt unter
// die Gruppe der angeklickten Kachel wandern, sonst haengt sie fix unter der
// unteren Gruppe (kpis-perf), auch wenn eine Qualitaets-Kachel angeklickt
// wurde. idx<4 ist dieselbe Slice-Grenze wie kpiDefs.slice(0,4)/.slice(4)
// in renderKpis. Muss VOR dem Oeffnen (open-Klasse) UND beim Umschalten
// zwischen den beiden Gruppen laufen (Re-Render in renderKpis fasst die
// Row selbst nicht an — nur die innerHTML der beiden Kacheln-Container —
// sie springt also zwischen Renders nicht zurueck).
if (row) {
const host = document.getElementById(idx < 4 ? 'kpis-quality' : 'kpis-perf');
if (host) host.insertAdjacentElement('afterend', row);
}

if (wasOpen && inner) {
inner.classList.add('switching');
setTimeout(() => {
Expand Down
Loading