Files
TerminalBasic/openspec/changes/archive/2026-09-05-ereigniszustellung-und-hostgrenzen/review.md

12 KiB
Raw Blame History

Verifikation: ereigniszustellung-und-hostgrenzen

Stand nach Behebung: 05.09.2026, aktueller Arbeitsbaum auf 57d6386. Alle fünf Verifikationsbefunde sind behoben. Die ursprünglichen sechs Review-Proben bestehen unverändert in ihren Erwartungen; zusätzlich wurden sie in die Workspace-Regressionen übernommen und um verwandte Pfade ergänzt.

Dimension Ergebnis
Vollständigkeit 12/12 Tasks erledigt; ursprüngliche Zuordnung der 9 Delta-Requirements und 33 Szenarien um Korrektur-Nachweise ergänzt.
Korrektheit 419 Workspace-Tests und alle sechs separaten Review-Proben bestanden; keine offenen V1V5-Befunde.
Kohärenz Gemeinsame Zustellung auch während Eingabe und nach Menüschluss; synchrone LOAD-Wirkungen getrennt, klassische Quellpriorität erhalten.

Korrekturen und Regressionen

Befund Behebung Nachweis in crates/tb-vm/tests/events.rs
V1 Fortsetzbarer Konsolenleser für INPUT, LINE INPUT, INPUT$ und RANDOMIZE ohne Argument. Frame hält Teiltext/Restlänge, Stack hält Operanden und Referenzen. Trap-Unwinding erhält gemeinsam genutzte Locals; Fehler und RETURN label verwerfen abgebrochene Eingaben. Ursprüngliche Signalprobe; Teiltext/BYREF/Ausdruck, verschachtelte Eingaben mit STOP/CONT, Timer, Redo, lokaler Fehlerhandler, RANDOMIZE und RETURN label.
V2 Implizite Objektaufrufe stellen ausschließlich notwendige LOAD-Handler zu. Deren Rückkehr zieht keine unabhängigen Forms-Ereignisse vor. LlGg mit Control-Argument, Property-Lesen/-Schreiben, Refresh und LOAD; bestehende Load-vor-Show- und Unload-Tests.
V3 Nach dem Schließen des Menüs wird die gemeinsame Auswahl vor jedem erneuten Warten wiederholt. Esc bei Zeit 0, UEVENT zugestellt nach genau einem Warteaufruf; bestehende Menüsperrtests einschließlich Forms-Timer.
V4 Modale und modellose Schleifen beenden bei EOF erst, wenn kein Handler mehr zugestellt wurde. Ursprüngliche MouseDown/Unload-Probe; jeweils zwei Mausereignisse vor EOF ergeben MM in beiden Schleifen.
V5 Getrappte Tasten am Queue-Anfang werden vor der klassischen Quellenauswahl gemeldet. Gleichzeitiges KEY/UEVENT ergibt KU; Maus vor getrappter Taste bleibt MK.

Ursprüngliche Befunde — historischer Stand vor der Behebung

Die folgenden Ist-Beobachtungen und Ursachen dokumentieren den fehlgeschlagenen Review vor diesen Korrekturen. Alle fünf sind durch die Nachweise oben geschlossen.

V1 — Während blockierender Eingabe werden eintreffende Traps nicht zugestellt (hoch)

Reproduktion: ON SIGNAL(2) GOSUB H, SIGNAL(2) ON, danach INPUT. Der Host liefert erst im blockierenden next_event(true) Signal(2), beim nächsten Aufruf Eingabeende. Der Handler H würde PRINT "H" und END ausführen.

Ist: INPUT, LINE INPUT und INPUT$(1) enden jeweils mit Fehler 62, H läuft nicht. Ohne nachfolgende Eingabe kann die Laufzeit stattdessen erneut blockieren, obwohl der Signal-Trap schon ansteht.

Soll: Vor dem erneuten Blockieren muss der erlaubte Zustellpunkt genutzt werden; H beendet das Programm, Ausgabe H, kein Fehler 62.

Ursache: Der einmalige VM-Check vor der Eingabeinstruktion genügt nicht. RtState::naechste_taste pumpt innerhalb seiner Schleife weitere Ereignisse und blockiert erneut, ohne zur VM-Zustellung zurückzukehren. Dasselbe betrifft die drei genannten Eingabefunktionen über ihren gemeinsamen Leser.

Vertrag: ereignissteuerung / Abschließende Liste der Zustellpunkte, Signal-Trap auf Betriebssystemsignalen; Design D2; Task 2.1. Korrektur: Blockierende Eingabe so fortsetzbar machen, dass nach einem Nicht-Tasten-Ereignis und vor dem nächsten Host-Warten die gemeinsame VM-Zustellung laufen kann. Eingabepuffer, Referenzen und Operanden erhalten.

