## 1. Vollständigkeits-Inventar

- [x] 1.1 Anweisungs-, Funktions- und Metabefehlsliste aus der Original-Hilfe erheben (dos-help.soulsphere.org, Topic-Listen, README der Professional Edition) und als Rohliste ablegen; verifiziert dadurch, dass die Zahl der erfassten Themen gegen die Topic-Übersicht der Quelle abgeglichen und im Change notiert ist
- [x] 1.2 `docs/inventar.md` als Pipe-Tabelle mit den Spalten Name, Art, Gruppe, Status, Fundstelle anlegen und alle Einträge aus 1.1 mit Erststatus füllen; verifiziert dadurch, dass jede Zeile sechs Spalten hat (Name, Art, Gruppe, Status, Fundstelle, Quelle) und das Statusvokabular nur `implementiert`/`offen`/`Non-Feature` enthält
- [x] 1.3 Abgleichstest schreiben, der die Tabelle parst und gegen `builtin_fn`, `builtin_stmt`, `banned_feature` sowie die `Unsupported`-Marker hält; verifiziert dadurch, dass der Test auf dem Ist-Stand grün ist und nach einer künstlich falsch gesetzten Statuszeile mit Nennung des Elements fehlschlägt
- [x] 1.4 Prüfung ergänzen, dass `Non-Feature`-Einträge eine Fundstelle in docs/sprachreferenz.md nennen und dokumentierte `offen`-Elemente namentlich abgewiesen werden (kein generischer Syntaxfehler); verifiziert durch je einen Testfall pro Regel
- [x] 1.5 Abdeckungsstand (Anzahl je Status) im Testausgabetext ausweisen; verifiziert dadurch, dass `cargo test` die drei Zahlen nennt
- [x] 1.6 Vom Inventar aufgedeckte Abweichung von der Phase-1-Spec schließen: Non-Features, die der Compiler nicht abwies, ergänzen — `CALLS`, `SSEG`, `SSEGADD`, `StringAddress`/`Assign`/`Length`/`Release`, `POINT`, `VIEW`, `COM`, `PEN`, `STRIG`, `STICK` in `banned_feature`; `LINE` ohne `INPUT` und `OPEN "COMn:"` als „Feature unavailable"; verifiziert durch `dokumentierte_elemente_werden_namentlich_abgewiesen`
- [x] 1.7 Signaturen in `builtin_fn`/`builtin_stmt` für alle bislang signaturlosen Inventarelemente ergänzen (Finanzmathematik, `MK…$`/`CV…`, `CURDIR$`, `DIR$`, `CHDRIVE`, `LPOS`, `STACK`, `SYSTEM`, `ERDEV`/`ERDEV$`, `SetFormatCC`); verifiziert durch Frontend-Test über ein Programm, das jedes davon einmal verwendet, ohne Diagnose „unbekannter Bezeichner"
- [x] 1.8 Sicherstellen, dass jedes als `offen` geführte Element namentlich abgewiesen wird (Diagnose oder Laufzeitfehler nennt den Namen); verifiziert durch Test, dass `MKL$()` ohne Argument eine Diagnose mit dem Namen `MKL$` erzeugt

## 2. Bruchschritt: Puffer, Host, Snapshot-Harness

