Zum Inhalt

touchstone/gui/glossary.py

"""Single source of truth for what every metric/label in the GUI means.

Pure data — no GUI imports — so it is unit-testable and so a render-time test can
assert that every metric key a template shows is defined here (no unexplained
number can ship). The `metric()` Jinja macro pulls `short` for tooltips.
"""

from __future__ import annotations

from dataclasses import dataclass


@dataclass(frozen=True)
class Glossary:
    term: str  # human label
    short: str  # one-line tooltip
    long: str  # full explanation (glossary page / explainer)


GLOSSARY: dict[str, Glossary] = {
    "quality_pct": Glossary(
        "Qualität %",
        "Σ(Score × Gewicht) / Max × 100 über die holistisch bewerteten Dimensionen.",
        "Der Judge vergibt pro Master-Dimension 1–5; gewichtet, normiert auf 0–100 %. "
        "Belegt durch eine Begründung mit zitierten Prompt-IDs.",
    ),
    "ttft_p50": Glossary(
        "TTFT P50",
        "Time-To-First-Token, Median (s): Wartezeit bis zum ersten sichtbaren Antwort-Token.",
        "Reasoning-Tokens zählen NICHT zur TTFT — erst der erste Content-Token stoppt die Uhr.",
    ),
    "decode_median": Glossary(
        "Decode Median",
        "Median der Decode-Geschwindigkeit (Token/s) im Antwort-Fenster nach der TTFT.",
        "completion_tokens / (e2e − ttft). Reine Generier-Rate, ohne Prefill.",
    ),
    "prefill_tps": Glossary(
        "Prefill",
        "Prompt-Verarbeitung (Token/s): prompt_tokens / TTFT.",
        "Wie schnell der Prompt eingelesen wird, bevor das erste Token kommt.",
    ),
    "e2e": Glossary(
        "Gesamtzeit",
        "End-to-End-Wandzeit einer Antwort (s), von Absenden bis letztem Token.",
        "Enthält Prefill + Thinking + Decode.",
    ),
    "total_throughput": Glossary(
        "Gesamt-Durchsatz",
        "(prompt_tokens + completion_tokens) / Gesamtzeit (Token/s).",
        "Effektiver Durchsatz inkl. Prompt-Verarbeitung — näher am gefühlten Tempo als Decode allein.",
    ),
    "system_peak_ram": Glossary(
        "System-Peak",
        "Höchster System-Speicher während des Laufs (GB) — OS + alle Prozesse, nicht nur das Modell.",
        "Auf Apple-Silicon mmap't mlx die Gewichte in den Unified Memory; RSS unterzählt. "
        "Diese Zahl ist NICHT maschinen-vergleichbar — siehe Modell-Delta.",
    ),
    "model_delta_ram": Glossary(
        "Modell-Delta",
        "System-Peak minus Baseline vor dem Lauf (GB) — der maschinen-vergleichbare Speicher-Zuwachs.",
        "Baseline = Systemspeicher unmittelbar vor der ersten Anfrage. Der Kontext-/KV-Anteil "
        "ist im Unified Memory nicht sauber von den Gewichten trennbar (dokumentierte Unschärfe).",
    ),
    "mem_pressure": Glossary(
        "Memory-Pressure",
        "macOS-Speicherdruck (normal/warn/critical) im Lauf-Fenster.",
        "Aus `memory_pressure`. Steigt, wenn das System komprimiert/auslagert.",
    ),
    "variant_baseline": Glossary(
        "baseline",
        "Lauf MIT dem im Pack definierten System-Prompt.",
        "Die »baseline«-Variante setzt den Einsatzzweck-Prompt; Vergleich gegen »none« misst dessen Effekt.",
    ),
    "variant_none": Glossary(
        "none",
        "Lauf OHNE System-Prompt (Kontrollgruppe).",
        "Misst das nackte Modell; Differenz zu »baseline« = Wirkung des Prompts.",
    ),
    "reasoning_only": Glossary(
        "reasoning-only",
        "Modell schrieb nur ins Reasoning-Feld, keine sichtbare Antwort → aus dem Mittel ausgenommen.",
        "Setup-Hinweis (z. B. Token-Budget zu klein), kein inhaltliches Urteil. Echt leer bleibt 1.",
    ),
    "reasoning_duration": Glossary(
        "Thinking-Dauer",
        "Spanne im Reasoning-Kanal (s): vom ersten bis zum letzten Thinking-Chunk.",
        "Getrennt von der Antwortzeit gemessen — die Zeit, in der das Modell sichtbar "
        "»denkt«. 0 s, wenn das Reasoning in einem einzigen Chunk ankommt.",
    ),
    "reasoning_tps": Glossary(
        "Thinking-Tempo",
        "Reasoning-Token/s (heuristisch gezählt).",
        "Die API liefert nur eine aggregierte completion_tokens-Zahl; Reasoning-Tokens werden geschätzt.",
    ),
    "cold_start": Glossary(
        "Cold-Start",
        "Allererste Anfrage des Laufs — separat ausgewiesen, nie in den Aggregaten.",
        "Misst »wird das Modell warm«; aus Mittelwerten ausgeschlossen.",
    ),
    "cpu": Glossary(
        "CPU Ø/Max",
        "System-CPU-Last (%) im Antwort-Fenster, Durchschnitt/Maximum.",
        "»n. v.«, wenn das Bundle vor der CPU-Erfassung lief.",
    ),
}


def describe(key: str) -> Glossary:
    """Glossary entry for a key, or a safe placeholder for an unknown key."""
    return GLOSSARY.get(key, Glossary(term=key, short="", long=""))