Prozessbibliothek als eigenes Repository auslagern (#9)
- ADR 0004 ersetzt ADR 0003: Die Prozessmodelle liegen im Repository AG_Prozesse/Prozessbibliothek, geklont nach Prozessbibliothek/ (neuer Eintrag in workspace.toml, .gitignore). prozesse/ ist entfernt; das Ablageformat (Ordner je Prozess, drei Dateien, Status) bleibt. - pruefe_prozesse.py prüft den Klon (Ort über setup_workspace.repos_root), lässt Punkt-Ordner wie .git aus und erlaubt in der Wurzel nur die Repo-Dateien. Fehlt der Klon, gibt es einen Hinweis statt eines Befunds; pytest warnt dann. - einlesen.py sucht den Bestand in der Bibliothek und nennt Treffer als Prozessbibliothek/<name>/, auch wenn der Klon woanders liegt. - Regeln aus prozesse/README.md nach docs/leitfaden/08_prozessbibliothek.md, inklusive Ablauf bei Konverteränderungen (zwei Pull Requests). - Verweise in AGENTS.md, README, Skills, Leitfäden, Vorlagen, Fallstricken und STATUS nachgezogen. - Tests: python -m pytest -q -> 88 bestanden, 1 xfail (#8), 1 Warnung (Bibliothek noch nicht geklont). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+11
-8
@@ -11,7 +11,8 @@ Mechanische; die fachliche Einschätzung und die Rückfrage an den Menschen mach
|
||||
geändert .md mit Vermerk, aber der Inhalt hat sich seitdem geändert
|
||||
eingelesen .md mit Vermerk, Inhalt unverändert – wird übersprungen
|
||||
Für neue und geänderte Dateien: vorgeschlagener Prozessname, ob die Datei schon eine
|
||||
gültige Arbeitsschritt-.md ist, und ähnliche vorhandene Prozesse (prozesse/, entwuerfe/).
|
||||
gültige Arbeitsschritt-.md ist, und ähnliche vorhandene Prozesse
|
||||
(Prozessbibliothek, entwuerfe/).
|
||||
vermerk Trägt nach erfolgreichem Einlesen oben in die .md einen Vermerk mit Zeitstempel ein.
|
||||
|
||||
Aufrufe (aus dem Workspace-Root):
|
||||
@@ -39,9 +40,11 @@ import unicodedata
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from setup_workspace import repos_root
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
EINGANG = ROOT / "input"
|
||||
PROZESSE = ROOT / "prozesse"
|
||||
BIBLIOTHEK = repos_root() / "Prozessbibliothek" # eigenes Repository (ADR 0004), wie in pruefe_prozesse.py
|
||||
ENTWUERFE = ROOT / "entwuerfe"
|
||||
SKILL = ROOT / ".agents" / "skills" / "sn-bpmn"
|
||||
|
||||
@@ -103,7 +106,7 @@ def setze_vermerk(pfad: Path, ergebnis: str, ziel: str, jetzt: datetime | None =
|
||||
# ------------------------------------------------------------ Einordnung ---
|
||||
|
||||
def slug(text: str) -> str:
|
||||
"""Ordnername nach ADR 0003: Kleinbuchstaben, Ziffern, Bindestriche; Umlaute ausgeschrieben."""
|
||||
"""Ordnername nach ADR 0004: Kleinbuchstaben, Ziffern, Bindestriche; Umlaute ausgeschrieben."""
|
||||
text = text.lower()
|
||||
for alt, neu in (("ä", "ae"), ("ö", "oe"), ("ü", "ue"), ("ß", "ss")):
|
||||
text = text.replace(alt, neu)
|
||||
@@ -138,16 +141,16 @@ def ist_arbeitsschritt_md(text: str) -> bool:
|
||||
|
||||
|
||||
def bestand() -> list[dict]:
|
||||
"""Vorhandene Prozesse (prozesse/) und lokale Entwürfe (entwuerfe/) mit Titel und Wörtern."""
|
||||
"""Vorhandene Prozesse (Prozessbibliothek) und lokale Entwürfe (entwuerfe/) mit Titel und Wörtern."""
|
||||
eintraege = []
|
||||
if PROZESSE.is_dir():
|
||||
for ordner in sorted(p for p in PROZESSE.iterdir() if p.is_dir()):
|
||||
if BIBLIOTHEK.is_dir():
|
||||
for ordner in sorted(p for p in BIBLIOTHEK.iterdir() if p.is_dir() and not p.name.startswith(".")):
|
||||
md = ordner / f"{ordner.name}.md"
|
||||
text = md.read_text(encoding="utf-8") if md.is_file() else ""
|
||||
readme = ordner / "README.md"
|
||||
titel = titel_von(readme.read_text(encoding="utf-8"), ordner.name) if readme.is_file() else ordner.name
|
||||
eintraege.append({"art": "Prozess", "name": ordner.name, "titel": titel_von(text, titel),
|
||||
"pfad": ordner.relative_to(ROOT).as_posix() + "/", "woerter": woerter(text)})
|
||||
"pfad": f"{BIBLIOTHEK.name}/{ordner.name}/", "woerter": woerter(text)})
|
||||
if ENTWUERFE.is_dir():
|
||||
for md in sorted(ENTWUERFE.glob("*.md")):
|
||||
if re.match(r"^\d{8}-\d{6}-(issue|kommentar)-", md.name):
|
||||
@@ -261,7 +264,7 @@ def main() -> int:
|
||||
v = unter.add_parser("vermerk", help="Einlese-Vermerk in eine .md schreiben")
|
||||
v.add_argument("datei", help="Datei in input/")
|
||||
v.add_argument("--ergebnis", required=True, choices=ERGEBNISSE)
|
||||
v.add_argument("--ziel", required=True, help="wo das Ergebnis liegt, z. B. entwuerfe/<name>.md oder prozesse/<name>/")
|
||||
v.add_argument("--ziel", required=True, help="wo das Ergebnis liegt, z. B. entwuerfe/<name>.md oder Prozessbibliothek/<name>/")
|
||||
args = ap.parse_args()
|
||||
|
||||
if args.befehl == "vermerk":
|
||||
|
||||
+49
-15
@@ -1,7 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Prüft die versionierten Prozessmodelle unter prozesse/ und die Beispiele des Skills sn-bpmn.
|
||||
"""Prüft die versionierten Prozessmodelle der Prozessbibliothek und die Beispiele des Skills sn-bpmn.
|
||||
|
||||
Jeder Prozess liegt in einem eigenen Ordner prozesse/<name>/ mit genau drei Dateien:
|
||||
Die Prozessbibliothek ist ein eigenes Repository (AG_Prozesse/Prozessbibliothek, ADR 0004). Sie wird von
|
||||
scripts/setup_workspace.py neben Projektwissen geklont – in den Workspace-Ordner oder nach repos_root aus
|
||||
workspace.local.toml. Jeder Prozess liegt dort in einem eigenen Ordner <name>/ mit genau drei Dateien:
|
||||
|
||||
README.md Steckbrief mit Status, Stand, Zuständigkeit (Vorlage docs/vorlagen/prozess_readme.md)
|
||||
<name>.md Arbeitsschritt-Beschreibung – die maßgebliche Quelle
|
||||
@@ -11,12 +13,17 @@ Geprüft wird:
|
||||
* Ordnername in Kleinbuchstaben, Ziffern und Bindestrichen,
|
||||
* genau diese drei Dateien, keine weiteren (Originalunterlagen gehören nach referenz/),
|
||||
* README.md nennt einen gültigen Status (Entwurf | abgenommen),
|
||||
* <name>.md lässt sich umwandeln, und <name>.bpmn ist byte-gleich mit dem Ergebnis.
|
||||
* <name>.md lässt sich umwandeln, und <name>.bpmn ist byte-gleich mit dem Ergebnis,
|
||||
* in der Wurzel der Bibliothek liegen außer den Prozessordnern nur README.md, AGENTS.md, CLAUDE.md,
|
||||
.gitattributes und .gitignore.
|
||||
Ist die Bibliothek nicht geklont, ist das kein Befund; es werden nur die Beispiele geprüft, und ein Hinweis
|
||||
nennt den Befehl zum Klonen.
|
||||
Die Beispiele in .agents/skills/sn-bpmn/beispiele/ werden auf die letzte Bedingung geprüft.
|
||||
|
||||
Aufrufe (aus dem Workspace-Root):
|
||||
python scripts/pruefe_prozesse.py # alles prüfen
|
||||
python scripts/pruefe_prozesse.py --erzeugen # alle .bpmn aus ihren .md neu erzeugen, dann prüfen
|
||||
Die neu erzeugten .bpmn der Bibliothek werden dort auf einem eigenen Branch committet (eigener Pull Request).
|
||||
|
||||
Exit-Code: 0 = in Ordnung, 1 = mindestens ein Befund.
|
||||
"""
|
||||
@@ -28,9 +35,11 @@ import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from setup_workspace import repos_root
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SKILL = ROOT / ".agents" / "skills" / "sn-bpmn"
|
||||
PROZESSE = ROOT / "prozesse"
|
||||
BIBLIOTHEK = repos_root() / "Prozessbibliothek"
|
||||
BEISPIELE = SKILL / "beispiele"
|
||||
|
||||
sys.path.insert(0, str(SKILL))
|
||||
@@ -38,6 +47,8 @@ import md_to_bpmn # noqa: E402 (liegt im Skill-Ordner, nicht als Paket install
|
||||
|
||||
ORDNERNAME = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
|
||||
STATUSWERTE = ("Entwurf", "abgenommen")
|
||||
# Dateien, die in der Wurzel der Bibliothek neben den Prozessordnern liegen dürfen
|
||||
REPO_DATEIEN = {"README.md", "AGENTS.md", "CLAUDE.md", ".gitattributes", ".gitignore"}
|
||||
STATUSZEILE = re.compile(r"^\|\s*Status\s*\|\s*(?P<wert>[^|]*?)\s*\|", re.MULTILINE)
|
||||
|
||||
|
||||
@@ -49,10 +60,13 @@ def erzeuge_bpmn(md_pfad: Path) -> bytes:
|
||||
|
||||
|
||||
def _relativ(pfad: Path) -> str:
|
||||
try:
|
||||
return pfad.relative_to(ROOT).as_posix()
|
||||
except ValueError:
|
||||
return pfad.as_posix()
|
||||
"""Pfad für Meldungen: relativ zum Workspace, Bibliotheks-Pfade beginnend mit „Prozessbibliothek/“."""
|
||||
for basis in (ROOT, BIBLIOTHEK.parent):
|
||||
try:
|
||||
return pfad.relative_to(basis).as_posix()
|
||||
except ValueError:
|
||||
pass
|
||||
return pfad.as_posix()
|
||||
|
||||
|
||||
def pruefe_modell(md_pfad: Path) -> list[str]:
|
||||
@@ -102,21 +116,39 @@ def pruefe_ordner(ordner: Path) -> list[str]:
|
||||
return befunde
|
||||
|
||||
|
||||
def prozessordner(wurzel: Path = PROZESSE) -> list[Path]:
|
||||
return sorted(p for p in wurzel.iterdir() if p.is_dir()) if wurzel.is_dir() else []
|
||||
def prozessordner(wurzel: Path = BIBLIOTHEK) -> list[Path]:
|
||||
"""Prozessordner der Bibliothek; .git und andere Punkt-Ordner zählen nicht."""
|
||||
if not wurzel.is_dir():
|
||||
return []
|
||||
return sorted(p for p in wurzel.iterdir() if p.is_dir() and not p.name.startswith("."))
|
||||
|
||||
|
||||
def beispiele(wurzel: Path = BEISPIELE) -> list[Path]:
|
||||
return sorted(wurzel.glob("*.md")) if wurzel.is_dir() else []
|
||||
|
||||
|
||||
def pruefe_alles() -> list[str]:
|
||||
def pruefe_bibliothek(wurzel: Path = BIBLIOTHEK) -> list[str]:
|
||||
"""Befunde zur Wurzel der Bibliothek und zu allen Prozessordnern; leer, wenn sie nicht geklont ist."""
|
||||
befunde: list[str] = []
|
||||
if PROZESSE.is_dir():
|
||||
for fremd in sorted(p for p in PROZESSE.iterdir() if p.is_file() and p.name != "README.md"):
|
||||
befunde.append(f"{_relativ(fremd)}: Dateien gehören in einen Prozessordner prozesse/<name>/")
|
||||
for ordner in prozessordner():
|
||||
if not wurzel.is_dir():
|
||||
return befunde
|
||||
for fremd in sorted(p for p in wurzel.iterdir() if p.is_file() and p.name not in REPO_DATEIEN):
|
||||
befunde.append(f"{_relativ(fremd)}: Dateien gehören in einen Prozessordner <name>/")
|
||||
for ordner in prozessordner(wurzel):
|
||||
befunde += pruefe_ordner(ordner)
|
||||
return befunde
|
||||
|
||||
|
||||
def hinweis_bibliothek(wurzel: Path = BIBLIOTHEK) -> str:
|
||||
"""Hinweis, wenn die Bibliothek nicht geklont ist; sonst leer."""
|
||||
if wurzel.is_dir():
|
||||
return ""
|
||||
return (f"Hinweis: Prozessbibliothek nicht geklont ({wurzel.as_posix()}) – nur die Beispiele geprüft. "
|
||||
f"Klonen mit: python scripts/setup_workspace.py")
|
||||
|
||||
|
||||
def pruefe_alles() -> list[str]:
|
||||
befunde = pruefe_bibliothek()
|
||||
for md_pfad in beispiele():
|
||||
befunde += pruefe_modell(md_pfad)
|
||||
return befunde
|
||||
@@ -145,6 +177,8 @@ def main() -> int:
|
||||
befunde = pruefe_alles()
|
||||
for befund in befunde:
|
||||
print(befund)
|
||||
if hinweis := hinweis_bibliothek():
|
||||
print(hinweis)
|
||||
anzahl = len(prozessordner())
|
||||
status = "GRÜN" if not befunde else "ROT"
|
||||
print(f"{status}: {len(befunde)} Befund/e, {anzahl} Prozess(e), {len(beispiele())} Beispiel(e).")
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ Das Skript erzeugt daraus eine einzelne, in sich geschlossene HTML-Datei (Biblio
|
||||
eingebettet) und öffnet sie im Standardbrowser. Es wird nichts übertragen; die Seite lädt nichts aus dem Netz.
|
||||
|
||||
Aufrufe (aus dem Workspace-Root):
|
||||
python scripts/vorschau.py prozesse/antrag-pruefen/antrag-pruefen.bpmn
|
||||
python scripts/vorschau.py Prozessbibliothek/antrag-pruefen/antrag-pruefen.bpmn
|
||||
python scripts/vorschau.py entwuerfe/antrag-pruefen.md # .md wird vorher umgewandelt
|
||||
python scripts/vorschau.py <datei> --ausgabe vorschau.html --nicht-oeffnen
|
||||
python scripts/vorschau.py --stdin < datei.bpmn > vorschau.html # Filter, z. B. als Gitea-Renderer
|
||||
|
||||
Reference in New Issue
Block a user