Files
Pascal MichelandClaude Opus 5 f86a54a6e7 Automatischer Push: 46 Datei(en) geändert
- .claude/agents/planer.md
- .claude/skills/plan-executer-pruefung/SKILL.md
- .claude/workflows/plankritik.js
- .claude/workflows/planung.js
- .claude/workflows/pruefung.js
- .claude/workflows/verbrauch.js
- .claude/workflows/welle-mit-pruefung.js
- .vault-tools/plan-kopie/LIESMICH.md
- .vault-tools/plan-kopie/plan_zeichen.py
- .vault-tools/plan-kopie/rot_nachweis.py
- .vault-tools/trading-plattform-pruefung/LIESMICH.md
- .vault-tools/trading-plattform-pruefung/abendkontrolle.py
- … und 34 weitere

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

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 04:00:02 +02:00

13 KiB

type, title, status, summary, tags, created, updated, modell, modell_begruendung
type title status summary tags created updated modell modell_begruendung
plan-task Task 05 — welle-mit-pruefung.js: Rückkehrpunkt nach dem Vergleich und Ablesung um die Prüfung draft Mit bis vergleich endet der Workflow vor der Prüfung und gibt pruefung_args zurück, damit der Koordinator seine Gegenprüfung parallel zur Prüfung fahren kann; sonst liest er vor und nach der Prüfung ab.
plan-task
vault-tools
codeworkflow
2026-09-24 2026-09-24 haiku Abschrift: jede Zeile steht wörtlich im Plan, Zieldateien und Verbote sind genannt, kein Codeblock trägt typografische Anführungszeichen, Striche, Auslassungspunkte oder das Zeichen ·.

Task 05 — welle-mit-pruefung.js: Rückkehrpunkt nach dem Vergleich und Ablesung um die Prüfung

Die globalen Vorgaben stehen in 00-uebersicht.md (Abschnitt „Globale Vorgaben“). Arbeitsverzeichnis ist der Vault-Wurzelordner D:/Claude; alle Pfade gelten von dort.

Was danach anders ist:

  • bis: "vergleich" gibt pruefung_args mit den Rohbelegen im schwerpunkt zurück. Der Koordinator startet pruefung damit selbst und fährt währenddessen seine Gegenprüfung, nur lesend.
  • Ohne bis liest der Workflow vor und nach dem Kind pruefung ab und gibt ihm verbrauch: false mit.

Zieldateien

  • .claude/workflows/welle-mit-pruefung.js (geändert)

Verbote

  • Keine andere Datei, auch nicht die übrigen Workflows unter .claude/workflows/ und nichts unter AI/Regelwerk/, .claude/agents/ oder CLAUDE.md.
  • Kein Commit, kein Push, kein Lauf eines echten Workflows.
  • Kein Umformulieren, auch nicht von Kommentaren oder Sonderzeichen; ein Widerspruch zwischen Plan und Baum wird gemeldet.

Umsetzung

.claude/workflows/welle-mit-pruefung.js

Die ganze Datei ist neu (sie ersetzt die bisherige Fassung vollständig):

export const meta = {
  name: 'welle-mit-pruefung',
  description: 'Schritt 3 und 4 in einem Aufruf: Kopie mit angewendetem Plan vor der Welle, executer-welle, Byte-Vergleich und Suite, danach pruefung mit den Rohbelegen; mit bis "vergleich" endet er vor der Prüfung',
  whenToUse: 'Nach der Plankritik, sobald eine Welle mit disjunkten Zieldateien steht (AI/Regelwerk/codeworkflow.md, Schritte 3 und 4). Args: {projekt, planordner, tasks: [{datei, modell, effort?}], kopie? oder ohne: [relpfade, nicht leer], prosa?: [relpfade], suite?, kritisch?, abschluss?, effort?, version?, schwerpunkt?, rot_nachweis_erbracht?, zusatz?, werkzeuge?, bis?: "vergleich"}. Ohne kopie wird sie vor der Welle gebaut; ohne nennt dann .git und Geheimnisdateien. Mit bis "vergleich" kommt pruefung_args zurück: pruefung damit selbst starten und währenddessen die eigene Gegenprüfung fahren. Ersetzt die eigene Gegenprüfung des Koordinators nicht.',
  phases: [
    { title: 'Kopie', detail: 'Hilfsagent: Stand vor der Welle kopieren und den Plan der Welle anwenden' },
    { title: 'Welle', detail: 'executer-welle' },
    { title: 'Vergleich', detail: 'Hilfsagent: welle_vergleich.py und Suite im echten Baum' },
    { title: 'Prüfung', detail: 'pruefung mit den Rohbelegen' },
  ],
}

