[FEAT] VF-Linienzug ohne GUI/Konsole baubar (Stufe 0) + hundm05-Testfall

Ziel: eine VF_n-Kette soll aus einem Stapel Eingabedaten gebaut werden
koennen - ohne Dialog, ohne Konsolenfrage. Fahrplan und Begruendungen in
doc/TODO-plan-vf-interactive.md. Alle Aenderungen sind No-Ops, solange
*ssg-gui-aus* und *vfl-headless* nil sind.

Produktion (Lisp/vf_linienzug.lsp, Lisp/vf_core.lsp):
- vfl-journal-reset im Dispatcher VOR die Modus-cond gezogen. Bisher nur im
  Modus-1-Zweig: ein frischer Modus-2-Lauf erbte das Journal des Vorlaufs und
  schrieb es in die XDATA, ein spaeterer Doppelklick spielte fremde Eingaben
  vor.
- Lokale Variable "member" in vf-linienzug-modus2 umbenannt. Sie verdeckte im
  selben Scope das Builtin member, das weiter unten gebraucht wird - jedes
  Kletterer-Segment waere in "bad function" gelaufen.
- Neu vfl-meldung: sammelt den Text nach *vfl-meldungen* + dbgmsg und zeigt
  ihn nur bei erlaubter GUI modal, sonst per princ. Die 12 Bau-Pfad-alerts
  darauf umgestellt; ein Alert blockierte sonst jeden Batch-Lauf, und sein
  Text ist die einzige Auskunft, WELCHE Sektion abgewiesen wurde. Die reinen
  Interaktiv-Alerts (fehlendes DCL, "nicht editierbar", "kein Journal")
  bleiben alert.
- Neu *vfl-headless* (+ vfl-headless-p/-abbruch/-notausgang/-ort, Diagnose
  *vfl-headless-fehler*, optionaler Antwort-Hook *vfl-headless-antwort-fn*):
  eine erschoepfte Replay-Queue ist damit ein harter Abbruch MIT Fundstelle
  (Art der Eingabe, Glied- und Eingabe-Nummer) statt eines stillen Rueckfalls
  auf Live-Eingabe. Eingebaut in vfl-in-value, vfl-in-value-p,
  vfl-in-selection und vfl-in-abstand.
- vfl-journal-reset loescht Meldungen und Diagnose mit (gehoeren zum Lauf);
  vfl-view-refresh ueberspringt headless _PLAN/_ZOOM.

Testfall HundM05 (5 echte Ketten aus data/polylines.dxf):
- tests/testdata/hundm05.json neu erzeugt aus den XDATA-Journalen der
  VF_n-Bloecke (lib/vf_journal_export.py) - flach, weil ssg-load-json
  zeilenweise liest. Die drei kopierten Ketten bekommen ihren echten
  Einfuegepunkt, nicht das veraltete HOEHE_VON-Attribut.
- tests/test_hundm05.lsp arbeitet jetzt per Journal-Replay statt mit
  Eingabe-Mocks: ein echtes Journal fuehrt die geerbte Fahrtrichtung nicht mit
  (vfl-in-abstand journalisiert hz nur beim ersten Segment), ein Mock kann sie
  also nicht kennen. Schaltet *vfl-headless* ein und schreibt prompts,
  headless_fehler und meldungen ins Ergebnis-JSON.
- Kettenschleife fangt je Kette: ein Fehler NACH dem Bau nimmt nicht mehr die
  restlichen Ketten mit.
- entprev gibt es in AutoLISP nicht (nur entnext/entlast) - die Suche nach dem
  fertigen Block laeuft vorwaerts ab dem Zeichnungsstand vor dem Bau. Dieselbe
  Falle in tests/test_mubea.lsp mitbehoben; sie schlug dort nie zu, weil
  entlast immer sofort traf.

Absicherung ohne CAD:
- tests/test_vf_headless_statisch.py: 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 und die
  Reset-Reihenfolge im Dispatcher. Dazu ein Waechter gegen erfundene
  AutoLISP-Funktionen (entprev u.a.) - diese Fehlerklasse kostet sonst jedes
  Mal einen CAD-Lauf.
- tests/test_hundm05.py prueft zusaetzlich prompts == 0, keine
  Headless-Abbrueche und keine Bau-Meldungen.

