Files
TerminalBasic/openspec/changes/archive/2026-09-05-forms-zustand-und-bedienung/review.md

11 KiB
Raw Blame History

Verifikation: forms-zustand-und-bedienung

Abnahme vom 05.09.2026, umgesetzt auf Basis von 644a862. Nach erfolgreicher Verifikation am selben Tag synchronisiert und archiviert. V1, V2 und V3 sind behoben. Keine offenen Befunde im Change. Beide Delta-Requirements, alle acht Szenarien, die ergänzten Abnahmetasks und D1D3 wurden erneut gegen Code und Tests geprüft.

Dimension Ergebnis
Vollständigkeit 7/7 Tasks vollständig umgesetzt; beide Delta-Requirements mit allen acht Szenarien abgedeckt. Task 4.2 einschließlich Mindestmaßen und verwandten Zeichenpfaden erfüllt.
Korrektheit 428 Workspace-Tests und alle vier Review-Proben bestanden. Keine kritischen Befunde, Warnungen oder offenen Verbesserungsvorschläge.
Kohärenz D1D3 umgesetzt. Die stabile Sortierung erhält die Auswahl; Simple-ComboBox und ListBox verwenden denselben Listenrenderer.

V3 — behoben; historischer Befund vor der Korrektur

Die folgenden Beobachtungen gelten für den vorherigen Stand. Die Korrektur und ihre erweiterten Nachweise stehen im nächsten Abschnitt.

V3 (ursprünglich mittel): Listenrenderer überschreitet zulässige Mindestmaße

Reproduktion: Sichtbare Simple-ComboBox mit Width = 1, Height = 5, Left = 2, Top = 2 in einem ausreichend großen Formular. Gegenüber dem Bildschirm mit ausgeblendetem Control werden auch die Zellen in Spalte 4, Zeilen 47 überschrieben; die einzige erlaubte Controlspalte ist Spalte 3. Eine ListBox mit Width = 1 hat denselben horizontalen Überlauf. Bei einer ListBox mit Width = 6, Height = 1 wird zusätzlich die vollständige Zeile unterhalb des Controls gezeichnet. Benachbarte Inhalte können dadurch überschrieben werden.

Ursache: list_lines verwendet box_lines, das Breite und Höhe auf mindestens 2 erhöht. Für Width < 3 kehrt der Listenrenderer ohne Begrenzung zurück; im ListBox-Pfad fehlt auch eine abschließende Höhenbegrenzung. write_at begrenzt ausschließlich auf den Bildschirm. Width und Height lassen ausdrücklich den Wert 1 zu.

Vertrag: Task 4.2 verlangt die Prüfung von Kürzung und Größenbegrenzung für die Simple-ComboBox. Der neue gemeinsame Renderer übernimmt die bereits vorhandene Mindestmaß-Lücke auch für die nun dargestellte Simple-Liste. Die bestehenden Regressionen prüfen Breite 6 und kleine Combo-Höhen, aber weder Breite 1 noch die ListBox-Höhe 1.

Behebung: Die gemeinsame Listenausgabe auf die tatsächlich angeforderte Breite und Höhe begrenzen. Mindestbreite 1 für beide Klassen und Mindesthöhe 1 für ListBox durch Bildschirmprüfungen absichern; normale Maße beibehalten.

Nachweis: listen_bleiben_auch_bei_minimalmassen_im_controlrechteck in review-probes.rs prüft den tatsächlichen Bildschirm vor und nach Einblenden des Controls. Die Kontrollfälle ComboBox 15×5 und ListBox 6×4 bleiben innerhalb ihrer Grenzen; die drei Mindestmaßfälle schlugen vor der Behebung fehl und bestehen jetzt mit unveränderten Erwartungen.

