Trend-Radar + Pruefstand: Box beobachtet Modell-/Engine-Trends und testet Kandidaten selbst

- trend-radar-feed.sh (Cron Sa 05:15): Live-Puls ALLER Rollen mit Vorwochen-Vergleich,
  Engine-A/B gegen neuen llama.cpp-Build (Fruehwarnung vor So-Auto-Update), mechanische
  Watch-Liste (MMQ-Issue, ROCm-Releases, Community-Grid), HF-Kandidaten-Suche mit
  Zitat-Gate -> max. 1 Pruefstand-Kandidat/Woche
- pruefstand.sh + harness.py (Cron So 01:00, no-agent): volles Programm je Kandidat -
  6 Coding-Aufgaben mit echten Unit-Tests, 4 Agenten-Aufgaben (Tool-Loop + Endzustand),
  4 Recherche-Fragen mit Zitat-Ehrlichkeits-Gate, Deutsch-Richter, Vision-Testbild,
  Tempo kurz+lang; Baseline der Amtsinhaber als Vergleichsmassstab
- Leitplanken (User-Entscheid 17.07.): Download-Deckel 35 GB (drueber -> Karte),
  1 Kandidat/Woche, Cache mit Auto-Aufraeumen, RAM-/Platz-Wache, Bench-Port :5899,
  Radar/Pruefstand EMPFEHLEN nur - Rollen-Wechsel bleibt Commander-Klick