- [x] 2.1 `Cell`/`TextScreen` samt Tests von `tb-ui::screen` nach `tb-runtime::screen` verschieben, ratatui-Importe entfernen; verifiziert dadurch, dass `cargo test -p tb-runtime` grün ist und `tb-runtime/Cargo.toml` weiterhin weder ratatui noch crossterm führt
- [x] 2.2 `tb-runtime` als Abhängigkeit in `tb-ui` aufnehmen; `basic_color()` und `impl Widget` in `tb-ui` belassen und auf den Runtime-Typ umstellen; verifiziert dadurch, dass `cargo run -p tb-ui --example spike` unverändert rendert
- [x] 2.3 `Host`-Trait neu schneiden: Übergabe des Zellenpuffers zur Anzeige, Ereignisabholung (Taste, Größenänderung), Abbruchprüfung; verifiziert dadurch, dass `tb-runtime` kompiliert und der Trait keine Stream-Methoden mehr trägt
- [x] 2.4 `ConsoleHost` auf Darstellung des Puffers im Terminal und Tastaturereignisse umstellen; verifiziert dadurch, dass `tbc run tests/compat/hello.bas` im Terminal die erwartete Ausgabe zeigt
- [x] 2.5 `CaptureHost` auf Bildschirmzustand plus vorbereitete Tastendrücke umstellen; verifiziert durch einen Unit-Test, der Zeichen und Attribut einer Zelle nach `LOCATE`/`COLOR`/`PRINT` prüft
- [x] 2.6 Darstellungsaufrufe an die bestehenden Tick-Grenzen und vor blockierende Eingaben hängen; verifiziert dadurch, dass ein Programm mit Ausgabe vor `INPUT` den Text vor der Eingabeaufforderung zeigt
- [x] 2.7 Snapshot-Serialisierung schreiben: Textbild getrimmt bis zur letzten belegten Zeile/Spalte, Attributebene nur bei verwendetem `COLOR`; verifiziert durch Unit-Tests für getrimmte Ausgabe, signifikante Zeilen-Innenleerzeichen und Weglassen der Attributebene
- [x] 2.8 Harness `crates/tb-cli/tests/compat.rs` auf Snapshot-Vergleich umstellen, inklusive Fehlermeldung mit Datei, erster abweichender Zeile sowie Zeile/Spalte/Soll/Ist bei Attributabweichung; verifiziert durch je einen absichtlich abweichenden Testfall
- [x] 2.9 Die acht bestehenden `.out`-Dateien neu erzeugen und jeden Diff einzeln prüfen und begründen; verifiziert dadurch, dass `PRINT`-only-Programme unverändert bleiben und jede Abweichung im Change begründet notiert ist
- [x] 2.10 `.gitattributes` auf die neuen Snapshot-Dateien prüfen; verifiziert dadurch, dass `.out`-Dateien weiterhin vor Zeilenenden-Konvertierung geschützt sind

## 3. Größenunabhängigkeit und Laufzeit-Größenänderung

- [x] 3.1 Alle Bildschirmpfade auf die Abmessungen des Puffers umstellen (`CLS`, voreingestellter Scrollbereich, Umbruchspalte, Scrollzeile, Grenzprüfungen von `LOCATE` und `SCREEN()`); verifiziert dadurch, dass eine Suche über `tb-runtime` und `tb-ui` keine Vergleiche gegen die Literale 80 oder 25 außerhalb der Mindestmaß-Prüfung der Darstellungsschicht mehr findet
- [x] 3.2 Größenänderungsereignis vom Host bis zum Puffer durchreichen; verifiziert durch Test, dass ein vom Test-Host ausgelöster Wechsel die Abmessungen des Puffers ändert
- [x] 3.3 Anpassung bei Größenänderung: Inhalt oben links erhalten, Cursor klemmen, `VIEW PRINT`-Bereich klemmen und bei leerem Ergebnis auf den vollen Bildschirm zurücksetzen; verifiziert durch je einen Unit-Test für Vergrößerung, Verkleinerung und ungültig gewordenen Scrollbereich
- [x] 3.4 Test-Host mit explizit gesetzter Bildschirmgröße je Korpusprogramm, ohne stillschweigenden Vorgabewert; verifiziert dadurch, dass ein Korpusprogramm ohne Größenangabe vom Harness abgewiesen wird
- [x] 3.5 Bildschirm-Korpusprogramm bei 80×25 und 120×40 mit je eigener Sollausgabe; verifiziert dadurch, dass sich die Sollausgaben in Umbruch- und Scrollverhalten unterscheiden und beide Läufe grün sind
- [x] 3.6 Korpusprogramm mit Größenänderung während der Ausführung; verifiziert dadurch, dass der Snapshot den erhaltenen Inhalt und die Ausgabe in den neuen Grenzen zeigt

## 4. Unicode-Doppelzellen

