11 KiB
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 D1–D3 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 | D1–D3 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 4–7 ü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_linesbegrenzt 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_lineverwendet den vorhandenen Zellenschreibpfad ohne Umbruch oder Scrollen;write_atnutzt 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