- E2E bewiesen (Mock-LLM): coding 6/6, recherche 4/4 inkl. Zitat-Gate, Agent-Roundtrip,
  Richter-Parsing; Suiten-Selbsttest mit Referenzloesungen 6/6

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-17 14:56:58 +02:00
parent 8579fe9934
commit b0dce954e9
34 changed files with 1786 additions and 1 deletions
@@ -0,0 +1,5 @@
{
"prompt": "Schreibe eine Python-Funktion `summiere_umsaetze(text)` in der Datei `loesung.py`. Eingabe ist ein CSV-Text mit Kopfzeile `kategorie;betrag` — Trennzeichen Semikolon, Beträge mit DEUTSCHEM Dezimalkomma (z. B. `12,50`). Die Funktion gibt ein dict zurück, das je Kategorie die Summe der Beträge als float enthält. Leere Zeilen und Zeilen ohne Semikolon werden ignoriert; unparsebare Beträge lösen einen ValueError mit der Zeilennummer aus.",
"antwort_datei": "loesung.py",
"timeout_s": 60
}
@@ -0,0 +1,28 @@
import sys
import unittest
from loesung import summiere_umsaetze
class Tests(unittest.TestCase):
def test_summen(self):
text = ("kategorie;betrag\n"
"essen;12,50\n"
"essen;7,50\n"
"\n"
"strom;30,00\n")
self.assertEqual(summiere_umsaetze(text),
{"essen": 20.0, "strom": 30.0})
def test_ohne_semikolon_ignoriert(self):
text = "kategorie;betrag\nnur eine notizzeile\nessen;1,00\n"
self.assertEqual(summiere_umsaetze(text), {"essen": 1.0})
def test_kaputter_betrag(self):
with self.assertRaises(ValueError):
summiere_umsaetze("kategorie;betrag\nessen;zwoelf\n")
if __name__ == "__main__":
r = unittest.main(exit=False).result
sys.exit(0 if r.wasSuccessful() else 1)
@@ -0,0 +1,8 @@
{
"prompt": "In der Datei `zeitfenster.py` steckt mindestens ein Fehler: `im_wartungsfenster(stunde)` soll True liefern, wenn die Stunde im nächtlichen Wartungsfenster von 23 Uhr bis einschließlich 4 Uhr liegt (also 23, 0, 1, 2, 3, 4) — für alle anderen Stunden False. Ungültige Stunden (<0 oder >23) sollen einen ValueError auslösen. Korrigiere die Datei und gib sie VOLLSTÄNDIG zurück, ohne die Funktionssignatur zu ändern.",
"antwort_datei": "zeitfenster.py",
"dateien": {
"zeitfenster.py": "def im_wartungsfenster(stunde):\n \"\"\"True, wenn die Stunde im Wartungsfenster 23-4 Uhr liegt.\"\"\"\n if stunde < 0 or stunde > 24:\n raise ValueError(\"ungueltige Stunde\")\n return 23 <= stunde or stunde < 4\n"
},
"timeout_s": 60
}
@@ -0,0 +1,24 @@
import sys
import unittest
from zeitfenster import im_wartungsfenster
class Tests(unittest.TestCase):
def test_im_fenster(self):
for h in (23, 0, 1, 2, 3, 4):
self.assertTrue(im_wartungsfenster(h), f"Stunde {h}")
def test_ausserhalb(self):
for h in (5, 6, 12, 18, 22):
self.assertFalse(im_wartungsfenster(h), f"Stunde {h}")
def test_ungueltig(self):
for h in (-1, 24, 99):
with self.assertRaises(ValueError):
im_wartungsfenster(h)
if __name__ == "__main__":
r = unittest.main(exit=False).result
sys.exit(0 if r.wasSuccessful() else 1)
@@ -0,0 +1,5 @@
{
"prompt": "Schreibe in `loesung.py` eine Funktion `fehler_zeilen(log_text)`. Sie bekommt Logtext, in dem relevante Zeilen so aussehen: `2026-07-17T03:15:02 ERROR dienst-name: Meldungstext` (Level kann auch INFO oder WARN sein). Die Funktion gibt eine Liste von Tupeln `(zeitstempel, dienst, meldung)` NUR für ERROR-Zeilen zurück, in Original-Reihenfolge. Zeilen in anderem Format werden still ignoriert. Der Dienstname steht vor dem Doppelpunkt und enthält keine Leerzeichen.",
"antwort_datei": "loesung.py",
"timeout_s": 60
}
@@ -0,0 +1,29 @@
import sys
import unittest
from loesung import fehler_zeilen
LOG = """2026-07-17T03:15:02 ERROR llama-swap: Modell nicht gefunden
2026-07-17T03:15:03 INFO mc2: Start ok
kaputte zeile ohne format
2026-07-17T03:16:10 WARN voice: Latenz hoch
2026-07-17T03:17:00 ERROR mem0-service: Timeout nach 30s
"""
class Tests(unittest.TestCase):
def test_nur_error(self):
erg = fehler_zeilen(LOG)
self.assertEqual(len(erg), 2)
self.assertEqual(erg[0][0], "2026-07-17T03:15:02")
self.assertEqual(erg[0][1], "llama-swap")
self.assertEqual(erg[0][2], "Modell nicht gefunden")
self.assertEqual(erg[1][1], "mem0-service")
def test_leer(self):
self.assertEqual(fehler_zeilen("nur INFO hier\n"), [])
if __name__ == "__main__":
r = unittest.main(exit=False).result
sys.exit(0 if r.wasSuccessful() else 1)
@@ -0,0 +1,5 @@
{
"prompt": "Schreibe in `loesung.py` eine Klasse `Lager`. Konstruktor ohne Argumente. Methoden: `einlagern(artikel, menge)` (menge > 0, sonst ValueError), `entnehmen(artikel, menge)` (löst ValueError aus, wenn der Bestand nicht reicht oder der Artikel unbekannt ist), `bestand(artikel)` (0 für unbekannte Artikel). Bestände sind ganze Zahlen je Artikelname.",
"antwort_datei": "loesung.py",
"timeout_s": 60
}
@@ -0,0 +1,31 @@
import sys
import unittest
from loesung import Lager
class Tests(unittest.TestCase):
def test_ablauf(self):
l = Lager()
l.einlagern("kabel", 10)
l.entnehmen("kabel", 4)
self.assertEqual(l.bestand("kabel"), 6)
self.assertEqual(l.bestand("unbekannt"), 0)
def test_unterbestand(self):
l = Lager()
l.einlagern("kabel", 2)
with self.assertRaises(ValueError):
l.entnehmen("kabel", 3)
with self.assertRaises(ValueError):
l.entnehmen("gibtsnicht", 1)
def test_menge_positiv(self):
l = Lager()
with self.assertRaises(ValueError):
l.einlagern("kabel", 0)
if __name__ == "__main__":
r = unittest.main(exit=False).result
sys.exit(0 if r.wasSuccessful() else 1)
@@ -0,0 +1,5 @@
{
"prompt": "Schreibe in `loesung.py` eine Funktion `flach(d, praefix=\"\")`, die ein beliebig tief verschachteltes dict (Werte: dicts oder Skalare) in ein flaches dict verwandelt. Schlüsselpfade werden mit Punkt verbunden, z. B. macht `{\"a\": {\"b\": 1}, \"c\": 2}` daraus `{\"a.b\": 1, \"c\": 2}`. Leere dicts verschwinden ersatzlos. Nicht-dict-Eingaben lösen einen TypeError aus.",
"antwort_datei": "loesung.py",
"timeout_s": 60
}
@@ -0,0 +1,22 @@
import sys
import unittest
from loesung import flach
class Tests(unittest.TestCase):
def test_verschachtelt(self):
self.assertEqual(flach({"a": {"b": 1, "c": {"d": 2}}, "e": 3}),
{"a.b": 1, "a.c.d": 2, "e": 3})
def test_leere_dicts(self):
self.assertEqual(flach({"a": {}, "b": 1}), {"b": 1})
def test_typfehler(self):
with self.assertRaises(TypeError):
flach([1, 2])
if __name__ == "__main__":
r = unittest.main(exit=False).result
sys.exit(0 if r.wasSuccessful() else 1)
@@ -0,0 +1,5 @@
{
"prompt": "Schreibe in `loesung.py` eine Funktion `slug(text)`: wandelt deutschen Text in einen URL-Slug. Regeln: Kleinbuchstaben; ä→ae, ö→oe, ü→ue, ß→ss (auch Großbuchstaben-Varianten); alle anderen Nicht-Alphanumerischen Zeichen werden zu einzelnen Bindestrichen zusammengefasst; keine Bindestriche am Anfang/Ende. Beispiel: `Größte \"Änderung\" 2026!` → `groesste-aenderung-2026`.",
"antwort_datei": "loesung.py",
"timeout_s": 60
}
@@ -0,0 +1,21 @@
import sys
import unittest
from loesung import slug
class Tests(unittest.TestCase):
def test_beispiel(self):
self.assertEqual(slug('Größte "Änderung" 2026!'),
"groesste-aenderung-2026")
def test_umlaute(self):
self.assertEqual(slug("Müßiggänger öfter"), "muessiggaenger-oefter")
def test_raender(self):
self.assertEqual(slug(" --Hallo Welt-- "), "hallo-welt")
if __name__ == "__main__":
r = unittest.main(exit=False).result
sys.exit(0 if r.wasSuccessful() else 1)