- [x] 4.1 `unicode-width` als Abhängigkeit aufnehmen und Zellenmodell um Fortsetzungszellen erweitern; verifiziert durch Unit-Test, dass ein CJK-Zeichen an Spalte 1 die Spalte 2 als Fortsetzung belegt
- [x] 4.2 Cursorfortschritt, `POS` und Umbruch am rechten Rand auf Darstellungsbreite umstellen; verifiziert durch Unit-Tests für Vorrücken um zwei Spalten und vollständigen Umbruch bei belegter letzter Spalte
- [x] 4.3 Überschreiben einer Zellenhälfte leert die andere; verifiziert durch Unit-Test, dass keine Geisterzeichen zurückbleiben
- [x] 4.4 `LOCATE` auf eine Fortsetzungszelle auf den Zeichenanfang abbilden; verifiziert durch Unit-Test
- [x] 4.5 Korpusprogramm mit CJK und Emoji inklusive Randumbruch ergänzen; verifiziert dadurch, dass der Snapshot der dokumentierten Sollausgabe entspricht
- [x] 4.6 Abweichung in docs/sprachreferenz.md festhalten; verifiziert durch den Abschnittseintrag

## 5. Bildschirmanweisungen und -funktionen

- [x] 5.1 `CLS` (inkl. `CLS 2`), `COLOR` mit ausgelassenen Argumenten, `LOCATE` mit ausgelassenen Argumenten und Fehler 5 bei Grenzüberschreitung; verifiziert durch Korpustest mit Snapshot und je einem Fehlerfall
- [x] 5.2 `WIDTH`, `VIEW PRINT` (setzen und zurücksetzen), Scrollen im begrenzten Bereich; verifiziert durch Korpustest, dass Zeilen außerhalb des Bereichs unverändert bleiben
- [x] 5.3 `CSRLIN`, `POS(0)` und die Funktionsform `SCREEN(zeile, spalte [, farbe])` inklusive Fehler 5 außerhalb des Bildschirms; verifiziert durch Korpustest mit Zurücklesen eines geschriebenen Zeichens
- [x] 5.4 Anweisungsform `SCREEN` entgegennehmen und dokumentiertes Verhalten festlegen; verifiziert dadurch, dass keine `Unsupported`-Absenkung mehr erfolgt und das Verhalten in der Sprachreferenz steht
- [x] 5.5 `INKEY$` nicht blockierend (leerer String, Zeichen, Sondertaste als zwei Zeichen mit führendem Nullzeichen); verifiziert durch Test mit vorbereiteten Tastendrücken im Capture-Host
- [x] 5.6 `INPUT$(n)` blockierend ohne Echo; verifiziert durch Test, dass genau `n` Zeichen gelesen werden und der Bildschirm unverändert bleibt
- [x] 5.7 `TAB` und `SPC` in der `PRINT`-Familie; verifiziert durch Korpustest mit Spaltenpositionen
- [x] 5.8 `KEY`-Umfang (`KEY LIST`/`ON`/`OFF`, Funktionstasten-Makros) aus der Original-Hilfe klären, umsetzen und in docs/sprachreferenz.md festhalten; verifiziert durch Korpustest und Dokumentationsabschnitt

## 6. String-, Zahlen- und Formatbibliothek

