## Context Siehe proposal.md — Why. Technisch entscheidend ist der Ist-Zustand dreier Stellen: - `tb-ui::screen::TextScreen` (385 Zeilen) trägt die Bildschirmsemantik bereits vollständig: `cls`, `set_color`, `locate`, `csrlin`, `pos`, `view_print`, `cell`, `print`, `scroll_up`, `resize`. Ratatui kommt darin an genau zwei Stellen vor: `basic_color()` (4 Zeilen) und `impl Widget for &TextScreen` (~35 Zeilen). - `tb-runtime::host::Host` ist ein Stream-Trait (`write(&str)`, `read_line()`). `tb-runtime` und `tb-ui` sind beide Blätter im Abhängigkeitsgraphen und treffen sich erst in `tb-cli`/`tb-ide`. - Rund 50 dokumentierte Elemente besitzen im Frontend eine Signatur in `builtin_fn`/`builtin_stmt`, senken aber auf `HStmtKind::Unsupported` bzw. `HExpr::Unsupported` ab → Opcode `0x05` → Laufzeitfehler 73. Zwei Entscheidungen vom 2026-09-03 rahmen die Arbeit: Das Windowing wird — wie beim Vorbild — vom erzeugten Programm mitgebracht und nicht von der IDE, sodass Forms und `PRINT` in denselben Zellenpuffer zeichnen. Die Forms-Engine selbst bleibt dabei am von PLAN.md vorgesehenen Ort `tb-ui::forms`. ## Goals / Non-Goals **Goals:** - Der Zellenpuffer liegt dort, wo sowohl die Laufzeitbibliothek als auch die spätere Forms-Engine in `tb-ui` ihn erreichen, ohne dass die Ausführungsschicht eine Terminal-Bibliothek zieht. - Bildschirmverhalten ist ohne Terminal automatisiert prüfbar. - Die Abdeckung misst sich selbst statt gepflegt zu werden. - Die Umstellung der acht bestehenden Golden Files geschieht in einem nachvollziehbaren, einmaligen Schritt. **Non-Goals:** - Optimierung der Bildschirmausgabe (Diff-Minimierung, Teilaktualisierung) — erst wenn Messungen sie verlangen. - Ein Rendering-Backend jenseits des Terminals. - Die Forms-Engine selbst (Phase 4, `tb-ui::forms`); dieser Change liefert ihr nur die Zeichenfläche. ## Decisions ### D1: Zellenpuffer nach `tb-runtime::screen`, ratatui-frei `Cell` und `TextScreen` ziehen unverändert nach `tb-runtime::screen`. `basic_color()` und `impl Widget` bleiben in `tb-ui` und arbeiten künftig auf dem Runtime-Typ. *Warum:* `PRINT`, `LOCATE`, `CLS`, `COLOR`, `CSRLIN`, `POS` und die Funktionsform von `SCREEN` sind Elemente der Laufzeitbibliothek. Sie müssen den Puffer erreichen, ohne dass `tb-runtime` eine Terminal-Bibliothek zieht — sonst braucht jeder VM- und Bibliothekstest ein Terminal. Das trägt die Entscheidung allein. *Verhältnis zur Forms-Engine:* Forms bleibt laut PLAN.md in `tb-ui::forms` (Entscheidung 2026-09-03). Das passt zur Richtung: `tb-ui` hängt künftig an `tb-runtime` und zeichnet von oben in denselben Puffer wie `PRINT` — ein `MSGBOX` über einer Konsolenausgabe überdeckt deren Zellen und gibt sie beim Schließen zurück. Läge der Puffer weiterhin in `tb-ui`, wäre genau diese gemeinsame Fläche für die Bibliothek unerreichbar. Umgekehrt entsteht kein Zyklus: die Ausführungsschicht erreicht die Forms-Engine über die Host-Schnittstelle (D2), die sie selbst deklariert und `tb-ui` implementiert. *Alternativen:* - `tb-runtime` hängt an `tb-ui`: null Doppelung, aber ratatui und crossterm landen in jedem VM-Test. Verworfen. - Semantik bleibt in `tb-ui`, jeder Host führt einen eigenen Puffer: dieselbe Scroll-/Umbruch-/Doppelzellenlogik dreimal. Verworfen. *Aufwand:* Der Umzug ist mechanisch — betroffen sind der `use`-Block, die zwei ratatui-Stellen und die Modulzuordnung. Die Semantik selbst wird nicht angefasst; erweitert wird sie nur um die Doppelzellen (D4). ### D2: `Host` wird Bildschirm- statt Stream-Schnittstelle `write`/`read_line` weichen einer Schnittstelle, die den Zellenpuffer zur Anzeige übergibt und Ereignisse (Tastendruck, Größenänderung, Abbruch) zurückliefert. Die Bibliothek schreibt nicht mehr in den Host, sondern in den Puffer; der Host stellt dar. *Warum:* `LOCATE 5,10`, `COLOR 14,1`, `CSRLIN` und besonders `SCREEN(r,c)` — das ein Zeichen vom Bildschirm *zurückliest* — sind über einen Zeichenstrom nicht ausdrückbar. Das ist ein Zwang, keine Präferenz. *Wann dargestellt wird:* Der Host wird an denselben Tick-Grenzen aufgerufen, an denen die VM heute schon die Abbruchprüfung macht, sowie vor jeder blockierenden Eingabe. Kein zusätzlicher Mechanismus. *Blockieren bleibt erlaubt* (Entscheidung D3 aus Phase 2 bleibt gültig): `INPUT` und `INPUT$` blockieren im Host. Erst die Ereignisschleife der Phase 4 bringt kooperative Zustellpunkte. *Alternativen:* - Stream-Host behalten und Bildschirmwirkungen als ANSI-Escapes hindurchreichen: `CSRLIN`/`POS`/`SCREEN()` bräuchten trotzdem einen Schattenpuffer, und der Capture-Host müsste ANSI parsen. Verworfen. ### D3: Korpusvergleich als getrimmter Snapshot Die `.out`-Datei hält das Textbild des Puffers bis zur letzten belegten Zeile und Spalte. Eine zweite Ebene mit Farbattributen kommt nur hinzu, wenn das Programm `COLOR` verwendet. *Warum getrimmt:* Ein voller 80×25-Snapshot für `hello.bas` wären 2000 Zeichen für zwei Zeichen Signal, und jeder Diff zeigte Rauschen. Getrimmt bleiben die bestehenden acht Sollausgaben inhaltlich fast unverändert — `PRINT`-only-Programme ergeben dasselbe Textbild wie bisher der Stream. *Warum Attribute optional:* Programme ohne `COLOR` erzeugen sonst eine zweite Ebene aus lauter identischen Werten. *Umstellung:* Die acht Golden Files werden einmalig neu erzeugt und der Diff wird geprüft — erwartet wird, dass sich nur Zeilen ändern, die vorher auf `\r`/Umbruchverhalten beruhten. Ein unerwarteter Diff ist ein Befund, kein Anpassungsgrund. *Alternativen:* - Zwei Harnesses (Stream für Alt-Tests, Snapshot für neue): dauerhaft doppelte Infrastruktur für einen einmaligen Umstellungsschmerz. Verworfen. - Voller Snapshot: siehe oben. Verworfen. ### D4: Doppelzellen über Darstellungsbreite Breite Zeichen belegen zwei Zellen: die erste trägt das Zeichen, die zweite ist als Fortsetzung markiert. Neue Abhängigkeit `unicode-width` in `tb-runtime`. *Warum eine Abhängigkeit:* Die Breitentabelle folgt einem Unicode-Annex und ändert sich mit jeder Unicode-Version; sie nachzubauen hieße, sie dauerhaft nachzupflegen. *Konsequenzen, die die Spec festhält:* Cursor rückt um zwei Spalten vor; `POS` zählt die Anfangsspalte; ein breites Zeichen in der letzten Spalte wird vollständig umgebrochen und die Spalte bleibt leer; `LOCATE` auf eine Fortsetzungszelle wirkt auf den Zeichenanfang. Beim Überschreiben einer Hälfte muss die andere geleert werden, sonst entstehen Geisterzeichen. ### D4a: 80×25 ist nirgends eine Konstante Anforderung des Projektinhabers (2026-09-03), Priorität für das ganze Programm: 80×25 ist stets Synonym für „voller Bildschirm", nie eine feste Grenze. Moderne Terminals haben keine feste Größe, und sie ändert sich während der Ausführung. *Konsequenz für die Umsetzung:* Kein Zweig darf gegen 80 oder 25 vergleichen. Die Abmessungen kommen ausschließlich aus dem Puffer (`cols()`/`rows()`), abgeleitet aus der Darstellungsfläche. Betroffen sind `CLS` (voller aktueller Bildschirm), der voreingestellte Scrollbereich, die Umbruchspalte, die Scrollzeile sowie die Grenzprüfungen von `LOCATE` und der Funktionsform von `SCREEN`. *Größenänderung zur Laufzeit* ist damit kein Sonderfall, sondern der Normalfall: Das Größenänderungsereignis kommt über den Host (D2), der Puffer wird angepasst, Inhalt bleibt oben links, Cursor und `VIEW PRINT`-Bereich werden geklemmt. Ein Bereich, der durch die Verkleinerung leer würde, fällt auf den vollen Bildschirm zurück, statt ungültig zu bleiben. *Das Mindestmaß bleibt eine Darstellungsschranke:* Ist die Fläche kleiner als 80×25, zeigt die Darstellungsschicht den Hinweis „Terminal zu klein" (bestehende Entscheidung 2026-09-02). Das ist eine untere Schranke der Anzeige, keine Bildschirmgröße für das Programm. *Prüfbarkeit:* Der Test-Host bekommt seine Größe je Korpusprogramm explizit gesetzt, ohne stillschweigenden Vorgabewert. Mindestens ein Bildschirmprogramm läuft bei zwei Größen mit je eigener Sollausgabe — eine hartkodierte 80 oder 25 fällt damit sofort auf. Ein weiteres durchläuft eine Größenänderung mitten in der Ausführung. ### D4b: Das Inventar geht der Umfangsschätzung vor Die Erhebung in Aufgabe 1.1 (2026-09-03) hat gezeigt, dass die ursprüngliche Umfangsliste dieses Changes drei ganze Gruppen nicht enthielt: die 13 finanzmathematischen Funktionen, die 14 Record-Konvertierungsfunktionen und einen Rest an Dateisystem- und Systemelementen. Sie hat außerdem zwei Elemente widerlegt, die `phase-3-isam` fälschlich führte (`CHECKPOINT`, `TEXTCOMP`). *Konsequenz für die Arbeitsweise:* Maßgeblich ist das Inventar, nicht die Aufzählung im Proposal. Wo beide auseinandergehen, wird das Proposal nachgezogen. Aufzählungen in Proposal und Specs sind Mindestumfang. *Konsequenz für die Quelle:* `bas7advr.hlp/TOPIC_LIST.html` ist nachweislich unvollständig — `SGN`, `SQR`, `SPACE$`, `STRING$`, `CSRLIN`, `BEEP` und `DATE$` als Funktion fehlen dort. Das Inventar bildet die Vereinigungsmenge aus dieser Liste, `qb45advr.hlp/TOPIC_LIST.html` und `docs/sprachreferenz.md`; jeder Eintrag nennt seine Fundstelle. Die Zählung einer einzelnen Themenliste ist kein Vollständigkeitsnachweis. ### D5: Inventar als Markdown-Tabelle mit Abgleichstest `docs/inventar.md` trägt eine Pipe-Tabelle mit festen Spalten (Name, Art, Gruppe, Status, Fundstelle). Ein Test parst sie und hält sie gegen `builtin_fn`/`builtin_stmt`, die `Unsupported`-Marker und `banned_feature`. *Warum Markdown und nicht TOML/YAML:* Der Plan nennt „maschinenlesbar", aber keinen Konsumenten außer der Messbarkeit selbst; Zielpfad ist ausdrücklich `docs/inventar.md`, und das IDE-Hilfesystem (Phase 5) rendert `docs/`-Markdown. Eine Pipe-Tabelle ist mit einem Split maschinenlesbar. Ein zweites Format bräuchte einen Generator, um wieder bei Markdown zu landen. *Der Test ist der eigentliche Punkt:* Ohne ihn verrottet der Status. Mit ihm kann das Inventar nicht falsch werden, ohne dass die Suite rot wird. ### D6: `Unsupported`-Marker bleiben, aber nur noch für Phase 4 Die Marker verschwinden nicht — Ereignissteuerung, `SETUEVENT`, `MSGBOX` und `INPUTBOX$` behalten sie bis Phase 4. Der Abgleichstest aus D5 stellt sicher, dass genau die im Inventar als `offen` geführten Elemente noch Marker tragen. ### D7: Reihenfolge der Umsetzung ``` 1. Inventar (Sollseite) -> misst alles Folgende 2. Puffer-Umzug + Host + Snapshot -> BREAKING, zusammen in einem Schritt 3. Bildschirmanweisungen -> braucht 2 4. Strings/Format/Datum/Mathematik -> unabhaengig, jederzeit 5. Datei-E/A -> unabhaengig von 2/3 6. Altlasten Phase 2 -> unabhaengig ``` Schritt 2 ist der einzige Bruch und wird bewusst als eine Einheit umgesetzt: Puffer-Umzug, `Host`-Neuschnitt und Snapshot-Umstellung hängen so eng zusammen, dass ein Zwischenzustand die Suite ohnehin rot ließe. Schritte 4–6 können vorgezogen werden, falls Schritt 2 sich zieht. ## Risks / Trade-offs - **Der `Host`-Bruch legt kurzzeitig die gesamte Suite lahm** → Schritt 2 als eine Einheit umsetzen, nicht in Teilschritten; erst wenn Puffer, Host und Harness zusammen stehen, wird gemessen. - **Neu erzeugte Golden Files zementieren einen Fehler** → Der Diff der acht Dateien wird einzeln geprüft. Erwartung: `PRINT`-only-Programme ändern sich nicht. Jede Abweichung wird begründet oder ist ein Bug. - **Doppelzellen brechen bestehende Annahmen** (`POS` = Zeichenzahl, Zelle = Zeichen) → Korpustest mit CJK/Emoji inklusive Umbruch am rechten Rand, bevor die übrige Bildschirmarbeit darauf aufsetzt. - **`RND`-Kompatibilität ist Rekonstruktionsarbeit** — die Zahlenfolge des Vorbilds ist nur über die Dokumentation und Beobachtung greifbar → Algorithmus dokumentieren; gelingt die exakte Folge nicht, wird die Abweichung in der Sprachreferenz festgehalten statt still abzuweichen. - **UTF-32-Records machen Dateien binär inkompatibel zum Vorbild** → bewusst entschieden (2026-09-02); Preis ist, dass Originaldateien nicht gelesen werden können. Muss in der Sprachreferenz stehen. - **`SHELL`, `FILES`, Satzsperren und `LPRINT` sind plattformabhängig** → jede Abweichung wird in der Sprachreferenz unter „Abweichungen" benannt; stilles Abweichen ist laut Guiding Principle ein Bug. - **Das Inventar aus der Original-Hilfe zu erheben ist der stillste Aufwandstreiber** → als eigener erster Schritt geführt, damit sein Umfang sichtbar wird, statt sich in die Implementierungsarbeit zu mischen. ## Migration Plan 1. Inventar anlegen (rein additiv, kein Bruch). 2. Bruchschritt in einem Zug: `TextScreen` nach `tb-runtime::screen`, `tb-ui` auf Adapterrolle, `Host` neu, Harness auf Snapshot, acht Golden Files neu erzeugen und Diff prüfen. 3. Alles Weitere additiv — jedes neue Element wechselt im Inventar von `offen` auf `implementiert`, der Abgleichstest hält beides zusammen. Rücknahme: Schritt 2 ist ein zusammenhängender Commit und als Ganzes rücknehmbar. Danach gibt es keinen weiteren Bruch. ## Open Questions - Umfang der `KEY n`-Funktionstasten-Makros (`KEY LIST`/`ON`/`OFF`): Die Anweisung steht im Scope; welche Makro-Semantik das Vorbild genau zeigt, ist bei der Umsetzung aus der Original-Hilfe zu klären und in docs/sprachreferenz.md festzuhalten. Berührt weder Puffer noch Host noch Aufgabenschnitt. - Ersatzwert für `FRE` auf einer Plattform ohne DOS-Speichermodell: bei der Umsetzung zu wählen und zu dokumentieren. - Konkrete Gestalt der Schnittstelle, über die die Forms-Engine in `tb-ui` später eigene Zeichenbereiche im Puffer belegt und wieder freigibt: erst in Phase 4 zu klären, wenn die Steuerelemente stehen. Ändert weder Puffer noch Host noch Aufgabenschnitt dieses Changes.