Automatischer Push: 11 Datei(en) geändert

- .claude/agents/planer.md
- .claude/workflows/plankritik.js
- .claude/workflows/quorum.js
- .claude/workflows/welle-mit-pruefung.js
- .vault-tools/plan-kopie/LIESMICH.md
- .vault-tools/plan-kopie/plan_bloecke.py
- .vault-tools/plan-kopie/plan_materialisiere.py
- .vault-tools/plan-kopie/plan_zaun_treiber.py
- .vault-tools/workflow-pruefung/LIESMICH.md
- .vault-tools/workflow-pruefung/faelle_workflows.mjs
- .vault-tools/workflow-pruefung/mutanten_workflows.py

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-11-03 03:00:01 +01:00
1 parent 7f484f9be5
commit 22761eb186
11 files changed
+1520 -65

No files matched your search

+104 -8
View File
@@ -30,7 +30,40 @@ Geltungsbereich:
enthaelt "Die ganze Datei ist neu" -> schreibt die Datei
beginnt mit "Häng diesen Block ans Ende" -> haengt an
Alles andere (Befehle, erwartete Ausgaben, Prosa-"wird: ...") wird uebergangen und gezaehlt.
- Zaeune aus n Backticks schliessen erst mit n Backticks.
- Zaeune aus n Backticks schliessen erst mit n Backticks, in einer Zeile ohne weiteren Text und hoechstens drei
Spalten tiefer als der Oeffner; tiefer ist es Inhalt. Eine Zeile mit weiterem Backtick hinter dem Zaun oeffnet
nichts, sie ist Inline-Code. Beides nach CommonMark 0.31.2, Abschnitt Fenced code blocks, nachgelesen 2026-11-01
("may be preceded by up to three spaces of indentation", "Info strings for backtick code blocks cannot contain
backticks"). Abweichend davon oeffnet ein Zaun bei jeder Einrueckung, und Tilde-Zaeune kennt das Werkzeug nicht.
- Zaunpruefung (seit 2026-11-02, Anlass in zaunbefunde()): Vor dem ersten Schreibvorgang liest zaunbefunde() alle
uebergebenen Taskdateien. Ein Befund in einer davon, und der ganze Lauf schreibt und loescht nichts, auch nicht
die heilen Dateien davor. Befund sind, mit n als Zaunlaenge des Blocks:
1. eine Zeile im Block, die auf mindestens n Backticks endet, ohne zu schliessen (klebender Zaun, auch ein
Zaun mehr als drei Spalten tiefer als der Oeffner),
2. eine Zeile im Block, die mit mindestens n Backticks beginnt, ohne zu schliessen (Schlusszaun fehlt,
Aussenzaun zu kurz),
3. ein Block, der bis zum Dateiende nicht schliesst,
4. eine Taskdatei, die sich nicht lesen laesst.
Herkunft: 1 und 3 stehen im Auftrag zur Haertung. 2 ist Projektvorgabe, denselben stillen Schaden richtet ein
fehlender Zaun an. 4 ist Projektvorgabe nach AI/Regelwerk/pruefwerkzeuge.md, vorher stuerzte der Lauf mittendrin ab.
Bewusst entschieden: Ein Text im Block, etwa eine Zeichenkette in einem Test, die am Zeilenende auf n Backticks
endet oder mit ihnen beginnt, ist derselbe Befund. Von einem klebenden Zaun ist er nicht zu unterscheiden, und die
Folgen sind ungleich: Der Fehlalarm kostet einen laengeren Zaun um den Block, der uebersehene Zaun schreibt
Planprosa in die Zieldatei. Gemessen am 2026-11-02 ueber alle verschiedenen Taskdateien im Vault und in den
Jobordnern: 1 und 3 ohne Treffer, 2 acht Zeilen in drei alten Doku-Tasks, alle echt (Aussenzaun zu kurz, der
Block endete zu frueh).
Nicht entscheidbar ist ein nackter Zaun als eigene Zeile im Text, hoechstens drei Spalten tiefer als der Oeffner:
Er schliesst den Block. Geht die Zahl der Zaeune auf, wird der Rest Prosa, der Block endet dort, und es kommt
kein Befund (Treiberfall "Luecke:"). Text mit Zaeunen braucht deshalb immer einen laengeren Zaun um den Block.
Kein Befund: laengere Zaeune um Markdown-Vorlagen mit ##-Ueberschriften und kuerzeren Zaeunen darin, Inline-Code
und Zaunfolgen mitten in der Zeile oder in Anfuehrungszeichen, Prosa ausserhalb von Bloecken.
Nicht gesehen (Fangnetz, kein Nachweis): Ein nackter Zaun als Oeffner ist von einem Schlusszaun nicht zu
unterscheiden. Fehlt der Schlusszaun und kommt als naechstes ein nackter Zaun derselben oder groesserer Laenge,
schliesst der den Block, und die Rollen tauschen bis zum naechsten Oeffner mit Sprache (das meldet 2) oder bis
zum Dateiende (das meldet 3 am letzten Zaun, zwei solche Fehler heben sich auf). Ebenso bei einem Oeffner, der
fehlt, an der Zeile davor klebt oder einen Backtick in der Sprachangabe traegt, bei Zaeunen hinter Listenpunkt
oder Zitatzeichen und bei Backtick-Zaeunen in Tilde-Bloecken. Nachweis: plan_zaun_treiber.py. plan_bloecke.py
nutzt dieselben Funktionen.
- Geschrieben wird immer mit LF.
Aufruf: python plan_materialisiere.py <planordner> <kopie> <taskdatei> [<taskdatei> ...]
Exit 0 ohne Befund, 2 mit Befund.
@@ -133,6 +166,65 @@ def normal(text: str) -> str:
return text.replace("\r\n", "\n").replace("\r", "\n")
def zaun(zeile: str) -> int:
"""Laenge des Zauns, der in dieser Zeile einen Block oeffnet, sonst 0."""
kern = zeile.lstrip()
laenge = len(kern) - len(kern.lstrip("`"))
return laenge if laenge >= 3 and "`" not in kern[laenge:] else 0
def schliesst(zeile: str, laenge: int, einzug: int) -> bool:
"""Schliesst die Zeile einen Block mit Zaun der Laenge laenge und Einzug einzug?
Mindestens so viele Backticks, sonst nichts in der Zeile, hoechstens drei Spalten tiefer als der Oeffner.
Nachbesserung 2026-11-02 (Pruefung der Zaunpruefung): Vorher schloss jeder Einzug und "``` ```". Ein eingerueckter
Zaun in einer Zeichenkette kappte den Block mit 0 Befunden, und plan_bloecke.py hatte das bis dahin gesehen.
"""
kern = zeile.lstrip()
return kern.startswith("`" * laenge) and not kern.rstrip().strip("`") and len(zeile) - len(kern) - einzug <= 3
def zaunbefunde(taskdatei: Path) -> list[tuple[int, str]]:
"""(Zeile, Meldung) je Stelle, an der die Bloecke der Taskdatei nicht stimmen; leer heisst: bloecke() liest sie richtig.
Nachbesserung 2026-11-01 (Kette 050 der Trading Plattform, Auftrag 13): In task-1020 klebte der Zaun an `])`,
der Block lief bis in den naechsten Task, es kam nur "Aus-Block steht 0-mal", und ein Aus/wird-Paar ging ohne
Meldung verloren. Unter "Die ganze Datei ist neu" schrieb derselbe Fehler Planprosa mit 0 Befunden in die Datei.
Fuer die Meldung endet ein Block am klebenden Zaun, und ein Zaun am Zeilenanfang im Block beginnt einen neuen: So
steht jeder Fehler einmal da, und die Bloecke dahinter stimmen wieder. War es doch ein Text mit Zaunfolge, oeffnet
der echte Schlusszaun fuer diese Suche einen Block, und ein Folgebefund steht weiter hinten; der laengere Zaun um
den Block loest beide.
"""
try:
zeilen = normal(taskdatei.read_text(encoding="utf-8")).split("\n")
except (OSError, UnicodeDecodeError) as fehler:
return [(0, f"Taskdatei nicht lesbar ({fehler})")]
befunde = []
i = 0
while i < len(zeilen):
laenge = zaun(zeilen[i])
start = i
i += 1
if not laenge:
continue
spalte = len(zeilen[start]) - len(zeilen[start].lstrip())
while i < len(zeilen) and not schliesst(zeilen[i], laenge, spalte):
if zeilen[i].rstrip().endswith("`" * laenge):
befunde.append((i + 1, f"Zaun klebt an der Codezeile, Block ab Zeile {start + 1}; der Schlusszaun "
"gehoert auf eine eigene Zeile, ein Text mit Zaunfolge in einen laengeren Zaun"))
break
kern = zeilen[i].lstrip()
if kern.startswith("`" * laenge):
befunde.append((i + 1, f"hier oeffnet ein Block, der Block ab Zeile {start + 1} ist aber nicht geschlossen; "
"es fehlt sein Schlusszaun, oder der Text braucht einen laengeren Zaun"))
start, laenge, spalte = i, len(kern) - len(kern.lstrip("`")), len(zeilen[i]) - len(kern)
i += 1
if i >= len(zeilen):
befunde.append((start + 1, f"Block schliesst nie (Zaun aus {laenge} Backticks)"))
i += 1
return befunde
def bloecke(taskdatei: Path, kopie: Path | None = None):
zeilen = normal(taskdatei.read_text(encoding="utf-8")).split("\n")
geplant = zieldateien(zeilen, wurzeln(taskdatei.parent))
@@ -149,17 +241,13 @@ def bloecke(taskdatei: Path, kopie: Path | None = None):
ziel, ungeklaert = neu, None
elif offen:
ungeklaert = (i + 1, offen)
if zeile.lstrip().startswith("```"):
laenge = zaun(zeile)
if laenge:
einzug = len(zeile) - len(zeile.lstrip())
kern = zeile.lstrip()
laenge = len(kern) - len(kern.lstrip("`"))
start = i
i += 1
inhalt = []
while i < len(zeilen):
kandidat = zeilen[i].lstrip()
if kandidat.startswith("`" * laenge) and not kandidat.strip("`").strip():
break
while i < len(zeilen) and not schliesst(zeilen[i], laenge, einzug):
inhalt.append(zeilen[i][einzug:] if zeilen[i][:einzug].strip() == "" else zeilen[i])
i += 1
k = start - 1
@@ -219,6 +307,14 @@ def loesche(taskdatei: Path, kopie: Path) -> int:
def main() -> int:
plan, kopie = Path(sys.argv[1]), Path(sys.argv[2])
befunde = 0
# Erst alle Zaeune aller Taskdateien, dann der erste Schreibvorgang: Hinter einem kaputten Zaun stimmt die Datei nicht mehr
for name in sys.argv[3:]:
for zeile, meldung in zaunbefunde(plan / name):
print(f"BEFUND {name}:{zeile}: {meldung}; nichts geschrieben")
befunde += 1
if befunde:
print(f"{befunde} Befund(e).")
return 2
for name in sys.argv[3:]:
taskdatei = plan / name
alt = None