Files
dxfmakros/doc/todo/modus2-achsenweise-bilanz.md
T
y.wang 35ebee1e88 fix: Laengenbilanz des gefalteten Modus-2-Laufs (U-Form)
Gefaltete VF-Laeufe wurden zu kurz gebaut, weil der Solver Posten dem
falschen Schenkel zurechnete. Vier Aenderungen, alle nach demselben
Leitsatz: die letzten freien Groessen folgen der GEMESSENEN Ist-Lage,
nicht einer vorab verteilten Gesamtplanung.

1. vfl-zsolve-schluss-ziel (neu): endet der Lauf auf einem flachen
   Fueller, werden RICHTUNG und LAENGE gemeinsam gegen den Zielpunkt
   geloest statt nur die Laenge. Geschlossene Loesung ueber
   A = sqrt(|D|^2 - P^2), hz = Winkel(D) - atan2(P, A); C und P sind
   von hz unabhaengig, daher ohne Iteration. Bisher uebernahm der
   Solve die Richtung aus dem gezeichneten Pfad - ein Querversatz der
   realen Eck-Bauteile war damit prinzipiell unerreichbar, weil eine
   Laenge die Kette nur entlang ihrer Achse verschiebt.

2. Eingangs-Hardware bei gefaltetem Lauf: Umlenkstation + Separator
   stehen auf dem Eingangs-Schenkel und verbrauchen die Kletterspanne
   nicht; ihr Laengenanteil wird der Spanne wieder zugeschlagen.
   feste-vf bleibt unveraendert - sein sin3-Hoehenanteil ist real.

3. kletter-ende-fp: endet der Lauf auf einem KLETTERER, gibt es keinen
   Schluss-Fueller, der Motorstation + Separator + ES abzieht - sie
   standen in keinem Budget. Nur bei flacher Zone, Pfadende und
   vorhandenem ES, sonst sind sie bereits anderweitig verbucht.

4. Nachrechner wieder aktiv (8 statt 4 Runden): GF1 steht im Budget,
   aber im Eingangs-Schenkel. Die Kollision mit filler-A-len, wegen
   der er abgeschaltet war, ist entfallen.

3 und 4 wirken NUR gemeinsam - die Betraege heben sich teilweise auf,
eine einzeln eingebaute Korrektur verschiebt den Fehler bloss in die
andere Richtung (GF1 1636.9 - (Motor+Sep+ES) 1235.1 = 401.8 mm).

Gemessen am selben Pfad: 9 Grad 0.56 mm, 12 Grad 0.7 mm quer (vorher
1424 bzw. 934 mm), dZ 0.1 mm. Beide Modus-2-Regressionsketten weiter
OK; TEST_UNIT 904/904 mit 7 neuen file-freien Tests.

doc/todo.md: Punkt "Modus-2-Solver: achsenweise Laengen-Bilanz" ist
damit erledigt. Die Detaildatei bleibt liegen, weil vier Kommentare in
vf_linienzug.lsp auf ihren Pfad verweisen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-29 12:14:13 +01:00

394 lines
18 KiB
Markdown