V2 — Control-Argumente stellen wartende Forms-Handler mitten in einer Anweisung zu (hoch)

Reproduktion: Fokuswechsel Text1 → Text2. Text1_LostFocus ruft als erste wirksame Anweisung CALL Mark(Text1) auf; Mark hängt L an eine gemeinsame Variable, LostFocus danach l. Text2_GotFocus hängt G und g an.

Ist: GgLl. Soll: LlGg.

Ursache: Instr::PushObject ruft nach dem Ablegen eines bereits geladenen Control-Objekts bedingungslos dispatch_next_form_event auf. Dadurch läuft GotFocus noch vor dem eigentlichen CALL, obwohl weder DOEVENTS noch modales Warten vorliegt. Der Schutz am ersten Stmt-Eintritt und forms_frei werden damit umgangen.

Vertrag: Fokus, Tabreihenfolge und Access-Keys / Handlerwirkungen in Fokusreihenfolge; Abschließende Liste der Zustellpunkte; Design D1/D2; Tasks 1.2 und 2.1. Korrektur: Unabhängig wartende Ereignisse aus Objekt-Opcodes heraus nicht zustellen. Notwendige synchrone Load-/Unload-Wirkungen gezielt behandeln; alle Aufrufer von dispatch_next_form_event gegen dieselben Zustellregeln prüfen.

V3 — Menüschließen während SLEEP führt zu erneutem Warten trotz bereitem Trap (hoch)

Reproduktion: Menü offen, UEVENT anstehend, SLEEP 60. Der erste Host-Warteaufruf liefert Esc bei unveränderter virtueller Zeit 0.

Ist: Esc schließt das Menü; die VM wartet ein zweites Mal bis Hostzeit 60.000 ms. Erst dann läuft der UEVENT-Handler. Soll: Nach Esc läuft der freigegebene Handler ohne zweiten Warteaufruf und beendet SLEEP sofort. Bei einer Wartephase ohne eigene Deadline droht entsprechend Warten auf ein weiteres externes Ereignis.

Ursache: Die klassische Trap-Auswahl in Vm::zustellen erfolgt vor der Eingabeverarbeitung. Nachdem Esc die Menüsperre aufgehoben hat, kehrt die Methode ohne erneute Auswahl zurück; SLEEP ruft unmittelbar wieder warten auf.

Vertrag: Menüsystem / Traps ruhen im geöffneten Menü und werden danach fortgesetzt; Abschließende Liste der Zustellpunkte / SLEEP endet durch Ereignis; Design D2/D3; Tasks 2.1/2.2. Korrektur: Nach einer Eingabe, die die Zustellbarkeit verändert, bereite Ereignisse vor jedem weiteren blockierenden Warten erneut auswählen.

V4 — Modale Schleife verliert bereits angenommenes Ereignis unmittelbar vor EOF (hoch)

Reproduktion: Form1.Show 1; nach der zweiten Anzeige liefert der Host MouseDown und unmittelbar danach Eingabeende. Der MouseDown-Handler hängt M an und entlädt das Formular.

Ist: VM meldet Ended, die gemeinsame Variable bleibt leer; der Handler wurde nicht ausgeführt. Soll: Das vor EOF eingetroffene Mausereignis wird noch wirksam, Ergebnis M, Formular entladen.

Ursache: In der modalen Run-Schleife setzt zustellen einen Handlerframe auf. Direkt danach wird ungeachtet von dispatched wegen rt.ende zurückgekehrt. Das Ereignis ist bereits aus der Queue entfernt und wird stillschweigend verloren.

Vertrag: Mausereignisse in Zellenkoordinaten / Reihenfolge bis zur beobachtbaren Handlerausführung; Design D1/D2; Tasks 1.2/2.1. Korrektur: EOF als Ende der Eingabequelle behandeln und bereits angenommene Ereignisse/Handler geordnet abarbeiten, bevor die modale Ausführung endet.

Ursprüngliche weitere Designabweichung

V5 — Gleichzeitig wartende klassische Quellen erhalten eine andere Priorität (mittel)

Reproduktion: KEY(15) ON und UEVENT ON. Vor demselben Zustellpunkt liegen eine passende Taste in der Eingabequeue und ein gemeldeter UEVENT vor. Die Handler hängen K bzw. U an.

Ist: UK. Soll: KU gemäß der bestehenden klassischen Quellpriorität.

Ursache: Vm::zustellen wählt bereits gemeldete Traps aus, bevor die wartende Taste durch taste_trappen gemeldet wird. Die Prioritätsauswahl in Traps sieht die Taste deshalb noch nicht. Früher erfolgte die Tastenprüfung vor der gemeinsamen Trap-Auswahl.

