Setzt den OpenSpec-Change phase-3-runtime-bildschirm um (77/77 Aufgaben). Abdeckung laut Inventar: 195 implementiert, 37 offen, 53 Non-Feature. Vollstaendigkeits-Inventar - docs/inventar.md mit 285 Eintraegen aus den Themenlisten von bas7advr.hlp und qb45advr.hlp, je mit Status und Fundstelle - crates/tb-frontend/tests/inventar.rs haelt die Tabelle in beide Richtungen gegen den Code; der Abdeckungsstand kann nicht veralten Bruchschritt (Puffer, Host, Korpus) - Cell/TextScreen ziehen ratatui-frei nach tb-runtime::screen; tb-ui behaelt Farbabbildung, Widget und den neuen Terminal-Host - Host wechselt vom Zeichenstrom auf Anzeige des Zellenpuffers plus Ereignisse (Taste, Groessenaenderung, Abbruch) - Korpusvergleich auf getrimmten Bildschirm-Snapshot; die acht bestehenden Sollausgaben blieben dabei unveraendert Groessenunabhaengigkeit - 80x25 ist nirgends mehr eine feste Grenze; Groessenaenderungen waehrend der Ausfuehrung werden zugestellt (Inhalt oben links erhalten, Cursor und VIEW PRINT geklemmt) - Korpusnachweis: dasselbe Programm bei 80x25 und 120x40 mit je eigener Sollausgabe, plus ein Programm mit Groessenwechsel mitten im Lauf Bibliothek - Breite Unicode-Zeichen belegen zwei Zellen (Cursor, POS, Randumbruch) - Bildschirm: CLS, COLOR, LOCATE, WIDTH, VIEW PRINT, SCREEN, CSRLIN, POS - Tastatur: INKEY$, INPUT$, Funktionstasten-Makros (KEY n / LIST / ON) - PRINT USING, LPRINT USING, FORMAT$, SetFormatCC - Mathematik mit kompatiblem PRNG (gleiche Saat, gleiche Folge) - Datum und Zeit mit Serienwerten ab 1899 - Finanzmathematik: FV#, PV#, Pmt#, IPmt#, PPmt#, NPer#, Rate#, NPV#, IRR#, MIRR#, SLN#, SYD#, DDB# - Datei-E/A: sequenziell, RANDOM (Recordpuffer und UDT-Variablen), BINARY, FIELD/LSET/RSET, Statusfunktionen, Dateisystem, MK$/CV - System: ENVIRON, FRE, CLEAR, TRON/TROFF, STACK, ERDEV, ERR-Anweisung Altlasten aus Phase 2 - ON ERROR GOTO auf Modulebene ist aus Prozeduren ansprechbar (prozeduruebergreifender Fixup im Codegenerator) - DATA behaelt seinen Rohtext (Gross-/Kleinschreibung, innerer Leerraum) - Die vier TODO-verify-Zellen der Konvertierungsmatrix sind aufgeloest Vom Inventar aufgedeckte Fehler - Zwoelf Non-Features wies der Compiler entgegen der Phase-1-Spec nicht ab (CALLS, SSEG, POINT, VIEW, COM, PEN, STRIG, STICK, die String*-Routinen, LINE und OPEN "COMn:") -- geschlossen - Drei Gruppen fehlten im urspruenglichen Umfang: Finanzmathematik, Record-Konvertierung, Rest der Dateisystemfunktionen - bas7advr.hlp allein ist keine vollstaendige Quelle; das Inventar bildet die Vereinigung mit qb45advr.hlp Neue Changes - phase-3-isam: schliesst Phase 3 ab (Speicherschicht redb) - phase-3-ortszeit: zieht die UTC-Abweichung zurueck Neue Abhaengigkeit: unicode-width. Dokumentiert: sprachreferenz.md und tbvm-design.md sind TODO-frei, docs/bibliothek.md neu, PLAN.md fortgeschrieben. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
14 KiB
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) undimpl Widget for &TextScreen(~35 Zeilen).tb-runtime::host::Hostist ein Stream-Trait (write(&str),read_line()).tb-runtimeundtb-uisind beide Blätter im Abhängigkeitsgraphen und treffen sich erst intb-cli/tb-ide.- Rund 50 dokumentierte Elemente besitzen im Frontend eine Signatur in
builtin_fn/builtin_stmt, senken aber aufHStmtKind::Unsupportedbzw.HExpr::Unsupportedab → Opcode0x05→ 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-uiihn 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-runtimehängt antb-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 undLPRINTsind 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
- Inventar anlegen (rein additiv, kein Bruch).
- Bruchschritt in einem Zug:
TextScreennachtb-runtime::screen,tb-uiauf Adapterrolle,Hostneu, Harness auf Snapshot, acht Golden Files neu erzeugen und Diff prüfen. - Alles Weitere additiv — jedes neue Element wechselt im Inventar von
offenaufimplementiert, 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
FREauf 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-uispä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.