// Ruft die gespeicherten Workflows executer-welle und pruefung verschachtelt auf, damit ihre
// Aufträge und Rollenparameter an genau einer Stelle stehen. Der Hilfsagent hat keinen
// agentType und bekommt seinen Effort deshalb mit (low). Opus läuft nur in den Kindern,
// und die laufen nacheinander; die Obergrenze von zwei hält executer-welle selbst.
// Verbrauch: Vor und nach der Prüfung liest dieser Workflow den Planverbrauch über verbrauch.js
// ab (nur messen); das Kind pruefung bekommt verbrauch: false, weil ein Kind keinen weiteren
// Workflow aufrufen kann.
const MODELLE = ['haiku', 'sonnet', 'opus']
const EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max']
const VERBRAUCH = 'D:/Claude/.claude/workflows/verbrauch.js'
// Einfache Anführungszeichen: In Bash bleiben darin $, Backtick und Backslash wörtlich.
const q = s => "'" + String(s).replace(/'/g, "'\\''") + "'"
const PY = 'PYTHONIOENCODING=utf-8 python -X utf8'

const LAUF = {
  type: 'object',
  properties: {
    laeufe: { type: 'array', items: { type: 'object', properties: { befehl: { type: 'string' }, exit: { type: 'integer' }, ausgabe: { type: 'string' } }, required: ['befehl', 'exit', 'ausgabe'] } },
  },
  required: ['laeufe'],
}

// Dieselben Regeln wie in executer-welle, aber VOR dem ersten Agenten: Ein ungültiger Task
// soll keine Projektkopie im Temp hinterlassen.
function pruefeArgs(a) {
  if (!a || typeof a !== 'object') throw new Error('welle-mit-pruefung: args fehlen')
  const fehlt = ['projekt', 'planordner', 'tasks'].filter(k => !a[k])
  if (fehlt.length) throw new Error('welle-mit-pruefung: args fehlen: ' + fehlt.join(', '))
  if (!Array.isArray(a.tasks) || a.tasks.length === 0) throw new Error('welle-mit-pruefung: tasks muss eine nicht leere Liste von {datei, modell, effort?} sein')
  a.tasks.forEach((t, i) => {
    if (!t || typeof t !== 'object' || !t.datei || typeof t.datei !== 'string') throw new Error(`welle-mit-pruefung: tasks[${i}] ohne datei`)
    if (!MODELLE.includes(t.modell)) throw new Error(`welle-mit-pruefung: ${t.datei}: modell "${t.modell}" nicht in ${MODELLE.join('/')}`)
    if (t.effort !== undefined && !EFFORTS.includes(t.effort)) throw new Error(`welle-mit-pruefung: ${t.datei}: effort "${t.effort}" nicht in ${EFFORTS.join('/')}`)
  })
  if (a.effort !== undefined && !EFFORTS.includes(a.effort)) throw new Error('welle-mit-pruefung: effort "' + a.effort + '" ungültig')
  if (a.prosa !== undefined && !Array.isArray(a.prosa)) throw new Error('welle-mit-pruefung: prosa muss eine Liste sein')
  if (a.bis !== undefined && a.bis !== 'vergleich') throw new Error('welle-mit-pruefung: bis kennt nur "vergleich"')
  if (!a.kopie) {
    const ok = Array.isArray(a.ohne) && a.ohne.length > 0 && a.ohne.every(x => typeof x === 'string' && x)
    if (!ok) throw new Error('welle-mit-pruefung: kopie oder ohne angeben. ohne ist eine nicht leere Liste von Ausschlüssen für kopie_bauen.py, als Pfade vom Projektwurzelordner, mindestens .git (falls vorhanden) und Geheimnisdateien')
  }
}

function werkzeugAgent(label, phase, befehl, zweck) {
  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}

Ä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' })
}

