02303ad7fc
Alle Aenderungen sind verhaltensgleich: die Frage-Schalen behalten ihre Namen, keine Aufrufstelle in Modus 1/2/3 wurde angefasst. Schritt 0 - vfl-ziel-report: der Soll-Ist-Vergleich am Kettenende stand zweimal WORTGLEICH in vfl-vf-einheit-abschluss (einmal fuer "Kettenende ohne ES", einmal "mit ES"); die Faelle unterscheiden sich nur darin, wann sie melden, nicht was. Schritt 1 - Winkelwahl aufgeteilt: vfl-winkel-gueltige (Kandidaten filtern) und vfl-winkel-nach-index (Kandidat waehlen) sind rein; die Frage-Schale vfl-waehle-winkel setzt sie zusammen. Neuer Vorgabe-Kanal *vfl-winkel-idx-vorgabe*: ist er gesetzt, wird nicht gefragt. Kanal statt Parameter, weil vfl-waehle-winkel aus vier Solvern gerufen wird (vfl-vf-winkel, vfl-vf-entscheidung, vfl-body-zerlegung, vfl-segment-entscheidung) - ein Parameter wuerde vier Signaturen und alle deren Aufrufer aendern. Default nil, also heute ohne Wirkung. Schritt 2 - vfl-es-masse-setzen: reines Globals-Setzen (ES-Winkel merken + vf-set-es-masse) aus vfl-frage-es-seite gezogen. *vfl-es-winkel* wird LAZY von den Blocknamen-Bauern gelesen und muss vor dem ersten ES-Insert stehen. Schritt 3 - vfl-hor-koerper-bauen: die drei Fragen (Separator vor/nach, Endpunkt) haengen an keinem berechneten Wert und stehen jetzt alle vor dem Bau. Journal-Reihenfolge UND Entity-Reihenfolge bleiben identisch; nur interaktiv erscheint der auf_3-Uebergangsblock erst nach den drei Fragen statt zwischen Frage 1 und 2. Die dL-Subtraktionskette wurde Zeile fuer Zeile uebernommen - jeder Schritt ist mit (max *vfk-restlaenge-min-clamp* ...) geklammert, also nicht kommutativ, und der auf_3-Insert sitzt bewusst zwischen Subtraktion 1 und 2 (sein Fussabdruck wird GEMESSEN). Nachweis: Zeilenvergleich alt/neu, dieselben 15 geometrie-relevanten Zeilen in derselben Reihenfolge. Schritt 4 - vfl-body-abschluss-bauen: hier laesst sich NICHT alles vorab fragen (vfl-neue-linie-messen braucht den Frame nach vfl-nach-3grad, die Hoehenvorschlaege brauchen dL und die Kettenhoehe). Die Schale macht darum 3-Grad-Abschluss -> messen -> Vorschlaege -> Zielhoehe fragen, der reine Teil beginnt bei der Zerlegung. Nachweis: Multiset-Vergleich der Zeilen, ausser Kopf, Klammer und Aufruf ist keine Zeile veraendert. Schritt 7 (Assertion-Teil) - vsp-journal-diff in Lisp/vf_spec.lsp: stellt das aus der Spec erzeugte Journal Token fuer Token gegen das beim Bau neu aufgezeichnete. Schaerfster Desync-Detektor - offene Queue-Werte und die Glied-Folge zeigen nur grobe Abweichungen, ein einzelner Wert, der an der falschen Stelle verbraucht wird, kann beide passieren lassen und trotzdem andere Geometrie erzeugen. Neues Record-Feld journal_diff, neuer Test test_journal_token_gleich. Zwei bewusste Abweichungen von der Planung (begruendet in doc/TODO-plan-vf-interactive.md, Abschnitt "Umsetzungsstand Stufe 2"): vfl-hor-koerper-bauen behaelt ziel-modus als eigenen Parameter neben ende-code (ende-code darf nil sein, die Separator-Subtraktionen haengen aber allein am Ziel-Modus); vfl-body-abschluss-bauen braucht letzt-hz und es-gewuenscht nicht. Offen: Schritte 5, 6, 8, 9, 10. Das sind die, bei denen die Reihenfolge selbst Geometrie ist - der Fahrplan verlangt nach jedem einen CAD-Lauf (TEST_HUNDM05 + TEST_VF_SPEC + TEST_LINIENZUG), nach den Geometrie-Schritten zusaetzlich DXF-Diff und Sivas-Export-Vergleich. Ohne Lauf zwischen den Schritten waere ein Fehler nicht mehr einem Schritt zuzuordnen. Sie bringen keine neue Faehigkeit: der Bau aus Daten laeuft seit Stufe 1 und ist mit VF_SPEC_BAU belegt (5 OK, 0 Fehler). Verifiziert: 109 pytest-Tests gruen, beide .lsp lint-sauber, kein neuer alert/get*/ssget im Bau-Pfad (statischer Waechter). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>