- [x] 6.1 Alle im Inventar geführten Stringfunktionen vervollständigen inklusive Randfälle (`VAL`-Präfix, `STR$`-Leerzeichen, Fehler 5 bei Startposition < 1, Länge über Stringende); verifiziert durch Korpustest je Randfall
- [x] 6.2 `PRINT USING`/`LPRINT USING`/`FORMAT$` mit numerischen Platzhaltern, Tausendertrennung, Vorzeichenführung, `$$`/`**`/`**$`, Exponentialform und String-Platzhaltern; verifiziert durch Korpustest je Formatzeichenklasse
- [x] 6.3 Feldüberlauf mit `%`-Präfix umsetzen und in docs/sprachreferenz.md festhalten; verifiziert durch Korpustest und Dokumentationsabschnitt
- [x] 6.4 Wiederverwendung der Formatzeichenkette bei mehreren Werten; verifiziert durch Korpustest
- [x] 6.5 Mathematikfunktionen vervollständigen inklusive Banker's Rounding, Fehler 6 bei Überlauf, Fehler 5 bei `SQR`/`LOG`, Fehler 11 bei Division durch null; verifiziert durch Korpustest je Fehlerfall
- [x] 6.6 Kompatiblen `RND`/`RANDOMIZE`-PRNG umsetzen (`RND(0)` wiederholt, negatives Argument setzt Startwert) und den Algorithmus dokumentieren; verifiziert durch Korpustest mit reproduzierbarer Folge nach `RANDOMIZE 42`
- [x] 6.7 Datums- und Zeitfunktionen inklusive Serienwert-Zählweise, `WEEKDAY` = 1 für Sonntag und Fehler 5 bei ungültigen Angaben; verifiziert durch Korpustest mit festem Datum
- [x] 6.8 `DATE$`/`TIME$` als Anweisung; verifiziert durch Test, dass die Funktionsform danach den gesetzten Wert liefert
- [x] 6.9 Finanzmathematische Funktionen `FV#`, `PV#`, `Pmt#`, `IPmt#`, `PPmt#`, `NPer#`, `Rate#`, `NPV#`, `IRR#`, `MIRR#`, `SLN#`, `SYD#`, `DDB#` in DOUBLE mit Fälligkeitsargument; verifiziert durch Korpustest je Funktion gegen dokumentierte Sollwerte
- [x] 6.10 Fehler 5 bei ungültigen Argumenten der Finanzfunktionen und bei erfolgloser Näherung von `Rate#`/`IRR#`; verifiziert durch Korpustest je Fall
- [x] 6.11 Abbruchbedingung der Näherung in docs/bibliothek.md dokumentieren; verifiziert durch den Abschnittseintrag
- [x] 6.12 `SetFormatCC` für Währungszeichen und -stellung von `$$`; verifiziert durch Korpustest, dass `PRINT USING "$$#.##"` das gesetzte Zeichen verwendet
- [x] 6.13 `docs/bibliothek.md` anlegen und mit dem umgesetzten Stand füllen; verifiziert dadurch, dass jede in Gruppe 6 umgesetzte Funktion dort einen Eintrag hat

## 7. Datei-E/A