# Modus-2-Solver: achsenweise Laengen-Bilanz
Status: **ERLEDIGT 2026-10-29.** Gefaltete Laeufe (U-Form) werden gebaut; am
selben Pfad gemessen 0.56 mm (9 Grad) und 0.7 mm (12 Grad) quer, beide
Regressionsketten weiter OK. Der Abschnitt "Stand 2026-10-29" und der "Nachtrag
2026-10-29" am Ende beschreiben Loesung und Herleitung.
Die Datei bleibt BEWUSST liegen, obwohl der Auftrag abgeschlossen ist: vier
Kommentare in `Lisp/vf_linienzug.lsp` verweisen auf diesen Pfad (Suche nach
`modus2-achsenweise-bilanz`). Sie dokumentiert damit nicht mehr einen Plan,
sondern WARUM der Solver so bilanziert, wie er es tut - einschliesslich der
fehlgeschlagenen Versuche, damit sie niemand ein zweites Mal unternimmt.
Alles unterhalb dieser Zeile ist der urspruengliche Plan von 2026-09-18 und
seine Zwischenstaende. Die dort genannten Zeilennummern sind veraltet; Phase B
von `vf-linienzug-modus2` findet man per Suche nach `climber-span`. Die damals
vorgeschlagene Zwischenloesung (gefaltete Laeufe mit Meldung abweisen) wurde
NICHT umgesetzt und ist gegenstandslos - solche Laeufe funktionieren jetzt.
## Kurzfassung
Der Modus-2-Solver (`vf-linienzug-modus2`, Phase B, `Lisp/vf_linienzug.lsp`
ca. Zeile 9915-10145) modelliert den VarioFoerderer-Lauf als EINE gerade
Bruecke. Bei einer gefalteten Kette (U-Form: hoch, quer, runter) zieht er die
festen Fussabdruecke aus der falschen Achse ab: **die erste GF wird zu lang,
die Kletterstrecke zu kurz, Motor/ES landen falsch bzw. fehlen.** Der Fix:
Laengen pro Schenkelrichtung bilanzieren statt als eine skalare Spanne.
Das ist ein **dokumentiertes v1-Naeherungs-Limit**, kein Regressionsfehler -
die Umbauten SEGS/Alert-Box/Mini-Filter haben Phase B nicht angefasst.
## Symptom (echter Testfall: results/test_modus2.dxf, logs/vfl_modus2.dbg)
U-Form-Kette, 6 Segmente, EIN VF-Lauf (Seg 2-6; die zwei Vario-Kurven zaehlen
als VF-Mitglieder):
```
^ Seg2 VF (1500 mm)
| Seg1 GF (2500 mm)
start Seg4 VF (2257 mm)
| +-----------------------+
| Seg3 Kurve Seg5 Kurve
| |
| Seg6 VF (3800 mm)
+ v
Ziel (3520, 180)
```
Ergebnis: `SOLL-ENDE=(3520, 180, 2000)`, `IST-ENDE=(3333, 2825, 2080)` ->
`dY=+2645 mm`, `dZ=+80 mm`. Die erste GF wird zu lang erzeugt; die
Kletterstrecke (Seg 6) endet ~2645 mm zu frueh; Motorstation, das
VF-Kurven-Zwischenstueck und das ES-Element sitzen falsch bzw. fehlen.
## Ursache, praezise lokalisiert
Der Solver waehlt die laengste VF-Gerade (Seg 6, 3800) als Kletterer, der die
ganze Hoehe traegt, und rechnet die geneigte Laenge skalar:
```lisp
;; vf_linienzug.lsp:9990 - Solver bekommt die SKALARE Spanne
(setq wahl3 (vfl-zsolve-winkel-waehlen climber-span dH-adj feste-vf))
;; feste-vf = Umlenk + Separator (+ Motor) -- ein fester Fussabdruck
;; vf_linienzug.lsp:10070 - Kletterer bekommt br-lvf proportional
(setq this-lvf (max clamp (* br-lvf (/ (caddr seg) climber-span))))
;; br-lvf = climber-span MINUS feste-vf
;; ABER: Umlenk/GF1/Motor sitzen physisch in ANDEREN Schenkeln
;; (GF1+Umlenk am Eingang entlang hz=90, nicht in Seg6/hz=-90)
```
**Der Modellbruch:** `br-lvf` = `climber-span` minus die festen Fussabdruecke
(Umlenk 500 + Separator 300 + GF1 `gf-total` + Motor). Diese Teile liegen aber
in den ANDEREN U-Schenkeln - nicht in Seg 6. Der Solver zieht sie trotzdem von
Seg 6s 3800er-Spanne ab. Weil GF1 = "alles am Einlauf" gewaehlt war, ist
`gf-total` gross -> Seg 6 wird um genau diese Summe (~2645 mm) zu kurz. Bei
einer GERADEN Bruecke liegen alle Teile auf derselben Achse - dann stimmt die
skalare Rechnung. Bei der U-Form nicht.
Zusaetzlich: die flache Zone nimmt GENAU EIN Uebergangspaar an
(`hor-pairs = 1`, Zeile 9950), obwohl die U-Form zwei 90-Grad-Kurven plus
Kletterstrecke mischt -> daraus die Rest-dZ von +80 mm.
## Beleg: dokumentiertes Limit, kein Regressionsfehler
| Kommentar-Fundstelle | Aussage |
|---|---|
| `vf_linienzug.lsp:9073-9075` | "v1-Naeherung Laenge ... feinere Laengen-Reservierung -> spaeter" |
| `vf_linienzug.lsp:9923-9926` | Modell explizit "EIN Vario mit Horizontal-Mitte" - eine gerade Bruecke ist die Design-Annahme |
| `vf_linienzug.lsp:9948-9950` | "flache Zone hat GENAU EIN Uebergangspaar ... unabhaengig von der Zahl der Fueller/Kurven" |
Verifiziert: SEGS-Umbau, Alert-Box und Mini-Filter haben Phase B (den Solver)
nachweislich nicht veraendert. Die Abweichung ist vorbestehend.
## Vorgeschlagener Umbau in sicheren Etappen
Nach jeder Etappe eine BricsCAD-Sichtpruefung (Geometrie ist nur interaktiv
pruefbar).
1. **Regressionsnetz zuerst.** Eine bekannt-gute GERADE Modus-2-Kette
(GF...VF...GF, eine Achse) bauen und mit `lib/dxf_vf_abbild.py
--schreibe-referenz` als Referenz einfrieren. Schuetzt den funktionierenden
Normalfall, bevor die Bilanz umgebaut wird.
2. **Schenkel erkennen.** Den VF-Lauf (Seg `vf-start`..`vf-ende`) an den
Vario-Kurven in Schenkel aufteilen - jeder Schenkel eine Fahrtrichtung (hz).
Pro Schenkel: Summe der VF-Geraden-Laengen, welche festen Teile darin liegen.
Neue Datenstruktur statt der skalaren `climber-span`. (ersetzt die
climber/nonclimber-Schleife 9935-9947)
3. **Fussabdruecke dem richtigen Schenkel zuordnen** (Risiko-Kern). Umlenk/GF1
nur vom Eingangs-Schenkel abziehen, Motor/GF2/ES nur vom Ausgangs-Schenkel -
nicht pauschal von der Kletterstrecke. Reicht ein Schenkel nicht, verteilt
sich die Restneigung auf weitere Schenkel. (feste-vf/dH-adj 9978-9989,
this-lvf 10070, fill-len 10094-10104)
4. **Uebergangspaare pro Kurve** statt pauschal eins. `hor-pairs` aus der
tatsaechlichen Schenkel-/Kurvenzahl ableiten - behebt die dZ-Restabweichung.
(9950, dH-adj-Bildung 9982-9989)
5. **Verifikation.** Regressionsnetz aus Schritt 1 muss gruen bleiben (gerader
Fall unveraendert). U-Form interaktiv: erste GF korrekt kurz,
Kletterstrecke trifft den Zielpunkt, Motor + Kurven-Zwischenstueck + ES an
der richtigen Stelle. SEGS-Journal bleibt formgleich.
## Risiko-Einschaetzung
- Der GERADE Fall funktioniert heute - er ist der Normalfall, fuer den der
Solver gebaut ist. Ein Umbau der Kern-Bilanz kann ihn brechen -> Schritt 1
(Referenznetz) ist nicht optional.
- Geometrie nur interaktiv in BricsCAD pruefbar -> mehrere Runden noetig.
- Gut eingegrenzt: der Umbau bleibt in Phase B von `vf-linienzug-modus2`
(~9915-10145). Klassifizierung, SEGS-Journal, Doppelklick-Replay und die
anderen Modi bleiben unberuehrt.
## Zwischenloesung (falls der Umbau nicht sofort kommt)
Gefaltete VF-Laeufe (mehr als eine Achsenrichtung im VF-Bereich, z.B. U-Form)
erkennen und mit klarer Meldung abweisen, statt still falsche Geometrie zu
bauen - analog zur bereits vorhandenen "nur EIN VF-Lauf"-Abweisung
(`vfl-m3-vf-lauf-alert`). Macht das Limit ehrlich sichtbar, kleiner Eingriff.
---
## Stand 2026-10-27 (nach Commit ce4ad0f)
**Teilweise entschaerft, Kern bleibt offen.**
Die Budget-Arbeit vom 26./27.10. hat genau das Prinzip eingefuehrt, das
dieses Dokument fordert - aber nur fuer DREI Posten. Sie werden jetzt dem
Segment zugeschlagen, auf dem sie physisch stehen, statt skalar von der
Gesamtspanne abgezogen zu werden:
| Posten | wie | Stelle |
|---|---|---|
| AS-Element | gemessener Fussabdruck, nur `vf-start` | `as-along-fix` |
| Abschlussbogen + Motorstation | nur `vf-ende` | `abschluss-fp` |
| Eck-Differenz (gezeichneter Bogen gegen Bauteil) | Alist je Segmentindex | `vfl-eck-korrekturen` / `vfl-eck-extra` |
`vfl-eck-extra` ist dabei bereits die hier geforderte Form: ein Zuschlag **je
Segment**, nicht ein Skalar fuer den ganzen Lauf. Er fliesst in alle vier
Budgets (Spannweite, Kletterer, Fueller, Rueckanker).
**Skalar geblieben sind genau die zwei Posten, die den U-Form-Fehler
verursachen:**
- `feste-vf` (Umlenkstation 500 + Separator 300, ggf. + Motor) - wird in
`vfl-zsolve-winkel-waehlen` als EIN Wert uebergeben
- `gf-total` (GF1) - bei "alles am Einlauf" gross, und genau diese Summe
fehlt dem Kletterer im anderen Schenkel
Das oben beschriebene Symptom (dY = +2645 mm) bleibt daher bestehen. Der
naechste Schritt waere, diese beiden ebenfalls dem Segment zuzuordnen, auf
dem sie stehen - also dieselbe Umstellung wie bei AS und Motorstation, nur
fuer den Lauf-EINGANG.
Hinweis zur Fehlersuche: Seit ce4ad0f meldet die Konsole jeden Zuschlag
namentlich (`AS-Fussabdruck ... von Segment N abgezogen`,
`Abschluss-Fussabdruck ...`, `Eck-Korrektur ... auf Segment N`). Eine
FEHLENDE Zeile ist das Warnsignal - so wurde ein 2,4-mm-Rest gefunden. Fuer
die U-Form-Diagnose sind diese Zeilen der schnellste Einstieg.
---
## Stand 2026-10-28: Fueller-Seite geloest, Solver-Seite offen
### Geloest und gemessen
`vfl-m2-eingang-fp`: GF1 + Separator + Umlenkstation + Uebergangsbogen stehen
auf dem Segment `vf-start`. Ist dieses Segment ein FUELLER (der Kletterer
liegt hinter einer Kurve), bekam der Fueller bisher die volle Restlaenge, als
staende dort nichts. Jetzt werden sie abgezogen.
Ist das Eingangs-Segment selbst der Kletterer - der gerade Normalfall -, gibt
die Funktion hart 0.0 zurueck; der funktionierende Fall kann sich also nicht
aendern. Gemessen am U-Form-Testfall: **Querabweichung 8005 -> 1424 mm**,
Segment 1 danach auf 0,2 mm genau belegt.
### Noch offen: der Solver rechnet GF und Stationen gegen die falsche Achse
Rest 1424 mm. Segment 5 (Kletterer) legt 6475,5 mm zurueck, verfuegbar waeren
7899,8 - der Solver reserviert dort Platz fuer Umlenkstation, Separator und
den GF1-Anteil, die auf Segment 1 stehen.
### Fehlgeschlagene Versuche (nicht wiederholen)
Drei Anlaeufe am 2026-10-27/28, jeder an einer anderen Kopplung gescheitert:
1. **`feste-vf` kleiner uebergeben.** Geht nicht: `feste-hz` fliesst in
`vf-winkel-AB` (vf_standard.lsp:241/245) sowohl als `feste*cos3` in die
LAENGE als auch als `feste*sin3` in die HOEHE. Die Hoehe ist real - die
Teile senken die Kette ab, egal auf welchem Schenkel sie stehen. Nur der
Laengenanteil darf verschoben werden.
2. **Spanne vorab korrigieren und iterieren.** Geht nicht direkt:
`vfl-zsolve-winkel-waehlen` enthaelt die WINKELFRAGE an den Nutzer - eine
Iteration wuerde mehrfach fragen. Und die Korrektur ist pro Winkel
verschieden, weil jeder Winkel ein anderes `L_GF` ergibt.
3. **Stiller Nachrechner nach der GF-Verteilungsfrage** (Code vorhanden, per
`(setq nachrechnen-k 4)` deaktiviert). Technisch sauber: kein Dialog,
Fragenfolge und Journal unveraendert, Konvergenz in 4 Runden
(3278 -> 4372 -> 4737 -> 4859 -> 4899 mm). ABER er kollidiert mit
**`filler-A-len`**: dieser Fueller belegt im Kletter-Segment genau den
Platz, den das halbe GF1 dort frei laesst. Nimmt man GF1 aus der
Kletterer-Spanne heraus, wird Fueller-A trotzdem gebaut - zusaetzlich zum
echten GF1 auf demselben Segment. Gemessen: Fueller nach der
Umlenkstation -369 mm (auf 100 geklemmt), Kette 746 mm daneben.
Kleinerer Endfehler, aber entartete Geometrie - deshalb zurueckgenommen.
### Daraus fuer den naechsten Anlauf
Der Nachrechner ist vermutlich der richtige Weg, aber **`filler-A-len` muss
mitbehandelt werden**: er gehoert zur Annahme "GF1 liegt im Kletter-Segment"
und darf bei gefaltetem Lauf nicht mehr entstehen. Wer das angeht, sollte
beide Mechanismen zusammen betrachten, nicht nacheinander.
Testfall vorhanden: U-Form 5855 / 270 / 7806 mm (Kletterer hinter zwei
90-Grad-Kurven), Soll-Querabweichung ~0, Stand heute 1424 mm. Die beiden
geraden Referenzketten in `c:TEST_LINIENZUG_MODUS2` schuetzen den Normalfall.
---
## Stand 2026-10-29: Eingangs-Segment exakt, Kletterer-Segment offen
### Zusaetzlich geloest (gegenueber dem Stand vom 2026-10-28)
**Fueller-A entfaellt bei gefaltetem Lauf**, und `vfl-m2-eingang-fp` zieht
seitdem `br-gf1` ab statt `gf-total`. Beides gehoert zusammen:
`filler-A-len` fuellt den Platz, den ein halbiertes GF1 auf DERSELBEN Achse
frei laesst - er gehoert zur Annahme "GF1 und GF2 liegen auf einer Geraden".
Bei gefaltetem Lauf wurde er auf dem Eingangs-Segment ZUSAETZLICH zu GF1
gebaut; zusammen mit GF2 im Kletterer-Schenkel entstanden damit 1.5 x
gf-total Gefaellestrecke bei einem Budget von gf-total.
Ergebnis, am U-Form-Testfall nachgerechnet (9 Grad, Verteilung 1/2+1/2):
```
Segment 1: AS 425,8 + GF1 1370,3 + Sep 299,6 + Umlenk 499,3
+ Bogen 199,9 + Fueller 3153,7 = 5948,6 mm
Budget: 5855 + 93,8 (Eck-Korrektur) = 5948,8 mm
```
Das Eingangs-Segment ist damit **auf 0,2 mm exakt belegt**, und im Protokoll
steht nur noch EIN Fueller statt zwei.
### Was offen bleibt
Das KLETTERER-Segment. Gemessen im selben Lauf: Segment 5 belegt 6965,8 mm,
verfuegbar waeren 7899,8 - es fehlen **934 mm**, exakt die Endabweichung.
Der Solver bekommt als Spanne 7704,16 mm und verplant darin u.a. GF1
(1370,3) sowie Umlenkstation + Separator (798,9) - Teile, die auf Segment 1
stehen. Umgekehrt enthaelt seine Spanne NICHT den Abschluss-Fussabdruck
(ab_3 + Motorstation, 695 mm), weil dieser nur von FUELLER-Segmenten
abgezogen wird (`fill-len`) und das Kletterer-Segment keines ist.
**Der Restfehler skaliert mit `L_GF`** und damit mit dem gewaehlten Winkel -
unabhaengig bestaetigt durch zwei Laeufe auf demselben Pfad:
| Winkel | L_GF | Querabweichung |
|---|---|---|
| 6 Grad | 1093 | 90 mm |
| 9 Grad | 2744 | 934 mm |
Praktische Folge: Mit flachem Winkel ist der gefaltete Lauf heute brauchbar,
mit steilem nicht.
### Hinweis zur Methodik fuer den naechsten Anlauf
Zwei Laeufe sind nur vergleichbar, wenn **Winkel UND GF-Verteilung gleich**
sind. Mehrere Messreihen dieser Sitzung waren nicht deutbar, weil sich
zwischendurch der Winkel geaendert hatte und der Restfehler mit `L_GF`
skaliert. Vor einer Aenderung also eine feste Kombination festlegen
(Vorschlag: 12 Grad, Verteilung 1/2+1/2) und nur die vergleichen.
---
## Nachtrag 2026-10-29: Loesungsansatz vom Nutzer
Der Abschnitt darueber beschreibt den Stand VOR dem folgenden Umbau; er bleibt
als Herleitung stehen.
Nutzer-Vorgabe: *"nach der zweiten VF-Kurve den passenden Winkel neu aus dem
KS_AUS der Kurve und dem Zielpunkt rechnen"* und *"da GF2 feststeht, steht auch
die fuer Auf/Ab verbleibende Laenge fest - passender Winkel plus eine
ausgleichende GF"*.
Das ist die Umkehrung der bisherigen Logik und trifft den Kern: bisher wurde
ALLES vorab global verplant und der aufgelaufene Fehler landete am Kettenende.
Richtig ist, die letzten freien Groessen aus der GEMESSENEN Ist-Lage zu
bestimmen. Je nachdem, was das letzte Segment ist, sind das verschiedene
Groessen:
| Letztes Segment | feste Groesse | freie Groessen |
|---|---|---|
| flacher Fueller | - | Richtung + Fuellerlaenge |
| Auf/Ab-Koerper (U-Form) | Laenge (aus dem Pfad) | Winkel (diskret) + GF-Ausgleich |
### Umgesetzt
**1. Flacher Fueller als Schlussstueck** - neue Funktion
`vfl-zsolve-schluss-ziel`. Bisher loeste `vfl-zsolve-es-fueller` nur die LAENGE
und uebernahm die Richtung aus dem gezeichneten Pfad. Eine Laenge verschiebt die
Kette aber nur ENTLANG ihrer Achse - steht der reale Kurvenausgang seitlich
NEBEN der gezeichneten Geraden, laeuft die gebaute Achse parallel zur Zielachse
und der Querversatz ist unerreichbar. Gibt man die Richtung mit frei, stehen
zwei Unbekannte zwei Gleichungen (X und Y) gegenueber, geschlossen loesbar:
```
D = Ziel - KS_AUS(letzte Kurve)
A = sqrt(|D|^2 - P^2) ; P = Querversatz des ES-Fussabdrucks
fill = A - C
hz = Winkel(D) - atan2(P, A)
```
`C` und `P` sind von `hz` unabhaengig, weil `vfl-zsolve-es-vektor` Vektor und
Bezugsrahmen um denselben Winkel dreht - deshalb ist keine Iteration noetig.
Scheitert der Solve (Ziel naeher als `P`), bleibt der bisherige Weg. Unit-Tests:
`tu-tests-vfl-schluss` (file-frei ueber `es-block = nil`).
**2. Eingangs-Hardware bei gefaltetem Lauf** - der am 2026-10-28 zurueck-
genommene Spannen-Zuschlag ist wieder da. Begruendung fuer die Ruecknahme war
die Kollision mit `filler-A-len`; dieser Blocker ist entfallen, seit Fueller-A
bei gefaltetem Lauf gar nicht mehr entsteht. Zugeschlagen wird weiterhin NUR
der Laengenanteil (`entry-fixed * cos3`), nie `feste-vf` selbst - dessen
`sin3`-Hoehenanteil ist real.
**3. Abschluss-Hardware auf dem Kletterer** (`kletter-ende-fp`) - endet der Lauf
auf einem FUELLER, zieht `vfl-zsolve-es-fueller` Motorstation + Separator + ES
beim Loesen der Fuellerlaenge selbst ab. Endet er auf einem KLETTERER, gibt es
diesen Fueller nicht: die drei Teile werden dort gebaut, standen aber in keinem
Budget. Abgezogen wird dasselbe wie in dessen Konstante `cc`, OHNE den
ab_3-Bogen (der steckt in diesem Fall schon in `uebergang-fp`).
**4. GF1-Fremdanteil** (Nachrechner wieder aktiv, 8 statt 4 Runden) - `gf-total`
ist ein ERGEBNIS des Winkel-Solves, sein auf dem Eingangs-Schenkel stehender
Teil laesst sich dort noch nicht abziehen (Henne-Ei). Der Nachrechner loest bei
UNVERAENDERTEM Winkel neu und konvergiert mit Faktor ~1/3.
### Der entscheidende Punkt: 3 und 4 wirken nur GEMEINSAM
| Posten | im Budget des Solvers | steht real auf dem Kletterer |
|---|---|---|
| GF1 | ja | nein - liegt im Eingangs-Schenkel |
| Motor + Separator + ES | nein | ja |
Die beiden Betraege heben sich TEILWEISE auf. Wer nur einen davon korrigiert,
verschiebt den Fehler bloss in die andere Richtung - genau das war der
746-mm-Befund vom 2026-10-28, der damals wie eine Verschlechterung aussah.
Gemessen am 9-Grad-Lauf: GF1 1636.9 - (Motor+Sep+ES) 1235.1 = 401.8 mm, exakt
die damalige Restabweichung von 401.7 mm.
### Messergebnis
| Lauf | vorher | nachher |
|---|---|---|
| U-Form 9 Grad | 1424 -> 934 mm | **0.56 mm** |
| U-Form 12 Grad | - | **0.7 mm** |
| Variante A (Vario-Kurve) | OK | OK |
| Variante B (GF-Bogen) | OK | OK |
Zwei verschiedene Winkel auf demselben Pfad - der Restfehler skaliert also
nicht mehr mit `L_GF`, die Bilanz selbst stimmt.
### Regression auf dem Weg dorthin (Lehrstueck)
`kletter-ende-fp` schlug zunaechst auch in Variante B zu und verkuerzte deren
Segment 1 um 798.9 mm. Dort ist `vf-start = vf-ende = 0`: der VF-Lauf besteht
aus EINEM Segment, die Segmente 2..5 sind Back-Lauf. Damit ist der Kletterer
zugleich Laufende, der Abzug griff - obwohl ohne flache Zone die Motorstation
bereits in `feste-vf` steckt und Separator + ES vom Back-Lauf reserviert werden.
Die drei Bedingungen am `if` (`hor-pairs > 0`, `vf-ende = n-1`, `es-vorhanden`)
sind deshalb keine Vorsichtsmassnahme, sondern benennen genau die Faelle, in
denen sonst doppelt gebucht wird.
Auffindbar war die Ursache nur, weil Segment 1 von Variante B bei `hz=0` liegt:
eine Verkuerzung dieses Segments uebersetzt sich 1:1 in `dX`, und `IST - SOLL =
(-799.11 | -104.68)` aus `logs/vfl_modus2.dbg` zeigte die reine X-Verschiebung.