[REFACTOR] Stufe 2, Schritte 0-4: Frage-Schale und reinen Bauteil trennen
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>
This commit is contained in:
+40
-2
@@ -529,6 +529,7 @@
|
||||
(cons "eingaben_offen" 0)
|
||||
(cons "glieder_soll" nil)
|
||||
(cons "glieder_ist" nil)
|
||||
(cons "journal_diff" nil)
|
||||
(cons "prompts" 0)
|
||||
(cons "meldungen" nil)
|
||||
(cons "spec_fehler" nil)
|
||||
@@ -600,6 +601,8 @@
|
||||
",\n"
|
||||
" \"glieder_ist\": " (vsp-json-liste (ssg-val rec "glieder_ist"))
|
||||
",\n"
|
||||
" \"journal_diff\": " (vsp-json-str (ssg-val rec "journal_diff"))
|
||||
",\n"
|
||||
" \"prompts\": " (vsp-json-int (ssg-val rec "prompts")) ",\n"
|
||||
" \"meldungen\": " (vsp-json-liste (ssg-val rec "meldungen"))
|
||||
",\n"
|
||||
@@ -687,6 +690,32 @@
|
||||
(setq soll (cdr soll) ist (cdr ist))))
|
||||
diff)
|
||||
|
||||
;; Das aus der Spec erzeugte Journal gegen das beim Bau NEU aufgezeichnete
|
||||
;; stellen. Beide muessen Token fuer Token gleich sein: der Replay gibt jeden
|
||||
;; Wert an denselben Wrapper, der ihn wieder journalisiert - passt der Ablauf
|
||||
;; zur Spec, entsteht dasselbe Journal.
|
||||
;;
|
||||
;; Das ist der SCHAERFSTE 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. Rueckgabe: nil bei Gleichheit, sonst ein Text
|
||||
;; mit der ersten Abweichung.
|
||||
(defun vsp-journal-diff (soll ist / i a b diff)
|
||||
(setq i 0 diff nil)
|
||||
(while (and (null diff) (or soll ist))
|
||||
(setq i (1+ i) a (car soll) b (car ist))
|
||||
(cond
|
||||
((null a) (setq diff (strcat "Token " (itoa i) ": Spec zu Ende, gebaut "
|
||||
(vl-princ-to-string b))))
|
||||
((null b) (setq diff (strcat "Token " (itoa i) ": erwartet "
|
||||
(vl-princ-to-string a) ", gebaut nichts")))
|
||||
((not (equal a b))
|
||||
(setq diff (strcat "Token " (itoa i) ": erwartet "
|
||||
(vl-princ-to-string a) ", gebaut "
|
||||
(vl-princ-to-string b))))
|
||||
(T (setq soll (cdr soll) ist (cdr ist)))))
|
||||
diff)
|
||||
|
||||
;; Eine Kette aus einer Spec bauen. Rueckgabe: Ergebnis-Record (Alist).
|
||||
;; Die Klammer um vf-linienzug-modus ist dieselbe wie in
|
||||
;; tests/test_hm_recformat.lsp: *error* sichern, fangen, *error* zurueck. Weil
|
||||
@@ -696,7 +725,7 @@
|
||||
;; schon SSG_VF_EDIT_SEG/_PRE geschrieben).
|
||||
(defun vsp-bau-aus-spec (spec / kopf sid journal rec vor-ent alt-error err
|
||||
offen hl meld ist-glieder soll-glieder diff
|
||||
ent ed dim)
|
||||
ist-journal jdiff ent ed dim)
|
||||
(setq kopf (vsp-kopf spec))
|
||||
(setq sid (vsp-spec-id kopf))
|
||||
(setq journal (vsp-journal spec))
|
||||
@@ -739,7 +768,8 @@
|
||||
(setq err (vl-catch-all-apply 'vf-linienzug-modus '()))
|
||||
(setq offen (vsp-queue-rest))
|
||||
;; Diagnose VOR dem Reset sichern (vfl-journal-reset loescht sie).
|
||||
(setq ist-glieder (vfl-journal-glieder (reverse *vfl-journal*)))
|
||||
(setq ist-journal (reverse *vfl-journal*))
|
||||
(setq ist-glieder (vfl-journal-glieder ist-journal))
|
||||
(setq hl (vsp-headless-fehler-text))
|
||||
(setq meld (if (boundp '*vfl-meldungen*) *vfl-meldungen* nil))
|
||||
(setq *error* alt-error)
|
||||
@@ -760,6 +790,8 @@
|
||||
(setq rec (vsp-set rec "attribs" (ssg-attrib-read ent)))))
|
||||
|
||||
(setq diff (vsp-glieder-diff soll-glieder ist-glieder))
|
||||
(setq jdiff (vsp-journal-diff journal ist-journal))
|
||||
(setq rec (vsp-set rec "journal_diff" jdiff))
|
||||
(cond
|
||||
(hl
|
||||
(princ (strcat "\n DESYNC: " hl))
|
||||
@@ -782,6 +814,12 @@
|
||||
(princ (strcat "\n DESYNC: " diff))
|
||||
(setq rec (vsp-set rec "status" "desync"))
|
||||
(setq rec (vsp-set rec "fehler_text" diff)))
|
||||
;; Feinster Detektor zuletzt: Queue geht auf, Glied-Folge stimmt -
|
||||
;; aber ein Wert wurde an anderer Stelle verbraucht als geplant.
|
||||
(jdiff
|
||||
(princ (strcat "\n DESYNC (Journal): " jdiff))
|
||||
(setq rec (vsp-set rec "status" "desync"))
|
||||
(setq rec (vsp-set rec "fehler_text" jdiff)))
|
||||
((null ent)
|
||||
(princ "\n FEHLER: kein VF_-Block entstanden")
|
||||
(setq rec (vsp-set rec "status" "abbruch"))
|
||||
|
||||
Reference in New Issue
Block a user