// Anfang und Ende behalten: Das Ergebnis der Suite steht am Schluss.
function kopfUndEnde(text, kopf, ende) {
  if (!text || text.length <= kopf + ende) return text || ''
  return text.slice(0, kopf) + '\n[... gekürzt ...]\n' + text.slice(-ende)
}

// Eine messende Hilfsfunktion ablesen() steht auch in pruefung.js; plankritik.js und planung.js
// haben eine mit Wunsch und Rückgabe. Die Regel (Fenster, Stufen, Rückfall) steht nur in
// verbrauch.js.
const ablesungen = []
async function ablesen(anlass) {
  let r = null
  try {
    r = await workflow({ scriptPath: VERBRAUCH }, { anlass: 'welle-mit-pruefung:' + anlass, wunsch: 0 })
  } catch (e) {
    r = { status: 'nicht_gelesen', grund: 'verbrauch.js nicht ausführbar: ' + (e && e.message) }
  }
  ablesungen.push({ anlass, ...(r || { status: 'nicht_gelesen', grund: 'verbrauch.js ohne Ergebnis' }) })
}

pruefeArgs(args)
const W = args.werkzeuge || 'D:/Claude/.vault-tools/plan-kopie'
const taskdateien = args.tasks.map(t => t.datei)
let kopie = args.kopie || null
let temp = null
const belege = {}
const fehler = []

phase('Kopie')
if (!kopie) {
  const befehl = `T=$(mktemp -d) && echo "KOPIE=$(cygpath -m "$T/mat")" && ${PY} ${q(W + '/kopie_bauen.py')} ${q(args.projekt)} "$T/mat" --ohne ${args.ohne.map(q).join(' ')} && ${PY} ${q(W + '/plan_materialisiere.py')} ${q(args.planordner)} "$T/mat" ${taskdateien.map(q).join(' ')}`
  const r = await werkzeugAgent('werkzeug:kopie', 'Kopie', befehl, 'Stand vor der Welle kopieren und die Taskdateien der Welle darauf anwenden')
  belege.kopie = r
  const lauf = r && r.laeufe && r.laeufe[0]
  const m = lauf && /^KOPIE=(.+?)\s*$/m.exec(lauf.ausgabe)
  if (m) temp = m[1].replace(/\/mat$/, '')
  const angewendet = lauf && /'(neu|ersetzt|angehaengt)': [1-9]/.test(lauf.ausgabe)
  if (lauf && lauf.exit === 0 && m && angewendet) kopie = m[1]
  else log('Kopie nicht verwendbar (' + (!lauf ? 'Hilfsagent ohne Ergebnis' : lauf.exit !== 0 ? 'Exit ' + lauf.exit : !m ? 'kein KOPIE-Pfad' : 'kein Block angewendet') + '); der Byte-Vergleich entfällt, die Welle läuft trotzdem')
}

phase('Welle')
let welle = null
try {
  welle = await workflow('executer-welle', {
    projekt: args.projekt, planordner: args.planordner, tasks: args.tasks,
    rot_nachweis_erbracht: args.rot_nachweis_erbracht, zusatz: args.zusatz,
  })
} catch (e) {
  fehler.push('executer-welle: ' + (e && e.message))
  log('executer-welle gescheitert: ' + (e && e.message))
}

phase('Vergleich')
if (welle) {
  const teile = []
  if (kopie) teile.push(`${PY} ${q(W + '/welle_vergleich.py')} --projekt ${q(args.projekt)} --mat ${q(kopie)}${args.prosa && args.prosa.length ? ' --prosa ' + args.prosa.map(q).join(' ') : ''} -- ${taskdateien.map(d => q(args.planordner + '/' + d)).join(' ')}; echo "EXIT welle_vergleich: $?"`)
  if (args.suite) teile.push(`if cd ${q(args.projekt)}; then export COLUMNS=300; ${args.suite}; echo "EXIT suite: $?"; else echo "EXIT suite: cd ins Projekt gescheitert"; fi`)
  if (teile.length) {
    belege.vergleich = await werkzeugAgent('werkzeug:vergleich', 'Vergleich', teile.join('; '), 'Nach der Welle: geänderte Dateien und Bytes gegen die Kopie, dann die Suite im echten Baum')
    if (!belege.vergleich) log('Vergleich: Hilfsagent ohne Ergebnis')
  } else log('Vergleich entfällt: weder Kopie noch suite')
} else log('Vergleich entfällt: keine Welle')

