Automatischer Push: 11 Datei(en) geändert

- .claude/agents/planer.md
- .claude/workflows/plankritik.js
- .vault-tools/plan-kopie/LIESMICH.md
- .vault-tools/plan-kopie/mutanten_lauf.py
- .vault-tools/plan-kopie/mutanten_lauf_ENTWURF.md
- .vault-tools/plan-kopie/mutanten_lauf_kopie.sh
- .vault-tools/plan-kopie/mutanten_lauf_treiber.py
- .vault-tools/workflow-pruefung/faelle_workflows.mjs
- .vault-tools/workflow-pruefung/mutanten_workflows.py
- AI/Regelwerk/codeworkflow.md
- CLAUDE.md

Erzeugt vom PostToolUse-Hook .vault-tools/auto-push/auto_push.py.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Pascal MichelandClaude Opus 5 committed 2026-09-28 04:00:02 +02:00
1 parent e50c8296d7
commit bc9b4f4497
11 files changed
+2214 -10

No files matched your search

+40 -5
View File
@@ -1,7 +1,7 @@
export const meta = {
name: 'plankritik',
description: 'Plankritik: pruefer-Linsen nach Verbrauch, doppelte Befunde zusammengefasst, wichtige und blockierende von einem zweiten pruefer widerlegt',
whenToUse: 'Schritt 2 der Standardschleife vor dem ersten Executer, Pflicht ab etwa drei Tasks (AI/Regelwerk/codeworkflow.md). Args: {projekt, planordner, spec?, kopie?, materialisieren?: {ohne: [relpfade], tasks?: [taskdateien]}, suite?, linsen?, plaetze?: 1..4, verifizieren?: true, verifizieren_ab?: "wichtig"|"blockierend", effort?, werkzeuge?: Ordner der Planwerkzeuge, zusatz?}. Einzelheiten im Kommentar unter meta.',
whenToUse: 'Schritt 2 der Standardschleife vor dem ersten Executer, Pflicht ab etwa drei Tasks (AI/Regelwerk/codeworkflow.md). Args: {projekt, planordner, spec?, kopie?, materialisieren?: {ohne: [relpfade], tasks?: [taskdateien]}, suite?, linsen?, mutanten?: "voll"|"muster"|"aus" (Vorgabe voll), plaetze?: 1..4, verifizieren?: true, verifizieren_ab?: "wichtig"|"blockierend", effort?, werkzeuge?: Ordner der Planwerkzeuge, zusatz?}. Einzelheiten im Kommentar unter meta.',
phases: [
{ title: 'Vorbereitung', detail: 'Hilfsagent: Kopie bauen, Plan anwenden, Planwerkzeuge fahren' },
{ title: 'Plankritik', detail: 'je Linse ein pruefer, gleichzeitig nach Verbrauch' },
@@ -17,6 +17,8 @@ export const meta = {
// - werkzeuge ist ein Pfad, keine Ausgabe; Vorgabe D:/Claude/.vault-tools/plan-kopie.
// - Ohne kopie baut materialisieren sie selbst (kopie_bauen.py plus plan_materialisiere.py);
// ohne() muss Geheimnisdateien und große Datenordner nennen.
// - mutanten: "voll" (Vorgabe), "muster" oder "aus". Nur wirksam mit gesetztem kopie; steuert den
// Hilfsagenten werkzeug:mutanten, der mutanten_lauf_kopie.sh fährt (siehe Kommentar dort unten).
// - plaetze begrenzt die gleichzeitigen Linsen; verbrauch.js senkt sie nach dem 5-Stunden-Fenster
// und der Woche.
// - Rückgabe mit status fertig oder gebremst; ein gebremster Lauf wird neu gestartet, nicht
@@ -39,8 +41,18 @@ const RANG = { blockierend: 0, wichtig: 1, klein: 2 }
// Einfache Anführungszeichen: In Bash bleiben darin $, Backtick und Backslash wörtlich.
const q = s => "'" + String(s).replace(/'/g, "'\\''") + "'"
// Text für die Linse arithmetik, wenn der Mutantenlauf (werkzeug:mutanten) etwas geliefert hat.
function mutantenText(m) {
if (!m) return ''
if (m.keineToml) return ' Der Plan hat keine mutanten.toml. Das ist ein Befund der Schwere wichtig, sobald der Plan Mutanten in "Fertig heißt" nennt.'
const zeilen = m.rohausgabe.split('\n')
const letzte = zeilen.slice(-200).join('\n')
const grenze = /ZEITGRENZE/.test(m.rohausgabe) ? ' Der Lauf hat seine Zeitgrenze erreicht: Mutanten ohne eigene Zeile sind nicht gefahren; setze für sie selbst höchstens die aus, die dir am riskantesten erscheinen, in einer eigenen Kopie.' : ''
return `${grenze} Bewerte jeden Mutanten mit LUECKE, UNKLAR, ZEIT oder MUSTER als Befund und prüfe bei OK an der Fehlermeldung, ob der Test an der gemeinten Stelle fällt; setze Mutanten nicht erneut von Hand.\n<mutantenlauf>\n${letzte}\n</mutantenlauf>`
}
const LINSEN = {
arithmetik: (a, ctx) => `Linse: Fixture-Arithmetik und Rot-Nachweise. Rechne jede Mindestzahl, jede Grenze und jeden Schwellenwert im Produktivcode des Plans gegen jede Fixture der Tests nach. Prüfe jede im Plan erwartete Fehlermeldung und jede vorhergesagte Testausgabe wörtlich: Würde der Test vor der Umsetzung genau so rot, und danach grün? pytest kürzt FAILED-Zeilen ohne Terminal auf 80 Zeichen; vergleiche Fehlerzeilen deshalb mit COLUMNS=300 vor dem Befehl.${ctx.kopie ? ` Der Plan ist auf die Kopie ${ctx.kopie} angewendet. Fahre dort die Suite (${a.suite || 'Testbefehl aus dem Plan'}) und vergleiche jede Vorhersage des Plans mit der echten Ausgabe. In der Kopie änderst du nichts außer dem, was die Testläufe selbst anlegen.` : ' Eine Kopie mit angewendetem Plan gibt es nicht; du rechnest am Text.'}`,
arithmetik: (a, ctx) => `Linse: Fixture-Arithmetik und Rot-Nachweise. Rechne jede Mindestzahl, jede Grenze und jeden Schwellenwert im Produktivcode des Plans gegen jede Fixture der Tests nach. Prüfe jede im Plan erwartete Fehlermeldung und jede vorhergesagte Testausgabe wörtlich: Würde der Test vor der Umsetzung genau so rot, und danach grün? pytest kürzt FAILED-Zeilen ohne Terminal auf 80 Zeichen; vergleiche Fehlerzeilen deshalb mit COLUMNS=300 vor dem Befehl.${ctx.kopie ? ` Der Plan ist auf die Kopie ${ctx.kopie} angewendet. Fahre dort die Suite (${a.suite || 'Testbefehl aus dem Plan'}) und vergleiche jede Vorhersage des Plans mit der echten Ausgabe. In der Kopie änderst du nichts außer dem, was die Testläufe selbst anlegen.` : ' Eine Kopie mit angewendetem Plan gibt es nicht; du rechnest am Text.'}${mutantenText(ctx.mutantenLauf)}`,
bezeichner: (a, ctx) => `Linse: Bezeichner, Signaturen und Byte-Treue. Prüfe jeden Namen, jede Signatur und jeden Import über Taskgrenzen hinweg. Jeder Aus-Block muss genau einmal im echten Baum stehen, jeder Codeblock muss sich parsen lassen, und Codeblöcke dürfen keine Zeilen- und Absatztrenner, Format- oder Steuerzeichen enthalten. Prüfbefehle im Plan dürfen nur Code treffen, nie ein Wort, das auch in einem Kommentar steht.${ctx.werkzeuge ? `\n\nDie Planwerkzeuge sind schon gelaufen, hier ihre Rohausgabe. Bewerte sie, statt sie erneut zu fahren; nur bei Zweifeln selbst nachfahren.\n<werkzeugausgabe>\n${ctx.werkzeuge}\n</werkzeugausgabe>` : ` Fahre dazu plan_bloecke.py vor und plan_zeichen.py aus ${a.werkzeuge || 'D:/Claude/.vault-tools/plan-kopie'}.`}`,
abdeckung: (a) => `Linse: Spec-Abdeckung in beide Richtungen. Jede Anforderung${a.spec ? ` aus ${a.spec}` : ' der Übersicht'} braucht einen Task und einen Test, und jeder Task braucht eine Anforderung. Die "Fertig heißt"-Liste der Übersicht muss je Check einen Beleg außerhalb der eigenen Meinung haben. Das Frontmatter jeder Taskdatei braucht modell und modell_begruendung; Abschrift-Tasks mit Anführungszeichen, Gedanken- und Streckenstrichen oder Auslassungspunkten im Code tragen modell sonnet und effort low statt haiku.`,
}
@@ -101,6 +113,7 @@ function pruefeArgs(a) {
if (a.verifizieren_ab !== undefined && !['wichtig', 'blockierend'].includes(a.verifizieren_ab)) throw new Error('plankritik: verifizieren_ab muss wichtig oder blockierend sein')
if (a.plaetze !== undefined && !(Number.isInteger(a.plaetze) && a.plaetze >= 1 && a.plaetze <= LINSEN_HOECHSTENS)) throw new Error('plankritik: plaetze muss eine ganze Zahl von 1 bis ' + LINSEN_HOECHSTENS + ' sein')
if (a.materialisieren && !(Array.isArray(a.materialisieren.ohne) && a.materialisieren.ohne.length > 0 && a.materialisieren.ohne.every(x => typeof x === 'string' && x))) throw new Error('plankritik: materialisieren.ohne muss eine nicht leere Liste sein, Ausschlüsse als Pfade vom Projektwurzelordner, mindestens .git (falls vorhanden) und Geheimnisdateien')
if (a.mutanten !== undefined && !['voll', 'muster', 'aus'].includes(a.mutanten)) throw new Error('plankritik: mutanten muss voll, muster oder aus sein')
}
// Höchstens n Aufgaben gleichzeitig, ohne Leerlauf zwischen Paaren.
@@ -137,12 +150,12 @@ async function ablesen(anlass, wunsch) {
return r
}
function werkzeugAgent(label, phase, befehl, zweck) {
function werkzeugAgent(label, phase, befehl, zweck, zusatz) {
return agent(`Du führst einen Werkzeugbefehl aus und gibst seine Ausgabe roh zurück. Zweck: ${zweck}
Führe genau diesen Befehl einmal im Bash-Werkzeug (Git-Bash) aus, unverändert:
${befehl}
${zusatz ? '\n' + zusatz + '\n' : ''}
Ändere keine Datei außer denen, die der Befehl selbst anlegt. Deute nichts und fasse nichts zusammen. Gib Befehl, Exit-Code und die vollständige Ausgabe zurück; bei mehr als 200 Zeilen die ersten 60 und die letzten 120, mit einer Zeile "[... N Zeilen gekürzt ...]" dazwischen.`,
{ label, phase, schema: LAUF, model: 'sonnet', effort: 'low' })
}
@@ -202,7 +215,8 @@ Gilt der Befund nur unter einer Bedingung, nenn sie. Gib deine eigene Einschätz
pruefeArgs(args)
const W = args.werkzeuge || 'D:/Claude/.vault-tools/plan-kopie'
const PY = 'PYTHONIOENCODING=utf-8 python -X utf8'
const ctx = { kopie: args.kopie || null, werkzeuge: null, temp: null }
const ctx = { kopie: args.kopie || null, werkzeuge: null, temp: null, mutantenLauf: null }
const MUTANTEN_MODUS = args.mutanten || 'voll'
const vorbereitung = []
// Eine Kopie gilt nur als verwendbar, wenn der Lauf sauber endet, den Pfad bis zum
@@ -247,6 +261,26 @@ if (!ctx.kopie && args.materialisieren) {
else log('Planwerkzeuge: Hilfsagent ohne Ergebnis; Linse bezeichner fährt sie selbst')
vorbereitung.push(r)
}
// Mutantenlauf (seit 2026-09-27). mutanten_lauf.py ändert Dateien in der Wurzel, die es bekommt,
// und setzt sie nach jedem Mutanten zurück. Die Linsen fahren gleichzeitig Tests in ctx.kopie;
// deshalb arbeitet mutanten_lauf_kopie.sh auf einer Kopie der Kopie unter /tmp in WSL.
// MSYS_NO_PATHCONV=1 ist Pflicht: Ohne sie übersetzt die Git-Bash /mnt/d/... in einen
// Windows-Pfad (Erinnerung git-bash-uebersetzt-pfade-fuer-wsl-exe). cygpath -l ist Pflicht, weil
// die Kopie oft unter dem Kurznamen PASCAL~1 liegt. cygpath -m statt -w: wsl -d Debian -- ...
// reicht die Befehlszeile an die Linux-Shell weiter, und die verschluckt jeden Backslash
// ("D:\Claude\foo" kam als "D:Claudefoo" an, gemessen 2026-09-27); Vorwärtsschrägstriche
// übersteht der Pfad, und wslpath -u im Skript wandelt ihn um. Das Bash-Werkzeug des Hilfsagenten
// endet nach höchstens zehn Minuten; das Skript begrenzt den Lauf deshalb selbst auf 540 s und
// meldet eine überschrittene Grenze mit ZEITGRENZE.
if (ctx.kopie && MUTANTEN_MODUS !== 'aus') {
const befehl = `MSYS_NO_PATHCONV=1 wsl -d Debian -- bash /mnt/d/Claude/.vault-tools/plan-kopie/mutanten_lauf_kopie.sh "$(cygpath -m -l ${q(ctx.kopie)})" "$(cygpath -m -l ${q(args.planordner)})" ${MUTANTEN_MODUS === 'muster' ? 'muster' : 'voll'}`
const r = await werkzeugAgent('werkzeug:mutanten', 'Vorbereitung', befehl, 'Mutanten aus mutanten.toml auf einer Kopie der Kopie fahren', 'Setze im Bash-Werkzeug den Parameter timeout auf 600000; der Befehl darf bis zu zehn Minuten laufen.')
const aus = r && r.laeufe && r.laeufe[0] ? String(r.laeufe[0].ausgabe || '') : ''
if (/KEINE_MUTANTEN_TOML/.test(aus)) ctx.mutantenLauf = { keineToml: true, rohausgabe: aus }
else if (/EXIT mutanten_lauf: \d+/.test(aus)) ctx.mutantenLauf = { keineToml: false, rohausgabe: aus }
else log('Mutantenlauf: Hilfsagent ohne verwertbares Ergebnis (kein KEINE_MUTANTEN_TOML, kein EXIT mutanten_lauf); Linsen laufen ohne Mutantenlauf weiter')
vorbereitung.push(r)
}
phase('Plankritik')
const gewaehlt = args.linsen && args.linsen.length ? args.linsen : Object.keys(LINSEN)
@@ -320,6 +354,7 @@ return {
zaehlung,
kopie: ctx.kopie,
temp_ordner: tempText(),
mutanten_lauf: ctx.mutantenLauf ? ctx.mutantenLauf.rohausgabe : null,
befunde,
selbst_ausgefuehrt: ergebnisse.map(e => ({ linse: e.linse, befehle: e.ergebnis.selbst_ausgefuehrt })),
nicht_pruefbar: ergebnisse.flatMap(e => e.ergebnis.nicht_pruefbar.map(x => e.linse + ': ' + x)),