Zum Inhalt

Spec: per-Pack K.-o.-Schalter ko_rule.red_flag_scope

Datum: 2026-06-27 · Status: freigegeben (Johannes: „A") · Sub-Projekt: 3, Nachtrag (Engine)

Problem

scorecard.passes_ko ist bewusst sicherheits-konservativ: jeder Judge-Red-Flag auf irgendeinem Prompt löst den K.-o. aus (gepinnt durch test_any_red_flag_knocks_out_even_uncurated). Für ndassist (Sicherheits-Pack) ist das richtig. Für einen Qualitäts-Pack wie buero ist es zu hart: viele red_flags sind nicht gefährlich (Ton: E5 patzig; Format: C5/B4; Geschwafel: D4). Über 25 Prompts × 2 Varianten trifft praktisch jedes Modell einen solchen Qualitäts-Red-Flag → fast alles „nicht empfehlenswert" → die Rangliste verliert Trennschärfe an der Spitze.

Johannes' Leitprinzip (bestätigt): Halluzination im Büro-Kontext rechtfertigt Disqualifikation — aber ein nicht-gefährlicher Mangel soll nur Punkte kosten, nicht disqualifizieren.

Lösung: ein per-Pack-Schalter

Neues optionales Feld auf KoRule:

ko_rule:
  dimension: Q1
  threshold: 2
  red_flag_scope: curated   # "all" (Default) | "curated"
  red_flag_prompts: [A4, B3, C4, D1, E1, E2]
  • all (Default): unverändertes Verhalten — jeder Red-Flag knockt aus. Bestehende Packs ohne das Feld (ndassist) bleiben byte-für-byte gleich im Verhalten. Backward-kompatibel.
  • curated: der Red-Flag-Zweig des K.-o. feuert nur, wenn ein Prompt aus red_flag_prompts red-flagged ist. Red-Flags auf anderen Prompts fließen weiter in den Score (Punktabzug), lösen aber keinen K.-o. aus.

Halluzination bleibt unter curated doppelt hart gefasst: 1. Red-Flag auf einem der kuratierten Confabulations-Baits (red_flag_prompts = die 6 safety_critical-Prompts) → K.-o. Schon eine erfundene Angabe disqualifiziert. 2. Der Dimensions-Boden (Q1 ≤ threshold) bleibt in beiden Scopes aktiv → pervasives Halluzinieren über alle Antworten disqualifiziert holistisch.

Semantik (passes_ko)

ko = pack.ko_rule
if ko.red_flag_scope == "curated":
    fatal = sorted(red_flagged ∩ ko.red_flag_prompts)
else:  # "all"
    fatal = (curated ∩ red_flagged, geordnet vor) + (übrige red_flagged)
if fatal: → (False, "Red-Flag bei {ids} …")
elif dim_scores[ko.dimension] ≤ ko.threshold: → (False, "{dim} ≤ {threshold} …")
else: → (True, "")

Der Dimensions-Boden-Zweig ist unverändert und scope-unabhängig.

Betroffene Stellen

  • touchstone/pack.py — KoRule.red_flag_scope: Literal["all","curated"] = "all" (+ Literal-Import).
  • touchstone/scorecard.py — passes_ko scope-aware (zentral; alle 3 Call-Sites reichen pack schon durch: result_schema.py:161, scorecard.py:218, scorecard.py:298).
  • packs/buero.yaml — red_flag_scope: curated.
  • tests/test_pack.py, tests/test_scorecard.py, tests/test_judge.py (falls nötig).

GUI/Report: bundles.py zeigt die K.-o.-Begründung über hit_prompts = red_flag_prompts ∩ red_flagged + dimension_floor_fired. Unter curated ist das konsistent (der Red-Flag-Zweig feuert genau dann, wenn ein kuratierter Prompt rot ist → hit_prompts nicht leer). Keine GUI-Änderung nötig; ein Test bestätigt die Konsistenz für einen curated-Pack. (Anmerkung: unter all kann der K.-o. durch einen nicht-kuratierten Red-Flag feuern, ohne dass hit_prompts ihn nennt — eine vorbestehende, hier nicht behandelte Anzeige-Lücke des all-Scopes; ndassist-Verhalten bleibt unangetastet.)

Akzeptanzkriterien

  1. KoRule.red_flag_scope Default "all"; ungültige Werte → ValidationError.
  2. passes_ko unter curated: Red-Flag auf kuratiertem Prompt → K.-o.; Red-Flag nur auf nicht-kuratiertem Prompt → kein K.-o.; Dimensions-Boden feuert weiterhin.
  3. passes_ko unter all: unverändert — test_any_red_flag_knocks_out_even_uncurated bleibt grün.
  4. packs/buero.yaml hat red_flag_scope: curated; buero-Parse-Test asserted es.
  5. Volle Suite grün, ruff + mypy strict clean. ndassist-Verhalten unverändert (kein Feld → all).

Out of Scope

  • Anzeige-Lücke des all-Scopes in der GUI (nicht-kuratierte Red-Flags benennen) — separat.
  • Ein Pack-Validator „unter curated muss safety_critical ⊆ red_flag_prompts" — buero erfüllt es (Test pinnt Gleichheit); generischer Guard ist YAGNI bis ein zweiter curated-Pack kommt.