Pensionsalter anpassen (Roadmap 44)
Deploy App / deploy (push) Successful in 1m1s

Das Pensionsalter laesst sich neu veraendern: Nicht das Alter wird gesetzt,
sondern die Phasengrenze verschoben -- Vorphase laenger, Folgephase kuerzer,
Gesamtdauer gleich. Faellt eine Phase dabei weg, werden die beiden Uebergaenge
nach Bestaetigung zusammengelegt.

- neues reines Modul lib/retirement.ts + POST /api/scenarios/<id>/retirement
- Pensionsalter als Tornado-Treiber und Live-Simulations-Regler
- AHV-Referenzalter 65: Rente ab 65 unabhaengig vom Pensionsalter; vor 65
  Beitrag als Nichterwerbstaetige(r) (neues Feld ahvContribution).
  AHV wird dafuer jahresweise statt phasenweise gerechnet.
- Punkt B: personenzugeordnetes Einkommen faellt bei Pensionierung auf 0
- Punkt A: Wiederkehr-Parameter werden live aus der Vorphase geerbt,
  sichtbar als "Aus Vorphase uebernehmen"
- Punkt C: Kapitalzufluss am Pensions-Uebergang per Quote auf Amortisation,
  Anlage und Cash verteilbar
- Fix: carry.flowBasis wurde vor der Jahresschleife berechnet, effektive
  Werte kamen deshalb nie in der Folgephase an