Behebung und Regressionen

  • V1: Gemeinsame Sortierung für Laufzeit- und initiale Property-Zugriffe. Sortierung ohne Beachtung der Groß-/Kleinschreibung; ursprüngliche Indizes erhalten die Auswahl auch zwischen gleichen Texten. Regressionen prüfen beide Klassen, alle ComboBox-Stile, Basis-/Arrayindex 0 und dynamische Arrayelemente, wiederholtes Sortieren sowie anschließendes Einfügen/Entfernen. Der Formular-Korpus prüft jetzt das Einschalten von Sorted nach dem Befüllen mit unveränderter Sollausgabe.
  • V2: Simple verwendet den bestehenden Listenrenderer samt Rahmen und Auswahlmarkierung. Der Bildschirmtest prüft tatsächliche Einträge, Auswahl, Entfernen und erhaltenen Eingabetext. V3 ergänzt die Mindestmaßabnahme.
  • V3: list_lines begrenzt sämtliche Rahmenzeilen auf die angeforderte Breite und Höhe, auch vor dem frühen Rücksprung für schmale Controls. Alle Aufrufer (ListBox, Simple-ComboBox, DirListBox und FileListBox) verwenden diese Korrektur. Die gemeinsame Textkürzung zählt dieselben Zellenbreiten wie TextScreen und behandelt Steuerzeichen als Leerzeichen. TextScreen::print_line verwendet den vorhandenen Zellenschreibpfad ohne Umbruch oder Scrollen; write_at nutzt ihn für Forms-Ausgaben. Das normale BASIC-PRINT behält Umbruch und Scrollen.

Die zusätzliche Regression listenrenderer_haelt_zellgrenzen_auch_an_bildschirmraendern_ein vergleicht alle Bildschirmzellen außerhalb des jeweiligen Controlrechtecks einschließlich Farben und Unicode-Fortsetzungsmarkierung. 3.360 Kombinationen bestehen: ListBox, Combo-Stile 0/1/2, DirListBox, FileListBox und DriveListBox; Basis- und dynamische Arrayelemente; Breiten 1/2/3/6/15/254 und Höhen 1/2/3/5/254; vier Positionen einschließlich rechtem/unterem Bildschirmrand und vollständig außerhalb; leere und gefüllte Listen mit langen Texten, breiten Unicode-Zeichen und CR/LF. Vor der Korrektur schlug dieser Test bereits bei einer ListBox 1×1 fehl.

ui_zeile_bleibt_am_rand_ohne_umbruch_oder_scrollen prüft zusätzlich vollständig passende und nicht passende breite Zeichen, Farben, CR/LF sowie den rechten/unteren Rand und einen eigenen VIEW-PRINT-Bereich. Bestehende Zeichenbild-, Auswahl-, Timer-, VM- und Korpustests bestehen unverändert in ihren Erwartungen.

Ursprüngliche Befunde — historischer Stand vor der Behebung

Die folgenden Ist-Beobachtungen dokumentieren den fehlgeschlagenen Review. Beide Befunde sind durch die Nachweise oben geschlossen.

V1: Nachträgliches Sorted lässt den Listeninhalt unsortiert

Reproduktion: In ListBox oder ComboBox zuerst b, dann a hinzufügen, Eintrag 0 (b) auswählen, anschließend Sorted = -1 setzen und c hinzufügen. Ist: List = [b, a, c], ListIndex = 0. Soll: sortierte Liste [a, b, c] mit weiterhin ausgewähltem b, Index 1.

Der Property-Setter speichert SORTED ohne Sortierung des vorhandenen Inhalts. ADDITEM verwendet anschließend partition_point, das bereits sortierte Daten voraussetzt. Der Fehler tritt bei beiden Klassen auf.

Vertrag: Delta „Steuerelemente mit Listeninhalt“, Sortierung bei Sorted = 1 und Konsistenz von List/ListIndex/Text; Task 1.1. Die Tests setzen Sorted ausschließlich vor dem Befüllen und decken den zulässigen Wechsel an einer gefüllten Liste nicht ab.

Behebung: Beim Einschalten der Sortierung vorhandene Einträge sortieren und die Auswahl ihrem bisherigen Eintrag zuordnen; anschließend Einfügen und Entfernen weiterhin konsistent halten. Regression für beide Klassen, einschließlich der Auswahl, ergänzen.

V2: ComboBox.Style 1 zeichnet keine Listeneinträge

Reproduktion: Sichtbare ComboBox mit Style = 1, Width = 15, Height = 5, Text = frei; ADDITEM apfel und birne. Ist: Der Bildschirm zeigt frei und einen leeren eingerahmten Listenbereich. Soll: Die beiden Einträge erscheinen in diesem ausreichend großen Bereich.

Der Renderer hängt für Style 1 nur box_lines mit leerem Inhalt an. Er liest die vorhandenen Listeneinträge für diesen Bereich nicht. Die Probe prüft zuerst, dass das Control über den Text frei tatsächlich sichtbar ist, und danach die beiden Listeneinträge.