tests/alltests.json: hundm05-Zeile laedt VarioFoerderer (nicht KreiselInsert)
und bleibt bis zu einem gruenen CAD-Lauf abgeschaltet.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-03 10:14:31 +02:00
parent bbc9e9b9f9
commit ba01455d52
14 changed files with 3590 additions and 1143 deletions
+1367 -448
View File
File diff suppressed because it is too large Load Diff
+94 -2
View File
@@ -401,6 +401,36 @@ JSON (Prompt-Protokoll, Auszug):
]
```
Dasselbe Protokoll steht produktionsseitig als **XDATA am fertigen
`VF_n`-Block** (App `SSG_VF_EDIT`, Marker `"linienzug"`, Serialisierung
`vfl-entry->string`): jede Eingabe wird beim Bau journalisiert und ist damit
wiederabspielbar (`vfl-journal-replay-start` + `vf-linienzug-modus`, genutzt
vom Doppelklick-Editieren). Ein Journal aus einer echten Zeichnung laesst
sich darum 1:1 in dieses Schema zuruecklesen — genau das tut
`lib/vf_journal_export.py` (siehe Abschnitt 8, `hundm05.json`). Zwei
Unterschiede zum handgeschriebenen `linienzug_tests.json`:
- Zusaetzlicher Eintragstyp `step` (Glied-Marker aus `vfl-journal-mark`,
Label = gewaehlter Segmenttyp). Beim Replay uebersprungen
(`vfl-replay-pop`), fuer den Sektions-/Glied-Edit aber der Anker.
- `hz` steht nur beim **ersten** Segment der Kette in einem `point_rel`
(`vfl-in-abstand` journalisiert die gesnappte Richtung nur bei freier
Richtungswahl); jedes weitere Segment erbt die Richtung des Vorgaengers
und traegt nur `dL`. Winkel von AS/ES stehen als **Wert** (`"90"`/`"30"`),
Seiten/Optionen als **Menue-Index** (`"1"`/`"2"`).
**Headless-Riegel (Stufe 0, siehe `doc/TODO-plan-vf-interactive.md`)**: der
Replay allein garantierte noch keinen prompt-freien Lauf - lief die Queue
mitten im Bau leer (Datenquelle passt nicht zum Ablauf), fielen die
`vfl-in-*`-Wrapper **stillschweigend** auf Live-Eingabe zurueck und der Lauf
blieb an einem `getpoint` haengen. Mit `*vfl-headless*` = T ist das jetzt ein
harter Abbruch mit Fundstelle (`vfl-headless-abbruch` -> `*vfl-headless-fehler*`
nennt Art der Eingabe, Glied-Nummer und Eingabe-Nummer). Die Meldungen der
geometrisch abgewiesenen Sektionen laufen ueber `vfl-meldung` statt `alert` und
stehen in `*vfl-meldungen*`, blockieren also nichts mehr. `tests/test_hundm05.lsp`
schaltet beides ein; die Diagnose landet im Ergebnis-JSON
(`headless_fehler`, `meldungen`, `prompts`).
### 3.4 Vario_Kette_Merge — kein Neubau
`c:Vario_Kette_Merge`: benoetigt nur **einen** Start-Entity-Pick (`entsel`),
@@ -572,9 +602,9 @@ unbaubar. `lib/dxf_scan_components.py` trennt solche Paare darum ueber
gibt den **Ausgangspunkt** zurueck, nicht die Entity — ein Treiber holt den
Block ueber `(entlast)`. Bei fehlender Blockdatei ruft sie `(exit)` auf und
wuerde einen Testlauf abbrechen, darum vorher mit `ssg-ils-block-laden`
pruefen (so macht es `hundm05:build-gerade` in `tests/test_hundm05.lsp`).
pruefen.
Vollstaendiges JSON (wie in `hundm05.json`):
Vollstaendiges JSON:
```json
{
"test_id": "GERADE_HundM05_08",
@@ -585,6 +615,9 @@ Vollstaendiges JSON (wie in `hundm05.json`):
"endpunkt": [220499.01, 154926.53, 0.0]
}
```
Einen Treiber dafuer gibt es derzeit nicht mehr: `tests/test_hundm05.lsp`
spielt seit dem Umbau auf die Linienzug-Journale nur noch Ketten ab (siehe
Abschnitt 8); der fruehere `hundm05:build-gerade` steht in der Git-Historie.
---
@@ -606,3 +639,62 @@ Vollstaendiges JSON (wie in `hundm05.json`):
| Omniflo TEF/Zubehoer | `omni:insert-dxf` (fester Sivasnr) | Position/Hoehe/Rotation ja, Punkt-Eingabe interaktiv |
| Omniflo TV_*/APBW_* | - | **nein** (nicht implementiert, DUMMY) |
| Separator/Scanner | `ils-insert-sensor` | **nein** (Schleife mit `getpoint`/`pause`) |
## 8. HundM05 — die 5 Linienzuege am Kreisel (`hundm05.json`)
`tests/testdata/hundm05.json` enthaelt die **Eingabe-Journale der 5
VarioFoerderer-Linienzuege** aus `data/polylines.dxf` (die Anlage HundM, ein
Kreisel mit fuenf daran haengenden Ketten). Quelle ist nicht die gezeichnete
Geometrie, sondern die XDATA `SSG_VF_EDIT` (Marker `"linienzug"`) an den
`VF_n`-Bloecken — also genau die Werte, mit denen die Ketten gebaut wurden.
Schema je Eintrag: Kopffelder (`test_id`, `block`, `dxf_handle`,
`startpunkt_mm`, `rotation_grad`, `sivas_id`, `beschreibung`,
`erwartung_hinweis`, `quelle`) plus die Prompt-Sequenz in `eingaben` — Format
wie `linienzug_tests.json`, siehe Abschnitt 3.3 (inkl. `step`-Marker).
| test_id | Block | Sivas | Startpunkt (mm) | Kette |
|---|---|---|---|---|
| VF_hundm05_LZ_01 | VF_87 | 0025 | 4912 / 1231 / 2154 | der komplizierte links: 2x Horizontal-VF, 4 Vario-Kurven (90/90/30/30) |
| VF_hundm05_LZ_02 | VF_46 | 0019 | 8572 / 1276 / 2495 | Standardkette |
| VF_hundm05_LZ_03 | VF_46 | 0018 | 12916 / 1276 / 2495 | Standardkette |
| VF_hundm05_LZ_04 | VF_46 | 0020 | 17202 / 1205 / 2154 | Standardkette (die zuerst gebaute) |
| VF_hundm05_LZ_05 | VF_46 | 0008 | 21490 / 1196 / 2495 | Standardkette |
Die vier `VF_46`-Bloecke sind **Kopien EINER** gebauten Kette: sie referenzieren
dieselbe Blockdefinition und tragen darum Wort fuer Wort dasselbe Journal,
inklusive des Startpunkts der zuerst gebauten Kette (17201.78/1205.36/2100 mit
Starthoehe 2154). Im JSON ist dieser eine absolute Eintrag je Instanz auf ihren
echten Blockeinfuegepunkt gezogen (alle weiteren Eintraege sind relativ), damit
jeder Testfall fuer sich abspielbar ist. Achtung bei den Kopien: ihre
Block-Attribute (`HOEHE_VON_mm` = 2154, so auch im Sivas-Export) stammen aus
dem Original und sind nach dem Verschieben veraltet — die drei Kopien liegen
tatsaechlich 340.93 mm hoeher (belegt durch ihre Separator-Z-Werte im
Sivas-Export: 2575.43 statt 2234.50).
Neu erzeugen:
```
python lib/vf_journal_export.py data/polylines.dxf \
tests/testdata/hundm05.json --csv results/HundM_export.csv
```
Die frueheren Inhalte (Kreisel/Gefaellestrecke/Sensor-Eintraege aus dem
Fenster 215000/148000..250000/161000 von `results/ST500592_05.dxf`, erzeugt mit
`lib/dxf_scan_components.py`) stehen in der Git-Historie dieser Datei.
**Aufbau flach, nicht verschachtelt**: `ssg-load-json`/`ssg-parse-json-array`
(`Lisp/ssg_core.lsp`) liest die Datei ZEILENWEISE und behandelt jedes `{` als
Objektanfang — Verschachtelung (z.B. `"eingaben": [ {...} ]`) wuerde die
Kopf-Objekte verschlucken. Darum steht je Kette ein Kopf-Objekt (traegt
`test_id`) und danach ihre Eingaben (tragen `typ`), wie in
`linienzug_tests.json`. Der Anlagetyp im Kopf heisst `anlagetyp` und NICHT
`typ`, damit Kopf und Eingabe unterscheidbar bleiben.
Abgespielt wird das per `tests/test_hundm05.lsp` (`TEST_HUNDM05`,
`TEST_HUNDM05_2D`/`_3D`): der Treiber gruppiert die Objekte
(`hundm05:gruppiere`), baut daraus das Vorwaerts-Journal
(`hundm05:eintrag->journal`) und spielt es je Kette ueber
`vfl-journal-replay-start` + `vf-linienzug-modus` ab — denselben Weg nimmt die
Produktion beim Editieren/Konvertieren (`vfl-konvertiere-ent`). Bewusst KEINE
Eingabe-Mocks wie in `test_linienzug.lsp`: ein Mock muesste zu jedem Segment
die Fahrtrichtung kennen, die im Journal nur beim ersten Segment steht.