SPEZIFIKATION 0.26 (neue Kapitel 3.12, 4.4.7, 4.16). 221 -> 261 Tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 14:24:40 +02:00
parent c429624635
commit d6855ef1a0
20 changed files with 2057 additions and 184 deletions
+316 -34
View File
@@ -4,10 +4,10 @@
| | |
|---|---|
| **Dokument** | Funktionale und Technische Spezifikation FPT |
| **Version** | 0.25 |
| **Datum** | 2026-07-18 |
| **Version** | 0.26 |
| **Datum** | 2026-07-21 |
| **Status** | Lebendes Dokument |
| **Codestand** | Arbeitsstand nach `1d046e9` inkl. zwei Monte-Carlo-Fragestellungen (Branch `main`) |
| **Codestand** | Arbeitsstand nach `c429624` inkl. anpassbarem Pensionsalter (Branch `main`) |
| **Ersetzt** | `FDD_TDD_FPT.docx` (v1v5) im Ordner `Info Dateien` diese sind ab Version 0.1 dieses Dokuments obsolet |
| **Geltungsbereich** | Gesamter Code im Verzeichnis `FPT` |
@@ -17,6 +17,7 @@
| Version | Datum | Autor | Änderung |
|---|---|---|---|
| 0.26 | 2026-07-21 | Claude (Opus 4.8) | **Pensionsalter anpassen** (Roadmap Nr. 44, neue Kapitel 3.12, 4.4.7 und 4.16). Bisher war das Pensionsalter faktisch unantastbar: Es bestimmt, wo eine Lebensphase endet ein frei geändertes Alter hätte die Phasengrenze zerrissen. Neu wird nicht das Alter geändert, sondern **die Grenze verschoben**: Die Phase davor wird länger, die danach kürzer, die Gesamtdauer bleibt gleich. Der Spielraum endet dort, wo eine angrenzende Phase unter ein Jahr fiele; ein Schritt weiter **entfällt sie ganz**, was vorher bestätigt wird, weil dabei zwei Übergänge **zusammengelegt** werden (bereits getroffene Entscheide bleiben, leere Felder werden aus dem entfallenden Übergang ergänzt, einmalige Cash-Beträge werden addiert der Steuersatz betragsgewichtet). Das Pensionsalter ist damit auch **Treiber im Tornado** und **Regler in der Live-Simulation**. **AHV-Referenzalter (4.4.7):** Die Rente beginnt neu **immer mit 65**, unabhängig vom Pensionsalter wer länger arbeitet, erhält sie zusätzlich zum Lohn; wer früher aufhört, zahlt bis 65 einen **Beitrag als Nichterwerbstätige(r)**, der als laufende Ausgabe auf die Verzehrquote schlägt und mit 65 wegfällt (neues Feld `ahvContribution`, ohne Default, Hilfetext nennt die reale Bandbreite von rund 530 bis 26'500 CHF pro Jahr). Beide Wechsel können **innerhalb** einer Phase liegen, die AHV wird deshalb **jahresweise** statt phasenweise gerechnet. **Punkt B:** Ein Einkommen, das einer **Person** zugeordnet ist, fällt bei deren Pensionierung auf 0 bisher lief der Lohn stillschweigend in die Pension weiter. Gemeinsame Einkommen (Mieterträge o. Ä.) bleiben; ein ausdrücklich erfasster Betrag gewinnt, damit ein Teilzeitpensum modellierbar bleibt. **Punkt A:** Wiederkehr-Parameter (Raten, Beiträge, Amortisation, Wertsteigerung, Zinssatz) werden neu **live aus der Vorphase geerbt** statt beim Anlegen der Phase kopiert sichtbar als angehaktes **«Aus Vorphase übernehmen»** je Feld. Vorher blieb die Kopie stehen, wenn man die Vorphase später änderte. **Punkt C:** Der Kapitalzufluss am Pensions-Übergang (PK, 3a, Verkaufserlös) lässt sich in **Prozent** auf Amortisation, Anlage und Cash aufteilen bewusst nicht in Franken, weil sich der Betrag mit dem Pensionsalter ändert und eine Quote mitskaliert. **Nebenbei ein echter Fehler behoben:** Der fortgeschriebene Basiswert für Einkommen und Ausgaben wurde **vor** der Jahresschleife berechnet effektive Werte kamen dadurch nie in der Folgephase an. Neues Modul `retirement.ts`, neuer Endpunkt `POST /api/scenarios/<id>/retirement`; 40 Tests ergänzt (221 → 261). |
| 0.25 | 2026-07-21 | Claude (Opus 4.8) | **PDF-Berichte** (Roadmap Nr. 11, neues Kapitel 3.11). Neuer Unterpunkt **«Berichte»** auf Plan-Ebene: Liste der erzeugten Berichte plus Assistent zum Anlegen (Titel, Notiz, nominal **oder** real, Plan- oder effektive Daten, bis zu **drei** Szenarien, beliebige gespeicherte Analysen). Das **Layout ist immer gleich**; die Auswahl bestimmt nur, welche Bausteine erscheinen: Deckblatt mit Zusammenfassung und drei Kernaussagen, dann je Szenario Kennzahlen, Vermögensverlauf, Lebensphasen und Annahmen, danach Vergleich, Plan/Ist, Analysen und die Hinweise. **Die PDF-Datei wird als Datei abgelegt** (BYTEA in Postgres, nicht im Container-Dateisystem, das jeder Deploy neu baut): Ein Bericht muss in drei Jahren byte-identisch wieder herunterladbar sein eine Neuerzeugung könnte das nach Änderungen an Plan, Rechenkern oder Layout nicht garantieren. **Kennzahlen je Szenario:** Endvermögen, Kapitalreichweite, Vermögen und Vorsorgekapital bei Pensionierung, AHV- und PK-Rente sowie die **offenen Entscheide** die einzige unmittelbar handlungsleitende Zahl. Damit Bericht und Matrix nie verschiedene Zahlen nennen, liegt deren Zählung neu als reine Funktion in `decisions.ts`, die beide benutzen. **Zu jeder Kennzahl steht ihre Grundlage** als kurzer Verweis; die vollständigen Annahmen (Startwerte, Renditen, Raten je Element) stehen **einmal** je Szenario, statt bei jeder Kennzahl wiederholt zu werden. Ein **Haftungsausschluss** ist verpflichtend und durch einen Test gesichert ein formal gesetztes PDF wird sonst als Beratung gelesen. **Technik:** `pdfkit` in der Node-Runtime statt Headless-Browser (kein Chromium im Image); `@react-pdf/renderer` schied aus, weil es mit React 19 / Next 16 bricht. Diagramme entstehen als **echte Vektoren** aus den gespeicherten Zahlen genau dafür wurden die Analysen in 0.24 als Zahlen und nicht als Bilder abgelegt. `pdfkit` ist als externes Paket deklariert, weil es Font-Metriken über Dateipfade lädt und gebündelt erst in der Produktion bräche. Neue Tabelle `Report`, Endpunkte unter `/api/plans/<id>/reports`, neue Module `report.ts`, `report-pdf.ts`, `decisions.ts`; 9 Tests ergänzt (212 → 221). |
| 0.24 | 2026-07-20 | Claude (Opus 4.8) | **Navigation auf Plan-Ebene und gespeicherte Analysen** (neues Kapitel 3.10). Die Seitenleiste ist neu zweistufig: Unter jedem Plan liegen die Unterpunkte **Szenarien**, **Effektive Werte** und **Analysen**; ein Klick auf den Plan-Namen öffnet ein **Plan-Dashboard** (Kennzahlen Haushaltsdaten direkt, gerechnete Werte ausdrücklich «laut Basisszenario», dazu die Ist-Abweichung, falls erfasst). Die **Szenario-Liste** zeigt je Szenario Version, Elementzahl, Endvermögen und Ruinalter mit den Aktionen Historie und Matrix; das Basisszenario ist hervorgehoben, der Szenario-Baum in der Seitenleiste bleibt daneben erhalten. Die **Analysen-Ansicht** bietet vier umklappende Kacheln (Grafiken, Live-Simulation, Monte-Carlo, Einflussfaktoren Umklappen auch per Antippen für Touch). **Grafiken** öffnen neu nicht mehr alle drei Diagramme, sondern lassen zuerst **eines** wählen; der Szenario-Vergleich zieht mit zu den Grafiken, der CSV-Export auf die Matrix. **Gespeicherte Analysen:** Jede Grafik, MC-Simulation und Einflussfaktoren-Berechnung kann festgehalten werden als **Zahlen, nicht als Bild** (read-only, es wird nichts neu gerechnet). Das hält den Datensatz klein und macht ihn druckfähig: Der spätere PDF-Bericht (Roadmap Nr. 11) zeichnet daraus vektoriell in Druckauflösung, was ein Screenshot nicht könnte. Bewusst **nicht** gespeichert wird `finalWealthSorted` (megabyteweise). Jedes Werkzeug schreibt sein Ergebnis in dieselbe generische Form, sodass eine Nur-Lese-Ansicht genügt. Neue Tabelle `SavedAnalysis`, neue Endpunkte unter `/api/plans/<id>/analyses` und `/dashboard`; neue Komponenten `PlanViews`, `SavedAnalysisView`, `SaveAnalysisButton`, neues Modul `analyses.ts`. Kein Eingriff in den Rechenkern; Testbestand 212 (Migration um `SavedAnalysis` erweitert). |
| 0.23 | 2026-07-20 | Claude (Opus 4.8) | **V7: Der Haushalt liegt am Plan, die Annahmen am Szenario.** **Haushaltsform**, **Personen** (Name, Alter) und **Planstartjahr** wandern vom Szenario auf den **Plan**; das **Pensionsalter** bleibt szenario-eigen (es ist der Kern jedes Früh-/Spätpensionierungs-Szenarios), ebenso Inflation und Cash-Anfangswert. Begründung: Diese Angaben beschreiben den Haushalt, nicht eine Planungsvariante unterscheiden sie sich, ist es ein anderer **Plan**, kein anderes Szenario. Neue Tabelle `PlanPerson` (Rolle, Name, Alter je Plan); `Person` behält nur noch Rolle und Pensionsalter; `Plan` bekommt `householdType` und `startYear`. **Der Rechenkern bleibt unberührt:** `toPlanInput()` fügt Plan- und Szenario-Ebene wieder zu einem unveränderten `PlanInput` zusammen, die 43 Golden Tests laufen durch. **Nebeneffekt, der ein reales Problem löst:** Weil das Startjahr nun plan-weit ist, landet ein erfasster Ist-Satz für 2031 in **allen** Szenarien zwingend auf demselben Planjahr vorher war das nicht garantiert. Das **Wiederherstellen einer Szenario-Version** setzt folgerichtig nur noch das Szenario-Eigene zurück; plan-weite Angaben über eine Version *eines* Szenarios zu überschreiben, hätte die übrigen stillschweigend mitverändert. Der Profil-Dialog kennzeichnet neu je Feld, ob es **plan-weit** oder **nur dieses Szenario** gilt. Die Migration übernimmt die Werte aus dem **Basisszenario**; zwei neue Tests spielen dafür echte V6-Daten ein und prüfen die Übernahme inkl. abweichender Nebenszenarien (210 → 212). |
@@ -970,8 +971,9 @@ analog zur Monte-Carlo-Simulation:
4. **Ergebnis** Basisfall, Tornado-Chart und Tabelle.
Der Dialog ist bewusst **nicht** Teil des Grafiken-Bereichs: Dieser ist reine Ausgabe, während der
Tornado Pflichteingaben braucht. Ein Hinweis am Ende der Parameterliste benennt, warum das
**Pensionsalter** nicht enthalten ist (siehe [9.18](#918-tornado-was-der-chart-nicht-leistet)).
Tornado Pflichteingaben braucht. Seit 0.26 gehört auch das **Pensionsalter** je Person zu den
Treibern es erscheint nur, wenn die Phasengrenze überhaupt Spielraum hat
(siehe [9.18](#918-tornado-was-der-chart-nicht-leistet) und [4.16](#416-pensionsalter-verschieben)).
Referenz: `src/components/SensitivityDialog.tsx`, `src/components/AppShell.tsx`.
@@ -1651,6 +1653,107 @@ das, was eingefroren wird, dasselbe, was geprüft wird.
Referenz: `src/lib/report.ts`, `src/lib/report-pdf.ts`, `src/lib/decisions.ts`,
`src/components/ReportsView.tsx`.
## 3.12 Pensionsalter anpassen
> Roadmap Nr. 44. Bedienung im Szenario-Profil, Abschnitt «Pensionsalter anpassen».
### 3.12.1 Warum das kein Zahlenfeld ist
Das Pensionsalter bestimmt, **wo eine Lebensphase endet**: `maxPhaseDuration` kappt jede
Phasendauer beim nächsten Pensionierungsereignis, jede Pensionierung liegt deshalb zwangsläufig
auf einer Phasengrenze. Ein frei änderbares Alter hätte diese Zusammengehörigkeit zerrissen
die Phasen blieben, wo sie sind, und der Phasentyp (Erwerb/Misch/Pension) käme mitten in einer
Phase ins Rutschen.
Deshalb ändert die Bedienung nicht das Alter, sondern verschiebt **die Grenze**:
| | vorher | nachher (4 Jahre) |
|---|---|---|
| Phase 3 «Misch» | 10 Jahre | **6 Jahre** |
| Phase 4 «Pension» | 15 Jahre | **19 Jahre** |
| Gesamtdauer | 60 Jahre | 60 Jahre |
Die Gesamtdauer des Plans bleibt immer gleich es wird Zeit umverteilt, nicht hinzugefügt.
### 3.12.2 Spielraum und Sperren
Angezeigt wird je Person das aktuelle Pensionsalter, Knöpfe für ±1 Jahr, Kurzwahl-Chips für
grössere Schritte und eine **Hilfebox**, die den Spielraum benennt. Ein deaktivierter Knopf
ohne Erklärung wirkt wie ein Fehler; die Box sagt deshalb immer, was möglich ist **und warum
nicht mehr**.
Der Spielraum ist `(Dauer der Vorphase 1)` bis `+(Dauer der Folgephase 1)`: Eine
Lebensphase muss mindestens ein Jahr dauern.
Gesperrt wird ganz, wenn:
| Situation | Meldung |
|---|---|
| Person ist bei Planbeginn schon pensioniert | es gibt keine Grenze zu verschieben |
| Pensionierung liegt am oder nach dem Planende | zuerst eine Lebensphase anhängen |
| Pensionierung liegt nicht auf einer Phasengrenze | zuerst die Lebensphasen anpassen (Altdaten) |
| **Beide Personen teilen dieselbe Grenze** | zuerst eine Lebensphase einfügen, um sie zu trennen |
Der letzte Fall ist der Kehrseite der Zusammenlegung: Sind zwei Pensionierungen auf demselben
Zeitpunkt, liesse sich die eine nicht bewegen, ohne die andere mitzunehmen.
### 3.12.3 Zusammenlegung: wenn eine Lebensphase entfällt
Genau ein Jahr über den Spielraum hinaus fällt die angrenzende Phase auf 0 und **verschwindet**.
Das ist erlaubt es ist der Fall «beide werden gleichzeitig pensioniert, die Mischphase gibt es
nicht mehr» , wird aber **vorher bestätigt**, weil dabei zwei Übergänge zu einem werden.
Regel für die Zusammenführung (überlebende Grenze ist die des **Vorgängers** der entfallenden
Phase):
| | Regel | Begründung |
|---|---|---|
| Element-Entscheide | Was am überlebenden Übergang schon entschieden ist, **bleibt**. Nur leere Felder werden aus dem entfallenden ergänzt. | Ein bewusster Entscheid darf nie von einem anderen überschrieben werden. |
| Einmalige Cash-Beträge | werden **addiert** | Beide Ereignisse finden weiterhin statt, nur zum selben Zeitpunkt. |
| Steuersatz auf dem Zufluss | **betragsgewichteter** Mischsatz | Nur so bleibt der Netto-Zufluss derselbe wie vorher. |
| Bezeichnungen | mit « + » verbunden | damit nachvollziehbar bleibt, woraus die Summe entstand |
Die Verschiebung ist **nicht** über die Undo-Funktion rückgängig zu machen sie erzeugt wie
jede Änderung eine neue Nebenversion, aus der sich der alte Stand wiederherstellen lässt
([3.8](#38-versionierung-und-änderungshistorie)).
### 3.12.4 Punkt A: «Aus Vorphase übernehmen»
Wiederkehr-Parameter Teuerungsausgleich, erwartete Rendite, jährliche Einzahlung, Bezugsrate,
Amortisation, Wertsteigerung, Hypothekarzins, Tilgung galten bisher als **Kopie**: Beim
Anlegen einer Phase wurde der Wert der Vorphase hineingeschrieben. Änderte man die Vorphase
später, blieb die Kopie stehen.
Neu ist das Feld in Folgephasen standardmässig **leer** und wird live geerbt; darunter steht ein
angehaktes Kästchen **«Aus Vorphase übernehmen»** mit dem geerbten Wert daneben. Ein Häkchen
weg macht das Feld editierbar und den Wert phasen-eigen.
Nicht vererbt werden bewusst: **Ausfalljahre** (sie gelten für genau eine Phase ein geerbter
Wert würde eine Lücke erfinden), der **Kaufpreis** einer Immobilie (eine Tatsache, keine
Annahme) und die **Zins-Behandlung** (ein Schalter ohne Zahlenwert).
Bestehende Pläne verhalten sich unverändert: Dort sind die Werte gespeichert und gewinnen daher
gegen die Vererbung, bis man das Häkchen aktiv setzt.
### 3.12.5 Punkt C: Verwendung des Kapitalzuflusses
Am Pensions-Übergang kommt oft ein grosser Betrag auf einmal herein (PK-Kapital, Säule 3a,
Verkaufserlös). Ihn vollständig als Cash liegen zu lassen ist selten die Absicht. Im
Cash-Übergang lässt sich deshalb erfassen, wie viel **in Prozent** in die Amortisation der
Hypothek und in eine Anlage fliesst; der Rest bleibt Cash.
**Warum Prozent und nicht Franken:** Verschiebt man das Pensionsalter, ändert sich das bezogene
Kapital. Ein Frankenbetrag müsste von Hand nachgezogen werden und würde bis dahin still eine
falsche Aufteilung rechnen. Eine Quote skaliert mit.
Die Amortisations-Quote ist am Restsaldo der Hypothek gekappt; ist sie grösser, bleibt der Rest
Cash. Die Anlage-Quote fliesst in ein wählbares Vermögens-Element (Vorgabe: das erste aktive).
Beide sind mechanisch nichts Neues die eine wirkt wie eine Sonderamortisation, die andere wie
eine Zusatzinvestition, und beide laufen dadurch korrekt durch die zwei Wasserfall-Brücken.
Referenz: `src/lib/retirement.ts`, `src/components/RetirementAdjuster.tsx`,
`src/components/FormField.tsx` (`InheritableField`).
---
# 4. Berechnungsmodell
@@ -1857,11 +1960,58 @@ falls (renteA + renteB) > cap:
Die Rente ist danach **nominal fix** sie wird über die Phasen hinweg nicht indexiert und
verliert damit real an Kaufkraft (siehe [9.11](#911-ahv-rente-wird-nach-der-pensionierung-nicht-indexiert)).
Sie fliesst in `renteTotal` und wird im Einkommen mitgeführt.
**Wann** sie fliesst, entscheidet seit 0.26 nicht mehr der Phasentyp, sondern das Alter im
jeweiligen Jahr siehe 4.4.7.
Referenz: `src/lib/calculations.ts` (`ahvMonthlyFullPension`, `ahvMdje`, `ahvAnnualPension`),
`src/lib/constants.ts`.
### 4.4.7 Referenzalter: Die Rente beginnt mit 65, nicht mit der Pensionierung
Bis Version 0.25 galt implizit «pensioniert = Rente». Sobald sich das Pensionsalter verschieben
lässt ([4.16](#416-pensionsalter-verschieben)), ist das falsch: Die AHV-Rente hängt am
**Referenzalter** (`AHV_REFERENCE_AGE = 65`), nicht daran, wann jemand aufhört zu arbeiten.
Daraus folgen drei Fälle:
| Fall | Was passiert |
|---|---|
| Pensionierung **mit 65** | unverändert die Rente fliesst ab Beginn der Pensionsphase |
| Pensionierung **nach 65** | Die Erwerbsphase deckt das Referenzalter ab. Die Rente fliesst ab 65 **zusätzlich zum Lohn**. Erfasst werden nur noch die Ausfalljahre bis 65. |
| Pensionierung **vor 65** | Die Pensionsphase beginnt vor 65. Bis dahin ist die Person **beitragspflichtig als Nichterwerbstätige(r)**; der Beitrag (`ahvContribution`) ist eine laufende Ausgabe. Mit 65 fällt er weg und die Rente setzt ein. |
Beide Wechsel können **innerhalb derselben Lebensphase** stattfinden. Die AHV wird deshalb
**jahresweise** ausgewertet statt als Phasenkonstante:
```
für jedes Jahr t der Phase:
alterImJahr = alterZuPhasenbeginn + t 1
alterImJahr ≥ 65 → Rente fliesst (Einkommen)
sonst, wenn pensioniert → Beitrag fällt an (Ausgabe, wirkt auf die Verzehrquote)
sonst → nichts
```
Der Verlaufspunkt des AHV-Elements zeigt den Beitrag als **negativen** Wert so ist in der
Grafik zu sehen, dass die AHV in diesen Jahren Geld kostet, statt welches zu bringen.
**Ein Aufschub der Rente wird nicht abgebildet.** Wer über 65 hinaus arbeitet, könnte den Bezug
aufschieben und erhielte dafür einen Zuschlag. Das Tool lässt die Rente stattdessen fliessen
die vorsichtigere Annahme, und eine, die keinen zusätzlichen Entscheid verlangt.
**Der Beitrag als Nichterwerbstätige(r)** bemisst sich am Vermögen und am Renteneinkommen, nicht
am Lohn. Die Bandbreite ist entsprechend enorm: vom Mindestbeitrag von rund **530 CHF/Jahr** bis
zum Höchstbeitrag von rund **26'500 CHF/Jahr**. Deshalb gibt es hier **keinen Default** ein
stiller Vorschlag würde nicht hinterfragt (vgl. [9.15](#915-defaults-für-annahmen-sind-gefährlich)).
Der Hilfetext nennt die Bandbreite ausdrücklich, damit auch jemand ohne Vorwissen ein Gefühl für
die Grössenordnung bekommt.
**Beitragsjahre:** Wer den Beitrag zahlt, hat keine Ausfalljahre die Rentenskala bleibt
unberührt. Das Modell kürzt die Rente bei Frühpensionierung deshalb nicht; eine Kürzung entsteht
nur, wenn man die Jahre ausdrücklich als Ausfalljahre erfasst.
Referenz: `src/lib/calculations.ts` (`ahvItems` in der Jahresschleife), `AHV_REFERENCE_AGE` in
`src/lib/constants.ts`.
## 4.5 Nominal, real und die Deflatoren
### 4.5.1 Das V5-Modell
@@ -1905,11 +2055,16 @@ Vorab-Abbruch: Ist der Carry-Status `SOLD` → Notiz „Verkauft"; ist er `SETTL
### 4.6.1 INCOME / EXPENSE
```
idx = phaseData.teuerungsausgleich ?? 0
idx = phaseData.teuerungsausgleich ?? carry.rates.teuerungsausgleich ?? 0 // Punkt A
baseValue = hasCarry ? round(carry.flowBasis) : round(phaseData.amount)
basis = !hasCarry → round(phaseData.amount)
phaseData.amount ist Zahl → round(phaseData.amount) // bewusster Override
sonst → baseValue // live vererbt
// Punkt B: Besitzer ist eine PERSON und in dieser Phase pensioniert,
// und es ist kein Betrag erfasst → basis = 0
// NACH der Jahresschleife (siehe 4.16.6):
carry.flowBasis = basis × (1 + idx/100)^duration // für die Folgephase
```
@@ -1921,10 +2076,17 @@ durch. Nur ein bewusst abweichender Wert wird fix gespeichert.
Man beachte den Exponenten-Unterschied: der **Endwert** der Phase nutzt `duration 1`
(letztes Jahr), der **Carry** für die Folgephase nutzt `duration` (ein Jahr weiter).
Die Fortschreibung passiert seit 0.26 **nach** der Jahresschleife sonst kämen effektive Werte
nie in der Folgephase an ([4.16.6](#4166-fehlerbehebung-fortgeschriebener-basiswert-und-effektive-werte)).
### 4.6.2 AHV
Erwerbstätig → nur Zusammenfassung („N Ausfalljahre" / „Keine Ausfalljahre"), kein Wert.
Pensioniert → `startValue = endValue = rente`, Summand in `renteTotal`.
Seit 0.26 **jahresweise** statt phasenweise ([4.4.7](#447-referenzalter-die-rente-beginnt-mit-65-nicht-mit-der-pensionierung)):
Das Element meldet Rente, Beitrag und Startalter des Besitzers an die Jahresschleife an, die je
Jahr entscheidet, was fliesst. `startValue` / `endValue` zeigen den Stand im ersten bzw. letzten
Jahr der Phase; die Zusammenfassung nennt beide Zustände, wenn das Referenzalter mitten in der
Phase liegt («Beitrag … → Rente …»). Die Rente läuft **nicht** mehr über `renteTotal`, weil sie
innerhalb einer Phase einsetzen kann.
### 4.6.3 PENSION_FUND
@@ -2258,6 +2420,7 @@ Zentral in `src/lib/constants.ts` geführt, weil sie sich periodisch durch Bunde
| `AHV_GROSS_FROM_NET_FACTOR` | 1.12 | Netto → Brutto für die AHV; Herleitung siehe [4.4.5](#445-netto-brutto-umrechnung-für-die-ahv) |
| `AHV_COUPLE_CAP_FACTOR` | 1.5 | Ehepaar-Plafonierung: 150 % der Einzel-Maximalrente |
| `AHV_FULL_CONTRIBUTION_YEARS` | 44 | Volle Beitragsdauer (Rentenskala 44) |
| `AHV_REFERENCE_AGE` | 65 | Referenzalter ab hier fliesst die Rente, **unabhängig vom Pensionsalter** ([4.4.7](#447-referenzalter-die-rente-beginnt-mit-65-nicht-mit-der-pensionierung)) |
| `PILLAR_3A_MAX_ANNUAL` | 7'258 | Max. 3a-Beitrag/Jahr für PK-Versicherte (2026) |
| `DEFAULT_PK_CONVERSION_RATE` | 6 % | Umwandlungssatz |
| `DEFAULT_CAPITAL_TAX_RATE` | 8 % | Kapitalbezugssteuer |
@@ -2526,6 +2689,7 @@ falsch zu werden:
| Einkommen | **relativ %** | skaliert `amount` aller `INCOME`-Elemente |
| Lohnentwicklung | **Δ Prozentpunkte** | verschiebt `teuerungsausgleich` der `INCOME`-Elemente |
| Wertsteigerung der Immobilie | **Δ Prozentpunkte** | verschiebt `valueGrowth` |
| Pensionsalter Person A / B | **Δ Jahre** | verschiebt die Phasengrenze der Pensionierung ([4.16](#416-pensionsalter-verschieben)) |
Die Begründungen im Einzelnen:
- **Absolut** nur bei der Inflation es gibt genau einen plan-weiten Wert.
@@ -2777,10 +2941,11 @@ Elemente einzeln um +1 pp zu heben ergibt exakt dasselbe Endvermögen wie der Sa
Frage, die man tatsächlich stellt; Ausgaben-Elemente sind typischerweise viele kleine Posten,
deren Einzelregler das Panel fluten würden, ohne eine bessere Frage zu ermöglichen.
**Das Pensionsalter fehlt weiterhin** aus demselben Grund wie beim Tornado
([9.18](#918-tornado-was-der-chart-nicht-leistet)): Es liesse sich nicht verschieben,
ohne die Phasengrenzen mitzuziehen. Ersatzweise gibt es **Lebensdauer** (letzte Phase
verlängern/verkürzen), was das Langlebigkeitsrisiko abdeckt, nicht aber die Frühpensionierung.
**Das Pensionsalter ist seit 0.26 als Regler dabei** (je Person einer, sofern überhaupt
Spielraum besteht). Sein Bereich ist **plan-abhängig**: Er endet dort, wo eine angrenzende
Lebensphase unter ein Jahr fiele ein Regler, der stumm an seiner Grenze klebt, wäre schlechter
als keiner. Der Treiber **Lebensdauer** bleibt daneben bestehen; er beantwortet die andere Frage
(wie lange muss es reichen, statt wann höre ich auf).
### 4.15.3 Referenz und Kennzahlen
@@ -2821,6 +2986,96 @@ echtes Szenario übertragen lässt.
Referenz: `src/lib/livesim.ts`, `src/lib/sensitivity.ts` (`applyElementDriver`,
`tunableElements`), `src/components/LiveSimDialog.tsx`, `src/components/AllocationChart.tsx`.
## 4.16 Pensionsalter verschieben
> Modul `src/lib/retirement.ts`. Rein: Es entscheidet nur, **was** geschehen soll; das
> Schreiben übernimmt der Aufrufer (Panel: API-Aufrufe; Tornado/Live-Simulation: reine
> Plan-Kopie).
### 4.16.1 Die tragende Invariante
`maxPhaseDuration(persons, yearsBefore)` kappt jede Phasendauer beim nächsten
Pensionierungsereignis. Daraus folgt: **Jede Pensionierung liegt auf einer Phasengrenze.** Genau
das macht die Anpassung überhaupt erst möglich «Pensionsalter ändern» ist gleichbedeutend mit
«diese eine Grenze verschieben».
`retirementBoundaries(plan)` liefert je Person:
| Feld | Bedeutung |
|---|---|
| `planYear` | Planjahr der Pensionierung (`retirementAge age`) |
| `phaseIndex` | Index der Phase **vor** der Grenze |
| `minDelta` / `maxDelta` | Spielraum, ohne dass eine Nachbarphase unter 1 Jahr fällt |
| `mergeDeltaDown` / `mergeDeltaUp` | genau der Wert, bei dem eine Phase entfällt |
| `blocked` | Erklärtext, wenn gar keine Anpassung möglich ist (siehe 3.12.2) |
### 4.16.2 `shiftRetirement(plan, role, delta)`
```
Phase[i].dauer += delta // vor der Grenze
Phase[i+1].dauer = delta // nach der Grenze
person.retirementAge += delta
```
Fällt eine der beiden auf 0, wird sie entfernt und die `sequenceNumber` lückenlos neu vergeben.
Die Übergangsdaten der entfallenden Phase werden nach der Regel aus 3.12.3 in den Vorgänger
gezogen (`mergeTransition`, `mergeCashTransition`). Ausserhalb des erlaubten Bereichs liefert
die Funktion `null` sie klemmt nicht still.
### 4.16.3 Als Treiber und Regler
`applyDriver(plan, "retirementA" | "retirementB", jahre)` benutzt dieselbe Funktion. Zwei
bewusste Abweichungen gegenüber der Bedienung:
* Der Bereich endet bei `minDelta`/`maxDelta`, **ohne** Zusammenlegung. Eine Zusammenlegung
verändert den Plan inhaltlich (zwei Übergänge werden einer) dafür ist eine
Was-wäre-wenn-Betrachtung der falsche Ort.
* Eine zu weite Eingabe wird auf das Mögliche **gekürzt** statt verworfen: Eine Bandbreite von
±5 Jahren soll auch dann etwas zeigen, wenn nur ±2 möglich sind. Bleibt gar kein Spielraum,
erklärt `ineffectiveReason` den Nullbalken.
Der Hebel ist doppelt länger Einkommen **und** kürzer Verzehr und deshalb meist einer der
grössten im Tornado.
### 4.16.4 Punkt B: Einkommen endet mit der Pensionierung
Bis 0.25 lief ein Erwerbseinkommen stillschweigend in die Pensionsphase weiter (der Basiswert
wird ja fortgeschrieben). Bei fixem Pensionsalter fiel das kaum auf; sobald sich die Grenze
verschieben lässt, ist es ein handfester Fehler «drei Jahre früher aufhören» hätte sonst gar
keine Wirkung gehabt.
```
Kategorie INCOME, Element ist EINER PERSON zugeordnet,
Person in dieser Phase pensioniert, kein ausdrücklicher Betrag erfasst
→ Basiswert = 0
```
Drei bewusste Einschränkungen:
* **Nur personenzugeordnete Einkommen.** «Gemeinsam» (Mieterträge, Ausschüttungen) hängt nicht
an der Erwerbstätigkeit einer Person und läuft weiter.
* **Ein ausdrücklich erfasster Betrag gewinnt.** Sonst liesse sich ein Teilzeitpensum oder eine
Überbrückungsrente nach der Pensionierung nicht abbilden.
* Das Element zeigt in dieser Phase den Hinweis, dass es wegen der Pensionierung auf 0 steht.
### 4.16.5 Vererbte Wiederkehr-Parameter (Punkt A)
Der `Carry` führt neu eine Tabelle `rates` mit den zuletzt verwendeten Werten. Ist ein Feld in
einer Phase nicht gesetzt, gilt der Wert aus der Vorphase; der verwendete Wert wird wieder
abgelegt, sodass die Kette über beliebig viele Phasen trägt. Betroffen sind
`teuerungsausgleich`, `expectedReturn`, `annualContribution`, `annualWithdrawal`,
`amortization`, `valueGrowth`, `interestRate` und `annualRepayment`.
### 4.16.6 Fehlerbehebung: fortgeschriebener Basiswert und effektive Werte
Der Basiswert der Folgephase (`carry.flowBasis`) wurde beim **Element-Setup** berechnet, also
**vor** der Jahresschleife. Ein effektiver Wert setzt den Basiswert aber erst **in** der
Jahresschleife neu (`rebaseFlow`). Folge: Ein für 2031 erfasster Lohn wirkte bis zum Ende seiner
Phase und fiel an der Phasengrenze stillschweigend auf den geplanten Wert zurück.
Die Fortschreibung passiert neu **nach** der Jahresschleife, gemeinsam mit den Endwerten. Zwei
Regressionstests in `actuals.test.ts` halten den Fall fest.
---
# 5. Technische Spezifikation
@@ -2905,6 +3160,8 @@ PlanComputed ← an den Client geliefert
| `versioning-db.ts` | Datenbank-Anbindung der Versionierung: Snapshot festhalten, Hauptversion, Wiederherstellen. Führt den Bauplan aus `versioning.ts` nur aus. |
| `livesim.ts` | Live-Simulation: Reglerkatalog mit Standardbereichen, Anwenden mehrerer Regler, Kennzahlen (Kap. 4.15). Rein, läuft im Browser. |
| `distribution.ts` | Kapitaltopf und Quoten-Zerlegung, Anwenden von Entwurfswerten für die Verteil-Werkzeuge (Kap. 3.6.9/3.6.10). Rein. |
| `retirement.ts` | Pensionsalter verschieben: Spielraum je Person, Verschiebung der Phasengrenze, Zusammenlegung zweier Übergänge (Kap. 4.16). Rein, ohne I/O. |
| `transitions.ts` | Reine Übergangs-Regeln (Vorbelegung, «beantwortet?», Cash-Zusammenfassung). Liegt hier und nicht in einer Komponente, weil auch der Server sie braucht -- ein Import aus `src/components` bricht erst in der Produktion. |
| `phaseplan.ts` | Ableitung der Lebensabschnitte (Erwerb/Misch/Pension) aus den fixen Pensionierungszeitpunkten für den Assistenten (Kap. 3.2.8). Rein. |
| `constants.ts` (erweitert) | zusätzlich `SYSTEM_PARAMETERS`: dieselben Werte maschinenlesbar mit Bedeutung, Herleitung, Quelle und Stand Grundlage der Systemparameter-Ansicht |
| `diff.ts` | Abweichungs-Erkennung eines Szenarios gegen sein Eltern-Szenario (Kap. 3.2.6) |
@@ -3041,6 +3298,7 @@ Referenz: `prisma/schema.prisma` Zeilen 46, `src/lib/elements.ts` Zeilen 48
| `amount` | INCOME, EXPENSE | ≥ 0 |
| `teuerungsausgleich` | INCOME, EXPENSE | 20 bis 50 |
| `gapYears` | AHV | Integer ≥ 0 |
| `ahvContribution` | AHV | ≥ 0 Beitrag als Nichterwerbstätige(r) bis zum Referenzalter ([4.4.7](#447-referenzalter-die-rente-beginnt-mit-65-nicht-mit-der-pensionierung)) |
| `avgIncomeBefore` | AHV nur wenn bei Planbeginn **bereits pensioniert** | ≥ 0, **real** |
| `gapYearsBefore` | AHV dito | Integer 050 |
| `currentValue` | PENSION_FUND, PILLAR_3A | ≥ 0 |
@@ -3057,6 +3315,11 @@ Referenz: `prisma/schema.prisma` Zeilen 46, `src/lib/elements.ts` Zeilen 48
| `valueGrowth` | REAL_ESTATE Wertsteigerung %/Jahr auf die Liegenschaft | 20 bis 20 |
| `annualRepayment` | OTHER_DEBT | ≥ 0 |
**Vererbbare Felder (Punkt A, Kap. 3.12.4):** `teuerungsausgleich`, `expectedReturn`,
`annualContribution`, `annualWithdrawal`, `amortization`, `valueGrowth`, `interestRate` und
`annualRepayment` sind ab Phase 2 in der Regel **nicht gesetzt** die Berechnung übernimmt dann
den Wert der Vorphase. Alle übrigen Felder bedeuten «nicht gesetzt = 0» wie bisher.
### 5.4.4 JSON-Payload `TransitionData`
| Feld | Kategorien | Zod-Regel |
@@ -3089,6 +3352,9 @@ Liegt in `Phase.cashTransition`. Validierung über `cashTransitionSchema`.
| `inflowTaxRate` | Steuer auf den Zufluss, Default 0 % | 0100 |
| `outflowLabel` | Bezeichnung der Kosten (z. B. „Poolbau") | ≤ 120 Zeichen |
| `outflowAmount` | Betrag **real** (heutige Kaufkraft) | ≥ 0 |
| `capitalUseAmortizationPct` | Anteil des Kapitalzuflusses in die Amortisation (Kap. 3.12.5) | 0100 |
| `capitalUseInvestPct` | Anteil des Kapitalzuflusses in eine Anlage | 0100 |
| `capitalUseTargetElementId` | Ziel der Anlage-Quote; ohne Angabe das erste aktive Sonstige Vermögen | ≤ 60 Zeichen |
Pro Übergang ist **genau ein** Zufluss und **eine** Kostenposition möglich siehe
[9.7](#97-nur-ein-zufluss-und-eine-kostenposition-pro-übergang).
@@ -3318,6 +3584,20 @@ Liefert Eingabe, Berechnung **und die Vergleichsbasis** in einem Zug:
`base` ist das Eltern-Szenario (null beim Basisszenario) daraus rechnet der Client den Diff.
Dies ist der einzige Endpunkt, der die Berechnung ausführt (neben `export`). → 404 wenn fremd.
### `POST /api/scenarios/<scenarioId>/retirement`
Verschiebt das Pensionsalter einer Person und damit die zugehörige Phasengrenze
([3.12](#312-pensionsalter-anpassen)):
```json
{ "role": "PERSON_A", "delta": -4, "confirmMerge": false }
```
Bewusst kein `PATCH` auf `retirementAge`: Die Änderung betrifft immer **zwei** Phasendauern
gleichzeitig und kann eine Phase entfallen lassen.
→ 200 `{ ok, removedPhaseId, retirementAge }` ·
→ 400 mit Erklärtext, wenn gesperrt oder ausserhalb des Spielraums ·
**409** `{ needsMergeConfirmation: true, removedPhaseId, removedPhaseName, mergedIntoPhaseId }`,
wenn dabei eine Lebensphase entfiele und `confirmMerge` nicht gesetzt ist. Der Client fragt
vorher selbst (er kennt den Plan), der 409 ist die serverseitige Absicherung.
### `PATCH /api/scenarios/<scenarioId>`
Akzeptiert eine **Union** von zwei Formen:
1. Vollständiges Profil: `{ householdType, inflationRateDefault, persons[], name? }` ersetzt
@@ -3467,12 +3747,12 @@ Include `src/**/*.test.ts`). Es gibt **keine** Komponenten-, API- oder E2E-Tests
| Datei | Tests | Schwerpunkt |
|---|---|---|
| `calculations.test.ts` | 43 | AHV-Rentenformel, Immobilie, Teilverkauf, Sonderamortisation, AHV einkommensabhängig, „V5 Golden Tests" |
| `sensitivity.test.ts` | 15 | Treiber-Transformationen (Reinheit, Einheiten, Kappung), Verfügbarkeit, Tornado-Sortierung und -Richtung, Erklärung wirkungsloser Treiber |
| `calculations.test.ts` | 53 | AHV-Rentenformel, Immobilie, Teilverkauf, Sonderamortisation, AHV einkommensabhängig, AHV-Referenzalter (Beitrag vor 65, Rente ab 65), Einkommen endet mit der Pensionierung, Vererbung der Wiederkehr-Parameter, „V5 Golden Tests" |
| `sensitivity.test.ts` | 20 | Treiber-Transformationen (Reinheit, Einheiten, Kappung), Verfügbarkeit, Tornado-Sortierung und -Richtung, Erklärung wirkungsloser Treiber, Pensionsalter als Treiber |
| `explain.test.ts` | 12 | Verlaufswerte je Element, Vollständigkeit beider Wasserfall-Zerlegungen, Rechenweg-Protokoll, Gültigkeit der Spezifikations-Verweise |
| `montecarlo.test.ts` | 18 | Determinismus, Volatilität/Vol-Drag, Böden, Reproduzierbarkeit; Element-Gruppierung, Szenario-Vergleich, Inflation je Szenario, plannedReturnOf; Schwellen-Ablesung (probabilityAtLeast), Monotonie über Schwellen, Fall 2 systematisch unter 50 % |
| `distribution.test.ts` | 8 | Kapitaltopf und Quoten-Zerlegung gegen die Cash-Brücke; Entwurfswerte anwenden ohne Verlust bestehender Felder |
| `actuals.test.ts` | 22 | Zuordnung über Kopie-Ketten, Sprung im Ist-Jahr, Weiterrechnen ab dem Ist-Wert, geschlossene Brücken, Fluss-Rückrechnung |
| `actuals.test.ts` | 24 | Zuordnung über Kopie-Ketten, Sprung im Ist-Jahr, Weiterrechnen ab dem Ist-Wert, geschlossene Brücken, Fluss-Rückrechnung, Wirkung über die Phasengrenze hinaus |
| `dataview.test.ts` | 7 | beide Sichten in einem Zug, Rückfall ohne Ist-Werte, Abweichungsmessung |
| `ratefields.test.ts` | 17 | Erkennung geänderter Raten, Reichweite (diese/folgende/alle), Erhalt der übrigen Werte in den Zielphasen |
| `versioning.test.ts` | 22 | Nummerierung und Zusammenfassung je Sitzung, unveränderte Stände, Benutzertrennung, Bauplan des Wiederherstellens, Auswirkung auf Kind-Szenarien |
@@ -3480,10 +3760,12 @@ Include `src/**/*.test.ts`). Es gibt **keine** Komponenten-, API- oder E2E-Tests
| `report.test.ts` | 9 | Zusammenfassung, Basis-Angabe zu JEDER Kennzahl, Szenario-Deckelung, Plan/Ist-Block, Haftungsausschluss, gültige PDF-Datei |
| `livesim.test.ts` | 15 | Element-Regler bewegt genau ein Element; Aufschlüsselung deckt sich mit dem Sammelregler; neutrale Stellung verändert den Plan nicht; Ruinmeldung |
| `phaseplan.test.ts` | 8 | Ableitung der Lebensabschnitte aus den Pensionierungszeitpunkten (Einzel/Paar/bereits pensioniert); letzter Teil immer offen |
| `bridges.test.ts` | 10 | Vermögens- und Cash-Brücke gehen über sieben Plankonstellationen ohne Restgrösse auf; Umbuchungen bleiben aus der Vermögensbrücke heraus |
| `bridges.test.ts` | 13 | Vermögens- und Cash-Brücke gehen über acht Plankonstellationen ohne Restgrösse auf; Umbuchungen bleiben aus der Vermögensbrücke heraus; Kapitalverwendung nach Quote (Punkt C) |
| `retirement.test.ts` | 16 | Spielraum und Sperren je Person, Verschiebung ohne Änderung der Gesamtdauer, Wegfall einer Phase, Zusammenführung der Übergangs-Entscheide |
| `server-boundary.test.ts` | 1 | statischer Wächter: kein Modul unter `src/lib` importiert aus `src/components` |
| `diff.test.ts` | 9 | Abweichungs-Erkennung gegen das Eltern-Szenario |
| `migrations.test.ts` | 3 | spielt alle Migrationen gegen echtes PostgreSQL (PGlite) ein; prüft zusätzlich die V7-**Datenübernahme** (Basisszenario gewinnt, Pensionsalter bleiben szenario-eigen) |
| **Total** | **221** | |
| **Total** | **261** | |
## 8.2 Testfälle
@@ -3768,25 +4050,25 @@ Aussagekräftig ist die **Reihenfolge**, nicht der absolute Betrag.
härter als die Summe der Einzelbalken weil in der Folge Kapital verzehrt wird, das später zur
Verzinsung fehlt. Für Kombinationen ist die Monte-Carlo-Simulation zuständig.
**Das Pensionsalter ist bewusst nicht enthalten.** Die Roadmap nennt es als Top-Hebel, aber
`retirementAge` lässt sich im aktuellen Datenmodell nicht isoliert variieren, ohne die
Phasengrenzen mitzuverschieben und das Ergebnis wäre nicht ungenau, sondern **irreführend**.
**Das Pensionsalter ist seit 0.26 enthalten** zuvor bewusst nicht, und die Begründung von
damals erklärt, warum die heutige Umsetzung so aussieht, wie sie aussieht.
Ein isoliert verändertes `retirementAge` wäre nicht ungenau gewesen, sondern **irreführend**.
Beispiel: Person 45, Pension mit 65, Phase 1 = 20 Jahre (45→65), Phase 2 = 20 Jahre.
- **Pensionsalter auf 62:** Phase 1 beginnt mit 45, also `45 < 62` → die Phase bleibt vollständig
Erwerbsphase. Die Person arbeitet im Modell weiterhin bis 65, der Pensions-Übergang liegt an
derselben Grenze. Wirkung auf das Ergebnis: **praktisch null.**
- **Pensionsalter auf 68:** Phase 2 beginnt mit 65, also `65 < 68` → Phase 2 wird zur
**Erwerbsphase**, das Einkommen läuft weiter. Zugleich wird `ownerRetiresNext` an der Grenze
nach Phase 1 falsch (65 ≥ 68 trifft nicht zu), womit der **Pensions-Übergang komplett entfällt**:
keine PK-Verrentung, kein 3a-Bezug, keine AHV-Rente. Der Balken wäre riesig er misst aber den
Ausfall der Vorsorgelogik, nicht „drei Jahre länger arbeiten".
- **Auf 62 gesetzt:** Phase 1 beginnt mit 45, also `45 < 62` → die Phase bliebe vollständig
Erwerbsphase. Die Person arbeitete im Modell weiterhin bis 65. Wirkung: **praktisch null.**
- **Auf 68 gesetzt:** Phase 2 beginnt mit 65, also `65 < 68` → Phase 2 würde zur Erwerbsphase.
Zugleich wäre `ownerRetiresNext` an der Grenze nach Phase 1 falsch, womit der
**Pensions-Übergang komplett entfiele**: keine PK-Verrentung, kein 3a-Bezug. Der Balken wäre
riesig er misst aber den Ausfall der Vorsorgelogik, nicht „drei Jahre länger arbeiten".
Fachlich korrekt wäre nur, `retirementAge` **und** die Phasengrenze gemeinsam zu verschieben
(Erwerbsphase kürzer, Pensionsphase länger). Das hat eigene Sonderfälle Paare mit
unterschiedlichem Pensionsalter, Grenzen abseits des Pensionsereignisses, Verschiebung grösser als
die Phasendauer und ist als eigener Arbeitsschritt offen. Der verwandte Treiber **Lebensdauer**
(Dauer der letzten Phase) ist dagegen sauber abgebildet und deckt einen Teil des Bedürfnisses ab.
Der Treiber verschiebt deshalb `retirementAge` **und** die Phasengrenze gemeinsam
([4.16](#416-pensionsalter-verschieben)). Zwei Eigenheiten bleiben und sind im Dialog benannt:
Der Spielraum endet bei den angrenzenden Phasendauern (eine **Zusammenlegung** findet im Tornado
bewusst nicht statt), und eine zu weite Bandbreite wird auf das Mögliche gekürzt statt verworfen.
Der verwandte Treiber **Lebensdauer** (Dauer der letzten Phase) bleibt daneben bestehen er
beantwortet die andere Frage: nicht „wann höre ich auf", sondern „wie lange muss es reichen".
## 9.19 Simulationsparameter werden nicht gespeichert