Vertrag: Delta „Steuerelemente mit Listeninhalt“ verlangt die Darstellung aller drei ComboBox-Stile; die Forms-Referenz zeigt für Simple einen sichtbaren Listeneintrag. Task 1.1 verlangt die Prüfung aller Stile. Der bestehende Stiltest prüft nur Zeilenzahl und Präfix; die neuen Auswahltests prüfen nur die oberste Zeile.

Behebung: Den vorhandenen Listeninhalt samt Auswahl im Simple-Bereich darstellen und dessen Inhalt mit einem Bildschirmtest absichern. Die bereits festgelegten Zeichenformen beibehalten.

Beide Lücken bestanden bereits vor diesem Change. Es handelt sich um verbleibende Abweichungen im übernommenen Listen-Requirement, nicht um neu eingeführte Regressionen. Die Korrekturen wurden nach diesem Review umgesetzt.

Szenarioabdeckung und positive Nachweise

Delta-Szenario Nachweis
Element hinzufügen Bestehender Sorted-Listentest und neue Auswahlmatrix: a/b, ListCount und List(i). Nachträgliches Einschalten einschließlich stabiler Auswahl durch V1-Regressionen abgesichert.
Keine Auswahl ListIndex 1 bei leerer Liste und nach Entfernen der Auswahl.
Auswahl ausdrücklich aufheben Modellmatrix für ListBox und ComboBox-Stile 0/1/2; Formular-Korpus.
Eintrag vor Auswahl einfügen Sortierte/unsortierte Modellmatrix prüft Indexverschiebung und erhaltenen Text.
Timer feuert im Abstand Zwei Ereignisse nach 250 ms aktiver Zeit, mehrere Timer und Arrayelemente, identische Wiederholung.
Interval 0 schaltet ab Modelltest, Arrayindex-0-Reset und Änderung im VM-Handler.
Späte Aktivierung VM: direkte Property, Control-Parameter und Enabled; Aktivierung bei 1000, still bei 1099, einmal bei 1100 ms. Zusätzliche erfolgreiche Probe für spät geladenes Timer-Arrayelement.
Abschalten verwirft anstehende Ereignisse Interval/Enabled-Reset, Array-Entladen und Handlerwechsel mit altem Rückstau.

Erneut ausgeführt:

  • cargo test --workspace: 428 bestanden, 0 fehlgeschlagen, 1 ignoriert. Ignoriert bleibt der Generator für Sollausgaben; keine Golden Files geändert.
  • openspec validate forms-zustand-und-bedienung --strict: gültig.
  • git diff --check: erfolgreich.
  • Zusätzliche Review-Proben: 4 bestanden, 0 fehlgeschlagen.

cargo clippy -p tb-ui -p tb-vm -p tb-runtime --all-targets --all-features -- -D warnings und cargo fmt --all -- --check wurden nach der Behebung erfolgreich ausgeführt. Kein interaktiver Terminal-/VBDOS-Vergleich und keine Windows-/Linux-Matrix. Die Darstellungsprobe prüft den echten Zellenpuffer ohne Terminal; Timerprüfungen verwenden ausschließlich virtuelle Hostzeit.

Review-Proben reproduzieren

Im Repository-Wurzelverzeichnis ausführen; erzeugt einen separaten temporären Cargo-Treiber. Auf dem korrigierten Stand bestehen alle vier Proben.

python3 - <<'PY'
from pathlib import Path
import json, subprocess, tempfile
root = Path.cwd()
p = Path(tempfile.mkdtemp(prefix='tb-forms-review-'))
manifest = '[package]\nname="tb-forms-review"\nversion="0.0.0"\nedition="2021"\n[workspace]\n'
manifest += '[[test]]\nname="probes"\npath=' + json.dumps(str(root / 'openspec/changes/archive/2026-09-05-forms-zustand-und-bedienung/review-probes.rs')) + '\n[dependencies]\n'
for name in ['tb-ui', 'tb-vm', 'tb-runtime', 'tb-frontend']:
    manifest += name + ' = { path = ' + json.dumps(str(root / 'crates' / name)) + ' }\n'
(p / 'Cargo.toml').write_text(manifest)
subprocess.run(['cargo', 'test', '--manifest-path', str(p / 'Cargo.toml'), '--offline', '--test', 'probes', '--', '--nocapture'], check=True, timeout=120)
PY