Lokale Matrix liefert Ergebnisse: 119 Anforderungen aus Gemma und Qwen

Skill 13.0.0/13.1.0, Adapter 2.5.2.

Spiegel-Arbeitsverzeichnis: OpenCode laeuft nicht mehr direkt im
Codebasis-Root, sondern in einem Verzeichnis aus Junctions auf die
Top-Level-Eintraege, mit einem echten Ergebnisverzeichnis, dessen Inhalt
nach dem Lauf uebernommen wird. Damit landen relative wie absolute
Ausgabepfade am richtigen Ort, ohne dass der Prompt vom Wortlaut der
Claude-Laeufe abweichen muss. Der Spiegel liegt in _meta des Laufs; die
Codebasis bleibt unberuehrt.

Der Spiegel allein genuegte nicht. Sechs Laeufe schrieben mit korrektem
absolutem Pfad und wurden dennoch abgewiesen, weil OpenCode Ziele im
Repository gegen den worktree-relativen Pfad abgleicht - ein Befund, der
seit Skill 10.0.2 dokumentiert war und erst sichtbar wurde, als der
Spiegel vom Temp-Verzeichnis ins Projekt wanderte.

analyse-anforderungen.py erkennt Kennungen als Markdown-Ueberschrift, auch
ohne Feldnamen, sofern die Pflichtfelder folgen. Regressionsprobe an fuenf
Claude-Laeufen unveraendert.

Ergebnisse der gueltigen Laeufe: Qwen 3.5-9B liefert 107 der 119
Anforderungen, davon 75 im Modus custom mit nur drei Subagenten. Gemma
kommt auf 12. Der Modus builtin fiel bei beiden Modellen aus - drei von
drei Laeufen endeten nach einem Turn ohne einen Werkzeugaufruf. Die 13
Laeufe mit Adapter 2.3.0 bis 2.5.1 sind Artefakte der Fehlersuche und
als adapterbedingte Fehlmessungen gekennzeichnet.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Christoph Schwörer
2026-09-01 22:49:53 +02:00
co-authored by Claude Opus 5
parent 28e927013b
commit 6c5c26a2e4
416 changed files with 85993 additions and 13 deletions
@@ -202,6 +202,81 @@ class ReadonlyShellTests(unittest.TestCase):
)
class SpiegelTests(unittest.TestCase):
"""Der Spiegel loest relative Ausgabepfade, ohne die Quelle zu beruehren."""
def test_relativer_schreibpfad_landet_im_laufverzeichnis(self):
with tempfile.TemporaryDirectory() as temp_dir:
temp = Path(temp_dir)
quelle = temp / "codebasis"
(quelle / "src").mkdir(parents=True)
(quelle / "src" / "a.cs").write_text("Quellcode", encoding="utf-8")
(quelle / "README.md").write_text("Liesmich", encoding="utf-8")
ausgabe = temp / "lauf" / "Ergebnisse"
ausgabe.mkdir(parents=True)
spiegel = temp / "spiegel"
ADAPTER.erstelle_spiegel(quelle, spiegel, ausgabe, lambda _: None)
try:
self.assertTrue((spiegel / "src" / "a.cs").is_file())
self.assertTrue((spiegel / "README.md").is_file())
# `Ergebnisse` ist im Spiegel ein echtes Verzeichnis - ein
# relativer Schreibpfad landet dort und wird danach uebernommen.
(spiegel / "Ergebnisse" / "StRS.md").write_text("X", encoding="utf-8")
self.assertFalse((ausgabe / "StRS.md").is_file())
anzahl = ADAPTER.uebernimm_ergebnisse(spiegel, ausgabe, lambda _: None)
self.assertEqual(1, anzahl)
self.assertTrue((ausgabe / "StRS.md").is_file())
self.assertEqual("X", (ausgabe / "StRS.md").read_text(encoding="utf-8"))
finally:
ADAPTER.entferne_spiegel(spiegel, lambda _: None)
# Der Abbau darf die Quelle nicht durch die Junction hindurch loeschen.
self.assertFalse(spiegel.exists())
self.assertTrue((quelle / "src" / "a.cs").is_file())
self.assertEqual("Quellcode", (quelle / "src" / "a.cs").read_text(encoding="utf-8"))
self.assertTrue((ausgabe / "StRS.md").is_file())
def test_freigabe_enthaelt_arbeitsverzeichnis_relative_form(self):
"""resolve() folgt der Junction - die relative Form darf nicht verloren gehen."""
with tempfile.TemporaryDirectory() as temp_dir:
temp = Path(temp_dir)
quelle = temp / "codebasis"
(quelle / "src").mkdir(parents=True)
ausgabe = temp / "lauf" / "Ergebnisse"
ausgabe.mkdir(parents=True)
spiegel = temp / "spiegel"
ADAPTER.erstelle_spiegel(quelle, spiegel, ausgabe, lambda _: None)
try:
config = ADAPTER.build_run_config(
{}, "lmstudio/x", "x", "solo", spiegel, ausgabe, None,
provider="lmstudio",
zusatz_ausgaben=[spiegel / ausgabe.name],
)
finally:
ADAPTER.entferne_spiegel(spiegel, lambda _: None)
erlaubt = [k for k, v in config["permission"]["edit"].items() if v == "allow"]
self.assertIn("Ergebnisse", erlaubt)
self.assertIn("Ergebnisse/**", erlaubt)
def test_quelle_bleibt_ohne_neue_eintraege(self):
with tempfile.TemporaryDirectory() as temp_dir:
temp = Path(temp_dir)
quelle = temp / "codebasis"
(quelle / "src").mkdir(parents=True)
vorher = sorted(p.name for p in quelle.iterdir())
ausgabe = temp / "lauf" / "Ergebnisse"
ausgabe.mkdir(parents=True)
spiegel = temp / "spiegel"
ADAPTER.erstelle_spiegel(quelle, spiegel, ausgabe, lambda _: None)
(spiegel / "Ergebnisse" / "datei.md").write_text("X", encoding="utf-8")
ADAPTER.uebernimm_ergebnisse(spiegel, ausgabe, lambda _: None)
ADAPTER.entferne_spiegel(spiegel, lambda _: None)
self.assertEqual(vorher, sorted(p.name for p in quelle.iterdir()))
class UsageCapturedTests(unittest.TestCase):
"""Eine Null aus einem laufenden Subagenten ist kein Messwert."""