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>
44 KiB
TODO/Plan: VF-Linienzug ohne GUI/Konsole aufrufbar machen
Stand: 2026-09-02 · Status: Stufe 0 fertig (im CAD noch ungetestet) Herkunft: Planungslauf (Plan-Modus) vom 2026-09-02, hier eingecheckt zur Nachverfolgung.
Fortschritt
| Schritt | Beschreibung | Status |
|---|---|---|
| P0 | vfl-journal-reset im Dispatcher hochziehen |
erledigt |
| P0b | member-Shadowing in vf-linienzug-modus2 |
erledigt |
| P1 | vfl-meldung statt alert in den Bau-Pfaden |
erledigt |
| P2 | *vfl-headless*: leere Replay-Queue wird zum Fehler |
erledigt |
| P3 | Kleinkram (*vfl-meldungen*-Reset, vfl-view-refresh) |
erledigt |
| S1 | Stufe 1: Lisp/vf_spec.lsp (Spec -> Journal -> Replay) |
Modus 1 fertig, im CAD ungetestet |
| S2 | Stufe 2: echte Funktionstrennung | Schritte 0-4 + 7-Assertion fertig, 5/6/8/9/10 offen, 11 zurueckgestellt |
| PY | lib/vf_journal_export.py: Grammatik vervollstaendigen |
erledigt |
Was Stufe 0 konkret gebracht hat
Neue Symbole in Lisp/vf_linienzug.lsp (Abschnitte "TEIL 0a-2" und "TEIL 0a-3"):
| Symbol | Zweck |
|---|---|
*vfl-meldungen* / vfl-meldung |
Bau-Meldungen sammeln statt blockierend zu alerten (alert nur bei ssg-gui-p, sonst princ) |
*vfl-headless* / vfl-headless-p |
Schalter "keine Live-Eingabe erlaubt" |
vfl-headless-abbruch / -notausgang / -ort |
harter Abbruch mit Fundstelle bzw. Hook-Variante |
*vfl-headless-fehler* |
Diagnose-Alist (was/glied/eingabe/ort) |
*vfl-headless-antwort-fn* |
optionaler Hook fuer nicht vorhersagbare Rueckfragen |
Eingebaut an den vier Eingabe-Engstellen (vfl-in-value, vfl-in-value-p,
vfl-in-selection 2x, vfl-in-abstand 2x). vfl-journal-reset loescht
Meldungen und Diagnose mit; vfl-view-refresh ueberspringt headless
_PLAN/_ZOOM. tests/test_hundm05.lsp schaltet *vfl-headless* ein
(Save/Restore in hundm05:stubs-an/-aus), zaehlt erreichte Live-Eingaben
(*hundm05-prompts*) und schreibt prompts, headless_fehler, meldungen
ins Ergebnis-JSON; tests/test_hundm05.py prueft alle drei.
Bereits abgesichert, ohne CAD lauffaehig: tests/test_vf_headless_statisch.py
(10 Tests) haelt das Design gegen Verrottung - eingechecktes Inventar aller
alert/get*/ssget/new_dialog-Fundstellen je Funktion (ein neues
getreal in einer Bau-Funktion faellt auf, auch wenn sein Zweig im Test nie
erreicht wird), Praesenz des Riegels in allen vier Wrappern, Diagnose-Reset
in vfl-journal-reset und die P0-Reihenfolge im Dispatcher. Der Waechter
wurde gegengeprobt: ein injizierter alert im Bau-Pfad wird erkannt, ein
alert in einem Kommentar nicht.
CAD-Lauf 1 (2026-09-03): die erste Kette wurde headless gebaut (">>> VF chain inserted! <<<", kein Prompt, kein Dialog) - der Riegel und der Replay funktionieren also. Danach brach der Treiber ab:
[TEST_HUNDM05] FEHLER in der Kettenschleife:
no function definition <ENTPREV>
entprev gibt es in AutoLISP nicht (nur entnext und entlast) - mein
Fehler in hundm05:last-insert-prefix, der Suche nach dem fertigen
VF_-Block. Erreicht wurde sie erst, weil entlast nach dem Bau nicht der
Block ist (danach entstehen noch Beschriftungstexte). Behoben:
- Suche laeuft vorwaerts (
hundm05:suche-vorwaerts, letzter Treffer gewinnt), und zwar ab dem Zeichnungsstand VOR dem Bau (vor-ent, inhundm05:build-linienzuggemerkt). Das ist schnell und kann nicht den Block eines FRUEHEREN Baus liefern - deshalb dort bewusst keinentlast-Kurzschluss. - Dieselbe Falle in
tests/test_mubea.lsp(mubea:last-insert-prefix) mitbehoben. Sie schlug dort nie zu, weilentlastbisher immer sofort traf;entprevwar nur der nie erreichte Schleifenschritt. - Die Kettenschleife fangt jetzt je Kette (
vl-catch-all-applyumhundm05:build-linienzug): ein Fehler NACH dem Bau nimmt nicht mehr die restlichen vier Ketten mit ("0 OK, 0 Fehler" ohne jede Auskunft). - Neuer Waechter
test_keine_nicht_existierenden_funktionenintests/test_vf_headless_statisch.pyprueft alle.lspinLisp/undtests/gegen eine Liste erfundener Funktionen (entprevu.a.) - genau diese Fehlerklasse (falscher Name in einem selten erreichten Zweig) kostet sonst jedes Mal einen CAD-Lauf. Gegengeprobt: ein wieder eingebautesentprevwird gefunden, das Wort im Kommentar nicht. vfl-meldungverkraftet jetzttxt= nil (fehlender i18n-Schluessel wuerdestrcatgenau dann abbrechen, wenn schon etwas schiefging).
Noch offen (braucht BricsCAD): TEST_HUNDM05 muss 5x
"status": "executed" mit prompts 0 liefern, und eine interaktive
Gegenprobe (FOERDERANLAGE -> Linienzug Modus 1, Doppelklick-Edit,
SSG_DIM_SWITCH) muss unveraendert aussehen. Erst danach kann in
tests/alltests.json das "disabled": true der hundm05-Zeile weg.
Bewusst nicht umgestellt: vfl-konvertiere-ent (Batch-2D/3D) laeuft
weiter ohne *vfl-headless* - eine Live-Rueckfrage ist dort bisher gewolltes
Verhalten. Kandidat fuer Stufe 1, wenn der Ergebnis-Record steht.
Kontext
VF_n-Ketten entstehen heute nur interaktiv: vf-linienzug-modus (Modus 1,
freies Zeichnen), vf-linienzug-modus2 (Modus 2, Pfad + Zielhoehe) und
vf-linienzug-modus3 (Modus 3, Vorwaerts-Nachbau, Legacy) fragen jeden Wert
einzeln per getpoint/getstring/getint/getreal bzw. per DCL-Wizard ab.
tests/testdata/object_data.md Abschnitt 3.3 fuehrt den Linienzug darum als
"nicht scriptbar".
Ziel: eine Kette soll aus einem Stapel Eingabedaten plus einer Handvoll
LISP-Funktionen gebaut werden koennen - ohne Dialog, ohne Konsolenfrage.
Damit werden Regressionstests (siehe tests/test_hundm05.lsp, 5 echte Ketten
aus data/polylines.dxf), Batch-Nachbauten und der 2D/3D-Umbau reproduzierbar,
und die Bau-Logik wird pro Abschnitt einzeln aufrufbar.
Entscheidungen des Auftraggebers (fix):
- Zweistufig: erst Daten-API (Spec -> Journal -> Replay), dann echte Trennung der Misch-Funktionen in Frage-Schale + reinen Bauteil.
- Modus 1 + 2 vollstaendig, Modus 3 nur duenn gewrappt (ist als "wird umgebaut" markiert).
- Eingabeformat: benannte LISP-Spec (Alist je Abschnitt) + JSON-Loader.
- Fehlerverhalten: fail fast mit Ergebnis-Record, nichts raten, kein Dialog.
Zeilennummern in diesem Dokument beziehen sich auf den Stand bei der Planung
(Lisp/vf_linienzug.lsp, Lisp/vf_core.lsp) und verschieben sich mit jeder
Aenderung - im Zweifel per Funktionsname suchen.
Teil 1 - Befund: was ist heute schon headless moeglich?
| Modus | Headless heute? | Mechanismus | Blocker |
|---|---|---|---|
1 (frei zeichnend, vf-linienzug-modus :3211) |
Ja, in der Praxis | Journal-Replay: vfl-journal-replay-start :1545 fuellt *vfl-replay-queue*, alle vfl-in-*-Wrapper lesen zuerst daraus. Produktiv genutzt von vfl-edit-ent :4322, vfl-edit-glied :4190, vfl-konvertiere-ent :4292 und von tests/test_hundm05.lsp |
Alerts nicht abschaltbar (:3523, :3550, :3559, :3650, :3772); leere Queue faellt still auf Live-Eingabe zurueck (:1186-1191); Daten muessen in exakter Frage-Reihenfolge vorliegen |
2 (Pfad + Zielhoehe, vf-linienzug-modus2 :5278) |
Ja, gleicher Mechanismus | Marker "linienzug2", Replay-Einstieg vfl-edit-ent2 :4397 |
Pfad-Objekte (LINE/ARC) muessen in der Zeichnung liegen - das Journal speichert nur Handles (OBJS, handent :1060); keine STEP-Marker -> kein Sektions-Edit; Dispatcher vf_core.lsp:1139 ruft vfl-journal-reset NICHT (Journal des Vorlaufs wird als Praefix mitgeschrieben); Alerts :5418, :5650; lokale Variable member :5289/:5496 verdeckt die Builtin-Nutzung :5686/:5759 |
3 (Vorwaerts-Nachbau, vf-linienzug-modus3 :4806) |
Nein | Alle Eingaben laufen zwar durch die vfl-in-*-Wrapper (im Prinzip replaybar), aber: kein vfl-journal-reset, kein vfl-journal-xdata-schreiben, kein Marker, *error*-Hook wickelt keine Teil-Geometrie (:4835-4844) |
bewusst so, Kommentar :4825-4827; fehlt: Reset + XDATA-Schreiben + Marker + Edit-Zweig |
Modus-uebergreifende Blocker:
- 40
alert-Aufrufe im Cluster, keiner durchssg-gui-pgesichert; im Bau-Pfad erreichbar: :3523/:3550/:3559/:3650/:3772 (M1), :5418/:5650 (M2), :4901/:4921/:5029 (M3), :1067 (Replay: Handles fehlen), :123 (GF-Modul fehlt). Mehrere mit anschliessendem(exit). (ssg-gui-aus)deckt nur zwei Stellen ab:vf_core.lsp:632(vf-frage-element-winkel) undvf_linienzug.lsp:447(vfl-wizard-mode-p-> allevflw-*-Dialoge). Die Nicht-Wizard-DCLs (variofoerderer_basis,variofoerderer_winkel,gefaellestrecke,vfl_edit_modus,vfl_editund die drei wiederverwendetenvflw_*-Edit-Dialoge :3962/:4000/:4044) bleiben modal.- Der Dispatcher selbst fragt:
c:VarioFoerderer(vf_core.lsp:1073) holt Anlagentyp (getint:1108) und Untermodus (getint:1130) roh ab. Ein headless Aufruf muss darum immer direktvf-linienzug-modus*aufrufen. - Rohe Eingaben ohne Journal in Nebenpfaden:
vfl-praeambel-erfragen:4445,c:VF_SEKTION_RESTORE:4496,c:VFL_KS_DIAG:4622,c:Vario_Kette_Merge:6347. ATTREQ/ATTDIA: ohne0fragt das(command "_.INSERT" ...)in den Einfuegeprimitiven nach Attributwerten - der wahrscheinlichste Haenger.
Namensfalle: die vfl3-*-Helfer (:5093-5276) gehoeren zu Modus 2, die
vfl2-*-Helfer (:4703-4804) zu Modus 3.
Teil 2 - Invarianten
| # | Invariante | Sicherung |
|---|---|---|
| I1 | Jeder fertige VF_n-Block traegt ein gueltiges SSG_VF_EDIT-Journal (Marker "linienzug"/"linienzug2") und bleibt per Doppelklick editier- und 2D/3D-konvertierbar |
Stufe 1 baut ueber die unveraenderte Modus-Funktion (schreibt :3867 selbst). Stufe 2: kein Bauteil beruehrt das Journal - im Frage-Pfad erzeugen es die vfl-in-*-Wrapper, im Daten-Pfad wird es einmal aus der Spec erzeugt und vor dem Bau gesetzt |
| I2 | Kein Prompt, kein Dialog | GUI aus + Wizard aus + zaehlende Eingabe-Stubs + *vfl-headless* (harter Fehler statt Frage) |
| I3 | Nichts geraten | Leere Queue = Fehler mit Fundstelle; jede abgewiesene Sektion erzeugt eine gesammelte Meldung; Spec-Validierung bricht vor dem ersten Insert ab |
| I4 | Interaktives Verhalten unveraendert | Jede Produktionsaenderung ist ein No-Op, solange *ssg-gui-aus* und *vfl-headless* nil sind |
Teil 3 - Stufe 0: Vorarbeiten in der Produktion
Fuenf kleine Aenderungen, alle No-Ops im interaktiven Betrieb. Reihenfolge = Empfehlung; P0 und P1 sind eigenstaendige Bugfixes und koennen sofort raus.
P0 - vfl-journal-reset hochziehen (Lisp/vf_core.lsp:1139). Heute nur im
Modus-1-Zweig. Folge: ein frischer Modus-2-Lauf erbt das Journal des
Vorlaufs und schreibt es in die XDATA - ein spaeterer Doppelklick spielt
Muell vor. Reset vor die cond ziehen. Reiner Bugfix (die Edit-Pfade laufen
nie hier durch), behebt zugleich ein veraltetes *vfl-seg-glied-letzte*.
P0b - member-Shadowing in vf-linienzug-modus2: lokale Variable
member (:5289, gesetzt :5496) gegen Builtin-Nutzung (:5686, :5759) im
selben Scope. Lokale umbenennen (z.B. vf-run-member).
P1 - vfl-meldung statt alert in den Bau-Pfaden. Neuer Helfer neben
vfl-journal-record (~:170): Text in *vfl-meldungen* sammeln, dbgmsg
schreiben, dann alert (GUI an) oder princ (GUI aus). alert ->
vfl-meldung an genau diesen Stellen: :123, :1067, :3523, :3550, :3559,
:3650, :3772, :5418, :5650, :4901, :4921, :5029. Die reinen
Interaktiv-Alerts (:3968, :4006, :4050, :4266, :4325, :4566, :4593) bleiben.
Ohne P1 blockiert ein Alert den Lauf und der Text - die einzige Auskunft,
welche Sektion abgewiesen wurde - ist verloren.
P2 - *vfl-headless*: leere Queue wird zum Fehler. Neuer Notausgang
vfl-headless-notausgang (was) neben vfl-replay-pop (~:210): setzt
*vfl-headless-fehler* samt Glied-Index und Eingabe-Nummer (aus
vfl-steps-zaehlen :1612 und (length *vfl-journal*)), meldet und bricht ab.
Optionaler Hook *vfl-headless-antwort-fn* darf einen Wert liefern (wird
journalisiert und als Warnung protokolliert). Vier Einbaustellen, je ein
neuer cond-Zweig vor der Live-Eingabe:
vfl-in-value:1185 undvfl-in-value-p:1196 - decktvfl-in-point,-string,-real,-int,vfl-menu,vfl-menu-int,vfl-menu-winkelund die AS/ES-Winkelfrage ab (rund 90 % aller Eingaben)vfl-in-selection:1055 (vor demssget:1069) und derfehlt > 0-Zweig :1066: unter headless abbrechen statt mit einer Teilauswahl weiterzubauen (aendert sonst still die Modus-2-Fragenzahl)vfl-in-abstand:2113 (eigene Replay-Logik)
P3 - Kleinkram: *vfl-meldungen* in vfl-journal-reset :157 mitloeschen;
vfl-view-refresh :2028 unter headless ueberspringen (_.PLAN/_.ZOOM vor
jeder Laengeneingabe, im Batch nur Kosten).
Teil 4 - Stufe 1: Daten-API (Spec -> Journal -> Replay)
Neue Datei Lisp/vf_spec.lsp, geladen aus vf_core.lsp direkt nach
vf_linienzug.lsp (:1062) - deckt beide Ladewege ab (MNL ueber
VarioFoerderer.lsp und Lisp/ssg_load.lsp), also keine Aenderung an
menu/SSG_LIB.mnl. Guarded Nachlade-load am Kopf fuers isolierte Testen
(Muster ssg_ks_insert in vf_core.lsp:66).
4.1 Spec-Form
'(("version" . 1) ("modus" . 1) ("name" . "VF_LZ_01") ("dim" . "3D")
("start" ("punkt" 4912.0 1231.0 2100.0) ("hoehe" . 2154.0)
("as" . T) ("as-winkel" . "90") ("as-seite" . "links"))
("sektionen"
(("glied" . "Linie-GF") ("dl" . 5500.0) ("hz" . 0.0)
("gefaelle" . "winkel") ("winkel" . 3.0) ("ende" . "nein"))
(("glied" . "Horizontal-VF") ("dl" . 4566.7)
("gf-verteilung" . "einlauf") ("sep-vor" . nil) ("sep-nach" . nil)
("weiter" (("sub" . "vario-kurve") ("winkel" . 90)
("seite" . "links") ("variante" . "aussen"))
(("sub" . "horizontal") ("dl" . 250.0))
(("sub" . "kettenende") ("es" . T) ("dl" . 6215.0)
("hoehe" . 4500.0)))
("ende" ("es-winkel" . "90") ("es-seite" . "rechts")))))
Durchgaengig Domaenenwerte ("links", "winkel", "aussen", T/nil),
keine Menue-Codes; rohe Codes ("1"/"2") werden als Durchreiche fuer
zurueckgelesene Journale akzeptiert. Glied-Typen: GF-Bogen, Linie-GF,
Linie-VF, Horizontal-VF, Linie, plus das automatische ES-Glied.
Die variable VF-Einheit (heute bewusst nicht im Schema, Kommentar :260-292)
wird als ("weiter" ...)-Liste modelliert, immer terminiert mit motorstation
oder kettenende; Sub-Typen horizontal, vario-kurve, auf-ab.
Drei Fallen, die der Uebersetzer besitzen muss:
- Menue-Code haengt am Frame: nur die erste Sektion laeuft ohne Frame
(4 Optionen :3396), alle spaeteren mit (5 Optionen :3378). Also
Linie-GF="1"in Sektion 1,"2"ab Sektion 2 usw.;GF-Bogenin Sektion 1 = Validierungsfehler (nicht angeboten). hzgenau einmal:vfl-in-abstandjournalisiert die Richtung nur beihz-vorgabe = nil(:2130) - das ist ausschliesslich das erste Segment der Kette.hzan spaeterer Stelle verschiebt die ganze Queue -> harter Fehler;hzfehlt in Sektion 1 -> harter Fehler.gf-verteilungist zwischen den Modi invertiert: Modus 1 :3118 ("1"= haelfte), Modus 2 :5729 ("2"= haelfte). Code-Tabelle pro Modus.
Nicht vorhersagbar bleibt die Winkelwahl (vfl-waehle-winkel :1656 fragt
nur, wenn mehrere Kandidaten gueltig sind - abhaengig von der real gemessenen
Restlaenge). Loesung: optionales Feld ("winkel-idx" . n); fehlt es und der
Lauf braucht es, greift P2 mit einer Fehlermeldung, die Sektion und
Eingabe-Nummer nennt. Kein Raten (I3).
4.2 Uebersetzer
vfl-spec-pruefen (nur Fehlerliste, fragt und baut nie) und
vfl-spec->journal / -m2 / -m3 (Vorwaerts-Journal). Rueckgabe-Alist
(("journal" . ...) ("fehler" . ...) ("warnungen" . ...)).
Wiederverwendung statt Neubau - diese Bausteine existieren schon:
vfl-schema-slice-bauen :326, vfl-schema-feld-pruefen :303 (mit den
erlaubten Werten aus *vfl-glied-schema* :243, *vfk-gf-bogen-winkel*,
*vfk-as-es-winkel*), vfl-gf-bogen-slice-bauen :3941, vfl-es-slice-bauen
:4093, vfl-vario-slice-bauen :4110, vfl-journal-list->string :1258.
Neu sind nur Linie-GF/Linie-VF/Horizontal-VF/Linie und der VF-Fluss.
Wichtig: vfl-schema-slice-bauen loggt Schemaverstoesse und schreibt den Wert
trotzdem ("Sicherung geht vor", :324) - richtig fuer den Recovery-Pfad,
falsch hier. Darum prueft vfl-spec-* mit vfl-schema-feld-pruefen selbst
vorab und ruft die Slice-Bauer erst mit sauberen Werten. vfl-schema-slice-bauen
bleibt unangetastet.
Emitter-Regel fuer den VF-Fluss (macht den Uebersetzer trivial): die
ist-Endpunkt-Antwort wird zwar an zwei Stellen gestellt (Schleifenkopf :2560
und innerhalb vfl-baue-horizontal-koerper im Ziel-Modus :2308, von dort als
vor-antwort zurueckgegeben), landet in der flachen Queue aber immer an
derselben linearen Position - direkt nach den Werten des Vorgaenger-Knotens.
Also je Knoten: STR ende-code ("1" Motor / "3" Kettenende / sonst "2"),
bei "2" zusaetzlich STR naechstes-vf plus die Nutzlast des Sub-Typs.
4.3 Headless-Rahmen und Ergebnis-Record
(vfl-headless-an opt) / (vfl-headless-aus) ; Save/Restore, MUSS immer laufen
(vfl-bau-aus-spec spec opt) ; -> Ergebnis-Record
(vfl-bau-aus-spec-liste specs opt) / (vfl-bau-aus-json datei opt)
(vfl-result->json rec) / (vfl-results-schreiben recs datei)
(c:VF_SPEC_BAU) ; Datei aus DXFM_VF_SPEC, fragt nichts
vfl-headless-an: *vfl-headless* T, *vfl-wizard-mode* nil, (ssg-gui-aus),
zaehlende Stubs fuer vfl-getpoint/getstring/getint/getreal/getkword/
alert/new_dialog (jeder erhoeht *vfl-spec-prompts* und liefert nil),
ssg-start mit OSMODE/ATTREQ/ATTDIA = 0, init-bibliothek falls noetig.
ssget/entsel bewusst NICHT stubben - vf-next-number
(vf_core.lsp:322) braucht (ssget "X" ...); die eine Bau-Pfad-ssget sitzt
in vfl-in-selection und ist ueber P2 abgedeckt.
Pro Kette: validieren (Fehler -> Status "spec-fehler", nichts gebaut) ->
*ssg-ils-dim* je Kette neu setzen (der Abbruch-Handler :3286 nullt es) ->
lastEnt merken -> vfl-journal-reset + vfl-journal-replay-start ->
*error* sichern, (vl-catch-all-apply 'vf-linienzug-modus '()), *error*
zurueck (genau die Klammer aus hundm05:build-linienzug) -> Record aus den
Globals sammeln -> aufraeumen.
Bewusster Kompromiss (wie beim Batch-Konverter vfl-konvertiere-ent :4292):
weil gefangen wird, laeuft der *error*-Handler der Modus-Funktion nicht, die
Teil-Geometrie wird also nicht zu einem Block gewickelt. Option
("bei-fehler" . "behalten"|"loeschen") entscheidet, ob sie stehenbleibt
(per c:VF_SEKTION_RESTORE rettbar, weil vfl-segment-xdata-sichern :3855
pro Iteration schon SSG_VF_EDIT_SEG/_PRE geschrieben hat) oder ab
lastEnt weggeraeumt wird.
Ergebnis-Record: Feldreihenfolge von hundm05:result-json beibehalten
(test_id, kind, status, dimension, block_name, block_handle,
insert_point, actual_attributes), dazu eingaben_gesamt,
eingaben_offen, sektionen_soll/sektionen_ist, glieder, prompts,
warnungen, fehler_sektion, fehler_text, ziel_abweichung, journal.
Status: executed | warnung | desync | abbruch | spec-fehler.
Drei unabhaengige Desync-Detektoren (eine geometrisch abgewiesene Sektion
wirft keinen Fehler, sie verbraucht nur weniger Eintraege): offene
Queue-Werte, Vergleich der erzeugten STEP-Labels (*vfl-journal*) gegen die
Glied-Folge der Spec (nennt die erste abweichende Sektion), und die
gesammelten Meldungen aus P1.
4.4 Modus 2 und Modus 3
Modus 2: Spec traegt ("pfad-handles" ...) (Entity-Handles der LINE/ARC-Trasse)
plus ("segmente" ...) in Pfadreihenfolge. Vor dem Bau wird die Segmentzahl
gegen die aufgeloesten Handles geprueft und bei Fehlbestand abgebrochen - die
Fragenzahl kommt aus gf-sortiere-objekte/gf-analysiere-kette auf der
realen Geometrie. Eine Gerade direkt nach einer Vario-Kurve wird nicht
gefragt (:5449); der Uebersetzer leitet das selbst ab.
Modus 3: nur vfl-bau-aus-spec mit Modus-3-Uebersetzer. Dokumentierte
Einschraenkung: I1 gilt nicht (kein Journal-XDATA, also kein Doppelklick-Edit,
keine 2D/3D-Konvertierung). Die volle Nachruestung braeuchte vier gekoppelte
Eingriffe (Reset, XDATA-Schreiben, Marker "linienzug3" in der Whitelist
:1340, vfl-edit-ent3) in dem Modus, der laut Code ohnehin ersetzt wird -
darum bewusst zurueckgestellt.
4.5 JSON-Form
ssg-load-json/ssg-parse-json-array (ssg_core.lsp:1146/1167) liest
zeilenweise und flach: jedes { beginnt ein Objekt, Verschachtelung ist
unmoeglich, Zahlen-Arrays muessen in einer Zeile stehen. Also dieselbe Form wie
tests/testdata/hundm05.json: ein Kopf-Objekt (spec_id) plus flache
Sektions-Objekte (glied), Sub-Objekte (sub) und Abschluss (ende),
gruppiert wie hundm05:gruppiere. Wahrheitswerte als 1/0
(ssg-cfg-parse-value kennt kein true/false). Ein nr-Feld pro Sektion
macht handgeschriebene Dateien selbstpruefend.
4.6 Umsetzungsstand Stufe 1 (2026-09-03)
Fertig fuer Modus 1. Was entstanden ist:
| Datei | Inhalt |
|---|---|
Lisp/vf_spec.lsp |
Code-Tabellen, Emitter vsp-journal, Validierung vsp-pruefen, flacher JSON-Loader vsp-json-laden/vsp-gruppieren, Headless-Rahmen vsp-headless-an/-aus, Ergebnis-Record, vsp-bau-aus-spec/-liste, c:VF_SPEC_BAU |
lib/vf_spec_export.py |
derselbe Emitter in Python PLUS die Umkehrung (spec_aus_journal), erzeugt die Spec-Testdaten |
tests/testdata/vf_spec_hundm05.json |
die 5 echten Ketten als Spec (57 flache Objekte), erzeugt statt handgeschrieben |
tests/test_vf_spec.lsp |
C:TEST_VF_SPEC: 7 handgebaute Faelle je Glied-Typ, 7 Validierungsfaelle, Gruppieren, und die 5 echten Ketten gegen ihr aufgezeichnetes Journal |
tests/test_vf_spec.py |
27 Tests ohne CAD + 10 fuer die VF_SPEC_BAU-Ergebnisse |
Abweichungen von der Planung, jeweils mit Grund:
vsp-pruefenruft den Emitter statt eine zweite Regelmenge zu pflegen. Zwei getrennte Regelwerke laufen auseinander; der Emitter validiert ohnehin jedes Feld, das er anfasst.- Das vollstaendige Journal steht NICHT im Ergebnis-Record. Es ist schon
in der Spec und in der XDATA des gebauten Blocks - eine dritte Kopie waere
nur Ballast. Statt dessen
glieder_sollundglieder_ist: das ist der Desync-Detektor, der auch dann greift, wenn die Queue zufaellig aufgeht. - Zusatzfeld
segment_typam GliedLinie: dort waehltvfl-segment-entscheidungselbst zwischen reiner Gefaellestrecke und VF-Einheit. Am Journal ist es erkennbar (VF-Einheit beginnt mit der GF-Verteilungsfrage), aus der Spec allein nicht - und Geometrie zu raten verstoesst gegen I3. vf_ende-Werteautomatischundzielpunkt-ohne-esnebenja-mit-es/nein: in beiden Faellen stelltvfl-vf-einheit-abschlussKEINE Frage (GliedLiniebzw. Kettenende am Zielpunkt ohne ES-Wunsch). Ohne diese Werte waere die Tokenzahl nicht bestimmbar.- Praefix
vsp-, nichtvfl-:vfs-ist schon vonvf_standard.lspbelegt, und die Spec-Ebene ist bewusst vonvf_linienzug.lspgetrennt (einseitige Abhaengigkeit).
Wie die Richtigkeit belegt ist - drei Implementierungen derselben Grammatik, die einander pruefen:
- Rundlauf gegen echte Daten: fuer alle 5 HundM-Ketten gilt
journal_aus_spec(spec_aus_journal(tok)) == tok, tokenweise numerisch verglichen. Damit ist bewiesen, dass die Spec das Journal verlustfrei abbildet - sonst waere ein spec-gebauter Nachbau eine andere Kette. - Der Weg, den LISP nimmt, ist separat geprueft: flaches JSON -> Spec -> Journal ergibt dieselben Journale wie das aufgezeichnete Protokoll.
- Der unabhaengige Dekoder (
lib/vf_journal_export.py, gegen die echten Ketten verifiziert) verdaut alle 7 synthetischen Emitter-Ausgaben restlos - auch die zwei Zweige, die in den echten Daten fehlen (Linie-VF, gewinkelter Erstkoerper). - Die Erwartungswerte im LISP-Test sind nicht von Hand abgeleitet: sie
kommen aus dem geprueften Python-Emitter, und
TestLispErwartungenintests/test_vf_spec.pyliest sie austests/test_vf_spec.lspzurueck und vergleicht sie erneut. Sonst koennte ein Uebertragungsfehler einen falschen Erwartungswert festschreiben und der CAD-Lauf waere gruen, obwohl der Emitter falsch liegt. Gegengeprobt: eine verfaelschte Zahl im LISP-Test wird erkannt.
CAD-Lauf VF_SPEC_BAU (2026-09-03): 5 OK, 0 Fehler. Alle 5 Ketten aus
der Spec gebaut, je Kette status: executed, prompts: 0 (keine Live-Eingabe
erreicht - der positive Beweis), eingaben_offen: 0, spec_fehler: [],
meldungen: [], glieder_ist == glieder_soll, Einfuegepunkt gleich dem
Kettenstart der Spec. Damit ist der Daten-Pfad in der Praxis belegt; die
9 Ergebnis-Tests in tests/test_vf_spec.py laufen gruen gegen diesen Lauf.
Zwei Nacharbeiten aus dem Lauf:
- Die Ergebnisdatei landete in
results/, weilc:VF_SPEC_BAUDXFM_RESULTSbevorzugte. Das ist das Verzeichnis der Sivas-/CSV-Exporte; Testergebnisse gehoeren nachtests/output(Konventiontest_run_all.lsp, von den pytest-Fixtures gelesen, per.gitignoreausgeschlossen). Default jetzttests/output, Override ueberDXFM_VF_SPEC_OUT. Die Fixture prueft beide Orte, damit ein alter Lauf nicht stumm uebersprungen wird. TEST_VF_SPECist ein Testbefehl und muss vorher geladen werden:(load (strcat (getenv "DXFMAKRO") "/tests/test_vf_spec.lsp"))- oder ueberSSG_RUN_ALL_TESTS, wovf_specinzwischen inalltests.jsonsteht.
4.7 Aufteilung der Testfaelle (2026-09-03)
Nach dem gruenen VF_SPEC_BAU-Lauf gab es zwei Tests, die dieselbe Geometrie
bauen. Aufgeloest:
| Aufzeichnungsformat | Spec | |
|---|---|---|
| Daten | tests/testdata/hm_recformat.json (281 Objekte) |
tests/testdata/hundm05.json (52 Objekte) |
| Treiber | tests/test_hm_recformat.lsp, TEST_HM_RECFORMAT |
tests/test_hundm05.lsp, TEST_HUNDM05 |
| pytest | tests/test_hm_recformat.py |
tests/test_hundm05.py |
In alltests.json |
abgeschaltet | aktiv |
Der Spec-Test ist damit der routinemaessige Bau-Test; die Spec ist auch die Datei, in der weitere Ketten der Anlage nachgetragen werden.
Warum die Aufzeichnung bleibt (und nicht durch die Spec ersetzt wird):
- Sie ist die einzige eingecheckte Kopie der Originaldaten -
data/polylines.dxfist mit 124 MB per.gitignoreausgeschlossen. Die Spec ist daraus abgeleitet; ohne die Aufzeichnung faellt die rechte Seite des Rundlauf-Beweises weg und die Spec belegt nur noch, dass der Emitter mit sich selbst uebereinstimmt. - Sie prueft eine andere Invariante: ihr Journal kommt roh aus der XDATA
einer Kundenzeichnung. Damit ist
TEST_HM_RECFORMATder einzige Test dafuer, dass ein BESTEHENDERVF_n-Block weiter abspielbar ist - also dass Doppelklick-Edit und 2D/3D-Konvertierung an Altbestand funktionieren (I1). Ein spec-gebautes Journal kann das nicht zeigen, es kommt aus dem Uebersetzer. Bei Aenderungen am Journal-Format, an denvfl-in-*-Wrappern oder am XDATA-Layout also bewusst einschalten. - Sie dokumentiert die Frage-Reihenfolge: jeder Eintrag traegt einen
kommentar, der die zugehoerige Frage nennt. Die Spec verbirgt den Dialog - das ist ihr Zweck - und kann diese Rolle nicht uebernehmen.
Damit es nur EINEN Code-Pfad gibt, der aus einer Spec Geometrie erzeugt, hat
tests/test_hundm05.lsp keine eigene Bau-Logik: es ruft vsp-bau-datei aus
Lisp/vf_spec.lsp - dieselbe Funktion, die auch c:VF_SPEC_BAU nutzt. Die
Ergebnisdatei heisst jetzt nach der Spec-Datei
(<basisname>_results.json), damit Befehl und Testrunner in dieselbe Datei
schreiben und keine zweite Kopie derselben Ergebnisse entsteht.
Nebenbei behoben: das Anlagenkuerzel der test_id in
lib/vf_journal_export.py kam aus dem Namen der Ziel-JSON. Nach der
Umbenennung haette eine Regenerierung die ids stillschweigend von
VF_hundm05_LZ_* auf VF_hm_recformat_LZ_* geaendert - und damit die
Paarung zwischen den beiden Testlaeufen zerlegt. Jetzt feste Konstante
TEST_ID_ANLAGE.
Noch offen in Stufe 1: die Uebersetzer fuer Modus 2 (pfad-handles +
Segmentliste, Abschnitt 4.4) und Modus 3 sind NICHT gebaut - Modus 2 braucht
laut Reihenfolge (Punkt 11) erst 2-3 echte "linienzug2"-Journale als
Referenz, und tests/testdata/hundm05.json enthaelt ausschliesslich
Modus-1-Ketten. Ebenfalls offen: der CAD-Lauf TEST_VF_SPEC (Uebersetzer,
ohne Zeichnung) und VF_SPEC_BAU (baut die 5 Ketten aus der Spec; danach
prueft tests/test_vf_spec.py das Ergebnis gegen
tests/output/hundm05_results.json - Attribut fuer Attribut, das ist der
Beweis "Spec-Pfad == Journal-Pfad" auf Geometrie-Ebene).
Teil 5 - Stufe 2: echte Funktionstrennung
Konvention: reiner Bauteil bekommt Suffix -bauen (Geometrie aus Parametern)
bzw. -setzen (nur Globals); die Frage-Schale behaelt den bestehenden
Namen - dadurch aendert sich keine einzige Aufrufstelle in Modus 1/2/3.
| heute gemischt | reiner Bauteil (neu) |
|---|---|
vfl-baue-horizontal-koerper :2270 |
vfl-hor-koerper-bauen (frame hz dL sep-vor sep-nach ende-code gf2-laenge) |
vfl-body-abschluss :2409 |
vfl-body-abschluss-bauen (frame letzt-hz p-umlenk dL hz-neu hoehe-ziel es-gewuenscht) |
vfl-vf-einheit :2497 |
vfl-vf-eingang-bauen / vfl-vf-sub-bauen / vfl-vf-ausgang-bauen / vfl-vf-einheit-bauen (frame vf-spec) |
vfl-vf-einheit-abschluss :3112 |
vfl-vf-abschluss-bauen (...) + vfl-ziel-report (frame) |
vfl-frage-es-seite :2956 |
vfl-es-masse-setzen (es-winkel es-seite) |
vfl-waehle-winkel :1656 |
vfl-winkel-gueltige + vfl-winkel-nach-index |
ende-code ersetzt das Flag ziel-modus; der Bauteil gibt dann immer nur
frame zurueck (die Doppelrueckgabe (frame ist-ende-antwort) existiert nur,
um die Antwort nach oben zu geben).
Die Winkelfrage sitzt im Solver, nicht in einer Schale.
vfl-body-zerlegung :2357 (also nicht rein, anders als zunaechst
angenommen), vfl-vf-winkel :1692, vfl-vf-entscheidung :1707 und
vfl-segment-entscheidung :1972 rufen alle vfl-waehle-winkel. Ein
Parameter wuerde vier Signaturen und alle Aufrufer aendern; stattdessen der
Kanal, den die Datei schon fuer vfl-menu nutzt (:1118, dynamisch gebundene
*vflw-menu-*): *vfl-winkel-idx-vorgabe*.
"Alles fragen, dann alles bauen" ist unmoeglich - und das ist der
zentrale Punkt: vfl-neue-linie-messen braucht (car frame), die
Hoehenvorschlaege brauchen (caddr (car frame)), und die dL-Reservierung
braucht den gemessenen auf_3-Fussabdruck. Deshalb behaelt der interaktive
Treiber seine while-Schleife, fragt aber pro Runde einen Knoten und baut
ihn sofort ueber denselben reinen Knoten-Bauteil; der Daten-Treiber ist
dieselbe Kette mit foreach statt while.
Knotenform: die rohen Antworten in Frage-Reihenfolge (nil = nicht gefragt)
plus die abgeleiteten Bauwerte. Dann ist der Serializer ein dummer Flattener.
Dazu gehoert das Feld dl-verworfen: vfl-in-abstand journalisiert
bedingungslos (:2129), abgewiesene 25-m-Eingaben (:2165) stehen also im
Journal - ohne dieses Feld ist Journal -> Spec verlustbehaftet und jeder
Round-Trip-Test scheitert an einer solchen Kette.
Journal-Invariante im Daten-Pfad: die Spec erzeugt das Journal einmal
(vfl-spec->journal), es wird vor dem Bau gesetzt, kein Bauteil ruehrt es an.
Als Dauerbeweis eine dbgmsg-Assertion dort, wo beide Erzeuger sich treffen -
in vf-linienzug-modus unmittelbar vor vfl-journal-xdata-schreiben (:3867)
das aus der Spec serialisierte Journal gegen (vfl-journal->string) stellen.
Ohne offene .dbg-Datei kostet das nichts, mit Logging beweist es die Treue
bei jedem Bau.
Reihenfolge (billig/risikoarm zuerst)
vfl-ziel-reportaus den zwei byte-identischen Bloecken :3150/:3176 ziehen- Winkelwahl (
vfl-winkel-gueltige/-nach-index+*vfl-winkel-idx-vorgabe*) - ES/AS-Masse (
vfl-es-masse-setzen) vfl-hor-koerper-bauenvfl-body-abschluss-bauen- VF-Einheit: Eingang/Sub/Ausgang + Schleifenrumpf
- Daten-Executor fuer die VF-Einheit
- Spec + Serializer + Assertion - dieser Schritt ist die Invariante, vorher nichts ausliefern
- Einheit-Abschluss
- Kettenebene, ein Glied-Zweig pro Commit: GF-Bogen -> ES -> Horizontal-VF -> Linie-GF -> Linie-VF -> Linie
vfl-spec-ausfuehren(Daten-Pfad ohne Replay-Umweg)- Modus 2 - erst wenn 2-3 echte
"linienzug2"-Journale als Referenz vorliegen (tests/testdata/hundm05.jsonenthaelt ausschliesslich Modus-1- Ketten); sonst zurueckstellen
Umsetzungsstand Stufe 2 (2026-09-03)
Fertig: Schritte 0-4 und der Assertion-Teil von Schritt 7. Alle fuenf sind verhaltensgleich - die Frage-Schalen behalten ihre Namen, keine Aufrufstelle in Modus 1/2/3 wurde angefasst.
| Schritt | Neu | Nachweis |
|---|---|---|
| 0 | vfl-ziel-report |
zwei byte-identische Bloecke ersetzt, Diff zeigt nur die Entfernung |
| 1 | vfl-winkel-gueltige, vfl-winkel-nach-index, Kanal *vfl-winkel-idx-vorgabe* |
Verzweigungen 1:1; ungueltiger Index faellt wie zuvor auf den ersten Kandidaten |
| 2 | vfl-es-masse-setzen |
reines Globals-Setzen aus vfl-frage-es-seite gezogen |
| 3 | vfl-hor-koerper-bauen |
Zeilenvergleich alt/neu: dieselben 15 geometrie-relevanten Zeilen in derselben Reihenfolge |
| 4 | vfl-body-abschluss-bauen |
Multiset-Vergleich: ausser Kopf, Klammer und Aufruf keine Zeile veraendert |
| 7 (Teil) | vsp-journal-diff + Record-Feld journal_diff |
neuer Test test_journal_token_gleich |
Zu Schritt 3 im Detail: die drei Fragen (Separator vor/nach, Endpunkt) haengen an keinem berechneten Wert und stehen jetzt alle vor dem Bau. Die Journal-Reihenfolge und die 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, mit dem auf_3-Insert an derselben Stelle dazwischen.
Zwei bewusste Abweichungen von der Planung:
vfl-hor-koerper-bauenbehaeltziel-modusals EIGENEN Parameter nebenende-code(der Fahrplan wollte ihn ersetzen). Die Separator-Subtraktionen haengen allein am Ziel-Modus, undende-codedarf nil sein (abgebrochene Menuefrage) - mit nur einem Parameter waere genau dieser Fall eine stille Verhaltensaenderung.vfl-body-abschluss-bauenhat eine schlankere Signatur als skizziert:letzt-hzundes-gewuenschtbraucht es nicht.es-gewuenschtwirkt beim Aufrufer (derein-dx/ein-dzum den Aufruf herum nullt),letzt-hzging nur in eine wirkungslose Zuweisung - beim Umzug wortwoertlich uebernommen und als solche markiert.
Schritt 7 ist nur zur Haelfte erledigt: die Spec und der Serializer stehen
schon aus Stufe 1, neu ist die Assertion - vsp-journal-diff stellt das
aus der Spec erzeugte Journal Token fuer Token gegen das beim Bau neu
aufgezeichnete. 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. Sitzt im Daten-Pfad (vf_spec.lsp), nicht als
dbgmsg im Bau-Pfad - dort waere er nur bei offener .dbg-Datei sichtbar.
Offen: 5, 6, 8, 9, 10 (VF-Einheit aufteilen, Daten-Executor,
Einheit-Abschluss, Kettenebene je Glied-Zweig, vfl-spec-ausfuehren).
Bewusst NICHT vorab erledigt: das sind die Schritte, bei denen laut Abschnitt
"Wo Geometrie still kippen kann" die Reihenfolge selbst Geometrie ist. Der
Fahrplan verlangt nach jedem Schritt einen CAD-Lauf (TEST_HUNDM05 +
TEST_VF_SPEC + TEST_LINIENZUG), nach den Geometrie-Schritten zusaetzlich
einen DXF-Diff und einen Sivas-Export-Vergleich. Ohne diese Laeufe zwischen
den Schritten waere ein Fehler nicht mehr einem Schritt zuzuordnen.
Zur Erwartungshaltung: die Schritte 5-10 bringen keine neue Faehigkeit.
Der Bau aus Daten funktioniert seit Stufe 1 (ueber den Replay) und ist mit
VF_SPEC_BAU in der Praxis belegt. Was 5-10 bringen, ist der direkte
Daten-Pfad ohne den Replay-Umweg und einzeln aufrufbare Knoten-Bauteile -
Architektur, nicht Funktion.
Wo Geometrie still kippen kann
- Die dL-Subtraktionskette in
vfl-baue-horizontal-koerper(:2280, :2293, :2301, :2319/:2323): jeder Schritt mit(max *vfk-restlaenge-min-clamp* ...)geklammert, also reihenfolgeabhaengig, und der auf_3-Insert sitzt zwischen Subtraktion 1 und 2 (Fussabdruck gemessen, nicht geschaetzt). Der Bauteil ist der heutige Rumpf ohne die dreivfl-menu-Bloecke und ohne jede Umsortierung. Die drei Fragen duerfen nach vorn in die Schale (keine haengt anpt/dL), die Subtraktionen nicht. vfl-nach-3grad:2415/:2643 darf von Schale und Bauteil gerufen werden - es ist idempotent (:2236 prueftvfl-frame-flach-p).ein-dx/ein-dz-Nullen (:2588-2593) wandert vom Aufrufer in den Bauteil und aendert damit das Budget inberechne-alle-winkel, also Geometrie. Nur der "ES nein"-Pfad fuehrt dort durch.ziel-gf2vs.L_GF2-bauim Ausgang (:2706): geht es verloren, entsteht still die falsche GF2 hinter dem Motor.- Die
vfl-acc-*-Aufrufe muessen an derselben Stelle in derselben Reihenfolge bleiben, sonst vertauschen sich die Komma-ListenL_VF_m/L_GF_m/GF_WINKEL- in der Zeichnung unsichtbar, im Sivas-Export falsch.
*vfl-as-winkel*/*vfl-es-winkel*werden lazy von den Blocknamen-Bauern gelesen (:111/:112) - spaeter gesetzt als heute heisst falscher Block.- Im Daten-Pfad muss
hzeines Fortsetzungsknotens "vom Frame erben" (nil) bedeuten, nie ein gespeicherter Absolutwert:vfl-insert-vario-kurve-blocksnappt den gemessenen Wert neu (:2838-2841), ein Absolutwert laesst die Kette driften. - Die
aus-dx/ein-dx-Save/Restore-Fenster (:1693, :2362, :5125, :5236) sind heute nie verschachtelt; zwei ineinander und das innere Restore ueberschreibt das aeussere Save.
Ausdruecklich nicht anfassen
vf-linienzug-modus3 + alle vfl2-*; die vfl-in-*-Wrapper und vfl-menu*;
vfl-entry->string und das XDATA-Layout/die Marker; alle Journal-Konsumenten
(brauchen sie Aenderungen, ist die Invariante gebrochen - das ist der
Lackmustest); die reinen vfs-*/berechne-* in vf_standard.lsp (via
*vf-typ-registry* mit Standard/Etage geteilt); die vflw-*-Wizard-Schicht
und die DCLs; das Buendeln der *vfl-acc-* zu einem Record; der
Abbruch-/*error*-Pfad.
Teil 6 - Nebenarbeit: Python-Grammatik vervollstaendigen
lib/vf_journal_export.py enthaelt die Journal-Grammatik schon als
Recursive-Descent-Parser (Journal.dekodiere), inklusive vorantwort-
Mechanik, bedingtem Winkel-INT und der erster_dl/REAL hz-Regel - aber
unvollstaendig: Linie-VF fehlt im Dispatch (lauf, sonst raise) und
vf_einheit ruft horizontal_koerper() unbedingt als ersten Koerper (nur fuer
Horizontal-VF richtig, falsch bei gewinkeltem Erstkoerper). Die 5
HundM-Ketten dekodieren nur, weil ihre Daten diesen Fall nicht enthalten. Beide
Luecken zusammen mit dem LISP-Serializer schliessen: dann pruefen zwei
unabhaengige Implementierungen der gleichen Grammatik einander.
Erledigt (2026-09-02): Linie-VF ist im Dispatch (glied_linie_vf: DL,
Zielhoehe, optionale Winkelwahl, dann VF-Einheit), und vf_einheit bekommt
erster_horizontal - das spiegelt die winkel1-Verzweigung in
vfl-vf-einheit: nur der horizontale Erstkoerper laeuft durch
vfl-baue-horizontal-koerper und fragt Separator vor/nach + Endpunkt vorab,
ein gewinkelter wird ohne Frage gebaut. glied_linie_kettenende uebergibt
False (fuer typ="VF" liefert vfl-segment-entscheidung immer einen Winkel
0).
Abgesichert von tests/test_vf_journal_grammatik.py (9 Tests, ohne CAD und
ohne die 118-MB-DXF: Journale stehen als Token-Listen im Test). Gegenprobe
gemacht: mit dem alten erster_horizontal-Verhalten scheitert die Linie-VF-
Tokenfolge (Token 11: STR erwartet, STEP:ES gefunden), der Fix ist also
tragend. tests/testdata/hundm05.json bleibt nach der Regenerierung
byte-identisch - die 5 echten Ketten enthalten keinen der beiden Faelle.
Offen bleibt der Gegenpart: der LISP-Serializer (vfl-spec->journal, Stufe 1).
Erst mit ihm pruefen zwei unabhaengige Implementierungen einander.
Verifikation
Stufe 0 (nach P0-P3, interaktiv unveraendert):
TEST_HUNDM05in BricsCAD: 5 Ketten, alle"status": "executed",eingaben_offen0 - beweist, dass Replay und Journal-XDATA unveraendert sind.python -m pytest tests/test_hundm05.py -q(Daten-Checks laufen ohne CAD).- Interaktive Gegenprobe:
FOERDERANLAGE-> Linienzug Modus 1 mit Wizard, eine kurze Kette bauen, Doppelklick-Edit, danachSSG_DIM_SWITCH- Alert- Texte und Dialoge muessen identisch aussehen.
Stufe 1:
- Neu
tests/test_vf_spec.lsp(C:TEST_VF_SPEC, Mustertest_vfl_schema.lspmittvs-eq/tvs-truthy/tvs-nil, inalltests.jsonohne"save"): Uebersetzer-Unit-Tests ohne Zeichnung - je Glied-Typ das erwartete flache Journal, die Menue-Code-Tabelle, diehz-Regel, die invertiertegf-verteilung, Validierungsfehler. Der entscheidende Test:tests/testdata/linienzug_tests.json(eine vollstaendig kommentierte Kette mit Linie-VF, Horizontal-VF, zwei Vario-Kurven, Option-3-Kettenende und ES-Glied) in eine Spec uebersetzen und pruefen, dassvfl-spec->journaldieselbe Liste liefert. - Neu
tests/test_vf_spec_bau.lsp(C:TEST_VF_SPEC_BAU,"save": "dxf"): die 5 HundM-Ketten als Spec (tests/testdata/vf_spec_hundm05.json) bauen und das Ergebnis gegentests/output/hundm05_results.jsonstellen - Attribut fuer Attribut, Einfuegepunkt fuer Einfuegepunkt. Das beweist Spec -> Journal -> Bau == aufgezeichnetes Journal -> Bau. - Neu
tests/test_vf_spec.py+ Fixtures inconftest.py(Muster der bestehendenhundm05_*-Fixtures mitpytest.skip): pro Kettestatusexecuted,eingaben_offen0,sektionen_soll==sektionen_ist,glieder== Spec-Glied-Folge,warnungenleer,prompts== 0. - "Kein Prompt, kein Dialog" in vier Schichten: statischer Waechter
(pytest ohne CAD, vergleicht die Fundstellen von
alert/get*/ssget/new_dialoggegen eine eingecheckte Liste - haelt das Design gegen Verrottung), zaehlende Stubs (promptsim Record als positiver Beweis), Schalterzustand (*ssg-gui-aus*T,*vfl-wizard-mode*nil mit Save/Restore in einervl-catch-all-apply-Klammer), und eintests/test_vf_spec.scr-Lauf (Mustertest_unit.scr) mit Sentinel in der letzten Zeile: fehlt der Sentinel im Log, hat doch ein Prompt geoeffnet.
Stufe 2: nach jedem Schritt TEST_HUNDM05 + TEST_VF_SPEC + TEST_LINIENZUG;
nach den Geometrie-Schritten (3, 4, 5, 9) zusaetzlich DXF-Diff Frage-Pfad gegen
Daten-Pfad ueber lib/dxf_abbild.py, und Sivas-Export-Vergleich
(EXPORTSIVAS) wegen der Reihenfolge in L_VF_m/L_GF_m.
Getroffene Entscheidungen (aenderbar)
- Modus-2-Pfadobjekte: die Spec traegt die Entity-Handles. Damit bleibt I1
exakt und es braucht keinen neuen Marker. Alternative waere ein Marker
"linienzug2s"plus Zweig invfl-edit-ent2- erweitert das Markerschema fuer jeden Leser, daher nicht gewaehlt. - Segment-XDATA im Daten-Pfad: bleibt erhalten (Paritaet mit dem
interaktiven Pfad), damit
c:VF_SEKTION_RESTOREauch bei spec-gebauten Ketten greift. In Stufe 1 automatisch (Bau laeuft durch die Modus-Funktion); in Stufe 2 braucht der Executor denselben Per-Glied-Hook. - Modus 3: nur Wrapper, kein Journal-XDATA (zurueckgestellt).
vf_spec.lspals neue Datei statt Anbau anvf_linienzug.lsp(schon ~6500 Zeilen, groesste Datei im Repo); Abhaengigkeit ist einseitig.
Betroffene Dateien
Lisp/vf_linienzug.lsp- P1/P2/P3-Hooks (:123, :157, :1055, :1066, :1185, :1196, :2028, :2113, :3523, :3550, :3559, :3650, :3772, :5418, :5650) und die ganze Stufe 2Lisp/vf_spec.lsp- neu: Spec, Uebersetzer, Headless-Rahmen, RecordLisp/vf_core.lsp- P0 (:1139), Ladezeile nach :1062lib/vf_journal_export.py- Grammatik vervollstaendigen (Linie-VF, erster Koerper)tests/test_hundm05.lsp- Prototyp zum Verallgemeinern (hundm05:gruppiere,-eintrag->journal,-result-json,-stubs-an/-aus,-queue-rest)tests/testdata/linienzug_tests.json- fixiert den VF-Fluss im Unit-Testtests/testdata/hundm05.json+tests/output/hundm05_results.json- Referenz fuer die Aequivalenz von Spec-Pfad und Journal-Pfad