- [x] 7.1 Dateitabelle und `OPEN` in beiden Syntaxen für sequenziell, `RANDOM` und `BINARY`, `CLOSE` (mit und ohne Argument), `RESET`, `FREEFILE`; verifiziert durch Korpustest inklusive Fehler 55, 52 und 53
- [x] 7.2 Sequenzielle Übertragung: `PRINT #`, `WRITE #`, `INPUT #`, `LINE INPUT #`, `EOF`, Fehler 62 beim Lesen über das Dateiende; verifiziert durch Korpustest, dass `WRITE #` und `INPUT #` gegenläufig sind
- [x] 7.3 Recordpuffer mit `FIELD`, `LSET`, `RSET` inklusive Abschneiden überlanger Werte; verifiziert durch Korpustest
- [x] 7.4 Festtextfelder als UTF-32 mit konstanter Recordlänge; verifiziert durch Korpustest, dass ein Record mit ASCII und einer mit Nicht-ASCII dieselbe Byteanzahl belegen
- [x] 7.5 `GET`/`PUT` für `RANDOM` mit Recordnummer und mit UDT-Variablen; verifiziert durch Korpustest mit Schreiben und Lesen an Position 3
- [x] 7.6 Binärzugriff mit byteweiser Positionierung, `SEEK` als Anweisung und Funktion; verifiziert durch Korpustest, dass ein positioniert überschriebenes Byte zurückgelesen wird und die Nachbarbytes unverändert bleiben
- [x] 7.7 `LOF`, `LOC`, `FILEATTR` inklusive Fehler 52 auf geschlossener Datei; verifiziert durch Korpustest
- [x] 7.8 `LOCK`/`UNLOCK` umsetzen; verifiziert durch Korpustest für Sperren und Freigeben, plattformbedingte Abweichungen in docs/sprachreferenz.md notiert
- [x] 7.9 Dateisystem-Anweisungen `KILL`, `NAME … AS`, `FILES`, `CHDIR`, `MKDIR`, `RMDIR`, `SHELL` mit plattformübergreifender Pfadsemantik (`\` und `/`, Laufwerksbuchstaben) inklusive Fehler 53 und 76; verifiziert durch Korpustest mit Rückwärts-Schrägstrich
- [x] 7.10 `LPRINT`/`LPRINT USING` mit dokumentiertem Ausgabeziel sowie `LPOS`; verifiziert durch Test, dass die Formatierung `PRINT` entspricht, `LPOS` die Druckerspalte liefert, und durch den Abschnitt in der Sprachreferenz
- [x] 7.11 Record-Konvertierungsfunktionen `MKI$`/`MKL$`/`MKS$`/`MKD$`/`MKC$` und `CVI`/`CVL`/`CVS`/`CVD`/`CVC`; verifiziert durch Korpustest, dass jedes Paar gegenläufig ist und falsche Argumentlänge Fehler 5 auslöst
- [x] 7.12 MBF-Varianten `MKSMBF$`/`MKDMBF$`/`CVSMBF`/`CVDMBF` umsetzen oder als Non-Feature namentlich abweisen und in docs/sprachreferenz.md listen; verifiziert durch Korpustest bzw. den Abschnittseintrag
- [x] 7.13 `CURDIR$`, `DIR$` (erster und Folgetreffer, leerer String am Ende), `CHDRIVE` und `SHELL` als Funktion; verifiziert durch Korpustest, der ein Verzeichnis mit `DIR$` vollständig durchläuft
- [x] 7.14 Korpus-Dateiprogramme in einem temporären Arbeitsverzeichnis ausführen; verifiziert dadurch, dass nach `cargo test` `git status` sauber ist

## 8. System- und Umgebungsanweisungen

- [x] 8.1 `ENVIRON$` (nach Name und Position), `ENVIRON`, `COMMAND$`; verifiziert durch Korpustest inklusive leerem String für unbekannte Namen
- [x] 8.2 `FRE`, `CLEAR`, `TRON`, `TROFF` mit definiertem, dokumentiertem Verhalten; verifiziert dadurch, dass keine `Unsupported`-Absenkung mehr erfolgt und der Ersatzwert für `FRE` in der Sprachreferenz steht
- [x] 8.3 `STACK` als Anweisung und Funktion, `SYSTEM`, `ERDEV`/`ERDEV$` mit definierten Ersatzwerten; verifiziert durch Korpustest, dass `SYSTEM` mit demselben Status endet wie `END`, und durch die Ersatzwert-Einträge in docs/sprachreferenz.md

## 9. Altlasten aus Phase 2

- [x] 9.1 `ON ERROR GOTO` auf Modulebene aus Prozeduren auflösbar machen (`sema.rs`, `lower_stmt`/`OnError`), `ON LOCAL ERROR` bleibt prozedurlokal; verifiziert durch je einen Frontend-Test für beide Fälle
- [x] 9.2 DATA-Rohtext im Lexer erhalten (keine Bezeichner-Normalisierung, Randleerraum entfernt, Innenleerraum erhalten); verifiziert durch Korpustest mit gemischter Schreibweise
- [x] 9.3 `TODO verify`-Zellen der Konvertierungsmatrix in docs/tbvm-design.md gegen die Original-Hilfe auflösen (CURRENCY-Promotion mit Gleitkomma, `^`-Ergebnistyp, Exponentialform-Schwellen, CURRENCY-Ausgabeformat); verifiziert dadurch, dass keine `TODO verify`-Zelle mehr im Dokument steht
- [x] 9.4 Korpustest `konvertierung.bas` um die in 9.3 geklärten Randfälle schärfen; verifiziert durch die erweiterte Sollausgabe

## 10. Abschluss

- [x] 10.1 Inventarstatus für alle in diesem Change umgesetzten Elemente auf `implementiert` setzen; verifiziert dadurch, dass der Abgleichstest aus 1.3 grün bleibt
- [x] 10.2 docs/sprachreferenz.md fortschreiben (Doppelzellen, `KEY n`, `PRINT USING`-Überlauf, UTF-32-Records, plattformbedingte Abweichungen); verifiziert durch die vorhandenen Abschnitte
- [x] 10.3 Vollständige Suite ausführen; verifiziert dadurch, dass `cargo test --workspace` grün ist. **Nur macOS geprüft** — Windows und Linux stehen aus und gehören zu den Plattformtests in Phase 6 (PLAN.md); die Laufzeit enthält keinen plattformspezifischen Code außer der Pfadnormierung und `SHELL`.
- [x] 10.4 Meilenstein prüfen: klassische Konsolenprogramme des Korpus laufen unverändert; verifiziert dadurch, dass jedes Korpusprogramm ohne Laufzeitfehler 73 durchläuft
- [x] 10.5 PLAN.md Phase 3 abhaken, soweit dieser Change reicht, und den offenen ISAM-Teil auf `phase-3-isam` verweisen; verifiziert durch den aktualisierten Planabschnitt