Vertrag: Design / Non-Goals: keine Änderung der festgelegten Priorität gleichzeitig fälliger klassischer Quellen; D1/D2; Task 2.1. Korrektur: Fälligkeitserfassung und Trap-Auswahl so koordinieren, dass die bestehende Quellpriorität erhalten bleibt, ohne die Reihenfolge zwischen Maus- und Tasteneingaben wieder nach Quellarten umzusortieren.

Abdeckung und positive Nachweise

Delta-Requirement Nachweis / Einschränkung
Ereignisquellen mit Zeit vom Host Host-Warteschnittstelle, eingefrorene virtuelle Zeit, klassischer Timer und Forms-Timer-SLEEP getestet. Keine reale Rückfalluhr in der VM; Zustellung nach Menüschluss durch V3-Regression abgesichert.
Mausereignisse in Zellenkoordinaten Mapper-/Bounds-Tests, leere Verbraucher, KM/MK-Korpus und gemischte Eingaben. V4-Regressionen sichern EOF in modalen und modellosen Schleifen ab.
Abschließende Liste der Zustellpunkte DOEVENTS-Wert, SLEEP, vorbereitete und erst beim Warten eintreffende INPUT-Ereignisse getestet; V1V3 geschlossen.
Getrappte Tasten verlassen den Eingabestrom ON/OFF/STOP × INKEY$/INPUT/LINE INPUT/INPUT$, mehrfaches STOP-Merken und Dialogrestpuffer getestet.
Signal-Trap auf Betriebssystemsignalen Beide Kennungen, Maskierung und ungültige Werte getestet. V1-Regression sichert Signalzustellung während blockierender Eingabe ab.
Fokus, Tabreihenfolge und Access-Keys Tab/Shift-Tab, BackTab-Mapper, Access-Keys und einfacher LostFocus→GotFocus-Lauf belegt. V2-Regressionen sichern Control-Argumente und verwandte Objektaufrufe ab.
Menüsystem Menüeigenschaften/-auswahl und Sperre an normalen Grenzen getestet. V3-Regression sichert Freigabe innerhalb von SLEEP ab.
Zellenpuffer ohne Terminalabhängigkeit Separater Workspace kompiliert FRM/VM und liefert KM; 16 Pakete im normalen Dependency-Graph, keines davon crossterm/ratatui/signal-hook. CLI schaltet das Feature ausdrücklich ein.
Ereigniszustellung an Anweisungsgrenzen Bestehende SUB-/GOSUB-/BYREF-/RESUME-Tests und Host ohne erlaubte Uhrabfragen grün. V2/V5-Regressionen sichern zulässige Handlerbeginn-Reihenfolge und klassische Priorität ab.

Erneut ausgeführt:

  • cargo test --workspace: 419 bestanden, 0 fehlgeschlagen, 1 ignoriert.
  • openspec validate ereigniszustellung-und-hostgrenzen --strict: gültig.
  • Isolierter Einbetter mit CaptureHost: KM, Dependency-Prüfung erfolgreich.
  • Separate Review-Proben: 6 bestanden, 0 fehlgeschlagen. Die Kontrollprobe prüft Maus unmittelbar vor getrappter Taste.
  • Workspace-Ereignistests: 25 bestanden, einschließlich Frist-Watchdog.
  • Keine bestehenden Sollausgaben neu aufgezeichnet oder geändert.

Warnings-denied Clippy, Formatprüfungen und Compile-/VM-Benchmarks wurden nach der Behebung erneut erfolgreich ausgeführt; Zahlen siehe verification.md. Kein interaktiver Terminaltest und keine Windows-/Linux-Matrix. Die Proben speisen Ereignisse gezielt über Host ein und benötigen weder echte Signale noch reale Wartefristen.

Review-Proben reproduzieren

Im Repository-Wurzelverzeichnis ausführen. Das erzeugt ausschließlich einen separaten temporären Cargo-Treiber und referenziert den aktuellen Produktcode:

python3 - <<'PY'
from pathlib import Path
import json, subprocess, tempfile
root = Path.cwd()
p = Path(tempfile.mkdtemp(prefix='tb-review-'))
manifest = '[package]\nname="tb-review"\nversion="0.0.0"\nedition="2021"\n[workspace]\n'
manifest += '[[test]]\nname="befunde"\npath=' + json.dumps(str(root / 'openspec/changes/archive/2026-09-05-ereigniszustellung-und-hostgrenzen/review-probes.rs')) + '\n[dependencies]\n'
for name in ['tb-vm', 'tb-runtime', 'tb-ui', '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'), '--test', 'befunde', '--', '--nocapture'], check=True, timeout=120)
PY

Alle sechs Proben müssen auf dem korrigierten Stand bestehen. Ihre Erwartungen wurden auch in den regulären Workspace-Testlauf übernommen.