Neues Wissensdokument docs/wissen/picture_import.md: Aufbau eines PICTURE-BPMN-Exports, Abbildung auf die Markdown-Syntax von sn-bpmn und die Befunde aus der Rückwandlung von 23 Diagrammen des AG-Bestands (Konverter, Syntax, Modelle). Kurzeinträge in fallstricke.md, Verweis im Wegweiser docs/README.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
14 KiB
Fallstricke und Erkenntnisse
Gemeinsames Gedächtnis: Dinge, die man nicht aus dem Code ablesen kann und die schon einmal Zeit gekostet haben. Kurz, konkret, mit Datum und Quelle. Neue Einträge oben in der passenden Rubrik. Veraltetes löschen, nicht auskommentieren.
BPMN und PICTURE (Skill sn-bpmn, md_to_bpmn.py)
-
Echte Daten brechen, was die Beispiele nicht zeigen. Der Stresstest mit 23 Diagrammen aus PICTURE ist strukturell sauber (keine Kante durch ein Element). Er zeigt aber: Gateway-Fragen über 80 Zeichen werden geschnitten, 31 Datenobjekte in einer Reihe machen das Diagramm über 11 000 breit, und ein unbeschriftetes Gateway lässt sich keiner Lane zuordnen (
TG:wird zum Namen). Exportformat, Abbildungsregeln und alle Befunde:picture_import.md. (28.09.2026) -
PICTURE-Exporte enthalten interne Kopfdaten. Mandant, Mandanten-URL, Arbeitsbereich und REST-URLs in jeder Verknüpfung, dazu in Anmerkungen gelegentlich Raumnummern und Standorte. Exporte gehören nach
referenz/, nie nachdocs/; beim Rückwandeln nur Namen übernehmen, Anmerkungen vor dem Ablegen durchsehen. (28.09.2026) -
Vorwärtskanten kennen die übrigen Elemente nur im Notfall.
orthogonal_points()rechnet rein geometrisch zwischen zwei Anschlusspunkten. Das reicht, solange das Layout regelmäßig ist. Eine Querverbindung zwischen Geschwisterzweigen schiebt aber eine Aufgabe eine Ebene tiefer in eine Zwischenspalte. Deshalb prüftbuild_bpmn()jeden Standardweg gegen alle fremden Elemente und sucht nur bei einer Kreuzung mitumweg_points()einen Weg über freie Linien (Lückenmitten, 15 neben jedem Element; erst ein, dann zwei Zwischenknicke; kürzester gewinnt). So bleiben saubere Kanten byte-gleich. Der Belastungstest aus #12 ist jetzt ein dauerhafter Test (test_belastung_keine_kante_durch_ein_element_und_rechtwinklig, 126 Fälle). (#22, 25.09.2026) -
Auch das Aufgaben-Ende einer Gateway-Kante braucht ein gerades Stück. Das Gateway-Ende bekommt einen festen Anschlusspunkt (N/O/S/W), das Aufgaben-Ende die Layout-Seite (mit Lanes O/W, ohne Lanes N/S). Liegen beide auf verschiedenen Achsen, lief die Kante früher direkt an der Aufgabenkante entlang. Jetzt bekommt die Aufgabe einen Stub (
RECHTECK_STUB = 20) senkrecht zu ihrer Seite, danach geht es wie zwischen zwei Rauten von Stub zu Stub. Geprüft mittest_kanten_setzen_an_aufgaben_rechtwinklig_anüber alle Beispiele. Im Belastungstest aus #12 sind 378 schräge Anschlüsse verschwunden. Dafür laufen in 4 künstlichen Fällen mit Querverbindung zwischen Zweigen Kanten durch eine Aufgabe, in 2 anderen nicht mehr (Art von #22). (#23, 25.09.2026) -
PICTURE übernimmt Beschriftungspositionen und Kästchengrößen aus der Datei. Ohne
BPMNLabelsetzt es die Gateway-Beschriftung auf 180° (unter die Raute), wo der südliche Pfad und dessen Beschriftung sie schneiden. Im PICTURE-Editor steht sie auf 45°. Der Konverter setzt die Position deshalb selbst: 45°, sonst 45° rechts vom Ost-Stub, 315°, 135°, 225° – die erste Stelle, die keine Kante, Kantenbeschriftung oder kein Element schneidet. Dafür werden die Gateway-Beschriftungen nach allen Kanten gesetzt. Zu kleine Anmerkungs-Kästchen vergrößert PICTURE beim Import, dann überlappen sie Nachbarn und Lane-Grenzen. Deshalb richtet sich die Höhe nach dem Text (text_zeilen(), grobe Schätzung 7 je Zeichen), und die Anmerkungen stehen rechts neben dem Pool.GATEWAY_LABEL_BREITE = 90hängt anAUSWEICHABSTAND(#8): Bei 100 ragte die Beschriftung über die Ausweichachse bei x + 130. Pool-Name über dem Namen der ersten Lane: nur in der Vorschau beobachtet, in PICTURE kein Problem. (PICTURE 2026.4.1, #14, 25.09.2026) -
Nachrichtenflüsse enden senkrecht unter ihrem Start, nicht an einem verteilten Punkt. Der externe Pool ist ein breites Rechteck, jeder Punkt an seiner Oberkante ist ein gültiger Anschluss. Die frühere Verteilung der Anschlusspunkte über die Pool-Oberkante erzeugte schräge Linien quer durch das Diagramm. Steht unter dem Schritt ein Element, geht der Fluss über einen Gang: mit Lanes 20 neben dem Gang der Rücksprungkanten und mit längerem Stub (30 statt 20), damit sich beide nicht überdecken; ohne Lanes rechts neben allen Elementen, dafür wird der Pool breiter. Belastungstest mit 342 Varianten: vorher 182 Fälle mit Kreuzung, jetzt keiner. (#13, 25.09.2026)
-
Rücksprungkanten brauchen je Layout eine eigene Führung. Mit Lanes stehen die Elemente in festen Spalten (linksbündig, 190 auseinander). Der Rückweg läuft senkrecht nur in den Gängen zwischen den Spalten und waagrecht in einem Kanalband, das am Boden der letzten Lane nach der Platzierung angehängt wird. So bleiben die Elemente, wo sie sind, und die Kante bleibt im eigenen Pool. Ohne Lanes gibt es keine festen Spalten, parallele Zweige stehen versetzt zur Mitte. Der Kanal liegt deshalb seitlich an allen Elementen zwischen Quelle und Ziel vorbei. Steht ein Nachbar in derselben Zeile im Weg, geht die Kante unten hinaus bzw. oben hinein. Geprüft mit allen 126 Rücksprung-Varianten zweier Testmodelle, mit und ohne Lanes. (#12, 25.09.2026)
-
Vorschau und PICTURE können sich unterscheiden, auch ohne Fehler im Modell. Beispiel XOR-Gateway: PICTURE zeichnet das „X“ nach eigenen Regeln, auch ohne
isMarkerVisible. Die Vorschau (bpmn-js) hält sich an das Attribut und zeigte ohne es leere Rauten. Seit #15 setzt der Konverter das Attribut, beide zeigen das X. Wirkt etwas nur in der Vorschau falsch, erst in PICTURE gegenprüfen, bevor der Konverter geändert wird. (PICTURE 2026.4.1, #15, 25.09.2026) -
Gateway → Gateway mit Ziel „hinter“ dem Start-Stub braucht einen seitlichen Umweg. Liegt der Stub des Start-Gateways schon jenseits des Ziel-Anschlusspunkts (z. B. Südpunkt unten, Ziel höher mit Nordpunkt), läuft das letzte gerade Stück durch die Ziel-Raute.
orthogonal_points()weicht dann über_ausweichachse()aus. Die Achse liegt im Gang direkt vor der Ziel-Spalte (Abstand 85 zur Mitte), nicht in der Mitte zwischen Quelle und Ziel: Liegen die beiden zwei Spalten auseinander, steht dort eine Aufgabe (im Referenzmodell S43). (#8, 25.09.2026) -
Bekannte Layoutfehler je Kreuzung als xfail, nie je Modell. Stünde ein ganzes Modell auf
xfail, bliebe jede neue Kreuzung darin unsichtbar, solange der alte Fehler besteht. Deshalb prüfttest_keine_unbekannte_kante_fuehrt_durch_ein_elementalle Kanten gegen alle Elemente und meldet alle Funde außer den Paaren inBEKANNTE_KREUZUNGEN. Jedes dieser Paare hat einen eigenen strikten xfail-Test. Anlass: Die alte Gateway-Prüfung brach beim ersten Fund ab; bei #8 stand nur S12→S13 im Issue, tatsächlich waren es sieben Kreuzungen. (#16, 25.09.2026) -
Zusammenführende Gateways brauchen eine Beschriftung mit Zuständigkeit, sonst landen sie in der Lane „Nicht zugeordnet“ (
split_lane()braucht Text nach dem Doppelpunkt). In BPMN bleiben Zusammenführungen üblicherweise unbeschriftet – ein Fall für eine spätere Konverteränderung. (23.09.2026, Referenzmodell) -
Das bpmn.io-Wasserzeichen ist Lizenzauflage. bpmn-js steht unter MIT, verlangt aber, dass das Wasserzeichen unten rechts sichtbar bleibt und nicht überdeckt wird. In
werkzeuge/vorschau/vorschau.htmldeshalb nichts in die untere rechte Ecke der Zeichenfläche legen. (bpmn-jsLICENSE, 23.09.2026) -
Diagramme nie roh in ein
<script>schreiben. Eine Beschriftung mit</script>würde den Skriptblock beenden.scripts/vorschau.pymaskiert jedes<im Diagramm als\u003c; die Bibliothek selbst wird nicht verändert, sondern nur auf<script/</scriptgeprüft. (23.09.2026) -
Jede Änderung an der Ausgabe von
md_to_bpmn.pymacht die abgelegten.bpmnrot. Der Test intests/test_pruefe_prozesse.pyvergleicht jede.bpmnder Prozessbibliothek und inbeispiele/byte-genau mit der Umwandlung ihrer.md. Nach einer Konverteränderungpython scripts/pruefe_prozesse.py --erzeugenausführen; die neuen.bpmnder Beispiele gehören in den Pull Request, die der Bibliothek in einen eigenen Pull Request dort (ADR 0004). Das setzt voraus, dass der Konverter deterministisch bleibt: keine Zufalls-IDs, keine Zeitstempel, keine Reihenfolge ausset-Iteration. (ADR 0003, 23.09.2026; ADR 0004, 25.09.2026) -
Zusätzliche Zeilen in einer Arbeitsschritt-
.mdnur ganz oben oder mit#.parse_markdown()bricht nach dem ersten Schritt bei jeder unbekannten Zeile ab; davor überspringt es Zeilen, die nicht wieSchlüssel: Wertaussehen. Deshalb steht der Einlese-Vermerk (<!-- eingelesen: … -->) als erste Zeile. (23.09.2026,scripts/einlesen.py) -
Path.read_text()macht aus CRLF stillschweigend LF. Wer eine Datei liest und mit Zusatz zurückschreibt, stellt so Windows-Dateien unbemerkt um.scripts/einlesen.pyliest deshalb als Bytes. (23.09.2026, Test) -
Metadaten gehören nicht als Kopfzeile in die Arbeitsschritt-
.md.parse_markdown()liest eine Zeile wieVerantwortliche Stelle: …als Schritt mit IDVerantwortlicheund TypStelleund bricht ab. Status und Stand stehen deshalb im SteckbriefREADME.mddes Prozessordners. (23.09.2026) -
Zuständigkeit gilt auch für Gateways und Ereignisse. Ohne
Rolle:-Präfix landen sie in der Lane „Nicht zugeordnet“. Ein?stört nur vor dem Doppelpunkt:Sachbearbeitung: Antrag vollständig?funktioniert. (23.09.2026, beim Erstellen der Beispiele) -
Ein Gateway hat in PICTURE nur vier feste Anschlusspunkte (N/O/S/W auf der Rautenkontur), keinen variablen Rand wie ein Rechteck. Eine Kante, die diesen Punkt verlässt bzw. dort ankommt, darf sich danach nicht direkt zur Ziel-/Quellkoordinate drehen, wenn diese auf der anderen Achse liegt – sonst läuft der rechtwinklige Streckenzug quer durchs Innere der Raute zurück, statt außen herumzugehen (
orthogonal_points()inmd_to_bpmn.py, behoben BPMN-Skill 21.09.2026). Ursache: die feste Anschlusspunkt-Zuteilung (assign_gateway_sides(), Präferenzreihenfolge S/O/W/N bzw. N/W/O/S) kennt die tatsächliche Lage des anderen Endes nicht. Die Kante muss beim Verlassen/Ankommen an einer Raute zuerst ein Stück auf der sicheren Stub-Achse bleiben (die einzige garantiert freie Koordinate außerhalb der Kontur), bevor sie zur anderen Achse abbiegt – sonst reicht ein einfacher Bounding-Box-Test nicht, um den Fehler zu erkennen (ein Punkt auf der Rautenkontur liegt immer innerhalb der Bounding-Box). Prüfen mit echter Diamant-Geometrie (Manhattan-Abstand zum Mittelpunkt, skaliert auf die Halbachsen, < 1 heißt innen), nicht mit der Bounding-Box – siehetest_kante_fuehrt_nicht_durchs_innere_eines_gatewaysintest_md_to_bpmn.py.
Text und Sprache
- Deutscher Text ohne Umlaute/ß ist ein eigenständiges Muster, kein Einzelfall. KI-generierter Text weicht
gern auf ASCII aus (
gueltigstattgültig,ueberstattüber) – in AG_QGIS über alle Plugins verteilt gefunden (Plugin_SN_Basis #42), im BPMN-Skill in Elementnamen und Docstrings. Neuen deutschen Text (Beschriftungen im Modell, Kommentare, Docstrings) immer mit echten Umlauten/ß schreiben. Vor dem Commitpython scripts/pruefe_umlaute.pylaufen lassen – findet das Muster in.py-Dateien (String-Inhalte und Kommentare mit Leerzeichen). Die Wortstammliste ist bewusst konservativ; Ersatz fürs Lesen ist sie nicht. Arbeitsschritt-.mdprüft das Skript nicht. (AG_QGIS 09/2026)
Umgebung und Werkzeuge
-
Relative Verweise in eingebetteten Stylesheets gehen in der Einzeldatei verloren. Die CSS der Bootstrap Icons lädt ihre Schrift über
url("fonts/bootstrap-icons.woff2?…"). Beim direkten Öffnen vonvorschau.htmlklappt das, in der vonscripts/vorschau.pyerzeugten Einzeldatei nicht. Deshalb setzt_schriften_einbetten()die woff2-Schrift alsdata:-URI ein und lässt den woff-Rückfall weg. Ein Test verlangt, dass jedeurl(...)der erzeugten Seitedata:oder ein Fragment (#…, SVG-Verweise aus bpmn-js) ist. (#27, 25.09.2026) -
Öffentliche Organisation heißt nicht öffentliches Repo. In Gitea haben Organisation und Repo getrennte Sichtbarkeit.
AG_Prozessewar öffentlich,Projektwissenprivat: Die Weboberfläche zeigte es angemeldeten Personen normal, die API ohne Anmeldung lieferte 404.scripts/gitea.pyliest bewusst ohne Token und braucht deshalb ein öffentliches Repo; es prüft das jetzt vor jeder Abfrage. Prüfen ohne Anmeldung:curl -s -o /dev/null -w "%{http_code}" https://entwicklung.flurneuordnung-sachsen.de/api/v1/repos/AG_Prozesse/Projektwissenmuss200liefern. (23.09.2026) -
Gitea ordnet Commits über die E-Mail-Adresse zu. Stimmt
user.emailnicht mit einer im Gitea-Konto hinterlegten Adresse überein, erscheinen die Commits ohne Zuordnung zum Benutzer. Es gilt die dienstliche Adresse, die im Gitea-Konto hinterlegt ist. Wer den Rechner auch privat nutzt, setzt sie je Repository mitgit config --localstatt global. Nachträglich nur durch Umschreiben der Historie korrigierbar. (AG_QGIS 04.09.2026) -
pytestist die einzige Abhängigkeit außerhalb der Standardbibliothek. Die Tests des Konverters brauchen es;md_to_bpmn.pyselbst läuft ohne. (23.09.2026) -
.vscode/gehört nicht ins Repository. Einstellungen mit Pfaden eines einzelnen Arbeitsplatzes gehören in die Benutzereinstellungen, siehedocs/leitfaden/04_werkzeuge_einrichten.md. (AG_QGIS 04.09.2026)
Zusammenarbeit
- Tool-Gedächtnis ist lokal. Die Claude-Auto-Memory sieht niemand sonst. Geteiltes Wissen nur in diesem Ordner.
- Issues sind teils Diskussionen, nicht Aufträge (Label
Diskussion). Vor der Umsetzung Konsens im Issue abwarten oder im PR als Annahme kennzeichnen. - Quelldokumente enthalten oft Interna. Word/PDF-Prozessbeschreibungen nur lokal unter
referenz/ablegen (nicht versioniert). Vor dem Committen eines Arbeitsschritt-Entwurfs prüfen, dass keine Namen, Aktenzeichen oder Verfahrensdaten darin stehen. (23.09.2026)