Compare commits
2
Commits
fca08de1c5
...
c56cc6291a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c56cc6291a | ||
|
|
42350a811e |
No files matched your search
@@ -15,7 +15,7 @@ Du denkst, du tippst nicht. Dein Ergebnis ist ein Plan, den ein Executer ohne R
|
||||
- **Nur Plandateien schreiben.** Erlaubt ist ausschließlich `docs/plans/` im Zielprojekt. Kein Produktivcode, keine Konfigurationsdateien, keine Tests im Repo.
|
||||
- **Ablageform hängt am Umfang.** Bis zwei Tasks eine Datei `docs/plans/JJJJ-MM-TT-<thema>.md`. **Ab etwa drei Tasks ein Ordner** `docs/plans/JJJJ-MM-TT-<thema>/` mit `00-uebersicht.md` (Ziel, Architektur, globale Vorgaben, Dateiübersicht, Tasktabelle, Abnahme) und je Task einer Datei `task-NN-<thema>.md`. Jede Taskdatei verweist im Kopf auf die globalen Vorgaben der Übersicht, statt sie zu wiederholen — zwei Fassungen derselben Vorgabe laufen auseinander.
|
||||
- **Jede Plandatei verlinkt ihren Hub direkt unter dem Frontmatter**, als relativen Markdown-Link, nicht nur als Pfad in Backticks. Die Übersicht und ein Einzeldatei-Plan verlinken das Projekt-README (`Projekt: [README](../../../README.md)`, die Tiefe passend zum Ort), jede andere Datei im Planordner die Übersicht (`Übersicht: [00-uebersicht.md](00-uebersicht.md)`). Leerzeichen und Umlaute im Pfad schreibst du URL-kodiert. Liegt der Plan unter `docs/` an der Vault-Wurzel, ist der Hub die `README.md` dort, und die Zeile beginnt mit `Vault:` statt `Projekt:`. Liegt er in einem Projekt im IT Workspace, etwa unter `_arbeitsstand/`, verlinkt die Übersicht stattdessen die Projektübersicht (`_MOC-*.md` im Projektordner) als Wikilink mit vollem Pfad. Die Planwerkzeuge vertragen die Zeile an dieser Stelle, weil sie nur Überschriften, Codezäune und den Abschnitt `## Zieldateien` auswerten (Befund im Plan `.vault-tools/linkcheck/docs/plans/2026-09-29-waisen/`). Regel und Begründung: `AI/Regelwerk/navigation.md`, Abschnitt „Links schreiben und Dateien verschieben“.
|
||||
- **Jede Taskdatei trägt im Frontmatter `modell:` und `modell_begruendung:`.** `title`, `summary` und `modell_begruendung` stehen in Anführungszeichen — ein `: ` im Text macht den Block sonst zu ungültigem YAML (Blöcke und Regel: `AI/Regelwerk/frontmatter.md`). Das Kriterium ist eine einzige Frage: Braucht der Executer für diesen Task Ermessen, oder steht alles wörtlich im Plan? Steht der Code wörtlich da, sind die Zieldateien namentlich genannt und die Verbote ausdrücklich, dann ist die Rolle Abschrift und `haiku` genügt — außer ein Codeblock des Tasks enthält Anführungszeichen wie „ “ ” ‚ ‘ ’ « », Gedanken- oder Streckenstriche – — oder Auslassungspunkte …: Dann `modell: sonnet` und zusätzlich `effort: low` im Frontmatter, weil Haiku solche Zeichen still ersetzt (Messung 2026-09-23). Bleibt Ermessen offen, ist es Fehlersuche, oder muss Fließtext formuliert statt abgeschrieben werden, dann `sonnet`.
|
||||
- **Jede Taskdatei trägt im Frontmatter `modell:` und `modell_begruendung:`.** `title`, `summary` und `modell_begruendung` stehen in Anführungszeichen — ein `: ` im Text macht den Block sonst zu ungültigem YAML (Blöcke und Regel: `AI/Regelwerk/frontmatter.md`). Das Kriterium ist eine einzige Frage: Braucht der Executer für diesen Task Ermessen, oder steht alles wörtlich im Plan? Steht der Code wörtlich da, sind die Zieldateien namentlich genannt und die Verbote ausdrücklich, dann ist die Rolle Abschrift und `haiku` genügt, auch wenn ein Codeblock typografische Zeichen wie „ “ – — … enthält (Haiku 5.5, Pascals Entscheidung vom 2026-10-09; die Ausnahme für Haiku 4.5 steht in `AI/Regelwerk/codeworkflow.md`, Schritt 3). Bleibt Ermessen offen, ist es Fehlersuche, oder muss Fließtext formuliert statt abgeschrieben werden, dann `sonnet`.
|
||||
- **Erst lesen, dann planen.** Bestehende Struktur, Namensgebung, Testkonventionen und Abhängigkeiten des Zielprojekts lesen. Der Plan passt sich der vorhandenen Umgebung an, nicht umgekehrt.
|
||||
- **Erwartete pytest-Fehlerzeilen nur mit breiter Ausgabe.** Ohne Terminal kürzt pytest (gemessen an 9.1.1) jede `FAILED`-Zeile der Kurzzusammenfassung auf 80 Zeichen, die Fehlerart ist dann abgeschnitten („Failed: D..."). Nennt der Plan eine erwartete Fehlerzeile wörtlich, steht im Befehl `COLUMNS=300` davor (Git-Bash) bzw. `$env:COLUMNS=300;` (PowerShell).
|
||||
- **Mutanten stehen in einer Datei, nicht als Prosa.** Verlangt der Auftrag Mutanten, schreibst du sie als `mutanten.toml` in den Planordner, Format 1 nach `D:\Claude\.vault-tools\plan-kopie\mutanten_lauf_ENTWURF.md`, Abschnitt 2; lies den Abschnitt, bevor du die Datei schreibst. Die Plankritik fährt die Datei mit `mutanten_lauf.py` auf ihrer Kopie. In „Fertig heißt“ steht danach nur der Aufruf mit der Erwartung „Exit 0, jeder Mutant `OK`“, keine Zählung. Drei Fallen, alle belegt:
|
||||
|
||||
@@ -5,7 +5,7 @@ title: "Planwerkzeuge: Plan auf eine Kopie anwenden und jede Welle dagegen vergl
|
||||
summary: "Skripte für die Standardschleife bei Plänen mit ausgeschriebenem Code — schlanke Kopie bauen, Plan auf die Kopie anwenden, je Welle Menge und Bytes vergleichen, Aus-wird-Blöcke prüfen, Codeblöcke auf unsichtbare Zeichen absuchen, Escape-Folgen per Codepunkt setzen. Entstanden 2026-09-17 in der Trading Plattform (Teil 3b)."
|
||||
tags: [vault-tools, codeworkflow]
|
||||
created: 2026-09-17
|
||||
updated: 2026-10-06
|
||||
updated: 2026-10-09
|
||||
---
|
||||
|
||||
# Planwerkzeuge für die Kopie mit angewendetem Plan
|
||||
@@ -24,7 +24,7 @@ Die Regel dazu steht in [[AI/Regelwerk/codeworkflow|codeworkflow.md]] („Die Ko
|
||||
7. **Rot-Nachweis je Task (seit 2026-09-18):** `rot_nachweis.py <basis-kopie> <planordner> <arbeitsordner> <spec.json> [--fixturen <ordner>] [--node-modules <pfad>] [--conftest-als-test] [--venv <wsl-pfad>] [--frontend <ordner>] [--projektname <ordnername>]`. **Für ein anderes Projekt als die Trading Plattform braucht es die drei letzten Schalter (seit 2026-09-24):** Ihre Vorgaben sind die der Trading Plattform (`~/venvs/trading`, `dashboard`, `trading-plattform`). Jedes andere Projekt nennt seine Werte, für den Nexhorizons Hub `--venv '~/venvs/hub' --frontend frontend --projektname 'active - Nexhorizons Hub'`, das Venv in einfachen Anführungszeichen, sonst macht die Git-Bash aus `~` einen Windows-Pfad. Das Skript druckt die benutzten Werte in der ersten Zeile. Die Vorgabe `trading-plattform` passt nur auf Pläne mit Arbeitsbaum-Pfaden; ältere Trading-Pläne mit absoluten Pfaden unter `active - Trading Plattform` brauchen `--projektname 'active - Trading Plattform'`, sonst endet der Lauf mit einem `ValueError`. Weiter fest verdrahtet bleiben die Distribution `Debian`, die Ordner `tests/` und `tests/fixtures/`, die Endungen `.test.ts`/`.test.tsx` und `npx.cmd vitest`. **Vorbedingung:** Das Projekt ist im Venv nicht editierbar installiert (`pip install -e`); sonst löst der Finder von setuptools ein fehlendes Untermodul gegen das echte Projekt auf, und ein Test ohne Umsetzung läuft grün. `tests/conftest.py` gilt dabei als Produktivseite und wird zurückgesetzt; nur wenn die neue Fixture eines Tasks dort liegt, lässt `--conftest-als-test` sie stehen (Beleg unten, 2026-09-22). `plan_materialisiere.py` wendet eine Taskdatei immer ganz an; „erst der Test, dann die Umsetzung" lässt sich damit nicht beobachten. Das Skript stellt den Zustand dazwischen auf Wegwerfkopien her — Basis plus Voraussetzungstasks plus der Task, danach die produktiven Zieldateien zurück auf den Stand vor dem Task — und fährt die Testdateien des Tasks (pytest in WSL, vitest unter Windows über eine Junction, die es vor dem Löschen löst). Es meldet je Task `ROT` mit der ersten Fehlerzeile oder `GRUEN`; ein Test, der ohne Umsetzung grün ist, misst sie nicht. Die Basis-Kopie zieht man **vor** der ersten Welle. `spec.json` nennt je Task die Voraussetzungstasks. Erster Einsatz am 2026-09-18 an vier Plänen der Trading Plattform: 35 Tasks, alle rot an der gemeinten Stelle, keiner grün ohne Umsetzung. Die Executer brauchen den Tanz mit dem Beiseitelegen der Produktivdatei dann nicht mehr; ihr Auftrag sagt das ausdrücklich.
|
||||
|
||||
8. **Mutanten fahren (seit 2026-09-27):** `mutanten_lauf.py --wurzel <wegwerfkopie> --mutanten <planordner>/mutanten.toml [--nur ID,…] [--nur-muster] [--bericht <datei.json>] [--zeitlimit <s>]`, in WSL mit einem Python ab 3.11. Die Mutanten stehen nicht mehr als Prosa im Plan, sondern in `mutanten.toml` im Planordner. Das Format, die Status und die Abdichtung stehen in `mutanten_lauf_ENTWURF.md`. Das Skript verweigert eine Wurzel mit `.git` und jeden Pfad aus `ohne`. Seit 2026-10-06 sucht es die pytest-Konfiguration wie pytest selbst, aber nie oberhalb der Wurzel, und gibt sie mit `-c` vor; eine fremde `pyproject.toml` im Windows-Temp stört damit nicht mehr, und ein Bedienfehler von pytest steht mit dem Ende der pytest-Ausgabe im Befund statt als `FEHLT` je Test (Entwurf, Abschnitt 3, „Konfiguration“ und „Abbruch von pytest“). Ob die Suche pytest selbst entspricht, prüft `mutanten_lauf_probe_konfig.py <mutanten_lauf.py> <arbeitsordner>` mit dem Python eines Venvs, in dem pytest liegt (26 Aufbauten, Exit 0 ohne Abweichung). Es fährt zuerst die Grundlinie, dann je Mutant nur die genannten Tests, setzt die Datei zurück und prüft das per SHA-256. Je Test gibt es die Fehlermeldung mit aus; ob ein Test an der gemeinten Stelle fällt, liest man dort. `--nur-muster` prüft nur, ob jedes Muster genau einmal dasteht, ohne pytest. Die Kopie legt man in WSL unter `/tmp` an (`cp -a`, danach `__pycache__` löschen). Auf `/mnt/d` läuft es auch, nur langsamer. **Aus der Git-Bash ein Skript nie mit `wsl … bash /mnt/d/…` starten:** Die Git-Bash macht aus dem Pfad einen Windows-Pfad. Aus der PowerShell starten oder `MSYS_NO_PATHCONV=1` davorsetzen. Ein SIGTERM auf `mutanten_lauf.py` selbst (etwa `timeout -k` oder ein Hilfsagent, der abgebrochen wird) löst dort einen eigenen Handler aus: Der laufende Mutant wird per SHA-Probe zurückgesetzt, die Temp-Ordner werden geräumt, und die Ausgabe trägt `ABBRUCH: SIGTERM` (Treiber-Fall 35, `mutanten_lauf_treiber.py`).
|
||||
**Die Plankritik fährt die Mutanten selbst (seit 2026-09-27, nachgebessert 2026-09-28):** Liegt `mutanten.toml` im Planordner, startet `plankritik.js` in der Vorbereitung `mutanten_lauf_kopie.sh`. Das Skript kopiert die Kopie mit angewendetem Plan nach `/tmp` in WSL, fährt dort den Läufer in einem eigenen Netz-Namensraum (`unshare --map-current-user --net`, gemessen in WSL Debian als Benutzer `claude`: UID innen bleibt 1000, nur Schnittstelle `lo`, jede Verbindung nach außen scheitert) und gibt die Ausgabe an die Linse `arithmetik`. Fehlt `unshare` ohne Netz, bricht das Skript vorher mit `MUTANTEN_LAUF_FEHLER` ab, statt ungesperrt zu laufen. Der Arg `mutanten` wählt `voll` (Vorgabe), `muster` oder `aus`; die Rückgabe trägt dazu `mutanten_status` (`aus`, `ohne_kopie`, `keine_toml`, `ohne_ergebnis` oder `exit_<n>`) und `mutanten_modus` (`voll`, `muster`, `aus`). Der Wrapper gibt vor dem Lauf eine Zeile `modus: voll` oder `modus: muster (…)` aus; bei `modus: muster` weiß die Linse, dass kein Mutant gefahren ist. Der ganze Lauf hat 540 s (`BUDGET_S`, `timeout -k 15`), weil das Bash-Werkzeug eines Hilfsagenten nach zehn Minuten endet; eine überschrittene Grenze meldet die Zeile `ZEITGRENZE`. Je Mutant gilt zusätzlich ein Zeitlimit `ZEITLIMIT_S` (Vorgabe 120 s, muss kleiner sein als `BUDGET_S`): B1 mit 74 Mutanten brauchte 168 s gesamt, rund 2 s je Mutant. Bei Exit 2 oder 3 des Läufers sagt die Linse, der Lauf sei vor oder während der Mutanten gescheitert. Pfade übergibt man mit Vorwärtsschrägstrichen: `wsl -d Debian -- …` reicht die Befehlszeile an die Linux-Shell, und die verschluckt Backslashes.
|
||||
**Die Plankritik fährt die Mutanten selbst (seit 2026-09-27, nachgebessert 2026-09-28):** Liegt `mutanten.toml` im Planordner, startet `plankritik.js` in der Vorbereitung `mutanten_lauf_kopie.sh`. Das Skript kopiert die Kopie mit angewendetem Plan nach `/tmp` in WSL, fährt dort den Läufer in einem eigenen Netz-Namensraum (`unshare --map-current-user --net`, gemessen in WSL Debian als Benutzer `claude`: UID innen bleibt 1000, nur Schnittstelle `lo`, jede Verbindung nach außen scheitert; seit 2026-10-09 mit `lo` oben, siehe Nachtrag unten) und gibt die Ausgabe an die Linse `arithmetik`. Fehlt `unshare` ohne Netz, fehlen `ip`, `setpriv` oder `python3` oder kommt `lo` im Namensraum nicht hoch, bricht das Skript vorher mit `MUTANTEN_LAUF_FEHLER` ab, statt ungesperrt oder ohne `lo` zu laufen. Der Arg `mutanten` wählt `voll` (Vorgabe), `muster` oder `aus`; die Rückgabe trägt dazu `mutanten_status` (`aus`, `ohne_kopie`, `keine_toml`, `ohne_ergebnis` oder `exit_<n>`) und `mutanten_modus` (`voll`, `muster`, `aus`). Der Wrapper gibt vor dem Lauf eine Zeile `modus: voll` oder `modus: muster (…)` aus; bei `modus: muster` weiß die Linse, dass kein Mutant gefahren ist. Der ganze Lauf hat 540 s (`BUDGET_S`, `timeout -k 15`), weil das Bash-Werkzeug eines Hilfsagenten nach zehn Minuten endet; eine überschrittene Grenze meldet die Zeile `ZEITGRENZE`. Je Mutant gilt zusätzlich ein Zeitlimit `ZEITLIMIT_S` (Vorgabe 120 s, muss kleiner sein als `BUDGET_S`): B1 mit 74 Mutanten brauchte 168 s gesamt, rund 2 s je Mutant. Bei Exit 2 oder 3 des Läufers sagt die Linse, der Lauf sei vor oder während der Mutanten gescheitert. Pfade übergibt man mit Vorwärtsschrägstrichen: `wsl -d Debian -- …` reicht die Befehlszeile an die Linux-Shell, und die verschluckt Backslashes.
|
||||
|
||||
## Was belegt ist
|
||||
|
||||
@@ -49,6 +49,15 @@ Nachbesserung vom 2026-10-06 (Plankritik 2 von C1 im Projekt After Install, Plan
|
||||
- Ein `pruefer` fand in der ersten Fassung den Symlink-Fall und fehlende Fälle; die Nachbesserung behob beides. Ein zweiter `pruefer` fand danach keinen Verhaltensfehler mehr, nur eine Aufräumliste (Kopfzeile je Interpreter ohne eigenen Fall, Kurzfassung bei Rückgabewert 3, `;` und Seitenvorschub in `tox.ini`, Selbstprüfung der Probe, lange Fassung im Bericht, zwei Lücken benennen); sie ist in Nachbesserung 2 erledigt, Treiber 46 von 46.
|
||||
- Rohdaten: `AI/secondbrain/linux-haertung-after-install-memory/2026-10-06-c1-abschluss/roh/` (`02-*`, `03-gegenprobe/`, `07-*`, `08-gegenprobe2/` mit dem nachgebesserten Läufer, `09-*` für Nachbesserung 2).
|
||||
|
||||
Nachbesserung vom 2026-10-09 (Paket RB3 der Trading Plattform, Plan `docs/plans/2026-10-09-mutanten-kopie-loopback.md`): Im frischen Netz-Namensraum war `lo` aus. Jeder Test mit einem Server auf `127.0.0.1` scheiterte dort mit „Network is unreachable“ (`Errno 101`), auch ohne Mutant; die Mutanten T1 und T12 des Pakets liefen deshalb von Hand außerhalb des Namensraums. `mutanten_lauf_kopie.sh` startet den Läufer jetzt mit `unshare --map-current-user --net --keep-caps`, fährt `lo` mit `ip` hoch, wirft mit `setpriv` alle vererbbaren und ambienten Fähigkeiten ab und geht per `exec` in `python3` über, ohne Zwischenschale. Eine Vorprüfung vor dem Kopieren verlangt `ip`, `setpriv` und `python3`, ein nutzbares `lo` mit einer Verbindung über `127.0.0.1` und `CapEff` und `CapAmb` gleich 0; sonst endet das Skript mit `MUTANTEN_LAUF_FEHLER` und Exit 2. `127.0.0.1` ist im Namensraum dessen eigenes `lo`, ein Dienst des Rechners bleibt unerreichbar. Belegt am selben Tag:
|
||||
- `mutanten_lauf_kopie_treiber.py` ruft das Skript wie die Plankritik mit Windows-Pfaden auf und fährt die Fälle W1 bis W13: Server auf `127.0.0.1` (W1), keine Route nach außen und `ENETUNREACH` (W2), uid wie außen und keine Fähigkeiten (W3), `ip`, `setpriv` oder `python3` fehlen (W4, W5, W9), Zeitgrenze mit `timeout` als Elternprozess des Läufers und ohne Prozessreste (W6), Grundlinie ohne Server in beiden Modi (W7), Dienst des Rechners unerreichbar (W8). Seit Nachbesserung 1 auch: `ip` scheitert in der Probe (W10), `ip` meldet Erfolg und `lo` bleibt aus (W11), `ip` scheitert erst im Hauptaufruf nach der Modus-Zeile (W12), `setpriv` wirft keine Fähigkeit ab (W13). W10 bis W13 ersetzen dazu einzelne Werkzeuge durch kleine `sh`-Skripte. Neuer Stand ohne Fehler.
|
||||
- Gegen das Skript vor der Änderung rot: W1, W2, W4, W5, W9. Gegen kaputte Varianten genau an ihrem Fall, gefahren mit W1 bis W9: ohne `setpriv` W3, `setpriv` ohne `exec` W6, ohne Vorprüfung W4, W5 und W9, ohne `--keep-caps` alle (die Vorprüfung meldet `Operation not permitted`), ohne Namensraum W2 und W8. Gefahren mit W1 bis W13 (Nachbesserung 1, `docs/plans/2026-10-09-mutanten-kopie-loopback-nachbesserung-1.md`): ohne `exit 2` nach der Probe W10, W11 und W13; Probe ohne `setpriv` W1 bis W9 und W12; Hauptaufruf ohne den Zweig nach `||` W12; Probe ohne Fähigkeitsprüfung W13.
|
||||
- Nicht abgeworfen und nicht geprüft: die Begrenzungsmenge (`CapBnd`) und `no_new_privs`. `plankritik.js` führt eine Vorprüfung mit `MUTANTEN_LAUF_FEHLER` wie bisher bei fehlendem `unshare` als `ohne_ergebnis`, ohne den Text der Meldung.
|
||||
- Die Fähigkeiten prüft das Skript nur an der Probe und nur `CapEff` und `CapAmb`, nicht am Läufer selbst. Alle vier Mengen am Läufer prüft Treiber-Fall W3.
|
||||
- Die Vorprüfung steht vor der Suche nach `mutanten.toml`. Fehlt auf einem Rechner `ip`, `setpriv` oder `python3` oder kommt `lo` nicht hoch, endet das Skript deshalb auch für einen Planordner ohne `mutanten.toml` mit `MUTANTEN_LAUF_FEHLER` und Exit 2 statt mit `KEINE_MUTANTEN_TOML`. `plankritik.js` meldet dann `ohne_ergebnis` statt `keine_toml`, und die Linse erfährt nicht, dass die `mutanten.toml` fehlt. Das bleibt so.
|
||||
- Lauf mit echten Daten: die 73 Mutanten des Pakets RB3 (Kopie `rb3d-kopie`) durch das neue Skript, alle `OK`, T1 und T12 im Namensraum.
|
||||
- Ein `pruefer` fand keinen blockierenden Befund. Seine Lücken (kein Fall für den Fehlerzweig der Probe und den Zweig nach `||` im Hauptaufruf, Kopfkommentar zu weit gefasst, der Satz zur Reihenfolge oben) behebt Nachbesserung 1. Rohdaten: `AI/secondbrain/trading-plattform-memory/2026-10-09-mkopie-roh/`.
|
||||
|
||||
Seit 2026-09-18 nimmt `welle_vergleich.py` unter `## Zieldateien` auch Pfade relativ zum Projekt (ohne Laufwerk und ohne Wurzel), weil Pläne für einen Git-Worktree keine absoluten Pfade nennen; ein `..` darin ist ein Befund wie ein fremder absoluter Pfad. Jede Zeile braucht weiter die Klammer hinter dem Pfad (`(neu)`, `(geändert)`, `(gelöscht)`). `plan_materialisiere.py` erkennt eine Zieldatei ohne Schrägstrich nur mit den Endungen py, ts, tsx, toml, md, css und json — für `compose.yaml` in der Projektwurzel schreibt die Überschrift `./compose.yaml`. Der Treiber fährt dazu drei weitere Fälle (relative Grundlinie, relative Abweichung, `..` nach außen), zusammen 17.
|
||||
|
||||
Seit 2026-09-24 hat `rot_nachweis.py` die Schalter `--venv`, `--frontend` und `--projektname`; vorher waren `~/venvs/trading`, `dashboard` und `trading-plattform/` fest verdrahtet. Ein Hub-Lauf im Trading-Venv wäre für die Tasks mit `argon2-cffi` und `pyotp` rot aus einem fehlenden Paket gewesen, nicht aus der fehlenden Umsetzung. Fehlt das Venv in WSL, steht beim Task jetzt `VORAUSSETZUNG FEHLT` statt `ROT`, und die Schlusszeile zählt diese Läufe getrennt. Belegt am selben Tag: Der Vorgabe-Befehl ist byte-gleich mit der alten Fassung, falsche Schalterwerte enden mit Exit 3, und der erste echte Lauf über 38 Tasks des Hub meldete keinen grün ohne Umsetzung. Im selben Lauf zeigte sich eine zweite Lücke: Beim Zurücksetzen blieben Ordner stehen, die erst der Task angelegt hatte. Ein leeres `hub/auth/` liest Python als Namespace-Paket, und die Fehlerzeile nannte `hub.auth.passwort` statt `hub.auth`. Jetzt gehen solche Ordner mit, sobald sie leer sind; derselbe Lauf für die Tasks 7, 9 und 11 zeigt danach genau die Zeile aus dem Plan. Die unabhängige Prüfung desselben Tages fand eine dritte Lücke: Ein vergessenes `--venv` fiel still auf das Trading-Venv zurück, und Task 7 stand als `ROT … No module named 'argon2'` da. Seitdem wird eine erste Fehlerzeile, die ein Modul außerhalb des Projekts und außerhalb der Zieldateien vermisst, als `VORAUSSETZUNG FEHLT` gemeldet. Das trifft auch den Ende-zu-Ende-Task des Hub, dessen Tests `playwright` brauchen. Mit den Vorgaben lieferte das Skript für die sieben Tasks des Trading-Pakets K vor und nach allen Änderungen dieselben Zeilen. Zwei weitere Lücken desselben Tages, beide ein ROT, das nichts misst: **Ein Arbeitsordner mit Windows-Kurznamen** (`C:/Users/PASCAL~1/…`) ließ vitest dort starten, die Dateien aber über den langen Namen auflösen, und jede Oberflächen-Testdatei endete als `Cannot find module '/src/…'`. Das Skript löst den Arbeitsordner jetzt auf den langen Namen auf; danach zeigte Trading-Task 395 wieder `9 failed | 52 passed` statt `no tests`, und die Hub-Tasks 24, 25, 29 und 37 die Zeile aus dem Plan (`Error: Failed to resolve import "./kontrast" …`). Die erste `Error:`-Zeile steht seitdem mit in der Ergebniszeile, weil die `FAIL`-Zeile allein den Grund nicht zeigt. **Ein Test, der über Vite eine Datei aus `node_modules` lädt** (`?raw`), scheitert hinter der Junction mit `Denied ID`, weil Vite nichts außerhalb seines Wurzelordners ausliefert; das Skript meldet das als `VORAUSSETZUNG FEHLT`. Für solche Tasks läuft der Nachweis in einer Kopie mit echtem `node_modules` (242 MB, gut 20 Sekunden).
|
||||
|
||||
+693
@@ -0,0 +1,693 @@
|
||||
---
|
||||
type: plan
|
||||
title: "Mutantenlauf auf der Kopie: Nachbesserung 1 (Fälle für die Fehlerzweige der lo-Prüfung)"
|
||||
status: active
|
||||
summary: "Delta zum Plan vom 2026-10-09: Treiber-Fälle W10 bis W13 (Probe scheitert an ip, lo bleibt aus, ip scheitert erst im Hauptaufruf, setpriv wirft nichts ab), Varianten v6 bis v9 als Regressionsnachweis, Kopfkommentar des Skripts berichtigt, Satz zur Reihenfolge vor KEINE_MUTANTEN_TOML in LIESMICH und Entwurf, Datensatz rb3d-kopie im Plan."
|
||||
tags: [plan, vault-tools, pruefwerkzeuge]
|
||||
created: 2026-10-09
|
||||
updated: 2026-10-09
|
||||
modell: haiku
|
||||
modell_begruendung: "Jeder Block steht wörtlich da, Zieldateien, Verbote und Haltepunkte sind genannt; kein Codeblock trägt typografische Anführungszeichen, Striche oder Auslassungspunkte."
|
||||
---
|
||||
|
||||
Übersicht: [LIESMICH der Planwerkzeuge](../../LIESMICH.md) · Vorgänger: [Plan lo im Netz-Namensraum](2026-10-09-mutanten-kopie-loopback.md)
|
||||
|
||||
# Mutantenlauf auf der Kopie: Nachbesserung 1
|
||||
|
||||
## Ziel
|
||||
|
||||
Der Treiber `mutanten_lauf_kopie_treiber.py` sieht danach auch die Fehlerzweige der lo-Prüfung: eine gescheiterte Probe (W10, W11), die Fähigkeitsprüfung der Probe (W13) und den Zweig nach `||` im Hauptaufruf (W12). Jeder dieser Fälle ist an einer kaputten Variante rot gesehen. Kopfkommentar, LIESMICH und Entwurf sagen genau, was die Vorprüfung prüft und dass sie vor `KEINE_MUTANTEN_TOML` steht. Der Plan nennt für den Lauf mit echten Daten den richtigen Datensatz.
|
||||
|
||||
## Nicht im Umfang
|
||||
|
||||
- Das Verhalten von `mutanten_lauf_kopie.sh` bleibt gleich. Im Skript ändert sich nur der Kopfkommentar; Schritt 2 prüft das.
|
||||
- Die Reihenfolge der Vorprüfung vor `KEINE_MUTANTEN_TOML` bleibt (Befund 3), sie wird nur beschrieben.
|
||||
- Kein neuer Lauf gegen das Skript aus HEAD, kein neuer Lauf der Varianten v1 bis v5, kein neuer Lauf mit echten Daten (siehe Getroffene Annahmen).
|
||||
- `mutanten_lauf.py`, `mutanten_lauf_treiber.py`, `.claude/workflows/*` und alles unter `D:/Claude/.arbeitsbaeume/` bleiben unberührt.
|
||||
|
||||
## Warum so
|
||||
|
||||
Der `pruefer` fand am 2026-10-09 keinen blockierenden Befund. Treiber W1 bis W9 grün, die 73 Mutanten von RB3 durch das neue Skript alle `OK`, T1 und T12 im Namensraum grün. Rohdaten: `D:/Claude/AI/secondbrain/trading-plattform-memory/2026-10-09-mkopie-roh/pruefer/` (`angriffe.py`, `angriffe.out`, `varianten_pruefer.py`).
|
||||
|
||||
| Befund | Hier |
|
||||
|---|---|
|
||||
| 1 (wichtig): kein Fall für `exit 2` nach der Probe und keiner für den Zweig nach `\|\|` im Hauptaufruf; v6 lief ganz grün | W10 (A1), W11 (A3), W12 (A4), dazu W13 für die Fähigkeitsprüfung der Probe ohne Variante; Varianten v6 und v7 des Prüfers, dazu v8 und v9 |
|
||||
| 2 (klein): Kopfkommentar Z. 42 bis 43 zu weit | Kopfkommentar trennt Probe und Hauptaufruf, nennt CapEff und CapAmb und nur die Probe |
|
||||
| 3 (klein): Vorprüfung vor `KEINE_MUTANTEN_TOML` | bleibt; Satz in LIESMICH, Entwurf und Kopfkommentar |
|
||||
| 4 (klein): Datensatz `rb3d-kopie` statt `rb3b-kopie` | drei Ersetzungen im Plan, Abschnitt „Lauf mit echten Daten“ |
|
||||
|
||||
### Bauweise der neuen Fälle
|
||||
|
||||
Aus `angriffe.py` des Prüfers übernommen: Der `PATH` des Skripts ist ein Ordner mit Verweisen auf alle Werkzeuge aus `WERKZEUGE`. Einzelne Werkzeuge sind dort durch kleine Skripte mit `#!/bin/sh` ersetzt. W4, W5 und W9 lassen ein Werkzeug weg, W10 bis W13 ersetzen eines.
|
||||
|
||||
| Fall | Ersatz | Erwartung | Gemessen oder gerechnet |
|
||||
|---|---|---|---|
|
||||
| W10 | `ip`: Meldung auf stderr, Exit 1 | Exit 2, `MUTANTEN_LAUF_FEHLER: lo im Netz-Namensraum nicht nutzbar`, Text der Attrappe in stdout, keine Modus-Zeile, keine `EXIT`-Zeile, keine Kopie | gemessen als A1 |
|
||||
| W11 | `ip`: Exit 0 ohne Wirkung | dasselbe, mit `Errno 101` in stdout | gemessen als A3 |
|
||||
| W12 | `ip`: zählt seine Aufrufe in einer Datei, ab dem zweiten Exit 1, sonst `exec` des echten `ip` | Exit 2, `modus: voll`, `MUTANTEN_LAUF_FEHLER: lo im Netz-Namensraum nicht hochgefahren`, `EXIT mutanten_lauf: 2`, kein `MW7`, Text der Attrappe in stderr, genau zwei Aufrufe, keine Kopie | gemessen als A4, ohne die Zählung |
|
||||
| W13 | `setpriv`: überspringt alles bis `--` und startet den Rest per `exec`, ohne etwas abzuwerfen | wie W10, mit `Faehigkeiten nicht abgeworfen` in stdout | gerechnet |
|
||||
|
||||
W13 rechnet so: `unshare --keep-caps` hebt die Fähigkeiten in die ambiente Menge. Sonst käme `ip` nach dem `exec` der `sh` nicht an `CAP_NET_ADMIN`. Ohne `setpriv` behält `python3` sie deshalb, wie bei Variante v1 des Plans (W3 rot, gemessen).
|
||||
|
||||
### Varianten
|
||||
|
||||
| Variante | Änderung | rot erwartet | gemessen oder gerechnet |
|
||||
|---|---|---|---|
|
||||
| `v6_probe_ohne_exit` | Zeile `exit 2` nach der Meldung der Probe gestrichen (v6 des Prüfers) | W10, W11, W13 | W1 bis W9 grün gemessen (Prüfer), W10 rot gemessen (A6), W11 und W13 gerechnet |
|
||||
| `v7_probe_ohne_setpriv` | Probe ohne `setpriv` (v7 des Prüfers) | W1 bis W9, W12 | gerechnet |
|
||||
| `v8_haupt_ohne_oder` | Hauptaufruf ohne den Zweig nach `\|\|` | W12 | gerechnet |
|
||||
| `v9_probe_ohne_faehigkeiten` | Probe ohne Fähigkeitsprüfung (`if False:`) | W13 | gerechnet |
|
||||
|
||||
Damit ist jeder neue Fall einmal rot: W10 und W11 an v6, W12 an v7 und v8, W13 an v6 und v9.
|
||||
|
||||
## Zieldateien
|
||||
|
||||
Pfade relativ zu `D:/Claude/.vault-tools/plan-kopie/`:
|
||||
|
||||
- `mutanten_lauf_kopie_treiber.py` (geändert)
|
||||
- `mutanten_lauf_kopie.sh` (geändert)
|
||||
- `LIESMICH.md` (geändert)
|
||||
- `mutanten_lauf_ENTWURF.md` (geändert)
|
||||
- `docs/plans/2026-10-09-mutanten-kopie-loopback.md` (geändert)
|
||||
|
||||
## Verbote
|
||||
|
||||
- Nur die fünf Zieldateien ändern. Kein `git add`, kein `git commit`.
|
||||
- Hilfsdateien nur im Rot-Ordner `C:\Users\PASCAL~1\AppData\Local\Temp\mkopie-rot-n1` (Git-Bash: `/c/Users/PASCAL~1/AppData/Local/Temp/mkopie-rot-n1`, WSL: `/mnt/c/Users/PASCAL~1/AppData/Local/Temp/mkopie-rot-n1`).
|
||||
- Jeden Block byte-genau übernehmen: keine Umformulierung, keine Ersetzung von Zeichen, keine zusätzlichen Leerzeilen. Aus-Block als `old_string`, wird-Block als `new_string` im Edit-Werkzeug; die Variantendatei mit dem Write-Werkzeug.
|
||||
- Kein `sed`, kein Suchen-und-Ersetzen über ganze Dateien.
|
||||
- WSL-Aufrufe nur aus der PowerShell.
|
||||
- Kein Netz außer `127.0.0.1`.
|
||||
- Den Treiber nicht fahren, während eine Plankritik läuft.
|
||||
- Steht ein Aus-Block nicht genau einmal in seiner Datei oder weicht eine Pflicht-Ausgabe ab: anhalten und melden. Den Treiber nie anpassen, damit ein Fall grün wird.
|
||||
- `python -m py_compile` legt `__pycache__` an; den Ordner danach löschen.
|
||||
|
||||
## Schritt 0 — Rot-Ordner und Ausgangsstand
|
||||
|
||||
In der Git-Bash:
|
||||
|
||||
```bash
|
||||
# Rot-Ordner neu anlegen, Skript im jetzigen Stand als Vergleichsdatei hineinlegen
|
||||
R=/c/Users/PASCAL~1/AppData/Local/Temp/mkopie-rot-n1
|
||||
rm -rf "$R" && mkdir -p "$R"
|
||||
cp /d/Claude/.vault-tools/plan-kopie/mutanten_lauf_kopie.sh "$R/skript_vor_n1.sh"
|
||||
# Ausgangsstand: Plan umgesetzt, nicht committet
|
||||
git -C /d/Claude status --porcelain -- .vault-tools
|
||||
```
|
||||
|
||||
Erwartet: genau diese sechs Zeilen, in beliebiger Reihenfolge. Sonst anhalten und melden.
|
||||
|
||||
```text
|
||||
M .vault-tools/plan-kopie/LIESMICH.md
|
||||
M .vault-tools/plan-kopie/mutanten_lauf_ENTWURF.md
|
||||
M .vault-tools/plan-kopie/mutanten_lauf_kopie.sh
|
||||
?? .vault-tools/plan-kopie/docs/plans/2026-10-09-mutanten-kopie-loopback-nachbesserung-1.md
|
||||
?? .vault-tools/plan-kopie/docs/plans/2026-10-09-mutanten-kopie-loopback.md
|
||||
?? .vault-tools/plan-kopie/mutanten_lauf_kopie_treiber.py
|
||||
```
|
||||
|
||||
## Schritt 1 — Tests zuerst: Treiber
|
||||
|
||||
### `mutanten_lauf_kopie_treiber.py`, Stelle 1 von 7
|
||||
|
||||
Aus:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""Treiber fuer mutanten_lauf_kopie.sh: Faelle W1 bis W9 (lo im Netz-Namensraum).
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""Treiber fuer mutanten_lauf_kopie.sh: Faelle W1 bis W13 (lo im Netz-Namensraum).
|
||||
```
|
||||
|
||||
### `mutanten_lauf_kopie_treiber.py`, Stelle 2 von 7
|
||||
|
||||
Aus:
|
||||
|
||||
```python
|
||||
Nicht im Treiber: ob plankritik.js das Skript so aufruft wie hier
|
||||
(MSYS_NO_PATHCONV, cygpath -m -l).
|
||||
"""
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```python
|
||||
Faelle W10 bis W13 (Nachbesserung 1, Plan
|
||||
docs/plans/2026-10-09-mutanten-kopie-loopback-nachbesserung-1.md) ersetzen im
|
||||
Attrappen-Ordner einzelne Werkzeuge durch kleine sh-Skripte, nach den
|
||||
Angriffen A1, A3 und A4 des Pruefers vom 2026-10-09: ip scheitert in der
|
||||
Probe (W10), ip meldet Erfolg und lo bleibt aus (W11), ip scheitert erst im
|
||||
Hauptaufruf (W12), setpriv wirft keine Faehigkeit ab (W13).
|
||||
|
||||
Nicht im Treiber: ob plankritik.js das Skript so aufruft wie hier
|
||||
(MSYS_NO_PATHCONV, cygpath -m -l); ob die Probe bei Exit 0 mit falscher
|
||||
Ausgabe scheitert.
|
||||
"""
|
||||
```
|
||||
|
||||
### `mutanten_lauf_kopie_treiber.py`, Stelle 3 von 7
|
||||
|
||||
Aus:
|
||||
|
||||
```python
|
||||
import os
|
||||
import shutil
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```python
|
||||
import os
|
||||
import shlex
|
||||
import shutil
|
||||
```
|
||||
|
||||
### `mutanten_lauf_kopie_treiber.py`, Stelle 4 von 7
|
||||
|
||||
Aus:
|
||||
|
||||
```python
|
||||
# Was mutanten_lauf_kopie.sh ueber PATH aufruft (Stand 2026-10-09); daraus
|
||||
# bauen W4, W5 und W9 ihre Attrappen-Ordner.
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```python
|
||||
# Was mutanten_lauf_kopie.sh ueber PATH aufruft (Stand 2026-10-09); daraus
|
||||
# bauen W4, W5, W9 und W10 bis W13 ihre Attrappen-Ordner.
|
||||
```
|
||||
|
||||
### `mutanten_lauf_kopie_treiber.py`, Stelle 5 von 7
|
||||
|
||||
Aus:
|
||||
|
||||
```python
|
||||
def fall_w9(skript):
|
||||
fahre_ohne_werkzeug("W9", skript, "python3")
|
||||
|
||||
|
||||
def prozesse_mit_marke(marke):
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```python
|
||||
def fall_w9(skript):
|
||||
fahre_ohne_werkzeug("W9", skript, "python3")
|
||||
|
||||
|
||||
def baue_attrappen_mit_ersatz(ordner, ersatz):
|
||||
# Wie baue_attrappen, aber jedes Werkzeug aus ersatz ist ein kleines
|
||||
# sh-Skript statt eines Verweises auf das echte Werkzeug (Bauweise aus den
|
||||
# Angriffen des Pruefers vom 2026-10-09).
|
||||
ordner.mkdir()
|
||||
for name in WERKZEUGE:
|
||||
pfad = ordner / name
|
||||
if name in ersatz:
|
||||
pfad.write_text("#!/bin/sh\n" + ersatz[name] + "\n", encoding="utf-8")
|
||||
pfad.chmod(0o755)
|
||||
else:
|
||||
os.symlink(shutil.which(name), pfad)
|
||||
|
||||
|
||||
def fahre_probe_scheitert(name, skript, ersatz, merkmal):
|
||||
# Die Vorpruefung muss scheitern: Exit 2 mit der Meldung der Probe und dem
|
||||
# Merkmal des Angriffs, ohne Modus-Zeile, ohne EXIT-Zeile, ohne Kopie.
|
||||
fall = fall_einfach()
|
||||
try:
|
||||
ordner = fall.basis / "attrappen"
|
||||
baue_attrappen_mit_ersatz(ordner, ersatz)
|
||||
vorher = plankritik_ordner()
|
||||
ergebnis = starte_skript(skript, fall, pfad=str(ordner))
|
||||
neu = sorted(str(p) for p in plankritik_ordner() - vorher)
|
||||
ok = (
|
||||
ergebnis.returncode == 2
|
||||
and "MUTANTEN_LAUF_FEHLER: lo im Netz-Namensraum nicht nutzbar" in ergebnis.stdout
|
||||
and merkmal in ergebnis.stdout
|
||||
and "modus:" not in ergebnis.stdout
|
||||
and "EXIT mutanten_lauf" not in ergebnis.stdout
|
||||
and not neu
|
||||
)
|
||||
melde(name, ok, "neue Kopien={0}, {1}".format(neu, kurz(ergebnis)))
|
||||
fall.pruefe_kopie(name)
|
||||
finally:
|
||||
fall.aufraeumen()
|
||||
|
||||
|
||||
def fall_w10(skript):
|
||||
# ip scheitert schon in der Probe (Angriff A1 des Pruefers).
|
||||
fahre_probe_scheitert("W10", skript, {"ip": "echo ip-attrappe scheitert >&2; exit 1"}, "ip-attrappe scheitert")
|
||||
|
||||
|
||||
def fall_w11(skript):
|
||||
# ip meldet Erfolg, lo bleibt aus (A3): Die Verbindung der Probe scheitert
|
||||
# mit Errno 101.
|
||||
fahre_probe_scheitert("W11", skript, {"ip": "exit 0"}, "Errno 101")
|
||||
|
||||
|
||||
def fall_w12(skript):
|
||||
# ip klappt in der Probe und scheitert erst im Hauptaufruf (A4); eine
|
||||
# Zaehlerdatei haelt fest, der wievielte Aufruf es ist. Erwartet:
|
||||
# Modus-Zeile, Meldung des Hauptaufrufs, EXIT-Zeile mit 2, kein Laeufer,
|
||||
# genau zwei Aufrufe von ip, keine Kopie unter /tmp.
|
||||
fall = fall_einfach()
|
||||
try:
|
||||
zaehler = fall.basis / "ip_zaehler"
|
||||
z = shlex.quote(str(zaehler))
|
||||
ip_echt = shlex.quote(shutil.which("ip"))
|
||||
ersatz = {"ip": (
|
||||
"n=0\n"
|
||||
"if [ -f " + z + " ]; then read n < " + z + "; fi\n"
|
||||
"n=$((n + 1))\n"
|
||||
"echo \"$n\" > " + z + "\n"
|
||||
"if [ \"$n\" -ge 2 ]; then echo \"ip-attrappe zweiter Aufruf\" >&2; exit 1; fi\n"
|
||||
"exec " + ip_echt + " \"$@\""
|
||||
)}
|
||||
ordner = fall.basis / "attrappen"
|
||||
baue_attrappen_mit_ersatz(ordner, ersatz)
|
||||
vorher = plankritik_ordner()
|
||||
ergebnis = starte_skript(skript, fall, pfad=str(ordner))
|
||||
neu = sorted(str(p) for p in plankritik_ordner() - vorher)
|
||||
try:
|
||||
aufrufe = zaehler.read_text(encoding="ascii").strip()
|
||||
except OSError:
|
||||
aufrufe = "keine"
|
||||
ok = (
|
||||
ergebnis.returncode == 2
|
||||
and "modus: voll" in ergebnis.stdout
|
||||
and "MUTANTEN_LAUF_FEHLER: lo im Netz-Namensraum nicht hochgefahren" in ergebnis.stdout
|
||||
and "EXIT mutanten_lauf: 2" in ergebnis.stdout
|
||||
and "nicht nutzbar" not in ergebnis.stdout
|
||||
and "MW7" not in ergebnis.stdout
|
||||
and "ip-attrappe zweiter Aufruf" in ergebnis.stderr
|
||||
and aufrufe == "2"
|
||||
and not neu
|
||||
)
|
||||
melde("W12", ok, "ip-aufrufe={0}, neue Kopien={1}, {2}".format(aufrufe, neu, kurz(ergebnis)))
|
||||
fall.pruefe_kopie("W12")
|
||||
finally:
|
||||
fall.aufraeumen()
|
||||
|
||||
|
||||
SETPRIV_OHNE_WIRKUNG = (
|
||||
"while [ \"$#\" -gt 0 ] && [ \"$1\" != \"--\" ]; do shift; done\n"
|
||||
"shift\n"
|
||||
"exec \"$@\""
|
||||
)
|
||||
|
||||
|
||||
def fall_w13(skript):
|
||||
# setpriv wirft keine Faehigkeit ab und startet nur den Befehl hinter --:
|
||||
# Die Faehigkeitspruefung der Probe muss anschlagen.
|
||||
fahre_probe_scheitert("W13", skript, {"setpriv": SETPRIV_OHNE_WIRKUNG}, "Faehigkeiten nicht abgeworfen")
|
||||
|
||||
|
||||
def prozesse_mit_marke(marke):
|
||||
```
|
||||
|
||||
### `mutanten_lauf_kopie_treiber.py`, Stelle 6 von 7
|
||||
|
||||
Aus:
|
||||
|
||||
```python
|
||||
FAELLE = [
|
||||
("W7", fall_w7),
|
||||
("W1", fall_w1),
|
||||
("W2", fall_w2),
|
||||
("W3", fall_w3),
|
||||
("W4", fall_w4),
|
||||
("W5", fall_w5),
|
||||
("W6", fall_w6),
|
||||
("W8", fall_w8),
|
||||
("W9", fall_w9),
|
||||
]
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```python
|
||||
FAELLE = [
|
||||
("W7", fall_w7),
|
||||
("W1", fall_w1),
|
||||
("W2", fall_w2),
|
||||
("W3", fall_w3),
|
||||
("W4", fall_w4),
|
||||
("W5", fall_w5),
|
||||
("W6", fall_w6),
|
||||
("W8", fall_w8),
|
||||
("W9", fall_w9),
|
||||
("W10", fall_w10),
|
||||
("W11", fall_w11),
|
||||
("W12", fall_w12),
|
||||
("W13", fall_w13),
|
||||
]
|
||||
```
|
||||
|
||||
### `mutanten_lauf_kopie_treiber.py`, Stelle 7 von 7
|
||||
|
||||
Aus:
|
||||
|
||||
```python
|
||||
zerleger = argparse.ArgumentParser(description="Treiber fuer mutanten_lauf_kopie.sh (Faelle W1 bis W9)")
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```python
|
||||
zerleger = argparse.ArgumentParser(description="Treiber fuer mutanten_lauf_kopie.sh (Faelle W1 bis W13)")
|
||||
```
|
||||
|
||||
Dann in der Git-Bash prüfen:
|
||||
|
||||
```bash
|
||||
# Treiber kompilieren, nur ASCII, keine CR, vier neue Faelle; __pycache__ danach weg
|
||||
cd /d/Claude/.vault-tools/plan-kopie
|
||||
python -m py_compile mutanten_lauf_kopie_treiber.py && echo kompiliert
|
||||
rm -rf __pycache__
|
||||
LC_ALL=C grep -cP '[^\x00-\x7F]' mutanten_lauf_kopie_treiber.py
|
||||
tr -cd '\r' < mutanten_lauf_kopie_treiber.py | wc -c
|
||||
grep -c '^def fall_w1[0-3](skript):$' mutanten_lauf_kopie_treiber.py
|
||||
```
|
||||
|
||||
Erwartet: `kompiliert`, dann `0`, `0`, `4`.
|
||||
|
||||
### Kein Rot vor der Umsetzung
|
||||
|
||||
Diese Nachbesserung ändert das Verhalten des Skripts nicht. Die neuen Fälle sind deshalb schon gegen den jetzigen Stand grün; W10 bis W12 hat der Prüfer als A1, A3 und A4 gemessen. Ihr Rot zeigen die Varianten in Schritt 4.
|
||||
|
||||
## Schritt 2 — Umsetzung: Kopfkommentar des Skripts
|
||||
|
||||
### `./mutanten_lauf_kopie.sh`, Stelle 1 von 1
|
||||
|
||||
Aus:
|
||||
|
||||
```bash
|
||||
# - Vorpruefung vor dem Kopieren: Fehlt ip, setpriv oder python3, kommt lo nicht hoch oder
|
||||
# bleiben Faehigkeiten, endet das Skript mit MUTANTEN_LAUF_FEHLER und Exit 2. Ein Lauf ohne
|
||||
# Netzsperre oder ohne lo ist nie die Ausweichloesung.
|
||||
# - Treiber: mutanten_lauf_kopie_treiber.py, Faelle W1 bis W9.
|
||||
set -u
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```bash
|
||||
# - Vorpruefung vor dem Kopieren: Fehlt ip, setpriv oder python3, kommt lo in einer Probe im
|
||||
# eigenen Namensraum nicht hoch, gelingt dort keine Verbindung ueber 127.0.0.1 oder hat die
|
||||
# Probe nach setpriv noch CapEff oder CapAmb ungleich 0, endet das Skript mit
|
||||
# MUTANTEN_LAUF_FEHLER und Exit 2, ohne EXIT-Zeile. Die Faehigkeiten prueft das Skript nur an
|
||||
# dieser Probe und nur CapEff und CapAmb, nicht am Laeufer selbst; alle vier Mengen am Laeufer
|
||||
# prueft Treiber-Fall W3. Die Vorpruefung steht vor der Suche nach mutanten.toml: Scheitert
|
||||
# sie, endet das Skript auch fuer einen Planordner ohne mutanten.toml mit Exit 2 statt mit
|
||||
# KEINE_MUTANTEN_TOML.
|
||||
# - Hauptaufruf: Kommt lo dort nicht hoch, endet das Skript nach der Modus-Zeile mit
|
||||
# MUTANTEN_LAUF_FEHLER, Exit 2 und EXIT-Zeile, ohne den Laeufer zu starten. Ein Lauf ohne
|
||||
# Netzsperre oder ohne lo ist nie die Ausweichloesung.
|
||||
# - Treiber: mutanten_lauf_kopie_treiber.py, Faelle W1 bis W13 (W10 bis W13 seit Nachbesserung 1,
|
||||
# docs/plans/2026-10-09-mutanten-kopie-loopback-nachbesserung-1.md).
|
||||
set -u
|
||||
```
|
||||
|
||||
Dann in der Git-Bash:
|
||||
|
||||
```bash
|
||||
# nur ASCII, keine CR, und ausser Kommentarzeilen nichts geaendert
|
||||
cd /d/Claude/.vault-tools/plan-kopie
|
||||
R=/c/Users/PASCAL~1/AppData/Local/Temp/mkopie-rot-n1
|
||||
LC_ALL=C grep -cP '[^\x00-\x7F]' mutanten_lauf_kopie.sh
|
||||
tr -cd '\r' < mutanten_lauf_kopie.sh | wc -c
|
||||
diff <(grep -v '^#' "$R/skript_vor_n1.sh") <(grep -v '^#' mutanten_lauf_kopie.sh) && echo nur-kommentar
|
||||
```
|
||||
|
||||
Erwartet: `0`, `0`, `nur-kommentar`.
|
||||
|
||||
In der PowerShell:
|
||||
|
||||
```powershell
|
||||
# Syntax des Skripts in WSL
|
||||
wsl -d Debian -- bash -n /mnt/d/Claude/.vault-tools/plan-kopie/mutanten_lauf_kopie.sh
|
||||
"exit=$LASTEXITCODE"
|
||||
```
|
||||
|
||||
Erwartet: nur `exit=0`.
|
||||
|
||||
## Schritt 3 — Verifikation: Treiber gegen das Skript
|
||||
|
||||
```powershell
|
||||
# Treiber in WSL gegen das Skript nach Nachbesserung 1
|
||||
wsl -d Debian -- timeout 900 /home/claude/venvs/trading/bin/python /mnt/d/Claude/.vault-tools/plan-kopie/mutanten_lauf_kopie_treiber.py *> "C:\Users\PASCAL~1\AppData\Local\Temp\mkopie-rot-n1\ausgabe-neu.txt"
|
||||
"exit=$LASTEXITCODE"
|
||||
Select-String -Path "C:\Users\PASCAL~1\AppData\Local\Temp\mkopie-rot-n1\ausgabe-neu.txt" -Pattern "^W\d.*FEHLER:|^gerechnete|^TREIBER_FEHLER|^rundreise"
|
||||
Select-String -Path "C:\Users\PASCAL~1\AppData\Local\Temp\mkopie-rot-n1\ausgabe-neu.txt" -Pattern "^W1[0-3] ok"
|
||||
```
|
||||
|
||||
Erwartet:
|
||||
|
||||
- `exit=0`.
|
||||
- Aus dem ersten `Select-String` genau zwei Treffer: einer mit `rundreise: /tmp/mkopie_treiber_rundreise_`, einer endet auf `gerechnete Fehler: 0`.
|
||||
- Aus dem zweiten genau vier Treffer, sie enden auf `W10 ok`, `W11 ok`, `W12 ok`, `W13 ok`.
|
||||
|
||||
Sonst anhalten und die ganze Datei `ausgabe-neu.txt` melden. Gerechnet, nicht gemessen ist nur W13; steht dort `W13 FEHLER: neue Kopien=[], exit=0`, hat die Probe ohne `setpriv` keine Fähigkeiten gesehen. Das ist ein Befund für den Koordinator, kein Grund, den Treiber anzupassen.
|
||||
|
||||
## Schritt 4 — Regressionsnachweis: vier Varianten
|
||||
|
||||
### Varianten bauen
|
||||
|
||||
Leg mit dem Write-Werkzeug die Datei `C:\Users\PASCAL~1\AppData\Local\Temp\mkopie-rot-n1\varianten_n1.py` an.
|
||||
|
||||
Inhalt:
|
||||
|
||||
```python
|
||||
# Baut vier kaputte Fassungen von mutanten_lauf_kopie.sh fuer Nachbesserung 1 (v6 bis v9).
|
||||
# Aufruf: python varianten_n1.py <skript> <zielordner>
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
quelle = Path(sys.argv[1])
|
||||
ziel = Path(sys.argv[2])
|
||||
text = quelle.read_bytes().decode("utf-8")
|
||||
if "\r" in text:
|
||||
raise SystemExit("Skript hat CR")
|
||||
|
||||
|
||||
def ersetze(text, aus, wird, anzahl):
|
||||
gefunden = text.count(aus)
|
||||
if gefunden != anzahl:
|
||||
raise SystemExit("{0!r}: {1} Treffer statt {2}".format(aus, gefunden, anzahl))
|
||||
return text.replace(aus, wird)
|
||||
|
||||
|
||||
varianten = {}
|
||||
# v6: Probe meldet, das Skript laeuft weiter; Zeile exit 2 nach der Meldung gestrichen (erwartet rot: W10, W11, W13)
|
||||
zeilen = text.split("\n")
|
||||
treffer = [i for i, z in enumerate(zeilen)
|
||||
if z.lstrip().startswith("echo \"MUTANTEN_LAUF_FEHLER: lo im Netz-Namensraum nicht nutzbar")]
|
||||
if len(treffer) != 1 or zeilen[treffer[0] + 1].strip() != "exit 2":
|
||||
raise SystemExit("Meldung der Probe mit exit 2 nicht eindeutig gefunden")
|
||||
k = treffer[0]
|
||||
varianten["v6_probe_ohne_exit"] = "\n".join(zeilen[:k + 1] + zeilen[k + 2:])
|
||||
# v7: Probe ohne setpriv (erwartet rot: W1 bis W9, W12)
|
||||
varianten["v7_probe_ohne_setpriv"] = ersetze(
|
||||
text, "exec setpriv --inh-caps=-all --ambient-caps=-all -- python3 -c ", "exec python3 -c ", 1)
|
||||
# v8: Hauptaufruf ohne den Zweig nach || (erwartet rot: W12)
|
||||
varianten["v8_haupt_ohne_oder"] = ersetze(
|
||||
text, " || { echo \"MUTANTEN_LAUF_FEHLER: lo im Netz-Namensraum nicht hochgefahren\"; exit 2; }", "", 1)
|
||||
# v9: Probe ohne Faehigkeitspruefung (erwartet rot: W13)
|
||||
varianten["v9_probe_ohne_faehigkeiten"] = ersetze(
|
||||
text, "if int(felder[\"CapEff\"], 16) != 0 or int(felder[\"CapAmb\"], 16) != 0:", "if False:", 1)
|
||||
|
||||
for name, inhalt in varianten.items():
|
||||
if inhalt == text:
|
||||
raise SystemExit(name + " unveraendert")
|
||||
(ziel / (name + ".sh")).write_bytes(inhalt.encode("utf-8"))
|
||||
print(name)
|
||||
```
|
||||
|
||||
In der Git-Bash:
|
||||
|
||||
```bash
|
||||
# Varianten aus dem Skript nach Nachbesserung 1 bauen
|
||||
R=/c/Users/PASCAL~1/AppData/Local/Temp/mkopie-rot-n1
|
||||
python "$R/varianten_n1.py" /d/Claude/.vault-tools/plan-kopie/mutanten_lauf_kopie.sh "$R"
|
||||
```
|
||||
|
||||
Erwartet genau diese vier Zeilen:
|
||||
|
||||
```text
|
||||
v6_probe_ohne_exit
|
||||
v7_probe_ohne_setpriv
|
||||
v8_haupt_ohne_oder
|
||||
v9_probe_ohne_faehigkeiten
|
||||
```
|
||||
|
||||
Endet das Skript mit einer Meldung statt der vier Zeilen: anhalten und melden.
|
||||
|
||||
### Treiber gegen jede Variante
|
||||
|
||||
```powershell
|
||||
# Treiber in WSL gegen jede kaputte Variante
|
||||
foreach ($v in "v6_probe_ohne_exit","v7_probe_ohne_setpriv","v8_haupt_ohne_oder","v9_probe_ohne_faehigkeiten") {
|
||||
wsl -d Debian -- timeout 900 /home/claude/venvs/trading/bin/python /mnt/d/Claude/.vault-tools/plan-kopie/mutanten_lauf_kopie_treiber.py --skript "/mnt/c/Users/PASCAL~1/AppData/Local/Temp/mkopie-rot-n1/$v.sh" *> "C:\Users\PASCAL~1\AppData\Local\Temp\mkopie-rot-n1\ausgabe-$v.txt"
|
||||
"$v exit=$LASTEXITCODE"
|
||||
Select-String -Path "C:\Users\PASCAL~1\AppData\Local\Temp\mkopie-rot-n1\ausgabe-$v.txt" -Pattern "^W\d.*FEHLER:|^gerechnete|^TREIBER_FEHLER"
|
||||
}
|
||||
```
|
||||
|
||||
Erwartet je Variante `exit=1`, und die `FEHLER`-Zeilen betreffen genau diese Fälle. Zeilen wie `W12 (kopie) FEHLER:` oder `W12 (aufraeumen) FEHLER:` zählen zu ihrem Fall:
|
||||
|
||||
| Variante | rote Fälle | gerechnet: Zeilen der neuen Fälle | was es belegt |
|
||||
|---|---|---|---|
|
||||
| `v6_probe_ohne_exit` | W10, W11, W13 | `W10 FEHLER: neue Kopien=[], exit=2`, `W11 FEHLER: neue Kopien=[], exit=0`, `W13 FEHLER: neue Kopien=[], exit=0` | W10, W11 und W13 sehen ein Skript, das nach gescheiterter Probe weiterläuft |
|
||||
| `v7_probe_ohne_setpriv` | W1 bis W9, W12 | `W12 FEHLER: ip-aufrufe=1, neue Kopien=[], exit=2` | die Fähigkeitsprüfung der Probe schlägt an; mit Fähigkeiten läuft kein Mutant |
|
||||
| `v8_haupt_ohne_oder` | W12 | `W12 FEHLER: ip-aufrufe=2, neue Kopien=[], exit=0` | W12 sieht den fehlenden Zweig nach `\|\|` |
|
||||
| `v9_probe_ohne_faehigkeiten` | W13 | `W13 FEHLER: neue Kopien=[], exit=0` | W13 sieht eine Probe ohne Fähigkeitsprüfung |
|
||||
|
||||
- Pflicht ist die Menge der roten Fälle je Variante. Weicht sie ab: anhalten und die ganze Ausgabedatei der Variante melden. Nicht weiter zu Schritt 5.
|
||||
- Gerechnet, nicht gemessen: die Zeilen in der dritten Spalte und die Zahl hinter `gerechnete Fehler:` (3, 10, 1, 1). Weicht nur ein solcher Wert ab, meldest du ihn und machst weiter.
|
||||
|
||||
## Schritt 5 — Doku und Plan
|
||||
|
||||
### `LIESMICH.md`, Stelle 1 von 1
|
||||
|
||||
Aus:
|
||||
|
||||
```markdown
|
||||
- `mutanten_lauf_kopie_treiber.py` ruft das Skript wie die Plankritik mit Windows-Pfaden auf und fährt neun Fälle: Server auf `127.0.0.1` (W1), keine Route nach außen und `ENETUNREACH` (W2), uid wie außen und keine Fähigkeiten (W3), `ip`, `setpriv` oder `python3` fehlen (W4, W5, W9), Zeitgrenze mit `timeout` als Elternprozess des Läufers und ohne Prozessreste (W6), Grundlinie ohne Server in beiden Modi (W7), Dienst des Rechners unerreichbar (W8). Neuer Stand ohne Fehler.
|
||||
- Gegen das Skript vor der Änderung rot: W1, W2, W4, W5, W9. Gegen kaputte Varianten genau an ihrem Fall: ohne `setpriv` W3, `setpriv` ohne `exec` W6, ohne Vorprüfung W4, W5 und W9, ohne `--keep-caps` alle (die Vorprüfung meldet `Operation not permitted`), ohne Namensraum W2 und W8.
|
||||
- Nicht abgeworfen und nicht geprüft: die Begrenzungsmenge (`CapBnd`) und `no_new_privs`. `plankritik.js` führt eine Vorprüfung mit `MUTANTEN_LAUF_FEHLER` wie bisher bei fehlendem `unshare` als `ohne_ergebnis`, ohne den Text der Meldung.
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```markdown
|
||||
- `mutanten_lauf_kopie_treiber.py` ruft das Skript wie die Plankritik mit Windows-Pfaden auf und fährt die Fälle W1 bis W13: Server auf `127.0.0.1` (W1), keine Route nach außen und `ENETUNREACH` (W2), uid wie außen und keine Fähigkeiten (W3), `ip`, `setpriv` oder `python3` fehlen (W4, W5, W9), Zeitgrenze mit `timeout` als Elternprozess des Läufers und ohne Prozessreste (W6), Grundlinie ohne Server in beiden Modi (W7), Dienst des Rechners unerreichbar (W8). Seit Nachbesserung 1 auch: `ip` scheitert in der Probe (W10), `ip` meldet Erfolg und `lo` bleibt aus (W11), `ip` scheitert erst im Hauptaufruf nach der Modus-Zeile (W12), `setpriv` wirft keine Fähigkeit ab (W13). W10 bis W13 ersetzen dazu einzelne Werkzeuge durch kleine `sh`-Skripte. Neuer Stand ohne Fehler.
|
||||
- Gegen das Skript vor der Änderung rot: W1, W2, W4, W5, W9. Gegen kaputte Varianten genau an ihrem Fall, gefahren mit W1 bis W9: ohne `setpriv` W3, `setpriv` ohne `exec` W6, ohne Vorprüfung W4, W5 und W9, ohne `--keep-caps` alle (die Vorprüfung meldet `Operation not permitted`), ohne Namensraum W2 und W8. Gefahren mit W1 bis W13 (Nachbesserung 1, `docs/plans/2026-10-09-mutanten-kopie-loopback-nachbesserung-1.md`): ohne `exit 2` nach der Probe W10, W11 und W13; Probe ohne `setpriv` W1 bis W9 und W12; Hauptaufruf ohne den Zweig nach `||` W12; Probe ohne Fähigkeitsprüfung W13.
|
||||
- Nicht abgeworfen und nicht geprüft: die Begrenzungsmenge (`CapBnd`) und `no_new_privs`. `plankritik.js` führt eine Vorprüfung mit `MUTANTEN_LAUF_FEHLER` wie bisher bei fehlendem `unshare` als `ohne_ergebnis`, ohne den Text der Meldung.
|
||||
- Die Fähigkeiten prüft das Skript nur an der Probe und nur `CapEff` und `CapAmb`, nicht am Läufer selbst. Alle vier Mengen am Läufer prüft Treiber-Fall W3.
|
||||
- Die Vorprüfung steht vor der Suche nach `mutanten.toml`. Fehlt auf einem Rechner `ip`, `setpriv` oder `python3` oder kommt `lo` nicht hoch, endet das Skript deshalb auch für einen Planordner ohne `mutanten.toml` mit `MUTANTEN_LAUF_FEHLER` und Exit 2 statt mit `KEINE_MUTANTEN_TOML`. `plankritik.js` meldet dann `ohne_ergebnis` statt `keine_toml`, und die Linse erfährt nicht, dass die `mutanten.toml` fehlt. Das bleibt so.
|
||||
- Lauf mit echten Daten: die 73 Mutanten des Pakets RB3 (Kopie `rb3d-kopie`) durch das neue Skript, alle `OK`, T1 und T12 im Namensraum.
|
||||
- Ein `pruefer` fand keinen blockierenden Befund. Seine Lücken (kein Fall für den Fehlerzweig der Probe und den Zweig nach `||` im Hauptaufruf, Kopfkommentar zu weit gefasst, der Satz zur Reihenfolge oben) behebt Nachbesserung 1. Rohdaten: `AI/secondbrain/trading-plattform-memory/2026-10-09-mkopie-roh/`.
|
||||
```
|
||||
|
||||
### `mutanten_lauf_ENTWURF.md`, Stelle 1 von 1
|
||||
|
||||
Aus:
|
||||
|
||||
```markdown
|
||||
Treiber: `mutanten_lauf_kopie_treiber.py` (W1 bis W9), Plan `docs/plans/2026-10-09-mutanten-kopie-loopback.md`.
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```markdown
|
||||
Treiber: `mutanten_lauf_kopie_treiber.py` (W1 bis W13), Plan `docs/plans/2026-10-09-mutanten-kopie-loopback.md` und seine Nachbesserung 1. Die Fähigkeiten prüft der Wrapper nur an der Probe (`CapEff`, `CapAmb`), nicht am Läufer. Weil die Vorprüfung vor der Suche nach `mutanten.toml` steht, endet er ohne `ip`, `setpriv`, `python3` oder nutzbares `lo` auch ohne `mutanten.toml` mit Exit 2 statt mit `KEINE_MUTANTEN_TOML`.
|
||||
```
|
||||
|
||||
### `docs/plans/2026-10-09-mutanten-kopie-loopback.md`, Stelle 1 von 3
|
||||
|
||||
Aus:
|
||||
|
||||
```markdown
|
||||
- **Datensatz:** Paket RB3 der Trading Plattform, Kopie `D:/Claude/.arbeitsbaeume/rb3b-kopie`, Planordner `D:/Claude/.arbeitsbaeume/trading-plattform-rb3/docs/plans/2026-10-08-paket-rb3-totmann-ping` (dieselben wie in `rb3_mutanten.sh`). Fehlt die Kopie, vorher neu bauen.
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```markdown
|
||||
- **Datensatz:** Paket RB3 der Trading Plattform, Kopie `D:/Claude/.arbeitsbaeume/rb3d-kopie`, Planordner `D:/Claude/.arbeitsbaeume/trading-plattform-rb3/docs/plans/2026-10-08-paket-rb3-totmann-ping` (dieselben wie in `rb3d_mutanten.sh`). Die Mutanten der `mutanten.toml` passen nur zum Stand in `rb3d-kopie`, nicht zu `rb3b-kopie` aus `rb3_mutanten.sh` (berichtigt in Nachbesserung 1). Fehlt die Kopie, vorher neu bauen.
|
||||
```
|
||||
|
||||
### `docs/plans/2026-10-09-mutanten-kopie-loopback.md`, Stelle 2 von 3
|
||||
|
||||
Aus:
|
||||
|
||||
```powershell
|
||||
wsl -d Debian -- env BUDGET_S=3000 ZEITLIMIT_S=300 timeout 3300 bash /mnt/d/Claude/.vault-tools/plan-kopie/mutanten_lauf_kopie.sh "D:/Claude/.arbeitsbaeume/rb3b-kopie" "D:/Claude/.arbeitsbaeume/trading-plattform-rb3/docs/plans/2026-10-08-paket-rb3-totmann-ping" voll *> "C:\Users\PASCAL~1\AppData\Local\Temp\mkopie-rot\rb3.txt"
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```powershell
|
||||
wsl -d Debian -- env BUDGET_S=3000 ZEITLIMIT_S=300 timeout 3300 bash /mnt/d/Claude/.vault-tools/plan-kopie/mutanten_lauf_kopie.sh "D:/Claude/.arbeitsbaeume/rb3d-kopie" "D:/Claude/.arbeitsbaeume/trading-plattform-rb3/docs/plans/2026-10-08-paket-rb3-totmann-ping" voll *> "C:\Users\PASCAL~1\AppData\Local\Temp\mkopie-rot\rb3.txt"
|
||||
```
|
||||
|
||||
### `docs/plans/2026-10-09-mutanten-kopie-loopback.md`, Stelle 3 von 3
|
||||
|
||||
Aus:
|
||||
|
||||
```markdown
|
||||
Die übrigen Mutanten haben denselben Status wie in Teil A von `rb3_mutanten.sh`.
|
||||
```
|
||||
|
||||
wird:
|
||||
|
||||
```markdown
|
||||
Die übrigen Mutanten haben denselben Status wie in Teil A von `rb3d_mutanten.sh`.
|
||||
```
|
||||
|
||||
## Schritt 6 — Abschlussprüfung
|
||||
|
||||
In der Git-Bash:
|
||||
|
||||
```bash
|
||||
# keine CR in den fuenf Zieldateien, nichts ausserhalb der Zieldateien geaendert
|
||||
cd /d/Claude/.vault-tools/plan-kopie
|
||||
for f in mutanten_lauf_kopie_treiber.py mutanten_lauf_kopie.sh LIESMICH.md mutanten_lauf_ENTWURF.md docs/plans/2026-10-09-mutanten-kopie-loopback.md; do printf '%s %s\n' "$f" "$(tr -cd '\r' < "$f" | wc -c)"; done
|
||||
ls -d __pycache__ 2>/dev/null || echo kein-pycache
|
||||
git -C /d/Claude status --porcelain -- .vault-tools
|
||||
```
|
||||
|
||||
Erwartet: je Datei die Zahl `0`, dann `kein-pycache`, dann dieselben sechs Zeilen wie in Schritt 0.
|
||||
|
||||
Den Rot-Ordner lässt du stehen; der Koordinator legt die Ausgabedateien ab und löscht ihn.
|
||||
|
||||
## Bericht
|
||||
|
||||
Melde:
|
||||
|
||||
- je Zieldatei die Zahl der angewendeten Aus/wird-Paare (Treiber 7, Skript 1, LIESMICH 1, Entwurf 1, Plan 3);
|
||||
- die Ausgaben aus Schritt 0, 1, 2, 3 (alle `Select-String`-Treffer im Wortlaut), 4 (Variantenzeilen und alle `Select-String`-Treffer im Wortlaut) und 6;
|
||||
- jede Abweichung vom Plan, jeden gerechneten Wert, der anders ausfiel, und jede getroffene Annahme. „Keine Abweichungen“ nur, wenn es keine gab.
|
||||
|
||||
## Fertig heißt (Koordinator)
|
||||
|
||||
1. Die fünf Zieldateien sind byte-gleich mit der Kopie, auf die diese Nachbesserung per `plan_materialisiere.py` angewendet wurde (`cmp`); sonst ist unter `.vault-tools/` nichts geändert.
|
||||
2. Treiber in WSL gegen das Skript nach Nachbesserung 1, selbst gefahren: Exit 0, `gerechnete Fehler: 0`, `W10 ok` bis `W13 ok` stehen da.
|
||||
3. Die vier Varianten selbst gesehen: rot genau an ihren Fällen laut Tabelle in Schritt 4. Die Ausgabedateien aus dem Rot-Ordner liegen als Rohdaten neben `pruefer/` unter `AI/secondbrain/trading-plattform-memory/2026-10-09-mkopie-roh/`.
|
||||
4. Schritt 2 hat `nur-kommentar` gezeigt: Das Verhalten des Skripts ist unverändert, der Lauf mit echten Daten vom 2026-10-09 gilt weiter.
|
||||
|
||||
## Lauf mit echten Daten
|
||||
|
||||
Entfällt. Das Skript ändert sich nur im Kommentar, Schritt 2 belegt das mit `grep -v '^#'`. Es gilt der Lauf des Prüfers vom 2026-10-09: 73 Mutanten von RB3 aus `rb3d-kopie`, alle `OK`, T1 und T12 im Namensraum.
|
||||
|
||||
## Risiken
|
||||
|
||||
1. **W13 auf einem Rechner ohne ambiente Fähigkeiten.** Hebt `unshare --keep-caps` die Fähigkeiten nicht in die ambiente Menge, sieht die Probe ohne `setpriv` keine, und W13 ist schon gegen das neue Skript rot. Merkmal: `W13 FEHLER: neue Kopien=[], exit=0` in Schritt 3. Dann wäre auch v7 grün statt rot; Befund für den Koordinator.
|
||||
2. **Zählerdatei in W12.** Die Attrappe schreibt im Namensraum in den Fallordner des Treibers. Gelingt das nicht, zählt `ip` nicht weiter. Merkmal: `ip-aufrufe=` ungleich `2` auf dem neuen Skript.
|
||||
3. **Gleichzeitige Plankritik.** Legt eine Plankritik während des Treiberlaufs `/tmp/plankritik-mut-*` an, meldet der Treiber `(aufraeumen)` für den gerade laufenden Fall.
|
||||
4. **Laufzeit.** Fünf Treiberläufe; v7 wartet in W6 bis zum Ende der Schleife (rund sechs Sekunden). Zusammen gerechnet unter einer Viertelstunde, gemessen nicht.
|
||||
|
||||
## Getroffene Annahmen
|
||||
|
||||
- W13 ließ sich ohne Variante bauen: eine `setpriv`-Attrappe, die nichts abwirft. v7 des Prüfers bleibt trotzdem im Nachweis, wie beauftragt. Weil v7 W13 nicht rot macht (die Probe scheitert dort ebenfalls), kommt v9 dazu: Probe ohne Fähigkeitsprüfung, rot nur an W13.
|
||||
- Für den Zweig nach `||` im Hauptaufruf kommt Variante v8 dazu. Der Auftrag nannte nur v6 und v7; v6 lässt W12 grün, v7 macht W12 nur über die Probe rot.
|
||||
- W10 bis W13 fahren keinen Kontrolllauf wie W4, W5 und W9. Jeder prüft stattdessen ein Merkmal, das nur seine Attrappe oder die Probe erzeugt (Text der Attrappe, `Errno 101`, Zählerstand, `Faehigkeiten nicht abgeworfen`). Dass ein Ordner nur aus Verweisen ein grünes Skript ergibt, zeigt der Kontrolllauf in W4.
|
||||
- „Keine Reste“ in W12 heißt: kein neuer Ordner `/tmp/plankritik-mut-*` und die übergebene Kopie byte-gleich. Prozessreste prüft W6.
|
||||
- Das echte `ip` holt W12 über `shutil.which("ip")` des Treibers statt fest über `/usr/bin/ip` wie der Prüfer.
|
||||
- Kein neuer Lauf gegen das Skript aus HEAD und gegen v1 bis v5: Sie belegen W1 bis W9, und an diesen Fällen ändert sich nichts. LIESMICH sagt deshalb, mit welchen Fällen welche Varianten gefahren sind.
|
||||
- Im Plan ändert sich neben dem Datensatz auch der Verweis auf das Skript mit Teil A (`rb3d_mutanten.sh` statt `rb3_mutanten.sh`), weil `rb3_mutanten.sh` `rb3b-kopie` benutzt. Die Verweise auf `rb3_mutanten.sh` im Anlass des Plans bleiben, sie beschreiben die Geschichte.
|
||||
- Der Satz zu Befund 3 steht in LIESMICH, wie beauftragt, und zusätzlich knapp im Kopfkommentar und im Entwurf, weil beide die Vorprüfung beschreiben.
|
||||
- `modell: haiku`: Alles steht wörtlich da, kein Codeblock trägt typografische Zeichen.
|
||||
|
||||
## Offene Punkte
|
||||
|
||||
- **Gerechnet, nicht gemessen:** W13 grün gegen das neue Skript; die roten Mengen von v7, v8 und v9; bei v6 W11 und W13 rot; alle Zeilen hinter `FEHLER:` und die Zahlen hinter `gerechnete Fehler:` in Schritt 4. Gemessen sind W10 bis W12 als A1, A3 und A4, v6 grün an W1 bis W9 und rot an W10 (A6).
|
||||
- **Ausgabevergleich der Probe ohne Fall.** Endet die Probe mit 0, aber mit anderer Ausgabe als `lo-probe ok`, greift der zweite Teil der Bedingung. Dafür gibt es weder Fall noch Variante; im Docstring des Treibers als Lücke benannt.
|
||||
- **`plankritik.js` verliert die Meldung** weiter (offener Punkt des Plans). Mit Befund 3 trifft das jetzt auch den Hinweis auf eine fehlende `mutanten.toml`.
|
||||
- **Weitere Prüfrunde:** Die Nachbesserung ändert nur Treiber und Text. Ob ein `pruefer` sie noch einmal liest oder Schritt 3 und 4 genügen, entscheidest du.
|
||||
File diff suppressed because it is too large.
Load diff
@@ -5,7 +5,7 @@ title: "Entwurf: mutanten_lauf.py — allgemeiner Mutantenläufer aus der Planta
|
||||
summary: "Entscheidungsliste, Dateiformat mutanten.toml, Ablauf, Status und Exit-Codes, Abdichtung und Angriffsliste für den allgemeinen Mutantenläufer. Punkt 3 der Arbeitsweise vom 2026-09-26."
|
||||
tags: [vault-tools, codeworkflow, pruefwerkzeuge]
|
||||
created: 2026-09-27
|
||||
updated: 2026-10-06
|
||||
updated: 2026-10-09
|
||||
---
|
||||
|
||||
# Entwurf: `mutanten_lauf.py`
|
||||
@@ -163,7 +163,7 @@ Jeder pytest-Aufruf bekommt eine Kopie der Umgebung mit diesen Änderungen:
|
||||
- `http_proxy`, `https_proxy`, `all_proxy` und dieselben in Großschrift zeigen auf `http://127.0.0.1:9`; `no_proxy` und `NO_PROXY` werden entfernt. Bibliotheken, die Proxy-Variablen lesen, laufen damit gegen einen geschlossenen Port.
|
||||
- `PYTHONDONTWRITEBYTECODE=1`, `COLUMNS=300`, `MUTANTEN_LAUF_ERGEBNIS=<temp-datei>`, `PYTHONPATH` mit dem Plugin-Ordner vorn.
|
||||
|
||||
**Netzsperre (seit 2026-09-28, Nachbesserung N1):** Der Wrapper `mutanten_lauf_kopie.sh` startet `mutanten_lauf.py` selbst unter `unshare --map-current-user --net`, nicht erst den einzelnen pytest-Aufruf. Gemessen in WSL Debian als Benutzer `claude` (util-linux 2.41.5): Die UID bleibt innen wie außen 1000, es gibt nur die Schnittstelle `lo`, `connect` auf eine Adresse außerhalb von localhost endet mit `OSError` (errno 101) oder `gaierror`. Nicht `-r` (macht UID 0, könnte Rechte-Tests der Mutanten selbst verfälschen). Fehlt `unshare` ohne Netz, bricht der Wrapper vorher mit `MUTANTEN_LAUF_FEHLER: unshare ohne Netz nicht moeglich` ab, statt einen ungesperrten Lauf durchzulassen.
|
||||
**Netzsperre (seit 2026-09-28, Nachbesserung N1):** Der Wrapper `mutanten_lauf_kopie.sh` startet `mutanten_lauf.py` selbst unter `unshare --map-current-user --net`, nicht erst den einzelnen pytest-Aufruf. Gemessen in WSL Debian als Benutzer `claude` (util-linux 2.41.5): Die UID bleibt innen wie außen 1000, es gibt nur die Schnittstelle `lo`, `connect` auf eine Adresse außerhalb von localhost endet mit `OSError` (errno 101) oder `gaierror`. Nicht `-r` (macht UID 0, könnte Rechte-Tests der Mutanten selbst verfälschen). Fehlt `unshare` ohne Netz, bricht der Wrapper vorher mit `MUTANTEN_LAUF_FEHLER: unshare ohne Netz nicht moeglich` ab, statt einen ungesperrten Lauf durchzulassen. **Seit 2026-10-09 (Paket RB3 der Trading Plattform):** `lo` ist im Namensraum oben. Der Wrapper startet `unshare … --keep-caps`, fährt `lo` mit `ip` hoch und geht über `setpriv` (alle vererbbaren und ambienten Fähigkeiten abgeworfen) per `exec` in den Läufer über. Eine Vorprüfung verlangt `ip`, `setpriv`, `python3`, ein nutzbares `lo` und `CapEff` und `CapAmb` gleich 0, sonst `MUTANTEN_LAUF_FEHLER` und Exit 2. Eine Verbindung auf `127.0.0.1` erreicht damit Dienste im Namensraum, nicht die des Rechners; nach außen bleibt es bei errno 101. Treiber: `mutanten_lauf_kopie_treiber.py` (W1 bis W13), Plan `docs/plans/2026-10-09-mutanten-kopie-loopback.md` und seine Nachbesserung 1. Die Fähigkeiten prüft der Wrapper nur an der Probe (`CapEff`, `CapAmb`), nicht am Läufer. Weil die Vorprüfung vor der Suche nach `mutanten.toml` steht, endet er ohne `ip`, `setpriv`, `python3` oder nutzbares `lo` auch ohne `mutanten.toml` mit Exit 2 statt mit `KEINE_MUTANTEN_TOML`.
|
||||
|
||||
**Was das nicht abdichtet:** einen Unterprozess mit absolutem Pfad (so kam der Vorfall vom 2026-09-26 zustande), einen Socket ohne Proxy, einen Client mit `trust_env=False` oder mit eigenem Transport, Dateien mit absolutem Pfad außerhalb von `HOME`. Die eigentliche Sperre bleibt die Netzsperre der Testdateien selbst und eine Kopie ohne Geheimnisdateien (`ohne`).
|
||||
|
||||
|
||||
@@ -27,6 +27,31 @@
|
||||
# mutanten_lauf.py nach dem SIGTERM nicht rechtzeitig endet; sein eigener SIGTERM-Handler setzt
|
||||
# die Zieldatei vorher zurueck und raeumt seine Temp-Ordner auf.
|
||||
# - chmod 700 auf die Kopie der Kopie direkt nach dem Kopieren.
|
||||
#
|
||||
# Nachbesserung 2026-10-09 (Paket RB3 der Trading Plattform, Plan
|
||||
# docs/plans/2026-10-09-mutanten-kopie-loopback.md):
|
||||
# - lo im Netz-Namensraum: Im frischen Namensraum war lo aus; jeder Test mit einem Server auf
|
||||
# 127.0.0.1 scheiterte mit Errno 101, auch ohne Mutant. Jetzt startet unshare zusaetzlich mit
|
||||
# --keep-caps, eine sh faehrt lo mit ip hoch, und setpriv wirft danach alle vererbbaren und
|
||||
# ambienten Faehigkeiten ab und geht per exec in python3 ueber. Gemessen vom Koordinator am
|
||||
# 2026-10-09 in WSL Debian als Benutzer claude: uid 1000 wie aussen, CapEff und CapAmb 0,
|
||||
# Verbindung ueber 127.0.0.1 gelingt. 127.0.0.1 ist das lo des Namensraums, nicht das des
|
||||
# Rechners; ein Dienst des Rechners auf 127.0.0.1 bleibt unerreichbar (Treiber-Fall W8).
|
||||
# - exec-Kette: unshare, sh, setpriv und python3 sind derselbe Prozess, das SIGTERM von timeout
|
||||
# trifft den Laeufer selbst; keine Zwischenschale bleibt stehen (Treiber-Fall W6).
|
||||
# - Vorpruefung vor dem Kopieren: Fehlt ip, setpriv oder python3, kommt lo in einer Probe im
|
||||
# eigenen Namensraum nicht hoch, gelingt dort keine Verbindung ueber 127.0.0.1 oder hat die
|
||||
# Probe nach setpriv noch CapEff oder CapAmb ungleich 0, endet das Skript mit
|
||||
# MUTANTEN_LAUF_FEHLER und Exit 2, ohne EXIT-Zeile. Die Faehigkeiten prueft das Skript nur an
|
||||
# dieser Probe und nur CapEff und CapAmb, nicht am Laeufer selbst; alle vier Mengen am Laeufer
|
||||
# prueft Treiber-Fall W3. Die Vorpruefung steht vor der Suche nach mutanten.toml: Scheitert
|
||||
# sie, endet das Skript auch fuer einen Planordner ohne mutanten.toml mit Exit 2 statt mit
|
||||
# KEINE_MUTANTEN_TOML.
|
||||
# - Hauptaufruf: Kommt lo dort nicht hoch, endet das Skript nach der Modus-Zeile mit
|
||||
# MUTANTEN_LAUF_FEHLER, Exit 2 und EXIT-Zeile, ohne den Laeufer zu starten. Ein Lauf ohne
|
||||
# Netzsperre oder ohne lo ist nie die Ausweichloesung.
|
||||
# - Treiber: mutanten_lauf_kopie_treiber.py, Faelle W1 bis W13 (W10 bis W13 seit Nachbesserung 1,
|
||||
# docs/plans/2026-10-09-mutanten-kopie-loopback-nachbesserung-1.md).
|
||||
set -u
|
||||
|
||||
KOPIE_WIN="${1:-}"
|
||||
@@ -55,6 +80,37 @@ if ! unshare --map-current-user --net true 2>/dev/null; then
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Vorpruefung lo (seit 2026-10-09): Werkzeuge da, lo kommt im eigenen Namensraum hoch, eine
|
||||
# Verbindung ueber 127.0.0.1 gelingt, und nach setpriv sind CapEff und CapAmb 0. Scheitert
|
||||
# etwas davon, endet das Skript hier, vor dem Kopieren.
|
||||
for WERKZEUG in ip setpriv python3; do
|
||||
if ! command -v "$WERKZEUG" >/dev/null 2>&1; then
|
||||
echo "MUTANTEN_LAUF_FEHLER: $WERKZEUG fehlt (gebraucht fuer lo im Netz-Namensraum)"
|
||||
exit 2
|
||||
fi
|
||||
done
|
||||
LO_PROBE='import socket
|
||||
server = socket.socket()
|
||||
server.bind(("127.0.0.1", 0))
|
||||
server.listen(1)
|
||||
client = socket.create_connection(server.getsockname(), timeout=3)
|
||||
client.close()
|
||||
server.close()
|
||||
felder = {}
|
||||
for zeile in open("/proc/self/status", encoding="utf-8", errors="replace"):
|
||||
schluessel, _, wert = zeile.partition(":")
|
||||
felder[schluessel] = wert.strip()
|
||||
if int(felder["CapEff"], 16) != 0 or int(felder["CapAmb"], 16) != 0:
|
||||
raise SystemExit("Faehigkeiten nicht abgeworfen: CapEff " + felder["CapEff"] + ", CapAmb " + felder["CapAmb"])
|
||||
print("lo-probe ok")'
|
||||
LO_AUSGABE=$(timeout 30 unshare --map-current-user --net --keep-caps \
|
||||
sh -c 'ip link set lo up && exec setpriv --inh-caps=-all --ambient-caps=-all -- python3 -c "$1"' sh "$LO_PROBE" 2>&1)
|
||||
LO_EXIT=$?
|
||||
if [ "$LO_EXIT" -ne 0 ] || [ "$LO_AUSGABE" != "lo-probe ok" ]; then
|
||||
echo "MUTANTEN_LAUF_FEHLER: lo im Netz-Namensraum nicht nutzbar (Exit $LO_EXIT): $LO_AUSGABE"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
KOPIE=$(wslpath -u "$KOPIE_WIN")
|
||||
PLANORDNER=$(wslpath -u "$PLANORDNER_WIN")
|
||||
|
||||
@@ -88,7 +144,10 @@ else
|
||||
echo "modus: voll"
|
||||
fi
|
||||
|
||||
timeout -k 15 "$BUDGET_S" unshare --map-current-user --net \
|
||||
# exec-Kette ohne Zwischenschale (seit 2026-10-09): unshare, sh, setpriv und python3 sind derselbe
|
||||
# Prozess, das SIGTERM von timeout trifft den Laeufer selbst (Treiber-Fall W6).
|
||||
timeout -k 15 "$BUDGET_S" unshare --map-current-user --net --keep-caps \
|
||||
sh -c 'ip link set lo up || { echo "MUTANTEN_LAUF_FEHLER: lo im Netz-Namensraum nicht hochgefahren"; exit 2; }; exec setpriv --inh-caps=-all --ambient-caps=-all -- "$@"' sh \
|
||||
python3 -u /mnt/d/Claude/.vault-tools/plan-kopie/mutanten_lauf.py \
|
||||
--wurzel "$TMPKOPIE" --mutanten "$MUTANTEN_TOML" --zeitlimit "$ZEITLIMIT_S" $MUSTER_SCHALTER
|
||||
EXITCODE=$?
|
||||
|
||||
@@ -0,0 +1,718 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Treiber fuer mutanten_lauf_kopie.sh: Faelle W1 bis W13 (lo im Netz-Namensraum).
|
||||
|
||||
Zweck: Baut je Fall unter /tmp ein kleines Projekt (kopie/) und einen
|
||||
Planordner (plan/) mit mutanten.toml, ruft mutanten_lauf_kopie.sh mit beiden
|
||||
Ordnern als Windows-Pfaden auf, wie plankritik.js es tut, und vergleicht
|
||||
Exit-Code und Ausgabezeilen mit der Erwartung aus dem Plan
|
||||
docs/plans/2026-10-09-mutanten-kopie-loopback.md. Jeder Fall raeumt seine
|
||||
Ordner selbst auf. Nach jedem Fall prueft der Treiber, dass die uebergebene
|
||||
Kopie byte-gleich ist und kein Ordner /tmp/plankritik-mut-* liegen blieb.
|
||||
|
||||
Aufruf (in WSL): python mutanten_lauf_kopie_treiber.py [--skript <pfad>]
|
||||
Ohne --skript faehrt er mutanten_lauf_kopie.sh neben sich, mit --skript eine
|
||||
andere Fassung (Regressionsnachweis: Stand aus git show HEAD, kaputte
|
||||
Varianten). W7 ist die Grundlinie und laeuft zuerst; ist sie rot, messen die
|
||||
anderen Faelle wenig.
|
||||
|
||||
Pfade: Das Skript wandelt seine Argumente mit wslpath -u um. Der Treiber gibt
|
||||
ihm deshalb wslpath -w seiner /tmp-Ordner und prueft vor dem ersten Fall,
|
||||
dass die Rundreise denselben Pfad ergibt.
|
||||
|
||||
Netz: Die Tests verbinden sich nur mit 127.0.0.1 und, nur im Netz-Namensraum
|
||||
des Skripts, mit 192.0.2.1 (TEST-NET-1). Der Test dazu prueft zuerst, dass es
|
||||
keine Route ausser ueber lo gibt; ohne Namensraum scheitert er dort, bevor er
|
||||
eine Verbindung versucht.
|
||||
|
||||
Faelle W10 bis W13 (Nachbesserung 1, Plan
|
||||
docs/plans/2026-10-09-mutanten-kopie-loopback-nachbesserung-1.md) ersetzen im
|
||||
Attrappen-Ordner einzelne Werkzeuge durch kleine sh-Skripte, nach den
|
||||
Angriffen A1, A3 und A4 des Pruefers vom 2026-10-09: ip scheitert in der
|
||||
Probe (W10), ip meldet Erfolg und lo bleibt aus (W11), ip scheitert erst im
|
||||
Hauptaufruf (W12), setpriv wirft keine Faehigkeit ab (W13).
|
||||
|
||||
Nicht im Treiber: ob plankritik.js das Skript so aufruft wie hier
|
||||
(MSYS_NO_PATHCONV, cygpath -m -l); ob die Probe bei Exit 0 mit falscher
|
||||
Ausgabe scheitert.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import os
|
||||
import shlex
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
|
||||
HIER = Path(__file__).resolve().parent
|
||||
SKRIPT_STANDARD = HIER / "mutanten_lauf_kopie.sh"
|
||||
INTERPRETER = "/home/claude/venvs/trading/bin/python"
|
||||
BASH = shutil.which("bash")
|
||||
# Was mutanten_lauf_kopie.sh ueber PATH aufruft (Stand 2026-10-09); daraus
|
||||
# bauen W4, W5, W9 und W10 bis W13 ihre Attrappen-Ordner.
|
||||
WERKZEUGE = (
|
||||
"unshare", "wslpath", "mktemp", "cp", "chmod", "find", "rm", "timeout",
|
||||
"sh", "true", "ip", "setpriv", "python3",
|
||||
)
|
||||
|
||||
FEHLERLISTE = []
|
||||
|
||||
|
||||
def melde(fallname, ok, zusatz=""):
|
||||
if ok:
|
||||
print("{0} ok".format(fallname))
|
||||
else:
|
||||
print("{0} FEHLER: {1}".format(fallname, zusatz))
|
||||
FEHLERLISTE.append(fallname)
|
||||
|
||||
|
||||
def kurz(ergebnis):
|
||||
return "exit={0}\n{1}{2}".format(ergebnis.returncode, ergebnis.stdout, ergebnis.stderr)
|
||||
|
||||
|
||||
def sha_von(pfad):
|
||||
return hashlib.sha256(pfad.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def plankritik_ordner():
|
||||
return set(Path("/tmp").glob("plankritik-mut-*"))
|
||||
|
||||
|
||||
def windows_pfad(pfad):
|
||||
ergebnis = subprocess.run(["wslpath", "-w", str(pfad)], capture_output=True, text=True, timeout=30)
|
||||
return ergebnis.stdout.strip()
|
||||
|
||||
|
||||
def linux_pfad(pfad):
|
||||
ergebnis = subprocess.run(["wslpath", "-u", pfad], capture_output=True, text=True, timeout=30)
|
||||
return ergebnis.stdout.strip()
|
||||
|
||||
|
||||
# --- Projektbausteine -------------------------------------------------------
|
||||
|
||||
GRUNDDATEIEN = {
|
||||
"pytest.ini": "[pytest]\n",
|
||||
"paket/__init__.py": "",
|
||||
"tests/__init__.py": "",
|
||||
}
|
||||
|
||||
MODUL = (
|
||||
"def f1(x):\n"
|
||||
" if x > 0:\n"
|
||||
" return True\n"
|
||||
" return False\n"
|
||||
)
|
||||
|
||||
TEST_MODUL = (
|
||||
"from paket.modul import f1\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_f1_positiv():\n"
|
||||
" assert f1(5) is True\n"
|
||||
)
|
||||
|
||||
DIENST = (
|
||||
"import socket\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def antwort_ueber_lo(nachricht):\n"
|
||||
" server = socket.socket()\n"
|
||||
" server.bind((\"127.0.0.1\", 0))\n"
|
||||
" server.listen(1)\n"
|
||||
" client = socket.create_connection(server.getsockname(), timeout=5)\n"
|
||||
" verbindung, _ = server.accept()\n"
|
||||
" client.sendall(nachricht)\n"
|
||||
" daten = verbindung.recv(1024)\n"
|
||||
" for sock in (client, verbindung, server):\n"
|
||||
" sock.close()\n"
|
||||
" return daten\n"
|
||||
)
|
||||
|
||||
TEST_DIENST = (
|
||||
"from paket.dienst import antwort_ueber_lo\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_echo_ueber_lo():\n"
|
||||
" assert antwort_ueber_lo(b\"hallo\") == b\"hallo\"\n"
|
||||
)
|
||||
|
||||
NETZ = (
|
||||
"AUSSEN = (\"192.0.2.1\", 9)\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def aussen_adresse():\n"
|
||||
" return AUSSEN\n"
|
||||
)
|
||||
|
||||
TEST_NETZ = (
|
||||
"import errno\n"
|
||||
"import socket\n"
|
||||
"\n"
|
||||
"import pytest\n"
|
||||
"\n"
|
||||
"from paket.netz import aussen_adresse\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_keine_route_nach_aussen():\n"
|
||||
" with open(\"/proc/net/route\", encoding=\"ascii\") as datei:\n"
|
||||
" zeilen = datei.read().splitlines()[1:]\n"
|
||||
" schnittstellen = [zeile.split()[0] for zeile in zeilen if zeile.strip()]\n"
|
||||
" assert all(name == \"lo\" for name in schnittstellen), \"Routen ausser lo: {0}\".format(schnittstellen)\n"
|
||||
" sock = socket.socket()\n"
|
||||
" sock.settimeout(5)\n"
|
||||
" try:\n"
|
||||
" sock.connect(aussen_adresse())\n"
|
||||
" except OSError as exc:\n"
|
||||
" assert exc.errno == errno.ENETUNREACH, \"erwartet ENETUNREACH: {0!r}\".format(exc)\n"
|
||||
" else:\n"
|
||||
" pytest.fail(\"Verbindung nach aussen gelungen\")\n"
|
||||
" finally:\n"
|
||||
" sock.close()\n"
|
||||
)
|
||||
|
||||
RECHTE = (
|
||||
"def status_feld(name):\n"
|
||||
" with open(\"/proc/self/status\", encoding=\"utf-8\", errors=\"replace\") as datei:\n"
|
||||
" for zeile in datei:\n"
|
||||
" schluessel, _, wert = zeile.partition(\":\")\n"
|
||||
" if schluessel == name:\n"
|
||||
" return wert.strip()\n"
|
||||
" raise KeyError(name)\n"
|
||||
)
|
||||
|
||||
HAENGEN = (
|
||||
"def schritt_a(n):\n"
|
||||
" return n + 1\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def schritt_b(n):\n"
|
||||
" return n + 2\n"
|
||||
)
|
||||
|
||||
TEST_HAENGEN = (
|
||||
"from paket.haengen import schritt_a, schritt_b\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_schritt_a():\n"
|
||||
" assert schritt_a(1) == 2\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_schritt_b():\n"
|
||||
" assert schritt_b(1) == 3\n"
|
||||
)
|
||||
|
||||
SCHLEIFE = " while True:\n pass\n"
|
||||
|
||||
PRUEFZEILE_AUSSEN = " assert info.value.errno in (errno.ECONNREFUSED, errno.ENETUNREACH), repr(info.value)\n"
|
||||
|
||||
|
||||
def text_test_rechte(uid):
|
||||
return (
|
||||
"from paket.rechte import status_feld\n"
|
||||
"\n"
|
||||
"UID_AUSSEN = \"" + str(uid) + "\"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_keine_faehigkeiten_gleiche_uid():\n"
|
||||
" for feld in (\"CapInh\", \"CapPrm\", \"CapEff\", \"CapAmb\"):\n"
|
||||
" wert = status_feld(feld)\n"
|
||||
" assert int(wert, 16) == 0, \"{0} ist {1}\".format(feld, wert)\n"
|
||||
" assert status_feld(\"Uid\").split()[0] == UID_AUSSEN\n"
|
||||
)
|
||||
|
||||
|
||||
def text_test_aussen(port):
|
||||
return (
|
||||
"import errno\n"
|
||||
"import socket\n"
|
||||
"\n"
|
||||
"import pytest\n"
|
||||
"\n"
|
||||
"PORT_AUSSEN = " + str(port) + "\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_dienst_des_rechners_unerreichbar():\n"
|
||||
" sock = socket.socket()\n"
|
||||
" sock.settimeout(5)\n"
|
||||
" try:\n"
|
||||
" with pytest.raises(OSError) as info:\n"
|
||||
" sock.connect((\"127.0.0.1\", PORT_AUSSEN))\n"
|
||||
" finally:\n"
|
||||
" sock.close()\n"
|
||||
+ PRUEFZEILE_AUSSEN
|
||||
)
|
||||
|
||||
|
||||
def kopf():
|
||||
return "format = 1\npython = \"{0}\"\n\n".format(INTERPRETER)
|
||||
|
||||
|
||||
def mutant(id_, datei, aus, wird, rot_bei):
|
||||
return (
|
||||
"[[mutant]]\n"
|
||||
"id = \"" + id_ + "\"\n"
|
||||
"datei = \"" + datei + "\"\n"
|
||||
"aus = '''\n" + aus + "'''\n"
|
||||
"wird = '''\n" + wird + "'''\n"
|
||||
"rot_bei = [\"" + rot_bei + "\"]\n"
|
||||
"\n"
|
||||
)
|
||||
|
||||
|
||||
class Fall:
|
||||
"""Ein Fall unter /tmp: kopie/ mit den Projektdateien, plan/ mit mutanten.toml."""
|
||||
|
||||
def __init__(self, dateien, mutanten):
|
||||
self.basis = Path(tempfile.mkdtemp(prefix="mkopie_treiber_"))
|
||||
self.kopie = self.basis / "kopie"
|
||||
self.plan = self.basis / "plan"
|
||||
self.plan.mkdir()
|
||||
alle = dict(GRUNDDATEIEN)
|
||||
alle.update(dateien)
|
||||
self.snap = {}
|
||||
for relpfad, inhalt in alle.items():
|
||||
pfad = self.kopie / relpfad
|
||||
pfad.parent.mkdir(parents=True, exist_ok=True)
|
||||
pfad.write_text(inhalt, encoding="utf-8")
|
||||
self.snap[pfad] = sha_von(pfad)
|
||||
(self.plan / "mutanten.toml").write_text(kopf() + mutanten, encoding="utf-8")
|
||||
|
||||
def pruefe_kopie(self, fallname):
|
||||
for pfad, sha in self.snap.items():
|
||||
if not pfad.exists() or sha_von(pfad) != sha:
|
||||
melde(fallname + " (kopie)", False, "uebergebene Kopie veraendert: {0}".format(pfad))
|
||||
return
|
||||
|
||||
def aufraeumen(self):
|
||||
shutil.rmtree(self.basis, ignore_errors=True)
|
||||
|
||||
|
||||
def starte_skript(skript, fall, modus="voll", pfad=None):
|
||||
env = dict(os.environ)
|
||||
if pfad is not None:
|
||||
env["PATH"] = pfad
|
||||
cmd = [BASH, str(skript), windows_pfad(fall.kopie), windows_pfad(fall.plan), modus]
|
||||
return subprocess.run(cmd, capture_output=True, text=True, env=env, timeout=180)
|
||||
|
||||
|
||||
# --- Faelle ----------------------------------------------------------------
|
||||
|
||||
def fahre_einfach(name, skript, dateien, mutanten, mutant_id):
|
||||
fall = Fall(dateien, mutanten)
|
||||
try:
|
||||
ergebnis = starte_skript(skript, fall)
|
||||
ok = (
|
||||
ergebnis.returncode == 0
|
||||
and "{0} OK".format(mutant_id) in ergebnis.stdout
|
||||
and "EXIT mutanten_lauf: 0" in ergebnis.stdout
|
||||
)
|
||||
melde(name, ok, kurz(ergebnis))
|
||||
fall.pruefe_kopie(name)
|
||||
finally:
|
||||
fall.aufraeumen()
|
||||
|
||||
|
||||
def fall_einfach():
|
||||
return Fall(
|
||||
{"paket/modul.py": MODUL, "tests/test_modul.py": TEST_MODUL},
|
||||
mutant("MW7", "paket/modul.py", " return True\n", " return False\n",
|
||||
"tests/test_modul.py::test_f1_positiv"),
|
||||
)
|
||||
|
||||
|
||||
def fall_w7(skript):
|
||||
# Grundlinie wie bisher: kein Server-Test, Modus voll und muster.
|
||||
fall = fall_einfach()
|
||||
try:
|
||||
voll = starte_skript(skript, fall)
|
||||
muster = starte_skript(skript, fall, modus="muster")
|
||||
ok = (
|
||||
voll.returncode == 0
|
||||
and "modus: voll" in voll.stdout
|
||||
and "MW7 OK" in voll.stdout
|
||||
and "EXIT mutanten_lauf: 0" in voll.stdout
|
||||
and muster.returncode == 0
|
||||
and "modus: muster" in muster.stdout
|
||||
and "EXIT mutanten_lauf: 0" in muster.stdout
|
||||
)
|
||||
melde("W7", ok, "voll " + kurz(voll) + "\nmuster " + kurz(muster))
|
||||
fall.pruefe_kopie("W7")
|
||||
finally:
|
||||
fall.aufraeumen()
|
||||
|
||||
|
||||
def fall_w1(skript):
|
||||
# Ein Test startet einen Server auf 127.0.0.1 und tauscht Daten aus.
|
||||
fahre_einfach(
|
||||
"W1", skript,
|
||||
{"paket/dienst.py": DIENST, "tests/test_dienst.py": TEST_DIENST},
|
||||
mutant("MW1", "paket/dienst.py", " return daten\n", " return daten[::-1]\n",
|
||||
"tests/test_dienst.py::test_echo_ueber_lo"),
|
||||
"MW1",
|
||||
)
|
||||
|
||||
|
||||
def fall_w2(skript):
|
||||
# Verbindung nach aussen scheitert mit ENETUNREACH; der Mutant zielt auf
|
||||
# 127.0.0.1:9 und faellt nur, wenn lo oben ist (ECONNREFUSED).
|
||||
fahre_einfach(
|
||||
"W2", skript,
|
||||
{"paket/netz.py": NETZ, "tests/test_netz.py": TEST_NETZ},
|
||||
mutant("MW2", "paket/netz.py", "AUSSEN = (\"192.0.2.1\", 9)\n", "AUSSEN = (\"127.0.0.1\", 9)\n",
|
||||
"tests/test_netz.py::test_keine_route_nach_aussen"),
|
||||
"MW2",
|
||||
)
|
||||
|
||||
|
||||
def fall_w3(skript):
|
||||
# CapInh, CapPrm, CapEff, CapAmb gleich 0 und dieselbe uid wie aussen.
|
||||
fahre_einfach(
|
||||
"W3", skript,
|
||||
{"paket/rechte.py": RECHTE, "tests/test_rechte.py": text_test_rechte(os.getuid())},
|
||||
mutant("MW3", "paket/rechte.py", " return wert.strip()\n", " return \"1\"\n",
|
||||
"tests/test_rechte.py::test_keine_faehigkeiten_gleiche_uid"),
|
||||
"MW3",
|
||||
)
|
||||
|
||||
|
||||
def baue_attrappen(ordner, ohne):
|
||||
ordner.mkdir()
|
||||
for name in WERKZEUGE:
|
||||
if name != ohne:
|
||||
os.symlink(shutil.which(name), ordner / name)
|
||||
|
||||
|
||||
def fahre_ohne_werkzeug(name, skript, werkzeug):
|
||||
# Erst ein Kontrolllauf mit allen Attrappen (muss gruen sein), dann einer
|
||||
# ohne das eine Werkzeug (muss vor dem Kopieren mit Exit 2 enden).
|
||||
fall = fall_einfach()
|
||||
try:
|
||||
alle = fall.basis / "attrappen_alle"
|
||||
ohne = fall.basis / "attrappen_ohne"
|
||||
baue_attrappen(alle, None)
|
||||
baue_attrappen(ohne, werkzeug)
|
||||
kontrolle = starte_skript(skript, fall, pfad=str(alle))
|
||||
vorher = plankritik_ordner()
|
||||
ergebnis = starte_skript(skript, fall, pfad=str(ohne))
|
||||
neu = sorted(str(p) for p in plankritik_ordner() - vorher)
|
||||
ok = (
|
||||
kontrolle.returncode == 0
|
||||
and "MW7 OK" in kontrolle.stdout
|
||||
and ergebnis.returncode == 2
|
||||
and "MUTANTEN_LAUF_FEHLER: {0} fehlt".format(werkzeug) in ergebnis.stdout
|
||||
and "modus:" not in ergebnis.stdout
|
||||
and "EXIT mutanten_lauf" not in ergebnis.stdout
|
||||
and not neu
|
||||
)
|
||||
melde(name, ok, "kontrolle exit={0}, ohne {1} exit={2}, neue Kopien={3}\nkontrolle {4}\nohne {1} {5}".format(
|
||||
kontrolle.returncode, werkzeug, ergebnis.returncode, neu, kurz(kontrolle), kurz(ergebnis)))
|
||||
fall.pruefe_kopie(name)
|
||||
finally:
|
||||
fall.aufraeumen()
|
||||
|
||||
|
||||
def fall_w4(skript):
|
||||
fahre_ohne_werkzeug("W4", skript, "ip")
|
||||
|
||||
|
||||
def fall_w5(skript):
|
||||
fahre_ohne_werkzeug("W5", skript, "setpriv")
|
||||
|
||||
|
||||
def fall_w9(skript):
|
||||
fahre_ohne_werkzeug("W9", skript, "python3")
|
||||
|
||||
|
||||
def baue_attrappen_mit_ersatz(ordner, ersatz):
|
||||
# Wie baue_attrappen, aber jedes Werkzeug aus ersatz ist ein kleines
|
||||
# sh-Skript statt eines Verweises auf das echte Werkzeug (Bauweise aus den
|
||||
# Angriffen des Pruefers vom 2026-10-09).
|
||||
ordner.mkdir()
|
||||
for name in WERKZEUGE:
|
||||
pfad = ordner / name
|
||||
if name in ersatz:
|
||||
pfad.write_text("#!/bin/sh\n" + ersatz[name] + "\n", encoding="utf-8")
|
||||
pfad.chmod(0o755)
|
||||
else:
|
||||
os.symlink(shutil.which(name), pfad)
|
||||
|
||||
|
||||
def fahre_probe_scheitert(name, skript, ersatz, merkmal):
|
||||
# Die Vorpruefung muss scheitern: Exit 2 mit der Meldung der Probe und dem
|
||||
# Merkmal des Angriffs, ohne Modus-Zeile, ohne EXIT-Zeile, ohne Kopie.
|
||||
fall = fall_einfach()
|
||||
try:
|
||||
ordner = fall.basis / "attrappen"
|
||||
baue_attrappen_mit_ersatz(ordner, ersatz)
|
||||
vorher = plankritik_ordner()
|
||||
ergebnis = starte_skript(skript, fall, pfad=str(ordner))
|
||||
neu = sorted(str(p) for p in plankritik_ordner() - vorher)
|
||||
ok = (
|
||||
ergebnis.returncode == 2
|
||||
and "MUTANTEN_LAUF_FEHLER: lo im Netz-Namensraum nicht nutzbar" in ergebnis.stdout
|
||||
and merkmal in ergebnis.stdout
|
||||
and "modus:" not in ergebnis.stdout
|
||||
and "EXIT mutanten_lauf" not in ergebnis.stdout
|
||||
and not neu
|
||||
)
|
||||
melde(name, ok, "neue Kopien={0}, {1}".format(neu, kurz(ergebnis)))
|
||||
fall.pruefe_kopie(name)
|
||||
finally:
|
||||
fall.aufraeumen()
|
||||
|
||||
|
||||
def fall_w10(skript):
|
||||
# ip scheitert schon in der Probe (Angriff A1 des Pruefers).
|
||||
fahre_probe_scheitert("W10", skript, {"ip": "echo ip-attrappe scheitert >&2; exit 1"}, "ip-attrappe scheitert")
|
||||
|
||||
|
||||
def fall_w11(skript):
|
||||
# ip meldet Erfolg, lo bleibt aus (A3): Die Verbindung der Probe scheitert
|
||||
# mit Errno 101.
|
||||
fahre_probe_scheitert("W11", skript, {"ip": "exit 0"}, "Errno 101")
|
||||
|
||||
|
||||
def fall_w12(skript):
|
||||
# ip klappt in der Probe und scheitert erst im Hauptaufruf (A4); eine
|
||||
# Zaehlerdatei haelt fest, der wievielte Aufruf es ist. Erwartet:
|
||||
# Modus-Zeile, Meldung des Hauptaufrufs, EXIT-Zeile mit 2, kein Laeufer,
|
||||
# genau zwei Aufrufe von ip, keine Kopie unter /tmp.
|
||||
fall = fall_einfach()
|
||||
try:
|
||||
zaehler = fall.basis / "ip_zaehler"
|
||||
z = shlex.quote(str(zaehler))
|
||||
ip_echt = shlex.quote(shutil.which("ip"))
|
||||
ersatz = {"ip": (
|
||||
"n=0\n"
|
||||
"if [ -f " + z + " ]; then read n < " + z + "; fi\n"
|
||||
"n=$((n + 1))\n"
|
||||
"echo \"$n\" > " + z + "\n"
|
||||
"if [ \"$n\" -ge 2 ]; then echo \"ip-attrappe zweiter Aufruf\" >&2; exit 1; fi\n"
|
||||
"exec " + ip_echt + " \"$@\""
|
||||
)}
|
||||
ordner = fall.basis / "attrappen"
|
||||
baue_attrappen_mit_ersatz(ordner, ersatz)
|
||||
vorher = plankritik_ordner()
|
||||
ergebnis = starte_skript(skript, fall, pfad=str(ordner))
|
||||
neu = sorted(str(p) for p in plankritik_ordner() - vorher)
|
||||
try:
|
||||
aufrufe = zaehler.read_text(encoding="ascii").strip()
|
||||
except OSError:
|
||||
aufrufe = "keine"
|
||||
ok = (
|
||||
ergebnis.returncode == 2
|
||||
and "modus: voll" in ergebnis.stdout
|
||||
and "MUTANTEN_LAUF_FEHLER: lo im Netz-Namensraum nicht hochgefahren" in ergebnis.stdout
|
||||
and "EXIT mutanten_lauf: 2" in ergebnis.stdout
|
||||
and "nicht nutzbar" not in ergebnis.stdout
|
||||
and "MW7" not in ergebnis.stdout
|
||||
and "ip-attrappe zweiter Aufruf" in ergebnis.stderr
|
||||
and aufrufe == "2"
|
||||
and not neu
|
||||
)
|
||||
melde("W12", ok, "ip-aufrufe={0}, neue Kopien={1}, {2}".format(aufrufe, neu, kurz(ergebnis)))
|
||||
fall.pruefe_kopie("W12")
|
||||
finally:
|
||||
fall.aufraeumen()
|
||||
|
||||
|
||||
SETPRIV_OHNE_WIRKUNG = (
|
||||
"while [ \"$#\" -gt 0 ] && [ \"$1\" != \"--\" ]; do shift; done\n"
|
||||
"shift\n"
|
||||
"exec \"$@\""
|
||||
)
|
||||
|
||||
|
||||
def fall_w13(skript):
|
||||
# setpriv wirft keine Faehigkeit ab und startet nur den Befehl hinter --:
|
||||
# Die Faehigkeitspruefung der Probe muss anschlagen.
|
||||
fahre_probe_scheitert("W13", skript, {"setpriv": SETPRIV_OHNE_WIRKUNG}, "Faehigkeiten nicht abgeworfen")
|
||||
|
||||
|
||||
def prozesse_mit_marke(marke):
|
||||
"""pid -> argv aller Prozesse, deren Umgebung die Marke traegt."""
|
||||
gefunden = {}
|
||||
for envdatei in Path("/proc").glob("[0-9]*/environ"):
|
||||
try:
|
||||
if marke.encode("ascii") not in envdatei.read_bytes():
|
||||
continue
|
||||
argv = (envdatei.parent / "cmdline").read_bytes().split(b"\0")
|
||||
except OSError:
|
||||
continue
|
||||
gefunden[envdatei.parent.name] = [teil.decode("utf-8", "replace") for teil in argv if teil]
|
||||
return gefunden
|
||||
|
||||
|
||||
def elternname(pid):
|
||||
try:
|
||||
stat = Path("/proc/{0}/stat".format(pid)).read_text()
|
||||
ppid = stat.rsplit(")", 1)[1].split()[1]
|
||||
return Path("/proc/{0}/comm".format(ppid)).read_text().strip()
|
||||
except (OSError, IndexError):
|
||||
return None
|
||||
|
||||
|
||||
def fall_w6(skript):
|
||||
# Zeitgrenze: zwei haengende Mutanten, BUDGET_S 10, ZEITLIMIT_S 6. Waehrend
|
||||
# des Laufs muss timeout der Elternprozess des Laeufers sein (keine
|
||||
# Zwischenschale); danach lebt kein Prozess des Falls mehr.
|
||||
fall = Fall(
|
||||
{"paket/haengen.py": HAENGEN, "tests/test_haengen.py": TEST_HAENGEN},
|
||||
mutant("MW6a", "paket/haengen.py", " return n + 1\n", SCHLEIFE, "tests/test_haengen.py::test_schritt_a")
|
||||
+ mutant("MW6b", "paket/haengen.py", " return n + 2\n", SCHLEIFE, "tests/test_haengen.py::test_schritt_b"),
|
||||
)
|
||||
try:
|
||||
wert = uuid.uuid4().hex
|
||||
marke = "KOPIE_TREIBER_MARKE=" + wert
|
||||
eigenes_tmpdir = fall.basis / "tmpdir"
|
||||
eigenes_tmpdir.mkdir()
|
||||
env = dict(os.environ)
|
||||
env.update({
|
||||
"BUDGET_S": "10",
|
||||
"ZEITLIMIT_S": "6",
|
||||
"TMPDIR": str(eigenes_tmpdir),
|
||||
"KOPIE_TREIBER_MARKE": wert,
|
||||
})
|
||||
cmd = [BASH, str(skript), windows_pfad(fall.kopie), windows_pfad(fall.plan), "voll"]
|
||||
proc = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
eltern = None
|
||||
pytest_gesehen = False
|
||||
for _ in range(12):
|
||||
time.sleep(0.5)
|
||||
for pid, argv in prozesse_mit_marke(marke).items():
|
||||
if (argv and Path(argv[0]).name.startswith("python")
|
||||
and any(teil.endswith("mutanten_lauf.py") for teil in argv)):
|
||||
eltern = elternname(pid)
|
||||
if "pytest" in argv:
|
||||
pytest_gesehen = True
|
||||
if eltern is not None and pytest_gesehen:
|
||||
break
|
||||
try:
|
||||
stdout, stderr = proc.communicate(timeout=90)
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.kill()
|
||||
stdout, stderr = proc.communicate()
|
||||
stderr += "\nTREIBER: Skript nach 90 s nicht beendet"
|
||||
reste = prozesse_mit_marke(marke)
|
||||
tmp_reste = sorted(p.name for p in eigenes_tmpdir.iterdir())
|
||||
ok = (
|
||||
proc.returncode == 124
|
||||
and "ZEITGRENZE" in stdout
|
||||
and "EXIT mutanten_lauf: 124" in stdout
|
||||
and "ABBRUCH: SIGTERM" in stdout
|
||||
and eltern == "timeout"
|
||||
and pytest_gesehen
|
||||
and not reste
|
||||
and not tmp_reste
|
||||
)
|
||||
melde("W6", ok, "exit={0}, eltern des laeufers={1}, pytest gesehen={2}, reste={3}, tmp={4}\n{5}{6}".format(
|
||||
proc.returncode, eltern, pytest_gesehen, reste, tmp_reste, stdout, stderr))
|
||||
fall.pruefe_kopie("W6")
|
||||
finally:
|
||||
fall.aufraeumen()
|
||||
|
||||
|
||||
def fall_w8(skript):
|
||||
# Ein Dienst des Treibers auf 127.0.0.1 darf aus dem Namensraum nicht
|
||||
# erreichbar sein, und bei ihm darf keine Verbindung ankommen.
|
||||
dienst = socket.socket()
|
||||
dienst.bind(("127.0.0.1", 0))
|
||||
dienst.listen(5)
|
||||
dienst.setblocking(False)
|
||||
fall = None
|
||||
try:
|
||||
fall = Fall(
|
||||
{"tests/test_aussen.py": text_test_aussen(dienst.getsockname()[1])},
|
||||
mutant("MW8", "tests/test_aussen.py", PRUEFZEILE_AUSSEN, " assert False\n",
|
||||
"tests/test_aussen.py::test_dienst_des_rechners_unerreichbar"),
|
||||
)
|
||||
ergebnis = starte_skript(skript, fall)
|
||||
try:
|
||||
verbindung, _ = dienst.accept()
|
||||
verbindung.close()
|
||||
angekommen = True
|
||||
except BlockingIOError:
|
||||
angekommen = False
|
||||
ok = (
|
||||
ergebnis.returncode == 0
|
||||
and "MW8 OK" in ergebnis.stdout
|
||||
and "EXIT mutanten_lauf: 0" in ergebnis.stdout
|
||||
and not angekommen
|
||||
)
|
||||
melde("W8", ok, "beim Dienst des Rechners angekommen={0}, {1}".format(angekommen, kurz(ergebnis)))
|
||||
fall.pruefe_kopie("W8")
|
||||
finally:
|
||||
dienst.close()
|
||||
if fall is not None:
|
||||
fall.aufraeumen()
|
||||
|
||||
|
||||
FAELLE = [
|
||||
("W7", fall_w7),
|
||||
("W1", fall_w1),
|
||||
("W2", fall_w2),
|
||||
("W3", fall_w3),
|
||||
("W4", fall_w4),
|
||||
("W5", fall_w5),
|
||||
("W6", fall_w6),
|
||||
("W8", fall_w8),
|
||||
("W9", fall_w9),
|
||||
("W10", fall_w10),
|
||||
("W11", fall_w11),
|
||||
("W12", fall_w12),
|
||||
("W13", fall_w13),
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
zerleger = argparse.ArgumentParser(description="Treiber fuer mutanten_lauf_kopie.sh (Faelle W1 bis W13)")
|
||||
zerleger.add_argument("--skript", default=str(SKRIPT_STANDARD), help="zu pruefende Fassung des Skripts")
|
||||
argumente = zerleger.parse_args()
|
||||
skript = Path(argumente.skript)
|
||||
print("skript: {0}".format(skript))
|
||||
|
||||
fehlend = [name for name in WERKZEUGE if shutil.which(name) is None]
|
||||
if BASH is None:
|
||||
fehlend.append("bash")
|
||||
if fehlend:
|
||||
print("TREIBER_FEHLER: Werkzeuge fehlen: {0}".format(", ".join(fehlend)))
|
||||
return 2
|
||||
if not skript.is_file():
|
||||
print("TREIBER_FEHLER: Skript fehlt: {0}".format(skript))
|
||||
return 2
|
||||
if not Path(INTERPRETER).is_file():
|
||||
print("TREIBER_FEHLER: Interpreter fehlt: {0}".format(INTERPRETER))
|
||||
return 2
|
||||
|
||||
probe = Path(tempfile.mkdtemp(prefix="mkopie_treiber_rundreise_"))
|
||||
try:
|
||||
windows = windows_pfad(probe)
|
||||
zurueck = linux_pfad(windows) if windows else ""
|
||||
finally:
|
||||
probe.rmdir()
|
||||
if not windows or zurueck != str(probe):
|
||||
print("TREIBER_FEHLER: wslpath-Rundreise: {0} -> {1} -> {2}".format(probe, windows, zurueck))
|
||||
return 2
|
||||
print("rundreise: {0} -> {1}".format(probe, windows))
|
||||
|
||||
for name, funktion in FAELLE:
|
||||
vorher = plankritik_ordner()
|
||||
try:
|
||||
funktion(skript)
|
||||
except Exception as exc:
|
||||
melde(name, False, "Ausnahme: {0!r}".format(exc))
|
||||
liegen_geblieben = sorted(str(p) for p in plankritik_ordner() - vorher)
|
||||
if liegen_geblieben:
|
||||
melde(name + " (aufraeumen)", False, "Kopien unter /tmp blieben liegen: {0}".format(liegen_geblieben))
|
||||
|
||||
print("gerechnete Fehler: {0}".format(len(FEHLERLISTE)))
|
||||
return 0 if not FEHLERLISTE else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -5,7 +5,7 @@ title: API-Mechanik für eigene Claude-Integrationen
|
||||
summary: Die modellübergreifenden Detailseiten der Anthropic-Doku — Preserved Thinking, Effort, Compaction, Task Budgets, Fast Mode, Thinking, Mid-Conversation-System-Nachrichten, Context Editing, Ablehnungen und Fallback. Gilt für Code-Projekte gegen die Messages API, nicht für die Claude-Code-Sitzung selbst.
|
||||
tags: [regelwerk, modelle, api, prompting]
|
||||
created: 2026-09-05
|
||||
updated: 2026-09-05
|
||||
updated: 2026-10-09
|
||||
---
|
||||
|
||||
# API-Mechanik für eigene Claude-Integrationen
|
||||
@@ -137,7 +137,7 @@ Was man sonst wissen muss: Mit `pause_after_compaction` lässt sich ein Gesamtbu
|
||||
|
||||
## 4 Task Budgets (Beta)
|
||||
|
||||
Header `task-budgets-2026-03-13`. Unterstützt: Fable 5.1, Mythos 5.1, Fable 5, Mythos 5, Opus 5, Opus 4.8, Opus 4.7. **Nicht** unterstützt: Sonnet 5, Opus 4.6, Sonnet 4.6, Haiku 4.5. **Nicht in Claude Code und nicht in Cowork** — nur direkt über die Messages API.
|
||||
Header `task-budgets-2026-03-13`. Unterstützt: Fable 5.1, Mythos 5.1, Fable 5, Mythos 5, Opus 5, Opus 4.8, Opus 4.7, laut Seite vom 2026-10-09 auch Opus 5.5, Sonnet 5.5 und Haiku 5.5 (Beta). **Nicht** unterstützt: Sonnet 5, Opus 4.6, Sonnet 4.6, Haiku 4.5. **Nicht in Claude Code und nicht in Cowork** — nur direkt über die Messages API.
|
||||
|
||||
`output_config.task_budget: {"type": "tokens", "total": N, "remaining": M}` sagt dem Modell, wie viele Tokens es für eine ganze agentische Schleife hat — Thinking, Werkzeugaufrufe, Werkzeugergebnisse, Ausgabe. Das Modell sieht einen serverseitig eingefügten Countdown und priorisiert danach. **Der Countdown ist nur für das Modell sichtbar:** Die Antwort enthält kein Restbudget, `usage` hat kein Feld dafür. Minimum 20.000 Tokens, darunter 400.
|
||||
|
||||
@@ -181,7 +181,7 @@ Die Grundseite, auf der Preserved Thinking (Abschnitt 1) und Effort (Abschnitt 2
|
||||
|
||||
**Fortschrittsmeldungen** (Fable 5.1, Mythos 5.1, Fable 5): ein bis zwei Sätze für den Zuschauer, je als eigener Thinking-Block mit eigener Signatur direkt vor dem `tool_use`, höchstens einer je Aufruf, jeder überspringbar. Sie sind kein Interleaved Thinking und können neben Reasoning-Blöcken stehen. Zurückgeben wie jeden Thinking-Block. Der Text ist eine Zusammenfassung; berechnet wird die volle Länge. Endet eine Antwort kurz nach einem Werkzeugaufruf auf `max_tokens`, `model_context_window_exceeded` oder `stop_sequence`, kann der letzte Block eine Fortschrittsmeldung mit dem Text „This part of the response was interrupted before it finished." sein — zum Fortsetzen die Runde unverändert zurückgeben und eine neue Nutzernachricht mit `tool_result` je `tool_use` anhängen.
|
||||
|
||||
**Bewahrung je Modell.** Alle früheren Runden behalten: Opus ab 4.5, Sonnet ab 4.6, alle Fable/Mythos. Nur die letzte Runde behalten: ältere Opus und Sonnet, **alle Haiku bis 4.5** — die API streicht ältere Blöcke selbst. Behalten bringt Cache-Treffer in Werkzeugschleifen ohne Intelligenzverlust; der Preis ist Kontextplatz, weil behaltene Blöcke wie Verlauf zählen. Ändern mit `clear_thinking_20251015` (Abschnitt 8). Beim Modellwechsel Blöcke unverändert mitsenden; selbst streichen nur zum Tokensparen auf Modellen, die ignorieren statt verwerfen — **nie beim Einlösen eines Fallback-Guthabens**, das den unveränderten Body verlangt.
|
||||
**Bewahrung je Modell.** Alle früheren Runden behalten: Opus ab 4.5, Sonnet ab 4.6, Haiku 5.5, alle Fable/Mythos. Nur die letzte Runde behalten: ältere Opus und Sonnet, **alle Haiku bis 4.5** — die API streicht ältere Blöcke selbst. Behalten bringt Cache-Treffer in Werkzeugschleifen ohne Intelligenzverlust; der Preis ist Kontextplatz, weil behaltene Blöcke wie Verlauf zählen. Ändern mit `clear_thinking_20251015` (Abschnitt 8). Beim Modellwechsel Blöcke unverändert mitsenden; selbst streichen nur zum Tokensparen auf Modellen, die ignorieren statt verwerfen — **nie beim Einlösen eines Fallback-Guthabens**, das den unveränderten Body verlangt.
|
||||
|
||||
**Thinking und Prompt-Cache.** Thinking-Konfiguration und aufgelöster Effort werden in den Prompt gerendert; jede Änderung (Modus, `budget_tokens`, Top-Level-Effort) startet den Cache neu — Nachrichten-Breakpoints treffen dann nie, Tool- und System-Breakpoints je nach Renderstelle. Explizit den Standardwert setzen ist gleich Weglassen. Thinking-Blöcke werden mit Werkzeugergebnissen gecacht, auch ohne `cache_control`, und zählen beim Lesen als Eingabetokens — Blöcke, die man nie wieder sieht, kosten beim Cache-Lesen trotzdem. Interleaved Thinking verstärkt Cache-Invalidierung. **Thinking-lastige Aufgaben dauern oft länger als die 5-Minuten-Cache-Lebensdauer — die 1-Stunden-Variante erwägen.**
|
||||
|
||||
@@ -213,7 +213,7 @@ Header `context-management-2025-06-27`, alle Claude-Modelle. Nur als Zusammenfas
|
||||
|
||||
**`clear_tool_uses_20250919`** — Werkzeugergebnisse älteste zuerst durch Platzhalter ersetzen, wenn der Kontext eine Schwelle überschreitet. Optionen: `trigger` (Standard 100.000 Eingabetokens, auch als `tool_uses` zählbar), `keep` (Standard 3 letzte Werkzeugpaare), `clear_at_least` (Mindestmenge zu löschender Tokens, damit sich die Cache-Invalidierung lohnt), `exclude_tools` (nie löschen), `clear_tool_inputs` (auch die Aufrufe löschen, Standard `false`). Löschen invalidiert den Cache an der Stelle — `clear_at_least` so setzen, dass es sich rechnet.
|
||||
|
||||
**`clear_thinking_20251015`** — behaltene Thinking-Runden steuern: `keep: {"type": "thinking_turns", "value": N}` oder `"all"`. Standard je Modellklasse: alles behalten bei Opus ab 4.5, Sonnet ab 4.6, allen Fable/Mythos; nur letzte Runde bei Opus bis 4.1, Sonnet bis 4.5, allen Haiku. Behalten hält den Cache, Löschen invalidiert ihn ab der Stelle — `keep: "all"` für beste Cache-Leistung. **Beide kombiniert: `clear_thinking_20251015` muss im `edits`-Array zuerst stehen.**
|
||||
**`clear_thinking_20251015`** — behaltene Thinking-Runden steuern: `keep: {"type": "thinking_turns", "value": N}` oder `"all"`. Standard je Modellklasse: alles behalten bei Opus ab 4.5, Sonnet ab 4.6, Haiku ab 5.5, allen Fable/Mythos; nur letzte Runde bei Opus bis 4.1, Sonnet bis 4.5, Haiku bis 4.5. Behalten hält den Cache, Löschen invalidiert ihn ab der Stelle — `keep: "all"` für beste Cache-Leistung. **Beide kombiniert: `clear_thinking_20251015` muss im `edits`-Array zuerst stehen.**
|
||||
|
||||
Die Antwort meldet `context_management.applied_edits` mit gelöschten Runden, Werkzeugpaaren und Tokens (beim Streaming im letzten `message_delta`). Der Token-Zähl-Endpunkt liefert `original_input_tokens` gegen `input_tokens`. Mit dem Memory Tool kombiniert bekommt Claude eine Warnung vor der Löschschwelle, um Wichtiges in Memory-Dateien zu sichern.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ title: Codeworkflow
|
||||
summary: Arbeitsweise für Code-Projekte — Standardschleife, Planaufteilung je Task, Subagenten und ihre Modellstufen und Effort, Gegenprüfung, Lauf mit echten Daten, Aufgabenmanagement.
|
||||
tags: [regelwerk, codeworkflow, code-projekte]
|
||||
created: 2026-08-03
|
||||
updated: 2026-10-05
|
||||
updated: 2026-10-09
|
||||
---
|
||||
|
||||
# Codeworkflow
|
||||
@@ -55,13 +55,13 @@ Die Lehre daraus gilt über diesen Fall hinaus: **Eine gerechnete Ersparnis ist
|
||||
|
||||
Steht der Code wörtlich da, sind die Zieldateien namentlich genannt und die Verbote ausdrücklich, dann ist die Executer-Rolle **Abschrift, nicht Autorschaft** — dafür genügt Haiku. Bleibt Ermessen offen, ist es Fehlersuche, oder muss Fließtext formuliert statt abgeschrieben werden, dann Sonnet.
|
||||
|
||||
**Ausnahme für Abschrift mit typografischen Zeichen (seit 2026-09-23, Pascals Entscheidung):** Enthält ein Codeblock des Tasks Anführungszeichen wie „ “ ” ‚ ‘ ’ « », Gedanken- oder Streckenstriche – — oder Auslassungspunkte …, dann `modell: sonnet` und `effort: low` statt Haiku. Haiku hat solche Zeichen in der Messung still ersetzt, siehe „Effort je Rolle". Nachsehen lässt sich das je Taskdatei, die Ausgabe `[]` heißt Haiku geht:
|
||||
**Typografische Zeichen (Pascals Entscheidung vom 2026-10-09, ersetzt die vom 2026-09-23):** Abschrift mit Anführungszeichen wie „ “ ” ‚ ‘ ’ « », Gedanken- oder Streckenstrichen – — oder Auslassungspunkten … läuft auf `modell: haiku` wie jede andere Abschrift. Haiku 5.5, auf das `haiku` seit 2026-10-07 zeigt, hat alle elf Zeichen am 2026-10-09 in 6 von 6 Läufen byte-genau übernommen ([[AI/Regelwerk/haiku-5-5|haiku-5-5.md]], A3). Haiku 4.5 hatte sie am 2026-09-23 still ersetzt, siehe „Effort je Rolle". Wählt der Alias außerhalb der Anthropic-API noch Haiku 4.5, gilt dort weiter `modell: sonnet` und `effort: low`. Der Byte-Vergleich bleibt in jedem Fall Pflicht. Ob ein Task solche Zeichen enthält, zeigt dieser Befehl, die Ausgabe `[]` heißt keine:
|
||||
|
||||
```bash
|
||||
python -X utf8 -c "import sys; t=open(sys.argv[1],encoding='utf-8').read(); b=''.join(t.split(chr(96)*3)[1::2]); print(sorted(set(b) & set('„“”‚‘’«»–—…')))" task-NN-thema.md
|
||||
```
|
||||
|
||||
Das Feld `effort:` im Task-Frontmatter ist freiwillig. Fehlt es, gilt das Frontmatter des Executers (`medium`); bei `modell: haiku` bleibt es wirkungslos.
|
||||
Das Feld `effort:` im Task-Frontmatter ist freiwillig. Fehlt es, gilt das Frontmatter des Executers (`medium`). Bei `modell: haiku` verwirft `executer-welle` einen Task-Effort derzeit und lässt das `medium` des Executers stehen, das Haiku 5.5 auch erhält ([[AI/Regelwerk/haiku-5-5|haiku-5-5.md]], A1 und A7).
|
||||
|
||||
**4 Gegenprüfen — der Kern der Schleife.** Ein Agentenbericht ist eine Behauptung, kein Beleg. Pflicht sind drei Dinge:
|
||||
|
||||
@@ -132,7 +132,7 @@ Was echte Daten aufdecken und Fixtures nicht: verdrehte Vorzeichen, Skalierungsp
|
||||
|
||||
### Nur für Claude Fable 5.1
|
||||
|
||||
Läuft der Koordinator auf Fable 5.1, gelten in der Schleife zusätzlich die Punkte 3, 8, 10, 13 und 15 aus [[AI/Regelwerk/fable-5-1|fable-5-1.md]]: unabhängige Werkzeugaufrufe in einer Antwort bündeln, einen entschiedenen Schritt ausführen statt ankündigen, Änderungen und Tests auf den Auftrag beschränken (der Regressionsfall je Nachbesserung aus Schritt 5 bleibt Pflicht — er ist beauftragt, kein Zusatz), Edit vor Write, und während ein Executer läuft das erledigen, was nicht von seinem Ergebnis abhängt. Opus 5, Sonnet 5, Sonnet 5.5 und Haiku 4.5 entscheiden selbst, ob sie etwas davon übernehmen — die Rollentabelle ändert sich dadurch nicht.
|
||||
Läuft der Koordinator auf Fable 5.1, gelten in der Schleife zusätzlich die Punkte 3, 8, 10, 13 und 15 aus [[AI/Regelwerk/fable-5-1|fable-5-1.md]]: unabhängige Werkzeugaufrufe in einer Antwort bündeln, einen entschiedenen Schritt ausführen statt ankündigen, Änderungen und Tests auf den Auftrag beschränken (der Regressionsfall je Nachbesserung aus Schritt 5 bleibt Pflicht — er ist beauftragt, kein Zusatz), Edit vor Write, und während ein Executer läuft das erledigen, was nicht von seinem Ergebnis abhängt. Opus 5, Opus 5.5, Sonnet 5, Sonnet 5.5 und Haiku 5.5 entscheiden selbst, ob sie etwas davon übernehmen — die Rollentabelle ändert sich dadurch nicht.
|
||||
|
||||
### Haltung zwischen den Schritten
|
||||
|
||||
@@ -176,7 +176,7 @@ Regelwerk-Änderungen im Vault lösen kein Quorum aus.
|
||||
|
||||
**Urteil.** Was zwei Stimmen an derselben Datei und Stelle melden, gilt, mit der höchsten Schwere der Gruppe. Einzelbefunde der Schwere blockierend und wichtig prüft ein Sonnet-Agent nach; Hinweise mit nur einer Stimme gehen ungeprüft in den Bericht. Ein Befund ohne Beleg zählt nicht für die Mehrheit und wird nicht nachgeprüft. Frei heißt: kein bestätigter blockierender Befund und kein belegter, der ungeprüft blieb. Ein blockierender Befund ohne Beleg sperrt nicht; er steht im Bericht unter „Unbelegt“, und der Grund des Urteils nennt ihn. Lies ihn, bevor du einspielst. Mit weniger als zwei abgegebenen Stimmen gibt es kein Urteil.
|
||||
|
||||
**Ersatz.** Gibt Codex keine gültige Stimme ab, springt Haiku ein. Gültig heißt: Der Status des Plugins ist vor dem Lauf gelesen, der Job endet `completed`, sein Log ist gelesen und trägt kein „usage limit“, und die Antwort zitiert die Lesemarke aus dem Paket. Mit `codex: false` springt Haiku sofort ein, etwa wenn das Kontingent bekannt aufgebraucht ist. Der Bericht sagt, wenn Haiku statt Codex drinsteht. Steht das oft da, ist das Quorum faktisch nur mit Claude besetzt.
|
||||
**Ersatz.** Gibt Codex keine gültige Stimme ab, springt Haiku ein — seit 2026-10-07 Haiku 5.5 mit dem `high` aus dem Frontmatter der Stimme; im Review-Prüfstand fand es am 2026-10-09 wie Sonnet 9 von 9 ([[AI/Regelwerk/haiku-5-5|haiku-5-5.md]], A3). Gültig heißt: Der Status des Plugins ist vor dem Lauf gelesen, der Job endet `completed`, sein Log ist gelesen und trägt kein „usage limit“, und die Antwort zitiert die Lesemarke aus dem Paket. Mit `codex: false` springt Haiku sofort ein, etwa wenn das Kontingent bekannt aufgebraucht ist. Der Bericht sagt, wenn Haiku statt Codex drinsteht. Steht das oft da, ist das Quorum faktisch nur mit Claude besetzt.
|
||||
|
||||
**Sperre.** Solange das Urteil nicht frei ist, also ein bestätigter oder ungeprüft gebliebener blockierender Befund mit Beleg offen ist oder der Lauf kein Urteil hat, gibt es kein Merge, keinen Push, kein Einspielen und keine Abgabe. Die Korrekturen entscheidest du, umgesetzt werden sie über die Standardschleife. Danach läuft kein neues Quorum: Eine `quorum-stimme` auf Sonnet, über das Agent-Werkzeug mit der Auftragsart Nachkontrolle gestartet, bestätigt je behobenem Befund, dass er behoben ist. Den Korrektur-Diff prüft das nächste Quorum mit, weil dessen Basis der Stand dieses Laufs ist.
|
||||
|
||||
@@ -234,7 +234,7 @@ Superpowers-Skills sprechen von „dispatch a `general-purpose` subagent". Diese
|
||||
|
||||
Die Modellwahl-Empfehlung in `subagent-driven-development` („use the least powerful model that can handle each role") bleibt gültig und wird hier auf drei Stufen gebracht: alles Urteilende auf Opus, alles Ausführende auf Sonnet, reine Abschrift auf Haiku. Nur wenn der Executer in der Fehlerbehebungsschleife zweimal hintereinander scheitert, wird die Nachbesserung an einen Opus-Agenten hochgestuft.
|
||||
|
||||
**Beleg für die dritte Stufe, damit sie nicht als Sparmaßnahme missverstanden wird.** Am 2026-08-27 lief Task 1 der Authentik-Werkzeugkette mit Haiku statt Sonnet, inklusive einer Korrekturrunde: null Abweichungen, null stille Zurechtbiegungen, korrekte Testreihenfolge auch bei der Nachbesserung. Die drei Befunde der Gegenprüfung waren Fehler im Plan, nicht in der Umsetzung. Haiku hat keine einzige zusätzliche Korrekturrunde verursacht.
|
||||
**Beleg für die dritte Stufe, damit sie nicht als Sparmaßnahme missverstanden wird.** Am 2026-08-27 lief Task 1 der Authentik-Werkzeugkette mit Haiku statt Sonnet, inklusive einer Korrekturrunde: null Abweichungen, null stille Zurechtbiegungen, korrekte Testreihenfolge auch bei der Nachbesserung. Die drei Befunde der Gegenprüfung waren Fehler im Plan, nicht in der Umsetzung. Haiku hat keine einzige zusätzliche Korrekturrunde verursacht. Diese Belege und die Tabelle darunter stammen von Haiku 4.5; für Haiku 5.5 steht die Messung in [[AI/Regelwerk/haiku-5-5|haiku-5-5.md]], A3.
|
||||
|
||||
Zwei später gelaufene Tasks erlauben einen fast sauberen Vergleich, weil sie sich im Zuschnitt gleichen — je ein Modul mit Tests und Codedoku, je drei Dateien, je eine Korrekturrunde, beide mit aufgeteiltem Plan und frischem Subagenten für die Korrektur:
|
||||
|
||||
@@ -254,9 +254,9 @@ Und der wichtigste Punkt zur Reihenfolge der Hebel: **Die teure Ressource ist ni
|
||||
|
||||
Der Effort ist neben dem Modell der zweite Regler, und bis 2026-09-23 war er nirgends gesetzt. Ein Subagent ohne eigenen Effort erbt den der Hauptsitzung. Läuft die auf `xhigh` oder `max`, laufen Planer, Prüfer und Executer mit. Was das gekostet hat, zeigt die Historie über 751 Subagenten aus 47 Sitzungen (2026-08-05 bis 2026-09-23). Der Median je Lauf lag beim Planer auf Opus 5 bei 5,16 $ mit `high` und 18,55 $ mit `max`, beim Prüfer bei 7,11 $ gegen 13,24 $, beim Sonnet-Executer bei 0,76 $ gegen 1,59 $. Die Aufgaben waren verschieden groß, sauber vergleichbar ist das also nicht. Der Modellkatalog im Claude-Code-Programm nennt für Sonnet 5 aber selbst die Kostenfaktoren: `xhigh` das 2,4-Fache, `max` das 5,6-Fache von `high`.
|
||||
|
||||
Woher ein Agent seinen Effort bekommt, in dieser Rangfolge (nachgelesen im Programm 2.1.280): eine gesetzte Umgebungsvariable `CLAUDE_CODE_EFFORT_LEVEL` schlägt alles, ist im Vault aber nicht gesetzt (geprüft 2026-09-23); danach der `effort`-Parameter eines Workflow-`agent()`-Aufrufs, dann `effort:` im Frontmatter der Agentendatei, dann der Effort der Sitzung, dann der Standard des Modells. Das Agent-Werkzeug hat keinen Effort-Parameter; dort wirkt nur das Frontmatter. Belegt am 2026-09-23 in einer frischen Sitzung auf `xhigh`: `executer` lief mit `medium`, `pruefer` mit `high`, beides aus dem Transkriptfeld `effort`. Belegt ist das auch im Workflow: Mit `agentType` liefen `executer` und `recherche` mit `medium` aus dem Frontmatter, der Agent ohne Typ mit dem `xhigh` der Sitzung. Zwei Fallstricke dabei. Eine geänderte Agentendatei wirkt in der laufenden Sitzung nicht sofort: Die Änderung von 13:58 zeigte sich um 14:00 noch nicht, knapp eine Stunde später schon. Was das Nachladen auslöst, ist nicht bekannt; sicher ist nur der Blick ins Transkriptfeld `effort`. Einen neu angelegten gespeicherten Workflow kannte die laufende Sitzung zuerst nicht, eine frische schon. Gut eine Stunde später war er auch in der laufenden aufrufbar. Und Haiku 4.5 kennt keinen Effort; ein gesetzter Wert wird gar nicht gesendet.
|
||||
Woher ein Agent seinen Effort bekommt, in dieser Rangfolge (nachgelesen im Programm 2.1.280): eine gesetzte Umgebungsvariable `CLAUDE_CODE_EFFORT_LEVEL` schlägt alles, ist im Vault aber nicht gesetzt (geprüft 2026-09-23); danach der `effort`-Parameter eines Workflow-`agent()`-Aufrufs, dann `effort:` im Frontmatter der Agentendatei, dann der Effort der Sitzung, dann der Standard des Modells. Das Agent-Werkzeug hat keinen Effort-Parameter; dort wirkt nur das Frontmatter. Belegt am 2026-09-23 in einer frischen Sitzung auf `xhigh`: `executer` lief mit `medium`, `pruefer` mit `high`, beides aus dem Transkriptfeld `effort`. Belegt ist das auch im Workflow: Mit `agentType` liefen `executer` und `recherche` mit `medium` aus dem Frontmatter, der Agent ohne Typ mit dem `xhigh` der Sitzung. Zwei Fallstricke dabei. Eine geänderte Agentendatei wirkt in der laufenden Sitzung nicht sofort: Die Änderung von 13:58 zeigte sich um 14:00 noch nicht, knapp eine Stunde später schon. Was das Nachladen auslöst, ist nicht bekannt; sicher ist nur der Blick ins Transkriptfeld `effort`. Einen neu angelegten gespeicherten Workflow kannte die laufende Sitzung zuerst nicht, eine frische schon. Gut eine Stunde später war er auch in der laufenden aufrufbar. Haiku 4.5 kennt keinen Effort; ein gesetzter Wert wird gar nicht gesendet. Haiku 5.5, auf das der Alias `haiku` laut Transkripten seit Claude Code 2.1.293 zeigt, kennt ihn und bekommt ihn nach derselben Rangfolge — ein Agent ohne `agentType` und ohne `effort` also den der Sitzung ([[AI/Regelwerk/haiku-5-5|haiku-5-5.md]], A1).
|
||||
|
||||
Die Werte der ersten drei Zeilen stammen aus einer Messung vom 2026-09-23 an drei Prüfständen mit bekanntem Ergebnis, je Stufe zwei Läufe; die Sonnet-5.5-Zeile vom 2026-09-29:
|
||||
Die Werte der ersten drei Zeilen stammen aus einer Messung vom 2026-09-23 an drei Prüfständen mit bekanntem Ergebnis, je Stufe zwei Läufe; die Sonnet-5.5-Zeile vom 2026-09-29, die Haiku-5.5-Zeile vom 2026-10-09:
|
||||
|
||||
| Rolle | Effort | Was gemessen wurde | Median je Lauf |
|
||||
|---|---|---|---|
|
||||
@@ -264,6 +264,7 @@ Die Werte der ersten drei Zeilen stammen aus einer Messung vom 2026-09-23 an dre
|
||||
| `planer` (Opus 5.5) | `high` | Korrekturplan für dieselben neun Fehler, danach mit `plan_materialisiere.py` angewendet. Alle sechs Pläne ließen sich anwenden, Suite grün, 9 von 9 behoben (eigene Probe). Gegen den alten Code schlugen je Plan 9 bis 13 der neuen Tests fehl; die 1 bis 3 schon vorher grünen sind laut Planerbericht bewusste Absicherungstests. Bei Anwendbarkeit, Suite und Probe kein Unterschied zwischen den Stufen. | `medium` 0,75 $, `high` 0,82 $, `xhigh` 2,90 $ |
|
||||
| `executer` (Sonnet 5) | `medium` | Abschrift-Task mit einem Prüf-grep, der den Docstring trifft. Alle Stufen schrieben gleich treu ab und meldeten den Widerspruch, statt den Docstring umzuformulieren. | `low` 0,13 $, `medium` 0,15 $, `high` 0,19 $ |
|
||||
| `executer` (Sonnet 5.5, 2026-09-29) | `medium` | Derselbe Abschrift-Task plus ein Doku-Task (Anleitung und Hintergrund aus zehn Dossier-Aussagen, bewertet per Skript). Abschrift auf allen Stufen gleich, mit derselben Schreibschicht-Abweichung; Doku: Bewerter ohne Befund, strengere Probe mit Schwächen bei `low` und einmal `medium`. Einzelheiten in [[AI/Regelwerk/sonnet-5-5|sonnet-5-5.md]], A1. | Ausgabetokens Doku: `low` 3.000, `medium` 3.370, `high` 5.070 |
|
||||
| `executer` (Haiku 5.5, 2026-10-09) | `medium` | Derselbe Abschrift-Task. Alle Stufen am Ende byte-gleich, „ “ erhalten, Widerspruch gemeldet; die Escape-Abweichung auf dem Write-Weg fanden die Läufe selbst. Sonnet 5.5 unter denselben Bedingungen ebenso. Einzelheiten in [[AI/Regelwerk/haiku-5-5|haiku-5-5.md]], A3. | je Lauf 0,008–0,009 $ auf jeder Stufe |
|
||||
|
||||
Warum nicht überall die billigste Stufe: Beim Prüfer ist Abdeckung der Zweck. Ab `high` brachten beide Läufe die drei Zusatzfunde, darunter nicht; `xhigh` brachte nicht mehr als `high`. Beim Planer war `medium` gleich gut und 9 Prozent billiger. Ein Fehler im Plan kostet aber Executer-Wellen und Korrekturrunden im Koordinatorkontext, deshalb `high`. Beim Executer auf Sonnet 5 entsprach `medium` laut Doku etwa Sonnet 4.6 bei `high`; für Sonnet 5.5 sagt die Doku nur, die Stufen seien neu geeicht. Ob `medium` bei Tasks mit Ermessen hält, ist nicht gemessen; scheitert ein Executer dort, gilt die Hochstufung auf Opus aus dem Abschnitt oben.
|
||||
|
||||
@@ -284,7 +285,7 @@ Deine eigene Gegenprüfung aus Schritt 4 ersetzt keiner davon; sie wird nur bill
|
||||
|
||||
**Bei Sonnet-Agenten treibt das Lesen die Kosten, nicht der Effort.** In den sechs Sonnet-Recherche-Läufen machte das Cache-Schreiben der gelesenen Dateien je Lauf ein Drittel bis gut 70 Prozent der Kosten aus, im Mittel gut die Hälfte; teurer oder billiger nach Effort sortierten sich die Läufe nicht. Gezielt lesen — `Grep` mit Zeilennummern, `Read` mit `offset` und `limit` — spart dort mehr als eine niedrigere Stufe. Bei Opus-Agenten dominiert die Ausgabe einschließlich Thinking, und genau die steuert der Effort.
|
||||
|
||||
**Haiku und typografische Zeichen.** Im Abschrift-Prüfstand ersetzte Haiku in beiden Läufen still ein deutsches schließendes Anführungszeichen (U+201C) durch ein gerades und meldete trotzdem „byte-genau". Sonnet tat das in keiner Stufe. Haiku kostete 0,08 $ gegen 0,13 $ für Sonnet auf `low`. Pascal hat am 2026-09-23 entschieden: Abschrift mit typografischen Zeichen läuft auf Sonnet `low`, die Regel steht in Schritt 3. Der Byte-Vergleich bleibt trotzdem Pflicht.
|
||||
**Haiku und typografische Zeichen.** Im Abschrift-Prüfstand ersetzte Haiku 4.5 in beiden Läufen still ein deutsches schließendes Anführungszeichen (U+201C) durch ein gerades und meldete trotzdem „byte-genau". Sonnet tat das in keiner Stufe. Haiku kostete 0,08 $ gegen 0,13 $ für Sonnet auf `low`. Pascal hat am 2026-09-23 entschieden: Abschrift mit typografischen Zeichen läuft auf Sonnet `low`, die Regel steht in Schritt 3. Der Byte-Vergleich bleibt trotzdem Pflicht. Haiku 5.5 hat dasselbe Zeichenpaar und in einem zweiten Prüfstand alle elf Zeichen der Regel am 2026-10-09 in je 6 von 6 Läufen erhalten; am selben Tag hat Pascal die Ausnahme für Haiku 5.5 aufgehoben (Schritt 3).
|
||||
|
||||
**Die Escape-Folge für U+2028 hat jedes Modell verloren.** Alle acht Abschrift-Läufe, Haiku wie Sonnet in jeder Stufe, schrieben sie als echtes Zeichen in die Datei. Alle acht Berichte nannten die Datei trotzdem „byte-genau" übernommen, die Tests blieben grün. Das liegt an der Schreibschicht, nicht am Modell. Der Byte-Vergleich nach jeder Welle bleibt Pflicht, egal mit welchen Parametern.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ title: Prompting-Hinweise für Claude Fable 5.1
|
||||
summary: Verhaltensunterschiede und Prompt-Muster von Claude Fable 5.1 (Teil A) sowie Spezifikation, API-Brüche, neue Funktionen, Preise und Datenhaltung (Teil B) aus der Anthropic-Doku — gilt nur, wenn Fable 5.1 das Modell ist; andere Modelle entscheiden selbst.
|
||||
tags: [regelwerk, modelle, fable, prompting]
|
||||
created: 2026-09-05
|
||||
updated: 2026-09-29
|
||||
updated: 2026-10-09
|
||||
source: https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-fable-5-1
|
||||
---
|
||||
|
||||
@@ -13,7 +13,7 @@ source: https://platform.claude.com/docs/en/build-with-claude/prompt-engineering
|
||||
|
||||
> **Geltungsbereich — bitte zuerst lesen.**
|
||||
> Diese Datei gilt **nur für Claude Fable 5.1** (und das baugleiche Claude Mythos 5.1). Läufst du als Fable 5.1, berücksichtigst du die Punkte unten als Teil deiner Arbeitsweise.
|
||||
> Läufst du als **Opus 5, Sonnet 5, Sonnet 5.5 oder Haiku 4.5**, dann sind das keine Anweisungen an dich. Diese Modelle arbeiten nach ihren eigenen Optimierungen und entscheiden selbst, ob sie einen Punkt übernehmen. Die Rollentabelle im Stamm ([[CLAUDE|Claude.md]], „Agenten & Modelle") bleibt unverändert.
|
||||
> Läufst du als **Opus 5, Opus 5.5, Sonnet 5, Sonnet 5.5, Haiku 4.5 oder Haiku 5.5** (Haiku 5.5: [[AI/Regelwerk/haiku-5-5|haiku-5-5.md]]), dann sind das keine Anweisungen an dich. Diese Modelle arbeiten nach ihren eigenen Optimierungen und entscheiden selbst, ob sie einen Punkt übernehmen. Die Rollentabelle im Stamm ([[CLAUDE|Claude.md]], „Agenten & Modelle") bleibt unverändert.
|
||||
> Angeordnet am 2026-09-05. Quellen: Anthropic-Doku „Prompting Claude Fable 5.1" (Teil A), „What's new in Claude Fable 5.1" (Teil B) und der Migrationsleitfaden (Teil C), alle abgerufen am 2026-09-05. Die Aussagen stammen aus diesen Seiten, nicht aus eigener Messung — wo die Doku eine Bedingung nennt, steht sie hier mit. Die modellübergreifenden Techniken stehen in [[AI/Regelwerk/prompting|prompting.md]].
|
||||
|
||||
## Wozu diese Datei
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
---
|
||||
type: resource
|
||||
title: "Arbeiten mit Claude Haiku 5.5"
|
||||
status: reference
|
||||
summary: "Haiku 5.5 als Abschrift-Executer, Quorum-Ersatzstimme, Verbrauchsablesung und Sitzungsmodell: Effort je Rolle nach Messung vom 2026-10-09, Prüfpunkte, offene Entscheidungen, Verhalten und Prompt-Muster, Spezifikation und API-Brüche."
|
||||
tags: [regelwerk, modelle, haiku, prompting]
|
||||
created: 2026-10-09
|
||||
updated: 2026-10-09
|
||||
source: "https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-haiku-5-5"
|
||||
---
|
||||
|
||||
# Arbeiten mit Claude Haiku 5.5
|
||||
|
||||
> **Geltungsbereich — zuerst lesen.**
|
||||
> - Diese Datei gilt für **Claude Haiku 5.5** (`claude-haiku-5-5`). Läufst du selbst als Haiku 5.5, ob als Hauptsitzung oder als Subagent, sind Teil A und Teil B deine Arbeitsweise.
|
||||
> - Schreibt ein Koordinator einen Auftrag an einen Haiku-Subagenten, nimmt er Teil A. Für Fable 5.1 als Koordinator ist das verbindlich, Opus 5.5 entscheidet selbst.
|
||||
> - Die Rollentabelle im Stamm ([[CLAUDE|Claude.md]], „Agenten & Modelle") nennt Haiku 5.5 für Abschrift, Quorum-Ersatz und die Haiku-Sitzung (A5); die Zuordnung der übrigen Rollen ändert sich nicht. Haiku 4.5 beschreibt [[AI/Regelwerk/sonnet-5|sonnet-5.md]], C3.
|
||||
> - Angeordnet von Pascal am 2026-10-09. Quellen: Anthropic-Doku (Rohtext am 2026-10-09 per curl abgerufen), Modellkatalog und Systemprompt-Bausteine im Programmabbild von Claude Code 2.1.296 (gelesen, nicht gelaufen), die Transkripte des Vaults und eine eigene Messung (A3). Wo die Doku eine Bedingung nennt, steht sie hier mit.
|
||||
|
||||
## Wozu diese Datei
|
||||
|
||||
Seit dem 2026-10-07 läuft alles, was im Vault `haiku` heißt, auf Haiku 5.5 — ohne dass eine Agentendatei geändert wurde. Haiku 5.5 kennt Effort, Haiku 4.5 nicht; mehrere Regeln und Workflows gehen noch vom alten Modell aus. Die Tabelle führt vom Symptom zum Abschnitt.
|
||||
|
||||
| Beobachtung | Abschnitt |
|
||||
|---|---|
|
||||
| Unklar, mit welchem Effort ein Haiku-Agent läuft oder laufen soll | A1, A2 |
|
||||
| Die Ablesung in `verbrauch` läuft mit `max` | A1, A7 |
|
||||
| Task mit `modell: haiku` und typografischen Zeichen | A3, A4 |
|
||||
| Pascal startet eine Sitzung auf Haiku | A5 |
|
||||
| Haiku-Executer meldet „fertig" ohne echte Prüfung | B3 |
|
||||
| Haiku hört bei langem Agent-Auftrag früh auf und gibt die Aufgabe zurück | A4, B2 |
|
||||
| Antwort aus dem Gedächtnis statt Suche | B4 |
|
||||
| Werkzeugaufruf fehlt bei JSON-Ausgabe ohne Thinking | B5 |
|
||||
| Nutzernachricht mitten im Zug wird übergangen | B6 |
|
||||
| Denktext steht in der sichtbaren Antwort | B7 |
|
||||
| Chatbot gibt bei Drängen nach | B8 |
|
||||
| `stop_reason: "refusal"`, kein Ausweichmodell | B9 |
|
||||
| 400 bei `budget_tokens`, `temperature`, Prefill oder geändertem Verlauf | C2 |
|
||||
| Nach dem Wechsel von Opus auf Haiku fehlt das frühere Denken | A5, C4 |
|
||||
|
||||
Zwei Sorten von Punkten sind gemischt: Manche greifen **in dieser Claude-Code-Sitzung oder bei Subagenten** (Kennung „Sitzung"), andere erst, **wenn wir selbst gegen die Claude-API bauen** (Kennung „API-Integration").
|
||||
|
||||
# Teil A — Was im Vault gilt
|
||||
|
||||
## A1 Wo Haiku 5.5 im Vault läuft
|
||||
|
||||
- Der Alias `haiku` löst im Katalog von Claude Code 2.1.296 auf der Anthropic-API auf `claude-haiku-5-5` auf. Auf Bedrock, Vertex, Foundry, Mantle, `anthropic_aws`, `anthropic_google_cloud` und Gateway löst er weiter auf `claude-haiku-4-5` auf.
|
||||
- In den Transkripten des Vaults steht der erste Haiku-5.5-Eintrag am 2026-10-07 um 20:55 UTC (CLI 2.1.293), der letzte Haiku-4.5-Eintrag am selben Tag um 11:58 UTC (CLI 2.1.292).
|
||||
- Haiku 5.5 ist das erste Haiku mit Effort. Ein Effort aus dem Frontmatter einer Agentendatei oder aus der Sitzung kommt jetzt beim Modell an. Bei Haiku 4.5 fehlte das Feld `effort` im Transkript (2026-09-23), und der Katalog führt dort keine Effort-Fähigkeit.
|
||||
|
||||
| Rolle | Gestartet von | Effort, der ankommt | Beleg |
|
||||
|---|---|---|---|
|
||||
| `executer` bei `modell: haiku` (Abschrift) | `executer-welle`, `agentType: executer`, ohne `effort` | `medium` aus dem Frontmatter des Executers | Transkripte 2026-10-09; Messung A3 |
|
||||
| Task mit `modell: haiku` und eigenem `effort:` | `executer-welle` | trotzdem `medium`: `effortFuer()` verwirft den Task-Effort und loggt ihn als „wirkungslos" | `.claude/workflows/executer-welle.js` |
|
||||
| `quorum-stimme` als Ersatz für Codex | `quorum`, `agentType: quorum-stimme`, ohne `effort` | `high` aus dem Frontmatter | Messung A3 |
|
||||
| Ablesung in `verbrauch` | `verbrauch.js`, ohne `agentType` und ohne `effort` | der Effort der aufrufenden Sitzung, am 2026-10-09 `max` oder `xhigh` | Transkripte 2026-10-09 |
|
||||
| Hauptsitzung | Modellwahl in der App | Sitzungseinstellung, Standard `medium` | Transkripte 2026-10-09; Katalog |
|
||||
|
||||
## A2 Effort je Rolle
|
||||
|
||||
| Rolle | Effort | Grund |
|
||||
|---|---|---|
|
||||
| `executer`, Abschrift | `medium` (Frontmatter, unverändert) | Messung: `low`, `medium` und `high` gleich treu, je Lauf 0,008–0,009 $; `low` sparte keine Ausgabe. Doku: `medium` ist der Start für agentisches Coding; auf `low` hört Haiku in langen Agent-Prompts eher früh auf, auf `low` und `medium` meldet es Änderungen teils ohne Prüfung als fertig (B2, B3). |
|
||||
| `quorum-stimme`, Ersatz | `high` (Frontmatter, unverändert) | Messung: 9 von 9 auf jeder Stufe; `high` brachte je Lauf zwei berechtigte Zusatzfunde, `low` einen, bei höchstens 0,010 $ je Lauf. Doku: `high` für strenges Befolgen von Anweisungen. |
|
||||
| Ablesung in `verbrauch` | `low` (angenommen, Umsetzung offen, A7) | Feste Ablesung ohne Urteil; Doku: `low` für kurze Werkzeugaufgaben. Nicht gemessen. |
|
||||
| Hauptsitzung | `medium` (Standard) | Doku: Startpunkt für die meiste Arbeit; `xhigh` und `max` nur mit Gewinn in eigenen Evals, dann auch Sonnet 5.5 vergleichen. Nicht gemessen. |
|
||||
|
||||
## A3 Messung vom 2026-10-09
|
||||
|
||||
Aufbau: Workflows in Claude Code 2.1.293 (laut Transkript), je Lauf ein Subagent mit `agentType` und `model` wie im echten Einsatz; „Standard" heißt ohne `effort`-Parameter, also Frontmatter. Effort und Modell je Lauf aus dem Transkript belegt. Abschrift und Quorum: Prüfstände vom 2026-09-23; Typografie: neuer Prüfstand vom 2026-10-09.
|
||||
|
||||
**Abschrift** — Task mit deutschen Anführungszeichen im Docstring, der Escape-Folge für U+2028 und einem Prüf-grep, der den Docstring trifft; Byte-Vergleich mit `cmp`:
|
||||
|
||||
| Einstellung | Läufe | Ende byte-gleich | „ “ erhalten | Widerspruch gemeldet | Ausgabetokens (Median) | Kosten je Lauf | Dauer |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| Haiku 5.5, Standard (`medium`) | 2 | 2 von 2 | 2 von 2 | 2 von 2 | 1.781 | 0,008 $ | 40–42 s |
|
||||
| Haiku 5.5, `low` | 2 | 2 von 2 | 2 von 2 | 2 von 2 | 2.244 | 0,008–0,009 $ | 29–52 s |
|
||||
| Haiku 5.5, `high` | 2 | 2 von 2 (ein Lauf erzeugte die Testdatei per awk aus der Taskdatei) | 2 von 2 | 2 von 2 | 2.279 | 0,008 $ | 41–50 s |
|
||||
| Sonnet 5.5, Standard (`medium`), Gegenprobe | 2 | 2 von 2 | 2 von 2 | 2 von 2 | 1.413 | 0,105–0,130 $ | 31–33 s |
|
||||
|
||||
**Quorum-Stimme** — neun eingebaute Fehler gegen eine SPEC, als echtes Prüfpaket mit `quorum_werkzeug.py` gebaut, Auftrag wortgleich mit `quorum.js`; ein Sonnet-Richter glich blind ab und prüfte jedes Zitat:
|
||||
|
||||
| Einstellung | Läufe | Schlüssel mit Zitat | Zusatzfunde je Lauf | Fehlalarme | Ausgabetokens (Median) | Kosten je Lauf | Dauer |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| Haiku 5.5, `low` | 2 | 9 von 9 | 1 und 1 | 0 | 4.072 | 0,004–0,007 $ | 18–20 s |
|
||||
| Haiku 5.5, `medium` | 2 | 9 von 9 | 2 und 1 | 0 | 6.055 | 0,004–0,008 $ | 26–30 s |
|
||||
| Haiku 5.5, Standard (`high`) | 2 | 9 von 9 | 2 und 2 | 0 | 8.321 | 0,005–0,010 $ | 35–40 s |
|
||||
| Sonnet 5.5, Standard (`high`) | 2 | 9 von 9 | 2 und 2 | 0 | 3.411 | 0,042–0,125 $ | 24–27 s |
|
||||
|
||||
**Typografie** — zweiter Abschrift-Task mit allen elf Zeichen der früheren Ausnahme („ “ ” ‚ ‘ ’ « » – — …), 47 Vorkommen in Docstring, Kommentar, Zeichenketten und Testerwartungen; Byte-Vergleich mit `cmp`:
|
||||
|
||||
| Einstellung | Läufe | Ende byte-gleich | Ausgabetokens (Median) | Kosten je Lauf | Dauer |
|
||||
|---|---|---|---|---|---|
|
||||
| Haiku 5.5, Standard (`medium`) | 4 | 4 von 4 | 1.425 | 0,005–0,009 $ | 21–53 s |
|
||||
| Haiku 5.5, `low` | 2 | 2 von 2 | 1.258 | 0,005–0,006 $ | 16–19 s |
|
||||
|
||||
Alle sechs schrieben per Write, und jede Write-Eingabe war schon beim ersten Mal richtig. Ein Lauf (Standard) legte die Hilfsdatei `_blocks.txt` neben der Taskdatei an, also außerhalb seines Laufordners, nannte sie im Bericht und löschte sie; derselbe Lauf versuchte per awk zwei Dateien weit außerhalb des Arbeitsbaums zu schreiben, die nicht entstanden und die er nicht meldete. Auf diese Messung hin hat Pascal am 2026-10-09 die Ausnahme für Haiku 5.5 aufgehoben ([[AI/Regelwerk/codeworkflow|codeworkflow.md]], Schritt 3).
|
||||
|
||||
Was beim Abschrift- und beim Quorum-Prüfstand auffiel:
|
||||
|
||||
- **Write-Weg:** In 5 von 6 Haiku-Läufen stand die Escape-Folge schon in der Eingabe des Write-Aufrufs als echtes Zeichen; ob das Modell oder die Harness-Schicht es erzeugte, zeigt das Transkript nicht. Alle fünf fanden es selbst per Bytesuche und setzten die Folge zurück, und alle fünf nennen dabei die Harness-Erinnerung zu Unicode-Escapes.
|
||||
- **Bash-Weg:** Ein Haiku-Lauf und beide Sonnet-Läufe schrieben per Heredoc. Dort kam die Escape-Folge richtig an, aber in der Testdatei gingen zuerst Backslashes verloren (3 von 3), sichtbar als SyntaxWarning bei grünen Tests.
|
||||
- Haiku 4.5 ersetzte am 2026-09-23 im selben Task U+201C in 2 von 2 Läufen still durch ein gerades Zeichen. Haiku 5.5 hat „ und “ in 6 von 6 Läufen erhalten.
|
||||
- **Verbotene Hilfsdateien:** Ein Haiku-Lauf (`low`) legte zwei Skripte kurz außerhalb seines Laufordners ab, meldete das und löschte sie. Ein zweiter (`high`) legte drei Hilfsdateien im Laufordner an und löschte sie wieder, ohne es zu melden.
|
||||
- **Kosten:** Haiku 5.5 kostete beim Executer etwa ein Fünfzehntel, bei der Quorum-Stimme (Standard gegen Standard) etwa ein Elftel von Sonnet 5.5; die Kosten streuen mit den Cache-Treffern. Haiku 4.5 kostete im selben Abschrift-Task am 2026-09-23 0,076 $ je Lauf (Median).
|
||||
|
||||
Was die Messung nicht belegt:
|
||||
|
||||
- Alle drei Prüfstände sind klein: ein Modul mit 73 Zeilen (Quorum), eines mit 25 Zeilen (Abschrift), eines mit 39 Zeilen Code und 18 Zeilen Tests (Typografie).
|
||||
- Beim Quorum fanden alle acht Läufe alle neun Fehler. Der Prüfstand trennt die Stufen deshalb nicht, nur über Zusatzfunde und Kosten.
|
||||
- Die Selbstkorrektur ist kein Vorsprung von Haiku: Sonnet 5.5 war unter denselben Bedingungen ebenso byte-treu. Dass alle fünf betroffenen Haiku-Läufe die Harness-Erinnerung nennen, spricht dafür, dass sie die Korrektur auslöste; bewiesen ist das nicht.
|
||||
- Der Vergleich mit Haiku 4.5 ist kein kontrollierter Versuch: anderer Tag, eine andere Fassung der Escape-Erinnerung im Index und weitere Erinnerungen zum Byte-Vergleich. Die Erinnerung selbst stand auch am 2026-09-23 im Kontext.
|
||||
- Typografisch gemessen sind zwei kleine Tasks. Lange Aufträge, in denen ein Executer viel Text abschreibt, sind nicht gemessen.
|
||||
- Lange Tasks mit vielen Dateien, Ermessen und langer Agentenschleife sind nicht gemessen — genau dort nennt die Doku frühes Aufhören auf `low` (B2).
|
||||
- Hauptsitzung und `verbrauch`-Ablesung sind nicht gemessen.
|
||||
|
||||
Rohwerte je Lauf: [[AI/secondbrain/regelwerk-memory/2026-10-09-haiku-5-5-messung|Messbericht Haiku 5.5]].
|
||||
|
||||
## A4 Aufträge an Haiku-Subagenten
|
||||
|
||||
- **Executer bei `modell: haiku`:** Die Vorlage aus [[AI/Regelwerk/sonnet-5-5|sonnet-5-5.md]], A2, gilt. Ihr Stoppsatz deckt nur die zweite Hälfte des Doku-Mittels aus B2 (aufhören, wenn erledigt und geprüft; keine Zusatzarbeit), ihr Prüfbefehl mit Erwartung den Doku-Absatz aus B3.
|
||||
- **Bei langen Haiku-Aufträgen** (viele Dateien, lange Werkzeugschleife) kommt die erste Hälfte als eigene Zeile dazu: „Arbeite weiter, bis alles Beauftragte erledigt ist; frag nur, wenn es ohne den Auftraggeber nicht weitergeht, oder vor einem riskanten Schritt."
|
||||
- **Wann Haiku statt Sonnet:** das Kriterium „Abschrift, nicht Autorschaft" aus [[AI/Regelwerk/codeworkflow|codeworkflow.md]], Schritt 3. Typografische Zeichen sind für Haiku 5.5 kein Grund mehr für Sonnet; die Regel steht dort.
|
||||
- **Quorum-Ersatz:** Der Auftrag steht fest in `quorum.js`; zu formulieren ist nichts.
|
||||
- **Agent ohne `agentType`:** bekommt `model` und `effort` (Stamm). Bei Haiku 4.5 war ein fehlender Effort folgenlos, bei Haiku 5.5 erbt der Agent den Effort der Sitzung.
|
||||
|
||||
## A5 Haiku 5.5 als Sitzungsmodell (Sitzung)
|
||||
|
||||
- **Wofür eine Haiku-Sitzung da ist (Pascals Entscheidung vom 2026-10-09):** Fragen und Nachschlagen. Vor Planen, Gegenprüfen, Committen oder Arbeit an Produktivsystemen wechselt die Sitzung auf Opus 5.5 — oder du sagst Pascal, dass der nächste Schritt das verlangt. Grund: Die Rollentabelle weist Klären, Entscheiden und Committen dem Koordinator auf Opus 5.5 zu.
|
||||
- **Subagenten aus einer Haiku-Sitzung:** zum Nachschlagen etwa `recherche` mit `model: sonnet` — jeder Subagent bekommt `model` ausdrücklich, sonst erbt er Haiku. `planer` und `pruefer` startet erst die Sitzung nach dem Wechsel auf Opus.
|
||||
- **Effort-Erbe:** Ein Agent ohne `effort:` erbt den Effort der Haiku-Sitzung, Standard `medium`.
|
||||
- **Wofür Anthropic Haiku 5.5 baut:** „high-volume, latency-sensitive work such as classification, routing, extraction, and subagent tasks" (What's new). Eine Messung für Vault-Sitzungen gibt es nicht.
|
||||
- **Was Claude Code selbst einfügt:** Claude Code 2.1.296 baut für Haiku 5.5 einen eigenen Absatz in den Systemprompt (Abschnitt `heron_brook`, Fähigkeit `haiku_5_5_early_stopping_guidance`, Schalter `tengu_idempotent_wolf`, im Programm mit an vorbelegt). Ein ferngesteuert gesetzter Ersatztext für denselben Abschnitt hat Vorrang. Was in Pascals Konto gilt und ob Subagenten den Absatz bekommen, ist nicht beobachtet. Kurz gefasst sagt er:
|
||||
- Der Effort steuert das Denken, nicht den Umfang; eine große Aufgabe ist kein Grund, vorher nachzufragen. Der Zug endet, wenn der Auftrag erledigt ist oder ohne den Nutzer nichts mehr geht.
|
||||
- Vorher fragen nur, wenn die wahrscheinlichste Lesart nicht benennbar ist oder die Aufgabe an einem Fakt, einer Datei oder einem Zugang hängt, den nur der Nutzer hat. Sonst handeln und die gewählte Lesart in der Schlussnachricht nennen. Die Zustimmung zu einer Wahl, die das Modell selbst treffen kann, ist kein Grund zu fragen.
|
||||
- Schwer umkehrbare und nach außen wirkende Schritte brauchen weiter die Bestätigung. Will der Nutzer etwas vorher freigeben, etwa einen Plan, dort anhalten; eine reine Reihenfolge wie „erst planen, dann bauen" ist kein Haltepunkt. Eine Frage oder ein offenes Abwägen will eine Antwort, keine Änderung; ist zusätzlich Arbeit verlangt, erst antworten, dann arbeiten.
|
||||
- Dateiänderungen im Arbeitsbaum gelten nicht als schwer umkehrbar, solange sie keine laufenden Änderungen des Nutzers überschreiben. Offene Entscheidungen trifft das Modell selbst und listet sie in der Schlussnachricht.
|
||||
- Ist ein Teil blockiert, den Rest fertig machen und die Schlussnachricht mit dem Blockierten beginnen; einen vermutlich scheiternden Schritt erst versuchen. Das Projekt bau- und testfähig machen, etwa deklarierte Abhängigkeiten installieren, zählt zur Arbeit.
|
||||
- **Wo der Absatz auf Vault-Regeln trifft:**
|
||||
|
||||
| Der Absatz sagt | Im Vault gilt |
|
||||
|---|---|
|
||||
| Zustimmung zu einer Wahl, die das Modell selbst treffen kann, ist kein Grund zu fragen | Jede Freigabe aus Stamm und Regelwerk bleibt Pflicht, etwa für Produktivsysteme, Push und Echtgeld |
|
||||
| „Erst planen, dann bauen" ist kein Haltepunkt | Die Standardschleife aus [[AI/Regelwerk/codeworkflow|codeworkflow.md]] legt die Schritte fest; der Absatz ändert sie nicht |
|
||||
| Deklarierte Abhängigkeiten installieren zählt zur Arbeit | `executer.md`: keine neuen Abhängigkeiten ohne Auftrag; im Zweifel entscheidet der Auftrag |
|
||||
|
||||
- **Der Stamm geht vor.** Jede Regel aus [[CLAUDE|Claude.md]] gilt unverändert, auch wo der eingefügte Absatz zum Weitermachen drängt.
|
||||
- **Modellwechsel mitten in der Sitzung:** Laut Doku verwirft die API die Thinking-Blöcke von Opus 5, Opus 5.5, Sonnet 5.5 sowie den Fable- und Mythos-Modellen ohne Fehler, wenn Haiku 5.5 übernimmt. Wer von Opus auf Haiku wechselt, verliert das frühere Denken; sichtbarer Text und Werkzeugergebnisse bleiben. Umgekehrt lesen Opus 5.5 und Sonnet 5.5 auf der Claude-API und Google Cloud die Blöcke von Haiku 5.5. In Claude Code nicht beobachtet. Vor einem Wechsel auf Haiku wichtige Zwischenstände als Text oder Datei festhalten.
|
||||
- **Das Sitzungsprotokoll** aus dem Stamm gilt für jedes Modell.
|
||||
|
||||
## A6 Prüfpunkte statt Garantie
|
||||
|
||||
| Fehlerquelle | Prüfpunkt |
|
||||
|---|---|
|
||||
| Executer weicht still ab | Byte-Vergleich Plan gegen Datei, Pflicht wie bei jedem Modell ([[AI/Regelwerk/codeworkflow|codeworkflow.md]], Schritt 4) |
|
||||
| Escape-Folgen | Byte-Vergleich. Am 2026-10-09 stand die Escape-Folge über den Write-Weg in 5 von 5 Läufen zuerst als echtes Zeichen in der Werkzeugeingabe; sichtbar nur per Bytesuche. Beim Schreiben des Messberichts traf es auch den Koordinator auf Opus 5.5, im Write-Werkzeug wie im Bash-Heredoc |
|
||||
| Backslashes | Über den Bash-Heredoc-Weg gingen sie in 3 von 3 Läufen (1 Haiku, 2 Sonnet) zuerst verloren; sichtbar als SyntaxWarning bei grünen Tests, also Testausgabe ganz lesen |
|
||||
| Fertigmeldung ohne Prüfung | Prüfbefehl mit Erwartung im Auftrag; der Koordinator wiederholt ihn selbst (B3) |
|
||||
| Frühes Aufhören bei langem Auftrag | Weiterarbeiten-Zeile aus A4 im Auftrag; offene Teile stehen im Bericht |
|
||||
| Hilfsdateien trotz Verbot | Wieder gelöschte Dateien und gescheiterte Schreibversuche zeigt kein Vergleich danach, nur das Transkript; bei Verdacht dort die Werkzeugaufrufe lesen. Beide Prüfstände vom 2026-10-09 hatten je mindestens einen solchen Lauf (A3) |
|
||||
| Effort geerbt statt gesetzt | Feld `effort` im Transkript; ein Agent ohne `agentType` bekommt `effort` |
|
||||
| Ablehnung ohne Ausweichmodell | Bericht führt sie als abgelehnt, nicht umformulieren, bis es durchgeht ([[AI/Regelwerk/sonnet-5|sonnet-5.md]], B4, sinngemäß); B9 |
|
||||
| Denken nach Modellwechsel verloren | Zwischenstände vor dem Wechsel auf Haiku als Text oder Datei (A5) |
|
||||
|
||||
## A7 Angenommen, Umsetzung offen
|
||||
|
||||
Pascal hat die Vorschläge am 2026-10-09 angenommen; umgesetzt werden sie als eigene Aufgabe, weil die Workflows Fall- und Mutantensuiten haben.
|
||||
|
||||
| Stelle | Befund | Umsetzung |
|
||||
|---|---|---|
|
||||
| `verbrauch.js`: Haiku-Ablesung ohne `effort` | läuft mit dem Effort der Sitzung, am 2026-10-09 `max` | `effort: 'low'` setzen und die Fälle in `faelle_workflows.mjs` um den Effort ergänzen; als eigene Aufgabe angelegt |
|
||||
| `executer-welle.js`: Task-Effort bei `haiku` verworfen, Logzeile „wirkungslos"; Kommentare „etwa low für Abschrift mit typografischen Zeichen" und „Haiku kennt keinen Effort" | stimmt seit Haiku 5.5 nicht mehr | Effort durchreichen wie bei Sonnet, Kommentar und Logzeile berichtigen; dieselbe Aufgabe |
|
||||
| `plankritik.js`, Linse „abdeckung": verlangt für Abschrift mit typografischen Zeichen `modell sonnet` und `effort low` statt `haiku` | würde jeden Plan nach der neuen Regel in Schritt 3 als Fehler melden | Linsentext an die Entscheidung vom 2026-10-09 anpassen, Fälle der Plankritik mitziehen; dieselbe Aufgabe |
|
||||
| Codex-Hilfsagenten im Quorum auf `sonnet` statt `haiku` (Kommentar in `quorum.js`) | Die Begründung beruht auf Haiku 4.5; die Ausnahme ist für Haiku 5.5 seit 2026-10-09 aufgehoben | Kommentar berichtigen; ob die Hilfsagenten auf `haiku` wechseln, gehört in dieselbe Aufgabe |
|
||||
|
||||
# Teil B — Verhalten und Prompt-Muster
|
||||
|
||||
Aus „Prompting Claude Haiku 5.5" (Rohtext 2026-10-09). Bestehende Haiku-4.5-Prompts laufen laut Doku ohne Änderung gut. Antwortlänge, Formatierung, Fortschrittsmeldungen, parallele Werkzeugaufrufe und Delegation behandelt die Seite nicht. Die Prompttexte der Doku stehen hier sinngemäß auf Deutsch; den Wortlaut hat die Doku im jeweiligen Abschnitt.
|
||||
|
||||
## B1 Effort und Thinking (Sitzung, API-Integration)
|
||||
|
||||
- `low`: billigste und schnellste Stufe; für Chat, kurze Werkzeugaufgaben und einfache Massenanfragen. In langen Agent-Prompts überspringt das Modell hier eher eine Suche, hört früh auf oder lässt eine Prüfung aus.
|
||||
- `medium`: Standard; Start für die meiste Arbeit, auch für agentisches Coding.
|
||||
- `high`: für Wissensarbeit, längere Agentenaufgaben und strenges Befolgen von Anweisungen.
|
||||
- `xhigh` und `max`: nur, wenn eigene Evals einen Qualitätsgewinn zeigen. Denken und Antworten werden deutlich länger; dann laut Doku auch Sonnet 5.5 auf Leistung, Kosten und Tempo vergleichen.
|
||||
- Thinking ist standardmäßig an und zählt zu `max_tokens` (bis 128.000). Wer weniger Denken will, senkt den Effort; die Anweisung im Prompt, direkt zu antworten, stoppte das Denken in Anthropics Tests nicht.
|
||||
- Sitzung: Claude Code lässt Thinking für Haiku 5.5 nicht abschalten (Katalog `rejects_disabled_thinking`, Meldung „Thinking can't be turned off" im Abbild 2.1.296; gelesen, nicht gelaufen).
|
||||
- API-Integration: `thinking: {"type": "disabled"}` geht nur bei `low`, `medium` und `high`, bei `xhigh` und `max` kommt 400.
|
||||
- API-Integration: Auf `xhigh` schreibt das Modell in mehrstufigen Chats manchmal die ganze Antwort ins Thinking und endet ohne sichtbaren Text. Jede Antwort auf Leere prüfen.
|
||||
- API-Integration: Ein geänderter Effort zwischen Anfragen entwertet den Prompt-Cache der Nachrichten. Ein Effort-Wechsel je Nachricht (Beta, Claude-API und Google Cloud, Header `mid-conversation-output-config-2026-07-01`, nur mit adaptivem Thinking) behält ihn.
|
||||
|
||||
## B2 Frühes Aufhören und Zusatzarbeit (Sitzung)
|
||||
|
||||
- Mit kurzem Systemprompt hört Haiku 5.5 selten zu früh auf. Mit langem Coding-Agent-Systemprompt auf `low` gibt es die Aufgabe manchmal früh an den Nutzer zurück.
|
||||
- Gegenmittel laut Doku, sinngemäß im Systemprompt, zwei Teile: (1) weiterarbeiten, bis alles Verlangte erledigt ist, und nur fragen, wenn es ohne den Nutzer nicht weitergeht oder vor einem riskanten Schritt; (2) ist die Arbeit erledigt und geprüft, aufhören und berichten, keine ungefragten Features, Doku oder Refactorings, Vorschläge ans Ende.
|
||||
- Im Vault deckt der Stoppsatz der Executer-Vorlage ([[AI/Regelwerk/sonnet-5-5|sonnet-5-5.md]], A2) nur Teil (2). Die gleichlautende Regel in `.claude/agents/executer.md` steht im Abschnitt zu Sonnet 5.5; für Haiku trägt also die Vorlage. Teil (1) steht für lange Haiku-Aufträge in A4. Für die Hauptsitzung fügt Claude Code einen eigenen Absatz ein (A5).
|
||||
- Höherer Effort hilft ebenfalls: Ohne den Text halbierte der Schritt von `low` auf `medium` das frühe Aufhören etwa und mehr als verdoppelte die Ausgabetokens je Versuch (Anthropics Tests).
|
||||
- API-Integration: Neue Systemprompt-Texte nur in neuen Gesprächen ergänzen. Ein Gespräch, das mit geändertem `system` Thinking-Blöcke zurückschickt, kann mit 400 scheitern. Mitten im Gespräch gehört eine neue Anweisung in den neuesten Zug oder, auf Claude-API, Bedrock und Google Cloud, in eine System-Nachricht.
|
||||
|
||||
## B3 Änderungen echt prüfen (Sitzung)
|
||||
|
||||
- Auf `low` und `medium` meldet Haiku 5.5 eine Codeänderung manchmal als erledigt, ohne eine Prüfung gefahren zu haben.
|
||||
- Gegenmittel laut Doku, sinngemäß im Systemprompt: Nach einer lauffähigen Codeänderung eine echte Prüfung fahren, die die Änderung ausübt — Tests, Typprüfung, Build oder der geänderte Befehl selbst. Eine reine Syntaxprüfung oder ein Prüfbefehl, der nicht startete, zählt nicht. Fehlen nur die deklarierten Abhängigkeiten, sie mit Paketmanager und Lockfile des Projekts installieren, nie über `sudo` oder den Systempaketmanager, sofern nicht anders angewiesen. Geht keine echte Prüfung, sagen, welche nicht lief und warum, statt die Änderung als erledigt zu melden.
|
||||
- In Anthropics Tests prüfte das Modell damit öfter und leistete mehr, bei mehr Tokens.
|
||||
- Im Vault abgedeckt durch `executer.md` (Arbeitsweise Punkt 4) und den Prüfbefehl mit Erwartung im Auftrag. Den Satz „Syntaxprüfung zählt nicht" führt `executer.md` im Abschnitt zu Sonnet 5.5; für Haiku steht er dort nicht ausdrücklich.
|
||||
|
||||
## B4 Suche und Datum (Sitzung, API-Integration)
|
||||
|
||||
- Mit einem Suchwerkzeug das heutige Datum mitgeben, im Systemprompt oder in der Werkzeugbeschreibung. Das Datum einmal zu Gesprächsbeginn einsetzen und `system` und `tools` danach unverändert lassen; an einem späteren Tag das neue Datum im neuesten Zug nennen.
|
||||
- Auf `low` und bei langen Systemprompts sucht Haiku 5.5 manchmal nicht. Gegenmittel laut Doku, sinngemäß direkt nach dem Datum: Das Training endet lange vor heute; Rekorde, Amtsinhaber, Preise, Versionen, Regeln und alles „Neueste" vor der Antwort suchen, auch wenn du dir sicher bist; Unveränderliches braucht keine Suche; hängt die Antwort vom Ort ab, Land oder Region in die Suchanfrage.
|
||||
- Wirkung in Anthropics Tests: mehr Suchen bei Fragen mit veränderter Antwort, bei Fragen ohne Suchbedarf nur 0 bis 3 Prozent zusätzliche Suchen. Bei kurzem Systemprompt kann der Zusatztext entfallen; auf `medium` ließ dort schon das Datum allein das Modell öfter suchen.
|
||||
- Pauschalsätze wie „bei jeder Gegenwartsfrage suchen, egal wie sicher" vermeiden: In Anthropics Tests suchte das Modell damit bei der Hälfte der Fragen ohne Bedarf, ohne mehr richtige Antworten.
|
||||
- Im Vault: Der Suchsatz der Recherche-Vorlage ([[AI/Regelwerk/sonnet-5-5|sonnet-5-5.md]], A3) gilt auch, wenn ein Recherche-Auftrag auf Haiku läuft.
|
||||
|
||||
## B5 JSON-Ausgabe mit eigenen Werkzeugen (API-Integration)
|
||||
|
||||
- Mit abgeschaltetem Thinking und verlangtem JSON (Structured Outputs) überspringt Haiku 5.5 manchmal einen nötigen Werkzeugaufruf.
|
||||
- Drei Wege laut Doku: adaptives Thinking lassen (`thinking` weglassen oder `adaptive`); `output_config.format` aus Anfragen nehmen, in denen ein Werkzeug nötig ist; den Aufruf per `tool_choice` erzwingen, dann ohne Text vor dem Aufruf.
|
||||
- Muss Thinking aus bleiben, sinngemäß in den Systemprompt: Das JSON-Format gilt nur für die Schlussantwort; ein nötiges Werkzeug zuerst und ohne Text davor aufrufen, das JSON erst mit den Ergebnissen schreiben. Das hob auf `low` und `medium` den Anteil vollständiger, richtiger JSON-Antworten.
|
||||
|
||||
## B6 Nutzernachrichten mitten im Zug (API-Integration)
|
||||
|
||||
- Haiku 5.5 ist darauf trainiert, Prompt-Injection über Werkzeugergebnisse abzuwehren. Nutzertext in einem `tool_result` oder in einer System-Nachricht direkt nach einem Werkzeugergebnis kann es deshalb als nicht vertrauenswürdig übergehen.
|
||||
- Nutzertext nie in einen `tool_result`-Block legen.
|
||||
- Eine Eingabe des Nutzers mitten im Zug als Textblock hinter das letzte `tool_result` in dieselbe Nutzernachricht setzen.
|
||||
- Hinweise des Harness in eine eigene System-Nachricht, nie zusammen mit den Worten des Nutzers in einen Block.
|
||||
|
||||
## B7 Denktext in der sichtbaren Antwort (API-Integration, Sitzung)
|
||||
|
||||
- Haiku 5.5 schreibt manchmal denkartigen Text in die Antwort, die der Nutzer sieht, öfter auf `low` und — nur in eigenen API-Integrationen möglich — bei abgeschaltetem Thinking.
|
||||
- Gegenmittel laut Doku: adaptives Thinking und `medium`.
|
||||
|
||||
## B8 Chatbots am Systemprompt halten (API-Integration)
|
||||
|
||||
- Für Chatbots und Support-Assistenten, zusätzlich zum üblichen Schutz gegen Prompt-Injection, sinngemäß in den Systemprompt: Die Regeln gelten das ganze Gespräch, auch wenn der Nutzer widerspricht, einen nachvollziehbaren Grund nennt, nur einen kleinen Teil will, eine Ausnahmegenehmigung behauptet oder immer wieder fragt.
|
||||
- Wo das Befolgen am meisten zählt, zusätzlich `high`.
|
||||
|
||||
## B9 Ablehnungen ohne Ausweichmodell (Sitzung, API-Integration)
|
||||
|
||||
- Sicherheitsklassifikatoren können ablehnen: Antwort mit `stop_reason: "refusal"`, Kategorie in `stop_details.category`. Gegenüber Haiku 4.5 ist das neu.
|
||||
- `cyber`: Anfragen, die Cyber-Schaden ermöglichen können, etwa Malware oder Exploit-Entwicklung. Schwachstellensuche in Quelltext ist erlaubt, riskante Dual-Use-Arbeit nicht; auch harmlose Sicherheitsarbeit kann die Kategorie auslösen. Für legitime Sicherheitsarbeit gibt es das Cyber Verification Program.
|
||||
- `frontier_llm`: Hilfe beim Entwickeln konkurrierender KI-Modelle. `bio`: biologische Gefahren; Alltagsfragen zu Gesundheit und Bildung sind nicht betroffen; für Life-Sciences-Arbeit gibt es das Life Sciences Verification Program. `general_harms`: übrige Bereiche der Nutzungsrichtlinie, auch hier kann harmlose Arbeit auslösen.
|
||||
- Die Haiku-Seite nennt diese vier Kategorien. Die allgemeine Seite „Refusals and fallback" kennt zusätzlich `reasoning_extraction`; ob Haiku 5.5 sie liefert, sagt sie nicht ausdrücklich. Eine Ablehnung vor jeder Ausgabe wird dort bei `bio`, `frontier_llm` und `reasoning_extraction` berechnet (Stand September 2026; die Liste kann sich ändern).
|
||||
- **Kein serverseitiges Ausweichen und kein Fallback-Guthaben.** Dieselbe Anfrage noch einmal an Haiku 5.5 bringt laut Doku meist wieder eine Ablehnung. API-Integration: clientseitig auf ein anderes Modell ausweichen, über die Refusal-Fallback-Middleware des SDK oder einen eigenen Retry. Ohne Fallback-Guthaben zahlt das Ausweichen das Cache-Schreiben des Ausweichmodells voll.
|
||||
- Sonnet 5.5 weicht bei `cyber` und `frontier_llm` auf Sonnet 5 aus ([[AI/Regelwerk/sonnet-5-5|sonnet-5-5.md]], C3), Haiku 5.5 nicht. Für den Vault: Bei Tasks aus Härtungs-, Firewall- und Sicherheitsprojekten bringt `modell: haiku` keinen Ausweichweg. Lehnt ein Haiku-Executer ab, führt er das im Bericht als abgelehnt (A6).
|
||||
|
||||
# Teil C — Spezifikation und API
|
||||
|
||||
## C1 Spezifikation
|
||||
|
||||
| Punkt | Wert | Quelle |
|
||||
|---|---|---|
|
||||
| Modell-ID | `claude-haiku-5-5`; veröffentlicht 2026-10-07, Stilllegung nicht vor 2027-10-07 | Doku, Übersicht |
|
||||
| Plattformen | Claude-API, Amazon Bedrock (`anthropic.claude-haiku-5-5`), Google Cloud, Microsoft Foundry, Claude Platform on AWS | Doku, Übersicht |
|
||||
| Kontext / Ausgabe | 1M / 128k; Batch bis 300k mit Header `output-300k-2026-03-24` | Doku; Katalog 1M / 128k |
|
||||
| Preis je Mio. Tokens, Prompt bis 100.000 Tokens | 0,10 $ Eingabe, 0,50 $ Ausgabe, 0,125 $ Cache-Schreiben 5 min, 0,20 $ Cache-Schreiben 1 h, 0,01 $ Cache-Lesen | Doku; Katalog `haiku_55` |
|
||||
| Preis je Mio. Tokens, Prompt über 100.000 Tokens | 0,50 $, 2,50 $, 0,625 $, 1 $, 0,05 $ | Doku; Katalog `haiku_55` |
|
||||
| Was als Promptlänge zählt | alle Eingabetokens einer Anfrage, auch Cache-Lesen und Cache-Schreiben; jede Anfrage wird einzeln eingestuft | Doku, Preise |
|
||||
| Batch | 50 % Nachlass auf Eingabe und Ausgabe | Doku, Übersicht |
|
||||
| Cache-Lesen | 10 % des Eingabepreises (Opus 5.5 und Sonnet 5.5: 5 %) | Doku, Übersicht |
|
||||
| Cache-Mindestlänge | 512 Tokens (Haiku 4.5: 4.096) | Doku, What's new |
|
||||
| Wissensstand | Juni 2026 | Doku; Katalog |
|
||||
| Effort | alle fünf Stufen; Standard `medium` auf der API und in Claude Code | Doku; Katalog `default_effort` |
|
||||
| Kostenfaktoren je Stufe | im Katalog nicht hinterlegt | Katalog |
|
||||
| Latenz | „Fastest" in der Vergleichstabelle (Sonnet 5.5: „Fast") | Doku, Übersicht |
|
||||
| Tokenizer | wie Claude 4.7 und später; derselbe Text etwa 30 % mehr Tokens als bei Haiku 4.5 | Doku, What's new |
|
||||
| Bilder | hochauflösende Stufe; große Bilder kosten mehr visuelle Tokens als bei Haiku 4.5 (Rechenbeispiel der Doku: 2000 × 1500 px etwa das 2,5-Fache) | Doku, Migration |
|
||||
| Priority Tier | nicht unterstützt | Doku, Migration |
|
||||
| Fast Mode | nicht in der Liste der unterstützten Modelle (dort nur Opus) | Doku, Fast Mode |
|
||||
| Datenhaltung | kein Covered Model: Die 30-Tage-Pflicht gilt nur für Fable 5.1, Mythos 5.1, Fable 5 und Mythos 5. Eine eigene Aussage zu Zero Data Retention für Haiku 5.5 gibt es nicht | Doku, API and data retention |
|
||||
| Fähigkeiten im Katalog 2.1.296 | `effort`, `max_effort`, `xhigh_effort`, `adaptive_thinking`, `rejects_disabled_thinking`, `per_turn_effort`, `mid_conv_tool_change`, `context_management`, `lean_prompt`, `org_locked_thinking`, `haiku_5_5_early_stopping_guidance`; kein `refusal_fallback`, kein `mid_conv_system` | Katalog |
|
||||
| Widersprüche Katalog gegen Doku | `rejects_disabled_thinking` gegen „`disabled` bis `high` erlaubt": Claude Code schaltet Thinking nicht ab, die Erlaubnis gilt nur für eigene API-Integrationen. Fehlendes `mid_conv_system` gegen die Doku, siehe C5 | Katalog; Doku |
|
||||
|
||||
## C2 Brüche und Änderungen gegenüber Haiku 4.5 (API-Integration)
|
||||
|
||||
Brüche mit 400:
|
||||
|
||||
- `thinking: {"type": "enabled", "budget_tokens": N}`. Ersatz: `thinking` weglassen oder `{"type": "adaptive"}`, gesteuert über den Effort.
|
||||
- `temperature`, `top_p`, `top_k`: erlaubt sind nur `temperature` 1 und `top_p` 0,99. Jeder andere Wert liefert 400, auch `top_p` 1, jeder `top_k`-Wert und `temperature` zusammen mit `top_p`.
|
||||
- Prefill, also eine abschließende Assistant-Nachricht, auch bei abgeschaltetem Thinking. `messages` endet mit einer Nutzernachricht.
|
||||
- `computer_20250124` auf Claude-API und Google Cloud. Ersatz: `computer_toolset_20260801`.
|
||||
- Thinking-Blöcke zurückschicken, nachdem `system`, `tools` oder frühere `messages` geändert wurden. Gespräche nur anhängen, nie ändern ([[AI/Regelwerk/api-mechanik|api-mechanik.md]]). Konten von vor dem 2026-08-31, 00:00 UTC, bekommen den Fehler nur mit gesetztem `thinking.block_binding.prefix_mismatch_behavior`.
|
||||
|
||||
Weitere Brüche, Fehlerbild in der Doku nicht genannt:
|
||||
|
||||
- `computer_20250124` nimmt Haiku 5.5 auch auf Bedrock nicht an. Ersatz dort: `computer_20251124` mit Header `computer-use-2025-11-24`.
|
||||
- Structured Outputs gibt es für Haiku 5.5 auf Bedrock nicht; dort das Format im Prompt beschreiben oder ein Werkzeug ohne `strict` nutzen und die Ausgabe im Code prüfen.
|
||||
- Ablehnungen über `stop_reason: "refusal"` sind neu (B9).
|
||||
- Priority Tier fällt weg (C1).
|
||||
|
||||
Geändert:
|
||||
|
||||
- Eine Antwort kann mit Thinking-Blöcken beginnen; Inhaltsblöcke nach `type` wählen, nicht nach Position.
|
||||
- Thinking-Text kommt standardmäßig leer zurück, nur mit Signatur; eine Zusammenfassung gibt es mit `"display": "summarized"`.
|
||||
- Thinking zählt zu `max_tokens`. Ein kleines `max_tokens` aus Haiku-4.5-Zeiten kann nach dem Thinking-Block und vor jedem Text enden.
|
||||
- Thinking-Blöcke aller früheren Züge bleiben im Kontext und zählen als Eingabe; Haiku 4.5 behielt nur die des letzten Zugs. Entfernen über Thinking Block Clearing.
|
||||
- Thinking-Blöcke gelten nur im erzeugenden oder einem damit verknüpften Konto.
|
||||
- Derselbe Text zählt etwa 30 % mehr Tokens, große Bilder mehr visuelle Tokens (C1): Prompts, `max_tokens` und Kostenschätzungen neu zählen.
|
||||
- Context-Awareness-Tags werden nicht eingefügt; für ein Budget in Agentenschleifen gibt es Task Budgets (Beta, Header `task-budgets-2026-03-13`).
|
||||
|
||||
Neu: das Browser-Use-Werkzeug auf Claude-API und Google Cloud.
|
||||
|
||||
## C3 Unterschiede zu Sonnet 5.5 (API-Integration)
|
||||
|
||||
| Punkt | Haiku 5.5 | Sonnet 5.5 |
|
||||
|---|---|---|
|
||||
| Preis je Mio. Tokens | 0,10 $ / 0,50 $, über 100.000 Prompt-Tokens 0,50 $ / 2,50 $ | 2 $ / 10 $ |
|
||||
| Cache-Lesen | 10 % des Eingabepreises | 5 % |
|
||||
| Standard-Effort auf der API | `medium` | `high` |
|
||||
| Thinking abschalten | `disabled` bis `high` erlaubt (nicht in Claude Code, C1) | `disabled` liefert 400 ([[AI/Regelwerk/sonnet-5-5|sonnet-5-5.md]], C2) |
|
||||
| Erzwungene Werkzeugwahl (`tool_choice` `any` oder `tool`) | angenommen, die Antwort beginnt dann ohne Thinking-Block mit dem Aufruf | 400 |
|
||||
| Serverseitiges Ausweichen bei Ablehnung | keins, auch kein Fallback-Guthaben | Sonnet 5 für `cyber` und `frontier_llm` |
|
||||
| Latenz laut Vergleichstabelle | „Fastest" | „Fast" |
|
||||
| Gleich | 1M / 128k, Wissensstand Juni 2026, Sampling-Grenzen, Prefill-Verbot, Ausgabe nur Text | |
|
||||
|
||||
## C4 Thinking-Blöcke zwischen Modellen (API-Integration, Sitzung)
|
||||
|
||||
- Haiku 5.5 liest die Thinking-Blöcke von Sonnet 5, Opus 4.8, Haiku 4.5 und älteren Modellen. Ein Gespräch, das von Haiku 4.5 auf Haiku 5.5 wechselt, behält sein Denken.
|
||||
- Die Blöcke von Opus 5, Opus 5.5, Sonnet 5.5 und allen Fable- und Mythos-Modellen liest es nicht; die API verwirft sie ohne Fehler.
|
||||
- Auf Claude-API und Google Cloud lesen Opus 5.5 und Sonnet 5.5 die Blöcke von Haiku 5.5.
|
||||
- Folge für die Sitzung: A5, „Modellwechsel mitten in der Sitzung".
|
||||
|
||||
## C5 Weitere Funktionen
|
||||
|
||||
- Effort je Nachricht: Beta, Claude-API und Google Cloud, nicht Bedrock (B1).
|
||||
- System-Nachrichten mitten im Gespräch: laut Doku auf Claude-API, Bedrock und Google Cloud. Der Katalog von Claude Code 2.1.296 führt für Haiku 5.5 aber kein `mid_conv_system`; welche Seite für Claude Code gilt, ist offen. Nutzertext gehört trotzdem in den Nutzerzug (B6).
|
||||
- Werkzeugwechsel mitten im Gespräch: Beta auf denselben Modellen, auf der Claude-API mit Header `inline-tools-2026-09-15`. Für Änderungen, die ein Werkzeug per Referenz nennen, gilt der Header `mid-conversation-tool-changes-2026-07-01` auf Claude-API, Bedrock und Google Cloud.
|
||||
- Task Budgets: Beta (C2).
|
||||
- Computer Use nur über das Toolset (C2); dazu das Browser-Use-Werkzeug.
|
||||
|
||||
## Wohin die Punkte im Regelwerk zeigen
|
||||
|
||||
| Regelwerk-Datei | Verweist auf Abschnitt |
|
||||
|---|---|
|
||||
| [[CLAUDE|Claude.md]] (Rollentabelle, Regelwerk-Liste) | Gesamtdatei |
|
||||
| [[AI/Regelwerk/codeworkflow|codeworkflow.md]] (Schritt 3, Quorum, Effort je Rolle) | A1, A3, A7 |
|
||||
| [[AI/Regelwerk/sonnet-5|sonnet-5.md]] (C3, Haiku 4.5) | Gesamtdatei, A1 |
|
||||
| [[AI/Regelwerk/fable-5-1|fable-5-1.md]] (Geltungsbereich) | Gesamtdatei |
|
||||
| [[AI/Regelwerk/prompting|prompting.md]] (Geltungsbereich) | Gesamtdatei |
|
||||
| `.claude/agents/planer.md` (Kriterium `modell:`, typografische Zeichen) | A3, A4 |
|
||||
|
||||
## Referenzen
|
||||
|
||||
- [[CLAUDE|↑ Claude.md (Stamm)]] — Rollentabelle
|
||||
- [[AI/Regelwerk/codeworkflow|codeworkflow.md]] — Standardschleife, Modellzuordnung, Effort je Rolle, Quorum
|
||||
- [[AI/Regelwerk/sonnet-5-5|sonnet-5-5.md]] — Auftragsvorlagen für Executer und Recherche
|
||||
- [[AI/Regelwerk/sonnet-5|sonnet-5.md]] — Haiku 4.5 (C3), Cyber-Schutz (B4)
|
||||
- [[AI/Regelwerk/opus-5|opus-5.md]] und [[AI/Regelwerk/fable-5-1|fable-5-1.md]] — die Schwestermodelle
|
||||
- [[AI/Regelwerk/prompting|prompting.md]] — modellübergreifende Techniken
|
||||
- [[AI/Regelwerk/api-mechanik|api-mechanik.md]] — Mechanik für eigene API-Integrationen
|
||||
- [[AI/secondbrain/regelwerk-memory/2026-10-09-haiku-5-5-messung|Messbericht Haiku 5.5]] — Rohwerte der Messung
|
||||
- Quellen (Rohtext abgerufen 2026-10-09): https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-haiku-5-5, https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5, https://platform.claude.com/docs/en/models/haiku-5-5/overview, https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide, https://platform.claude.com/docs/en/build-with-claude/effort, https://platform.claude.com/docs/en/about-claude/pricing, https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback, https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages, https://platform.claude.com/docs/en/build-with-claude/task-budgets, https://platform.claude.com/docs/en/build-with-claude/fast-mode, https://platform.claude.com/docs/en/build-with-claude/thinking, https://platform.claude.com/docs/en/build-with-claude/context-windows, https://platform.claude.com/docs/en/build-with-claude/api-and-data-retention
|
||||
@@ -5,13 +5,13 @@ title: Prompting-Grundlagen für aktuelle Claude-Modelle
|
||||
summary: Die allgemeinen Prompt-Techniken aus der Anthropic-Doku „Prompting best practices" — Klarheit, Beispiele, XML-Struktur, Werkzeugnutzung, Thinking, lange Aufgaben, Subagenten. Verbindlich für Fable 5.1; andere Modelle entscheiden selbst.
|
||||
tags: [regelwerk, modelle, prompting, subagenten]
|
||||
created: 2026-09-05
|
||||
updated: 2026-09-29
|
||||
updated: 2026-10-09
|
||||
source: https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices
|
||||
---
|
||||
|
||||
# Prompting-Grundlagen für aktuelle Claude-Modelle
|
||||
|
||||
> **Geltungsbereich.** Anthropic führt diese Seite als Referenz für **alle** aktuellen Modelle (Fable 5.1, Mythos 5.1, Fable 5, Opus 5, Opus 4.8 bis 4.6, Sonnet 5, Sonnet 4.6, Haiku 4.5). Im Vault gilt trotzdem dieselbe Regel wie für [[AI/Regelwerk/fable-5-1|fable-5-1.md]]: **Verbindlich nur für Claude Fable 5.1.** Opus 5, Sonnet 5 und Haiku 4.5 arbeiten nach ihren eigenen Optimierungen und entscheiden selbst, ob sie einen Punkt übernehmen. Wo die Doku eine Technik an einem bestimmten Modell gemessen hat, steht das Modell dabei — Anthropic selbst sagt, man solle sie vor der Übertragung auf ein anderes Modell an eigenen Evals nachprüfen.
|
||||
> **Geltungsbereich.** Anthropic führt diese Seite als Referenz für **alle** aktuellen Modelle (Fable 5.1, Mythos 5.1, Fable 5, Opus 5, Opus 4.8 bis 4.6, Sonnet 5, Sonnet 4.6, Haiku 4.5). Im Vault gilt trotzdem dieselbe Regel wie für [[AI/Regelwerk/fable-5-1|fable-5-1.md]]: **Verbindlich nur für Claude Fable 5.1.** Opus 5, Sonnet 5, Haiku 4.5 und Haiku 5.5 ([[AI/Regelwerk/haiku-5-5|haiku-5-5.md]]) arbeiten nach ihren eigenen Optimierungen und entscheiden selbst, ob sie einen Punkt übernehmen. Wo die Doku eine Technik an einem bestimmten Modell gemessen hat, steht das Modell dabei — Anthropic selbst sagt, man solle sie vor der Übertragung auf ein anderes Modell an eigenen Evals nachprüfen.
|
||||
> Angeordnet am 2026-09-05. Quelle abgerufen am 2026-09-05. Aussagen stammen aus der Doku, nicht aus eigener Messung.
|
||||
|
||||
## Wozu diese Datei
|
||||
@@ -100,7 +100,7 @@ Randnotiz: Opus 4.5 ohne Thinking reagiert empfindlich auf das Wort „think"
|
||||
|
||||
**Lange Aufgaben und Zustand.** Aktuelle Modelle halten über lange Sitzungen die Orientierung, indem sie schrittweise vorgehen — wenige Dinge zugleich, stetig. Das trägt über mehrere Kontextfenster: arbeiten, Zustand sichern, in frischem Kontext weitermachen.
|
||||
|
||||
**Kontextbewusstsein** haben Sonnet 5, Sonnet 4.6, Sonnet 4.5 und Haiku 4.5 — sie kennen ihr verbleibendes Tokenbudget. Läuft ein Harness mit Kompaktierung oder Dateispeicher (wie Claude Code), sagt man das dem Modell, sonst wickelt es bei nahendem Limit von sich aus ab:
|
||||
**Kontextbewusstsein** haben Sonnet 5, Sonnet 4.6, Sonnet 4.5 und Haiku 4.5 — sie kennen ihr verbleibendes Tokenbudget. Haiku 5.5, Sonnet 5.5 und die Opus-Modelle ab 4.7 bekommen die Tags nicht; für ein Budget gibt es dort Task Budgets (Doku „Context windows“, abgerufen 2026-10-09). Läuft ein Harness mit Kompaktierung oder Dateispeicher (wie Claude Code), sagt man das dem Modell, sonst wickelt es bei nahendem Limit von sich aus ab:
|
||||
|
||||
```text
|
||||
Your context window will be automatically compacted as it approaches its limit, allowing you to continue working indefinitely from where you left off. Therefore, do not stop tasks early due to token budget concerns. As you approach your token budget limit, save your current progress and state to memory before the context window refreshes. Always be as persistent and autonomous as possible and complete tasks fully, even if the end of your budget is approaching. Never artificially stop any task early regardless of the context remaining.
|
||||
|
||||
@@ -5,7 +5,7 @@ title: "Arbeiten mit Claude Sonnet 5.5"
|
||||
summary: "Sonnet 5.5 als executer und recherche: Effort je Rolle nach Messung vom 2026-09-29, tokensparende Auftragsvorlagen, Prüfpunkte, Verhalten und Prompt-Muster, Spezifikation und API-Brüche."
|
||||
tags: [regelwerk, modelle, sonnet, prompting]
|
||||
created: 2026-09-29
|
||||
updated: 2026-09-29
|
||||
updated: 2026-10-09
|
||||
source: "https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-sonnet-5-5"
|
||||
---
|
||||
|
||||
@@ -28,7 +28,7 @@ Angeordnet von Pascal am 2026-09-29. Quellen: Anthropic-Doku (abgerufen 2026-09-
|
||||
| Rolle | Effort | Grund |
|
||||
|---|---|---|
|
||||
| `executer` | `medium` | Katalog-Standard und Doku-Empfehlung für gut spezifizierte Agentenarbeit. Die Messung unten stützt die Wahl nur schwach: `low` fiel bei der strengeren Doku-Probe zweimal durch, `medium` einmal, `high` nie, bei gut 50 % mehr Ausgabe |
|
||||
| `executer`, Abschrift mit typografischen Zeichen | `low` | Regel aus [[AI/Regelwerk/codeworkflow|codeworkflow.md]], Schritt 3; auf 5.5 gleich treu wie `high` |
|
||||
| `executer`, Abschrift mit typografischen Zeichen, nur wo `haiku` noch auf Haiku 4.5 auflöst (außerhalb der Anthropic-API) | `low` | Regel aus [[AI/Regelwerk/codeworkflow|codeworkflow.md]], Schritt 3; auf der Anthropic-API läuft solche Abschrift seit 2026-10-09 auf Haiku 5.5; auf 5.5 gleich treu wie `high` |
|
||||
| `recherche` | `medium` | nicht neu gemessen; Doku: `medium` für mehrstufige Werkzeugarbeit, `low` für einfache Subagenten |
|
||||
|
||||
Messung vom 2026-09-29, je Stufe zwei Kopfsitzungen `claude -p --model claude-sonnet-5-5 --effort <stufe>` mit dem Executer-Prompt als `--append-system-prompt`, Effort und Modell aus dem Transkript belegt, Mediane vom `pruefer` nachgerechnet:
|
||||
@@ -41,7 +41,7 @@ Messung vom 2026-09-29, je Stufe zwei Kopfsitzungen `claude -p --model claude-so
|
||||
Was die Messung nicht belegt:
|
||||
|
||||
- Beide Prüfstände sind klein. Lange Aufgaben mit vielen Dateien und Ermessen sind nicht gemessen.
|
||||
- Die Kosten je Lauf (0,17–0,32 $) streuen nach Cache-Treffern der parallel gestarteten Läufe, nicht nach Stufe. Vergleichbar sind nur die Ausgabetokens.
|
||||
- Die Kosten je Lauf (0,17–0,32 $ im Messbericht, vermutlich mit 0,20 $ Cache-Lesen gerechnet; mit dem Tarif aus C1 laut `pruefer` vom 2026-10-09 etwa 0,15–0,30 $) streuen nach Cache-Treffern der parallel gestarteten Läufe, nicht nach Stufe. Vergleichbar sind nur die Ausgabetokens.
|
||||
- Die Abschrift ist auf allen Stufen gleich — gleich fehlerhaft an derselben Stelle. Das liegt an der Schreibschicht, nicht am Modell (Abschnitt A4).
|
||||
- Laut Doku prüft Sonnet 5.5 auf `low` Änderungen manchmal nicht nach. Auf `low` **und** `medium` hält es bei langen Aufgaben eher an und fragt zurück (B2).
|
||||
- Gemessen in Kopfsitzungen ohne Vault-`CLAUDE.md`, nicht als Subagent mit Frontmatter. Gemessen wurden Vorfassungen von `executer.md` (ohne den Stoppsatz aus A2) und `schreibstil.md`.
|
||||
@@ -141,7 +141,7 @@ Aus „Prompting Claude Sonnet 5.5". Die Seite behandelt Antwortlänge, Code-Rev
|
||||
|---|---|---|
|
||||
| Modell-ID | `claude-sonnet-5-5`, veröffentlicht 2026-09-28 | Doku, Übersicht |
|
||||
| Kontext / Ausgabe | 1M / 128k (Doku, Katalog); Batch bis 300k mit `output-300k-2026-03-24` (nur Doku) | Doku; Katalog |
|
||||
| Preis je Mio. Tokens | 2 $ Eingabe, 10 $ Ausgabe, 0,20 $ Cache-Lesen (wie Sonnet 5) | Doku; Katalog `tier_2_10` |
|
||||
| Preis je Mio. Tokens | 2 $ Eingabe, 10 $ Ausgabe, 0,10 $ Cache-Lesen (5 % des Eingabepreises; Sonnet 5: 0,20 $) | Doku, Preise; Katalog `tier_2_10_cache_read_0_10`, nachgelesen 2026-10-09 |
|
||||
| Cache-Mindestlänge | 512 Tokens (Sonnet 5: 1.024) | Doku |
|
||||
| Wissensstand | Juni 2026 | Doku; Katalog |
|
||||
| Standard-Effort | API: `high`; Claude Code: `medium` | Doku; Katalog `default_effort` |
|
||||
|
||||
@@ -5,7 +5,7 @@ title: Prompting-Hinweise für Claude Sonnet 5
|
||||
summary: Verhaltensunterschiede und Prompt-Muster von Claude Sonnet 5 (Teil A) sowie Spezifikation, API-Brüche, Tokenizer, Cyber-Schutz, ZDR-Fähigkeit (Teil B) aus der Anthropic-Doku. Betrifft den Executer und die Recherche-Agenten.
|
||||
tags: [regelwerk, modelle, sonnet, prompting]
|
||||
created: 2026-09-05
|
||||
updated: 2026-09-29
|
||||
updated: 2026-10-09
|
||||
source: https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-sonnet-5
|
||||
---
|
||||
|
||||
@@ -204,7 +204,9 @@ Von Claude 3.x zusätzlich: Sampling-Parameter entfernen; Werkzeugversionen `tex
|
||||
|
||||
## C3 Von Haiku 4.5 — für den Vault der wichtigste Abschnitt
|
||||
|
||||
Haiku 4.5 ist unser Modell für reine Abschrift-Tasks ([[AI/Regelwerk/codeworkflow|codeworkflow.md]], Schritt 3). Der Leitfaden benennt, wie weit Haiku 4.5 und Sonnet 5 auf API-Ebene auseinanderliegen — weiter als benachbarte Modelle einer Klasse:
|
||||
> Seit 2026-10-07 löst `haiku` in Claude Code auf der Anthropic-API auf Haiku 5.5 auf. Dieser Abschnitt beschreibt Haiku 4.5, das der Alias nur noch außerhalb der Anthropic-API wählt (Liste der Anbieter: haiku-5-5.md, A1). Haiku 5.5: [[AI/Regelwerk/haiku-5-5|haiku-5-5.md]].
|
||||
|
||||
Haiku 4.5 war bis 2026-10-07 unser Modell für reine Abschrift-Tasks ([[AI/Regelwerk/codeworkflow|codeworkflow.md]], Schritt 3). Der Leitfaden benennt, wie weit Haiku 4.5 und Sonnet 5 auf API-Ebene auseinanderliegen — weiter als benachbarte Modelle einer Klasse:
|
||||
|
||||
| | Haiku 4.5 | Sonnet 5 |
|
||||
|---|---|---|
|
||||
|
||||
@@ -67,14 +67,14 @@ Rollen sind fest auf Modelle verteilt. **Beim Starten eines Subagenten immer das
|
||||
|
||||
| Rolle | Agent | Modell | Effort |
|
||||
| -------------------------------------------- | ----------------- | ----------------------------------------------- | ---------------------------------------- |
|
||||
| Koordinator (klären, entscheiden, committen) | Hauptsitzung | Opus 5.5 (`opus`) | Sitzungseinstellung |
|
||||
| Koordinator (klären, entscheiden, committen) | Hauptsitzung | Opus 5.5 (`opus`); eine Sitzung auf Haiku 5.5 nur für Fragen und Nachschlagen ([[AI/Regelwerk/haiku-5-5]], A5) | Sitzungseinstellung |
|
||||
| Planen, Spezifizieren | `planer` | Opus 5.5 (`opus`) | `high` (Frontmatter) |
|
||||
| Prüfen, Review, Verifikation | `pruefer` | Opus 5.5 (`opus`) | `high` (Frontmatter) |
|
||||
| Quorum am Meilenstein, nur lesend | `quorum-stimme` | Opus 5.5 (`opus`), im Workflow `quorum` auch `sonnet`, Ersatz `haiku` | `high` (Frontmatter); Haiku kennt keinen |
|
||||
| Umsetzen (Code schreiben, ändern, testen) | `executer` | Sonnet 5.5 (`sonnet`), bei reiner Abschrift Haiku | `medium` (Frontmatter); Haiku kennt keinen |
|
||||
| Quorum am Meilenstein, nur lesend | `quorum-stimme` | Opus 5.5 (`opus`), im Workflow `quorum` auch `sonnet`, Ersatz `haiku` | `high` (Frontmatter), auch für Haiku 5.5 |
|
||||
| Umsetzen (Code schreiben, ändern, testen) | `executer` | Sonnet 5.5 (`sonnet`), bei reiner Abschrift Haiku 5.5 (`haiku`) | `medium` (Frontmatter), auch für Haiku 5.5 |
|
||||
| Recherche, Suche, Erkundung | `recherche` | Sonnet 5.5 (`sonnet`) | `medium` (Frontmatter) |
|
||||
|
||||
Die Aliasse `opus` und `sonnet` lösen in Claude Code 2.1.285 auf `claude-opus-5-5` bzw. `claude-sonnet-5-5` auf (Modellkatalog im Programm, beide nachgelesen 2026-09-29). Effort `medium` für den `executer` auf Sonnet 5.5 ist am 2026-09-29 gemessen, für `recherche` nicht: [[AI/Regelwerk/sonnet-5-5|sonnet-5-5.md]], A1. Der eingebaute Agent `Explore` lädt diese Datei nicht und kennt die Vault-Regeln deshalb nicht — nur für reine Dateisuche; `general-purpose` erbt den Sitzungs-Effort und ist durch `recherche` ersetzt. Wann Haiku statt Sonnet, die Belege dazu und die Zuordnung der Superpowers-Skills: [[AI/Regelwerk/codeworkflow|codeworkflow.md]].
|
||||
Die Aliasse `opus` und `sonnet` lösen in Claude Code 2.1.285 auf `claude-opus-5-5` bzw. `claude-sonnet-5-5` auf (Modellkatalog im Programm, beide nachgelesen 2026-09-29). `haiku` löst laut Transkripten seit 2.1.293 auf `claude-haiku-5-5` auf, das anders als Haiku 4.5 Effort kennt und ihn aus dem Frontmatter oder der Sitzung bekommt (nachgelesen 2026-10-09 in 2.1.296): [[AI/Regelwerk/haiku-5-5|haiku-5-5.md]]. Effort `medium` für den `executer` auf Sonnet 5.5 ist am 2026-09-29 gemessen, für `recherche` nicht: [[AI/Regelwerk/sonnet-5-5|sonnet-5-5.md]], A1. Der eingebaute Agent `Explore` lädt diese Datei nicht und kennt die Vault-Regeln deshalb nicht — nur für reine Dateisuche; `general-purpose` erbt den Sitzungs-Effort und ist durch `recherche` ersetzt. Wann Haiku statt Sonnet, die Belege dazu und die Zuordnung der Superpowers-Skills: [[AI/Regelwerk/codeworkflow|codeworkflow.md]].
|
||||
|
||||
**Ein Subagent ohne eigenen Effort erbt den der Hauptsitzung.** Läuft sie auf `xhigh` oder `max`, kostete ein Sonnet-5-Agent laut Katalog das 2,4- bzw. 5,6-Fache von `high`; für Sonnet 5.5 nennt der Katalog keine Faktoren. Deshalb trägt jede Agentendatei `effort:`. In Workflows bekommt jeder `agent()`-Aufruf `model`; den Effort liefert mit `agentType` dessen Frontmatter, ohne `agentType` wird er mitgegeben, und ein `effort`-Parameter neben `agentType` steht nur für eine bewusste Abweichung. **Wie viele Opus-Agenten gleichzeitig laufen, entscheidet der Verbrauch:** Vor jeder Opus-Staffel liest der Workflow `verbrauch` das 5-Stunden-Fenster und die Woche ab und senkt die Plätze bei hohem Verbrauch bis auf keinen. Bis zur Eichung der Stufen laufen drei Opus-Agenten gleichzeitig nur in den Linsen der Plankritik, sonst höchstens zwei; danach bis vier für Reviews und Erstplanung. Ohne Ablesung, also außerhalb der Desktop-App oder als Kind eines Workflows, gilt die Zwei; wer Opus-Agenten über das Agent-Werkzeug startet, liest vorher selbst `get_usage`. Für Plankritik, Executer-Welle, Prüfung und Erstplanung gibt es gespeicherte Workflows unter `.claude/workflows/`, in denen das eingebaut ist (`plankritik`, `executer-welle`, `pruefung`, `planung`), dazu `welle-mit-pruefung` für Schritt 3 und 4 in einem Aufruf und `quorum` für die Prüfung am Meilenstein. Eine geänderte Agentendatei oder ein neuer gespeicherter Workflow wirkt in der laufenden Sitzung nicht sofort, sondern erst nach einer Weile (am 2026-09-23 knapp eine Stunde, am 2026-09-24 gut 20 Minuten) oder in der nächsten Sitzung. Ob ein Effort greift, zeigt nur das Feld `effort` im Transkript; ein noch unbekannter Workflow geht so lange über `scriptPath`. Messung und Begründung je Rolle: [[AI/Regelwerk/codeworkflow|codeworkflow.md]], „Effort je Rolle"; Stufen und Belege zum Verbrauch dort unter „Verbrauch und Opus-Plätze".
|
||||
|
||||
@@ -99,6 +99,7 @@ Jede Datei triggert nur den betreffenden Teil — nicht bei jeder Aufgabe alles
|
||||
- Wöchentlicher Depotbericht → [[AI/Regelwerk/portfolio-monitor|portfolio-monitor.md]] — der Lauf handelt nicht.
|
||||
- Wöchentliche Rückschau → [[AI/Regelwerk/woechentliche-rueckschau|woechentliche-rueckschau.md]]
|
||||
- Sitzung läuft auf Claude Fable 5.1, oder eine API-Integration zielt auf Fable 5.1 → [[AI/Regelwerk/fable-5-1|fable-5-1.md]]
|
||||
- Sitzung läuft auf Claude Haiku 5.5, ein Task trägt `modell: haiku`, Haiku springt im Quorum ein, oder eine API-Integration zielt auf Haiku 5.5 → [[AI/Regelwerk/haiku-5-5|haiku-5-5.md]]
|
||||
- Auftrag an `planer` oder `pruefer` (Opus 5) schreiben → [[AI/Regelwerk/opus-5|opus-5.md]]; an `executer` oder Recherche (Sonnet 5.5) → [[AI/Regelwerk/sonnet-5-5|sonnet-5-5.md]], Vorgänger und Cyber-Schutz in [[AI/Regelwerk/sonnet-5|sonnet-5.md]]; Subagenten-Auftrag, Agent- oder Skill-Datei, System-Prompt allgemein → [[AI/Regelwerk/prompting|prompting.md]]. Verbindlich für Fable 5.1 als Auftraggeber, andere Modelle entscheiden selbst.
|
||||
- Code gegen die Claude Messages API (eigener Agent, Harness, Werkzeug) → [[AI/Regelwerk/api-mechanik|api-mechanik.md]] — nicht für die Claude-Code-Sitzung selbst.
|
||||
|
||||
|
||||
Reference in new issue
Block a user