Prozessmodelle versioniert unter prozesse/<name>/ ablegen

Jedes Modell bekommt einen eigenen Ordner mit Steckbrief (README.md,
Status Entwurf|abgenommen), der maßgeblichen Arbeitsschritt-.md und der
daraus erzeugten .bpmn (ADR 0003).

- scripts/pruefe_prozesse.py prüft Ordnername, Dateien, Status und ob
  jede .bpmn byte-gleich mit der Umwandlung ihrer .md ist; --erzeugen
  erzeugt alle .bpmn neu. md_to_bpmn.py arbeitet deterministisch.
- tests/test_pruefe_prozesse.py: Bestandsprüfung plus 11 Fälle für die
  Prüflogik; pytest.ini sammelt .agents/skills und tests.
- Die in Anleitung.md genannten, nie committeten Beispiele liegen jetzt
  unter .agents/skills/sn-bpmn/beispiele/ und werden mitgeprüft.
- Skill sn-bpmn: Entwürfe nach entwuerfe/, neuer Schritt 5 „Ablegen“.
- Vorlage docs/vorlagen/prozess_readme.md, Doku und Fallstricke ergänzt.
- Tests: python -m pytest -q -> 44 bestanden.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-23 13:02:48 +02:00
co-authored by Claude Opus 5.5
parent 012509b6d1
commit 55c024dbc9
25 changed files with 835 additions and 35 deletions
+109
View File
@@ -0,0 +1,109 @@
"""Tests für scripts/pruefe_prozesse.py und für den Bestand unter prozesse/ – reines Python/pytest."""
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "scripts"))
import pruefe_prozesse as pp # noqa: E402
MODELL = """Prozess: Testprozess
S1 Start: Beginn
S2 Task: Etwas tun
S3 Ende: Fertig
"""
STECKBRIEF = """# Testprozess
| | |
|---|---|
| Status | {status} |
| Stand | 2026-09-23 |
"""
def lege_prozess_an(wurzel, name="test-prozess", status="Entwurf"):
ordner = wurzel / name
ordner.mkdir()
md = ordner / f"{name}.md"
md.write_text(MODELL, encoding="utf-8")
(ordner / f"{name}.bpmn").write_bytes(pp.erzeuge_bpmn(md))
(ordner / "README.md").write_text(STECKBRIEF.format(status=status), encoding="utf-8")
return ordner
def test_bestand_unter_prozesse_und_beispiele_ist_konsistent():
"""Prüft, dass alle Prozessordner und Skill-Beispiele im Repository ohne Befund sind."""
assert pp.pruefe_alles() == []
def test_es_gibt_mindestens_ein_beispiel():
"""Prüft, dass der Abgleich .md/.bpmn wenigstens an den Skill-Beispielen tatsächlich greift."""
assert pp.beispiele(), "keine Beispiele in .agents/skills/sn-bpmn/beispiele/"
def test_gueltiger_prozessordner_hat_keine_befunde(tmp_path):
"""Prüft, dass ein vollständiger Ordner mit aktueller .bpmn und gültigem Status durchgeht."""
assert pp.pruefe_ordner(lege_prozess_an(tmp_path)) == []
def test_status_abgenommen_ist_gueltig(tmp_path):
"""Prüft, dass der Status 'abgenommen' akzeptiert wird."""
assert pp.pruefe_ordner(lege_prozess_an(tmp_path, status="abgenommen")) == []
def test_unbekannter_status_wird_gemeldet(tmp_path):
"""Prüft, dass ein Status außerhalb von Entwurf/abgenommen gemeldet wird."""
befunde = pp.pruefe_ordner(lege_prozess_an(tmp_path, status="fertig"))
assert any("Status 'fertig' unbekannt" in b for b in befunde)
def test_fehlende_statuszeile_wird_gemeldet(tmp_path):
"""Prüft, dass ein Steckbrief ohne Statuszeile gemeldet wird."""
ordner = lege_prozess_an(tmp_path)
(ordner / "README.md").write_text("# Testprozess\n", encoding="utf-8")
assert any("Status | … |' fehlt" in b for b in pp.pruefe_ordner(ordner))
def test_ungueltiger_ordnername_wird_gemeldet(tmp_path):
"""Prüft, dass Großbuchstaben oder Unterstriche im Ordnernamen gemeldet werden."""
befunde = pp.pruefe_ordner(lege_prozess_an(tmp_path, name="Antrag_Pruefen"))
assert any("Ordnername" in b for b in befunde)
def test_fehlende_bpmn_wird_gemeldet(tmp_path):
"""Prüft, dass ein Ordner ohne erzeugte .bpmn gemeldet wird."""
ordner = lege_prozess_an(tmp_path)
(ordner / "test-prozess.bpmn").unlink()
befunde = pp.pruefe_ordner(ordner)
assert any("test-prozess.bpmn fehlt" in b for b in befunde)
def test_fremde_datei_im_prozessordner_wird_gemeldet(tmp_path):
"""Prüft, dass zusätzliche Dateien (etwa eine Original-PDF) im Prozessordner gemeldet werden."""
ordner = lege_prozess_an(tmp_path)
(ordner / "quelle.pdf").write_bytes(b"%PDF")
assert any("quelle.pdf gehört nicht hierher" in b for b in pp.pruefe_ordner(ordner))
def test_veraltete_bpmn_wird_gemeldet(tmp_path):
"""Prüft, dass eine .bpmn gemeldet wird, die nach einer Änderung der .md nicht neu erzeugt wurde."""
ordner = lege_prozess_an(tmp_path)
md = ordner / "test-prozess.md"
md.write_text(MODELL.replace("Etwas tun", "Etwas anderes tun"), encoding="utf-8")
assert any("passt nicht zu test-prozess.md" in b for b in pp.pruefe_ordner(ordner))
def test_zeilenenden_der_bpmn_spielen_keine_rolle(tmp_path):
"""Prüft, dass eine unter Windows mit CRLF ausgecheckte .bpmn nicht als veraltet gilt."""
ordner = lege_prozess_an(tmp_path)
bpmn = ordner / "test-prozess.bpmn"
bpmn.write_bytes(bpmn.read_bytes().replace(b"\n", b"\r\n"))
assert pp.pruefe_ordner(ordner) == []
def test_nicht_umwandelbare_md_wird_gemeldet(tmp_path):
"""Prüft, dass eine .md mit Syntaxfehler (doppelte Schritt-ID) als Befund statt als Absturz endet."""
ordner = lege_prozess_an(tmp_path)
(ordner / "test-prozess.md").write_text(MODELL + "S2 Task: Noch einmal S2\n", encoding="utf-8")
assert any("lässt sich nicht umwandeln" in b for b in pp.pruefe_ordner(ordner))