phase('Prüfung')
let pruefung = null
let pruefungGrund = null
if (!welle) pruefungGrund = 'keine Welle'
else if (welle.ohne_bericht && welle.ohne_bericht.length) pruefungGrund = 'Welle unvollständig, ohne Bericht: ' + welle.ohne_bericht.join(', ')
let pruefungArgs = null
if (!pruefungGrund) {
  const vl = belege.vergleich && belege.vergleich.laeufe && belege.vergleich.laeufe[0]
  const vergleichstext = vl ? kopfUndEnde(vl.ausgabe, 1500, 2500) : ''
  const schwerpunkt = [
    args.schwerpunkt || '',
    welle.mit_abweichung.length ? `Diese Tasks melden Abweichungen vom Plan: ${welle.mit_abweichung.join(', ')}.` : '',
    vergleichstext ? `Rohausgabe von Byte-Vergleich und Suite nach der Welle (vom Hilfsagenten, nicht von dir gefahren):\n${vergleichstext}` : '',
  ].filter(Boolean).join('\n')
  pruefungArgs = {
    projekt: args.projekt, plan: args.planordner, tasks: taskdateien, suite: args.suite,
    kritisch: args.kritisch, abschluss: args.abschluss, version: args.version, effort: args.effort, schwerpunkt,
  }
}

const tempText = temp ? `${temp} bleibt liegen (Projektkopie ohne die Ausschlüsse); löschen, wenn der Diff nicht mehr gebraucht wird` : null

if (args.bis === 'vergleich') {
  if (pruefungGrund) log('Prüfung wäre übersprungen worden: ' + pruefungGrund)
  return {
    status: 'bis_vergleich',
    kopie,
    temp_ordner: tempText,
    welle,
    vergleich: belege.vergleich || null,
    kopie_lauf: belege.kopie || null,
    pruefung_args: pruefungArgs,
    pruefung_grund: pruefungGrund,
    fehler,
    verbrauch: ablesungen,
    naechster_schritt: pruefungArgs
      ? 'pruefung mit pruefung_args als eigenen Workflow im Hintergrund starten. Währenddessen die eigene Gegenprüfung nach Schritt 4, nur lesend: nichts in Projektbaum oder Planordner schreiben, Rot- und Mutantentests nur auf einer Kopie, den pruefer nicht abbrechen. Plankorrektur und Commit erst nach seinem Bericht.'
      : 'Keine Prüfung möglich (' + pruefungGrund + '). Welle nachziehen, dann erneut.',
  }
}

if (pruefungGrund) log('Prüfung übersprungen: ' + pruefungGrund)
else {
  await ablesen('vor Prüfung')
  try {
    pruefung = await workflow('pruefung', { ...pruefungArgs, verbrauch: false })
  } catch (e) {
    fehler.push('pruefung: ' + (e && e.message))
    pruefungGrund = 'pruefung gescheitert: ' + (e && e.message)
    log(pruefungGrund)
  }
  await ablesen('nach Prüfung')
}

return {
  status: 'fertig',
  kopie,
  temp_ordner: tempText,
  welle,
  vergleich: belege.vergleich || null,
  kopie_lauf: belege.kopie || null,
  pruefung: pruefung || { uebersprungen: pruefungGrund },
  fehler,
  verbrauch: ablesungen,
  naechster_schritt: 'Eigene Gegenprüfung nach Schritt 4: Testlauf selbst wiederholen, zentrale Artefakte selbst lesen, eigener Lauf mit echten Daten; bei Abweichung im Byte-Vergleich diff auf die ganze Datei. Befunde am Plan korrigieren, nicht am Code.',
}

Verifikation

Im Vault-Wurzelordner:

node -e "const t=require('fs').readFileSync(process.argv[1],'utf8').replace(/^export const meta = /m,'const meta = ');new (Object.getPrototypeOf(async function(){}).constructor)('agent','parallel','pipeline','phase','log','workflow','args','budget',t);console.log('PARSE OK')" .claude/workflows/welle-mit-pruefung.js

Erwartet: PARSE OK, Exit 0.

Danach git status --porcelain -- .claude/workflows/welle-mit-pruefung.js zeigen.