192 lines
12 KiB
Markdown
192 lines
12 KiB
Markdown
# 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 V1–V5-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](../../../../crates/tb-runtime/src/builtins.rs#L209)
|
||
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](../../../../crates/tb-vm/src/interp.rs#L1344)
|
||
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](../../../../crates/tb-vm/src/interp.rs#L625) erfolgt vor der
|
||
Eingabeverarbeitung. Nachdem Esc die Menüsperre aufgehoben hat, kehrt die
|
||
Methode ohne erneute Auswahl zurück;
|
||
[SLEEP](../../../../crates/tb-vm/src/interp.rs#L707) 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](../../../../crates/tb-vm/src/interp.rs#L890)
|
||
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](../../../../crates/tb-vm/src/interp.rs#L631) 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; V1–V3 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](review-probes.rs): **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](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:
|
||
|
||
```sh
|
||
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.
|