Projektmodule und vollständiges TBC-Kompilat umsetzen und Change archivieren

This commit is contained in:
2026-09-05 23:06:56 +02:00
parent 58b1f620ea
commit 815825dde7
40 changed files with 4177 additions and 555 deletions

View File

@@ -1,6 +1,6 @@
## Why
Mehrere Module/Formulare werden zu einem Quelltext und globalen Objektraum zusammengelegt. Dadurch scheitern formularlokale Namen, Fehlerorte stimmen nicht und FRM-Anfangswerte fehlen nach dem Kompilat-Rundlauf (F09F11); Containerdokumentation und Spec sind außerdem überholt (F24). Siehe [Review vom 05.09.2026](../../../docs/reviews/2026-09-05-openspec-code-review.md).
Mehrere Module/Formulare werden zu einem Quelltext und globalen Objektraum zusammengelegt. Dadurch scheitern formularlokale Namen, Fehlerorte stimmen nicht und FRM-Anfangswerte fehlen nach dem Kompilat-Rundlauf (F09F11); Containerdokumentation und Spec sind außerdem überholt (F24). Siehe [Review vom 05.09.2026](../../../../docs/reviews/2026-09-05-openspec-code-review.md).
## What Changes

View File

@@ -0,0 +1,223 @@
# Verifikation: projektmodule-und-kompilat
Geprüft am 05.09.2026: Arbeitsbaum auf Basis von `58b1f62`, alle sieben
Delta-Requirements mit 21 Szenarien, Tasks, D1D4, Implementierung und
Abnahmenachweis. **Sechs offene Befunde; der Change ist nicht abnahmebereit.**
Die vorherige Aussage vollständiger Umsetzung wird durch diese Verifikation
korrigiert. Der Produktcode wurde bei diesem Review nicht verändert.
| Dimension | Ergebnis |
| --- | --- |
| Vollständigkeit | 7/7 Tasks sind angehakt und alle sieben Requirements haben Implementierungspfade. Die Befunde widerlegen jedoch die vollständige Erfüllung insbesondere von 1.1, 1.2 und 2.2; Checkboxen allein sind kein Abnahmenachweis. |
| Korrektheit | 437 bestehende Workspace-Tests bestanden; zusätzliche unabhängige Review-Proben: 1 bestanden, 6 fehlgeschlagen. Vier Kernfunktionslücken (CRITICAL), zwei weitere Vertragsabweichungen (WARNING). |
| Kohärenz | D4 und die FRM-Grundpfade von D3 sind umgesetzt. Quellorte und Modulkontexte gehen in weiteren Absenkungs-/Importpfaden verloren; der gemeinsame Objektraum berücksichtigt `$FORM` nicht vollständig. |
## CRITICAL — vor Archivierung beheben
### V1 — Quellorte und Breakpoints fehlen an Zweig- und Schleifengrenzen
**Priorität: hoch.** Delta „Zeilentabelle für Fehlerortung“ und
„Unterbrechbare step()-Ausführung“, D1, Tasks 1.1/2.2.
Die Fehlerortung funktioniert bei einfachen Anweisungen, nicht jedoch bei
weiteren ausführbaren Teilen zusammengesetzter Anweisungen:
| Probe | Erwartet | Beobachtet |
| --- | --- | --- |
| `IF 0 THEN` / `PRINT 1` / `ELSEIF 1/0 THEN` | Fehler 11 in Zeile 3 | Zeile 1 |
| `SELECT CASE 1` / `CASE 1/0` | Fehler 11 in Zeile 2 | Zeile 1 |
| `FOR i%=32767 TO 32767` / `PRINT 1` / `NEXT` | Überlauf beim NEXT in Zeile 3 | Zeile 2 |
| `DO` / `PRINT 1` / `LOOP UNTIL 1/0` | Fehler 11 in Zeile 3 | Zeile 2 |
| ELSEIF-Bedingung aus `cond.bi:1` | Include-Datei `cond.bi` | `main.bas:1:1` |
| Breakpoint auf ELSEIF in Zeile 3 | Halt vor Bedingung | Programm endet ohne Halt |
**Ursache:** [ELSEIF-Absenkung](../../../../crates/tb-frontend/src/sema.rs#L1937)
und [CASE-Absenkung](../../../../crates/tb-frontend/src/sema.rs#L2914) verwenden
den Quellort des äußeren Statements. NEXT-/LOOP-Positionen werden nicht
vollständig durch AST/HIR bis zur auszuführenden Grenze getragen. Der
[FOR-Codegenerator](../../../../crates/tb-vm/src/codegen.rs#L737) dokumentiert
selbst die bisherige Verschiebung einer genauen NEXT-Zuordnung auf Phase 5;
das widerspricht der hier übernommenen vollständigen Quellortanforderung.
**Korrektur:** Physische Positionen aller ausführbaren Zweig-/Schleifenteile
bereits beim Parsen erhalten und passende Source-/Stmt-Grenzen ausgeben.
Nicht nur Fehlermeldungen umbenennen: Breakpoints, Einzelschritt und RESUME
müssen dieselbe richtige Zuordnung verwenden. Numerische ERL-Labels separat
lassen. Probe `v1_zweige_und_schleifen_behalten_eigene_quellorte`.
### V2 — Deklarationsimport verändert Typkontext und Abhängigkeitsreihenfolge
**Priorität: hoch.** Projektpipeline und vollständige Prozedursignaturen,
D2, Tasks 1.2/2.1.
Drei zulässige Mehrmodulkonstellationen werden abgewiesen:
- MAIN ruft `Doppelt(3)` auf; LIB enthält `DEFINT A-Z` und
`FUNCTION Doppelt(x)`. Erwartete Ausgabe 6, tatsächlich
`Parameter type mismatch: MAIN!DOPPELT`.
- MAIN enthält `CONST A=3` und verwendet B; LIB enthält `CONST A=3` und
`CONST B=A+1`. Erwartet B=4, tatsächlich `LIB.bas:2:1: Invalid constant`.
- Beide Module enthalten denselben TYPE Inner. LIB definiert anschließend
TYPE Outer mit einem Feld `i AS Inner`; MAIN verwendet Outer.
Erwartet korrektes Layout und Feldausgabe 3, tatsächlich `Type not defined`
an der gültigen Outer-Definition sowie Folgefehler für Feldzugriffe.
**Ursache:** [import_declarations](../../../../crates/tb-vm/src/project.rs#L103)
kopiert rohe Signatur-ASTs ohne den DEFtype-Kontext des definierenden Moduls.
Fremde CONST-/TYPE-Knoten werden [vor sämtliche lokalen Deklarationen
gehängt](../../../../crates/tb-vm/src/project.rs#L158). Dadurch fehlen ihnen zu
diesem Zeitpunkt lokal vorhandene Abhängigkeiten. Die Fehlerposition in LIB
ist hier irreführend: Die dortige Originalreihenfolge ist gültig.
**Korrektur:** Exportierte Signaturen und Konstanten im Ursprungskontext
auflösen; abhängige Typdefinitionen mit erhaltenen Identitäten und gültiger
Abhängigkeitsreihenfolge verbinden. Lokale Definitionen und echte Duplikate
nicht wieder durch Text-Deduplizierung verstecken. Probe
`v2_importierte_deklarationen_behalten_kontext_und_abhaengigkeiten`.
### V3 — `$FORM`-Module teilen versehentlich dasselbe Formularobjekt
**Priorität: hoch.** Delta „Objektzugriffe in Grammatik und Semantik“
einschließlich `$FORM`, getrennte Formulare, D2/D3, Task 1.2.
A.bas und B.bas enthalten jeweils `'$FORM`. A setzt `Caption="a"`, ruft eine
SUB aus B auf, die dort `Caption="b"` setzt, und liest anschließend die
eigene Caption. **Erwartet: a. Beobachtet: b.** Das verknüpfte Objektverzeichnis
enthält nur SCREEN und A. Auch `B.Caption` aus A wird als unbekanntes Objekt
abgewiesen. Der Fehler besteht nach TBC-Rundlauf fort.
**Ursache:** [lower_with_forms](../../../../crates/tb-frontend/src/sema.rs#L404)
erweitert pro Modul eine lokale Katalogkopie um das jeweilige `$FORM`-Objekt.
Der Linker übernimmt [nur die Objekte des ersten Moduls](../../../../crates/tb-vm/src/project.rs#L188)
und versetzt die Objektoperanden weiterer Module nicht. Deren Form-ID zeigt
anschließend auf A.
**Korrektur:** Sämtliche FRM- und `$FORM`-Formulare vor der modulweisen
Semantik in einen gemeinsamen Katalog mit stabilen IDs aufnehmen oder die
Objekt-/Ereignisreferenzen beim Linken vollständig versetzen. Zugriffe,
Form_Load-Bindungen und gegenseitige Formreferenzen für beide Quellarten
prüfen. Probe `v3_form_metabefehle_erzeugen_getrennte_formularobjekte`.
### V4 — COMMON verliert Variablenidentität und initialisiert Arrays mehrfach
**Priorität: hoch.** Designrisiko SHARED/COMMON, D2, Task 1.2 und Erhalt der
bestehenden COMMON-Sprachsemantik.
- Bereits ein Modul mit `COMMON SHARED c%, c$` wird mit
`COMMON type mismatch: C` abgewiesen. Die beiden durch Typ-Suffixe
verschiedenen Variablen dürfen nebeneinander existieren.
- MAIN und LIB deklarieren dasselbe `COMMON SHARED a%(2)`. MAIN soll
`a%(1)=7` setzen und LIB den gemeinsamen Wert 7 ausgeben. Stattdessen
entsteht vor dem Nutzcode `LIB.bas:1:1: Runtime error 10: Duplicate definition`.
**Ursache:** Die [COMMON-Zuordnung](../../../../crates/tb-vm/src/project.rs#L270)
verwendet nur Block und untypisierten Basisnamen. Arrays haben zusätzlich
nur `TypeInit::Empty` als Slotvorbelegung; Elementtyp und Form gehen in der
Vergleichsprüfung verloren. Der Slot wird zwar zusammengeführt, aber
[beide DIM-Initialisierungen](../../../../crates/tb-vm/src/project.rs#L381)
werden ausgeführt.
**Korrektur:** Vollständige Variablenidentität und Arrayvertrag beim Binden
berücksichtigen. Kompatible gemeinsame Arrays einmal initialisieren;
inkompatible Deklarationen vor der Ausführung am ursprünglichen Quellort
ablehnen. Probe `v4_common_behaelt_typidentitaet_und_initialisiert_arrays_einmal`.
## WARNING — weitere Vertragsabweichungen
### V5 — LOAD/UNLOAD umgehen die explizite Containerauflösung
**Priorität: mittel.** Formularnamensraum und expliziter Containerzugriff,
D2, Task 1.2.
Bei zwei Formularen mit jeweils Text1 als Control-Array werden
`LOAD Form2!Text1(3)` und `UNLOAD Form2!Text1(3)` mit
`Unknown object 'FORM2!TEXT1'` abgewiesen. Property-Zugriffe und die Übergabe
desselben qualifizierten Controls an einen CONTROL-Parameter funktionieren.
**Ursache:** Der [LOAD-/UNLOAD-Pfad](../../../../crates/tb-frontend/src/sema.rs#L3370)
übergibt den gesamten Bang-Pfad an `find_object`; die bereits vorhandene
containerbezogene Auflösung wird hier nicht verwendet.
**Korrektur:** LOAD/UNLOAD über dieselbe Objekt-/Containerauflösung wie
Property- und Referenzzugriffe führen; gleichnamige Arrays beider Formulare
und dynamische Instanzen gemeinsam prüfen. Probe
`v5_load_und_unload_loesen_den_expliziten_container_auf`.
### V6 — Linkerdiagnosen verlieren Datei, Zeile und Spalte
**Priorität: mittel.** Delta „Diagnostik mit Vorbild-Meldungen“, D1, Task 1.1.
MAIN deklariert `SUB F(x%)`, LIB implementiert `SUB F(x$)`. Die Ablehnung ist
richtig, die Meldung jedoch `0:0: Parameter type mismatch: MAIN!F` ohne Datei.
Das ist eine quellbezogene Diagnose, kein Fehler ohne zuordenbare Quelle.
**Ursache:** [diagnostic](../../../../crates/tb-vm/src/project.rs#L17) erzeugt
`file=None` und `SourcePos::default()`. [Linkfehler](../../../../crates/tb-vm/src/project.rs#L66)
werden erst nach `locate_diagnostics` in dieses Format umgewandelt. Dasselbe
Problem betrifft COMMON-Konflikte und weitere symbolbezogene Linkfehler.
**Korrektur:** Ursprung der betroffenen Deklaration bzw. Aufrufstelle mit
in die Linker-Symbolinformationen übernehmen und strukturierte Diagnosen
mit tatsächlicher SourcePos zurückgeben. Keine pauschale Ersatzposition
1:1 eintragen. Probe `v6_linkerdiagnose_nennt_den_urspruenglichen_dateiort`.
## Szenarioabdeckung und positive Nachweise
Alle 21 vorhandenen Delta-Szenarien wurden abgeglichen. Die einfachen
Originalbeispiele besitzen Implementierungs- und Testnachweise; die oben
reproduzierten Randpfade widersprechen den umfassenderen Requirements.
| Requirement / Szenarien | Ergebnis |
| --- | --- |
| Monomorpher Opcode-Satz: gemischter Ausdruck, aufgelöste Namen | Vorhandene Codegen-/HIR-Tests bestanden. Alle 152 Opcodes samt Operandentypen und Encodingbreiten stimmen mit der Dokumentation überein. |
| TBC: Roundtrip, unbekannte Version, Formularwerte | CLI-/VM-Projekttests bestanden: bytegleicher Rundlauf, hello/world aus Designarrays 0/2 nach Entfernen sämtlicher BAS-/FRM-/MAK-/BI-Quellen, Ablehnung alter/höherer Versionen. V2/V3 begrenzen dennoch das vollständige Projektmodell. |
| Quellorte: Fehlerzeile, Bibliotheksfehler | `lib.bas:2` und verschachtelte Include-Fehler bestehen. Unabhängig zusätzlich Fehler in physischer Zeile 42 geprüft. V1 zeigt fehlende Zweig-/Schleifenorte. |
| Benannte Objekte: Lesen/Schreiben, keine Standardeigenschaft, Wertebereich, getrennte Controls | Bestehende Semantik-/VM-/Modelltests und neuer Zwei-FRM-Test bestanden; Check1.Value=3 bleibt Fehler 5. V3 betrifft weitere Formularquellen, V5 die weiteren qualifizierten Zugriffspfade. |
| Diagnosen: Position, Include-Diagnose | Lexer-/Parser-/Semantikpfad trägt Originalpositionen. V6 betrifft die anschließende Linkerphase. |
| Objektgrammatik/-semantik: unbekanntes Objekt/Eigenschaft, Typkonflikt, TYPEOF, gleiche Controls | Bestehende Tests bestanden. V3/V5 verletzen den allgemeinen Modul-/Containervertrag trotz grüner Property-Beispiele. |
| Unterbrechung: Breakpoint, Inspektion, gleiche Zeile in zwei Modulen | Unabhängige Probe: MAIN passiert Zeile 10, LIB hält in Zeile 10; qualifizierte Array-/UDT-Inspektion liefert 7/8; Einzelschritt meldet Spalte 5; ERR/ERL bleiben 6/200. V1 lässt Breakpoints an ELSEIF aus. |
Erneut ausgeführt:
- `cargo test --workspace`: **437 bestanden, 0 fehlgeschlagen, 1 ignoriert**.
Golden-Generator nicht ausgeführt, keine Sollausgaben geändert.
- [Review-Proben](review-probes.rs): **1 bestanden, 6 fehlgeschlagen**.
Jede fehlgeschlagene Probe entspricht einem der sechs Befunde; mehrere
verwandte Reproduktionen werden innerhalb einer Probe gesammelt.
- Zusätzlich zeitlich begrenzte CLI-Proben für die Befunde; temporäre
Quellverzeichnisse anschließend entfernt.
- `cargo bench -p tb-vm --bench compile`: 508 Zeilen **0,54 ms**, 49.760 Zeilen
in 20 verbundenen Modulen **67 ms**; beide Budgets erfüllt.
- Dokumentation: **152/152 Opcodes**, Operanden-/Gesamtbreiten und **9/9
Containerabschnitte** gegen den aktuellen Code abgeglichen.
- `cargo fmt --all -- --check`, `openspec validate projektmodule-und-kompilat --strict`
und `git diff --check`: bestanden.
- Clippy nicht nochmals ausgeführt: keine Produktcodeänderung seit dem
erfolgreichen Clippy-Lauf der Implementierungsabnahme. Kein neuer
interaktiver Originalsystemvergleich und keine Windows-/Linux-Testmatrix.
## Review-Proben reproduzieren
Im Repository-Wurzelverzeichnis ausführen. Der temporäre Treiber hält die
noch roten Vertragsproben außerhalb der normalen Workspace-Suite; ihre
Erwartungen beschreiben das Sollverhalten. Exit-Code ist bis zur Behebung 101.
```sh
python3 - <<'PY'
from pathlib import Path
import json, subprocess, tempfile, os
root = Path.cwd()
with tempfile.TemporaryDirectory(prefix='tb-project-review-') as folder:
p = Path(folder)
manifest = '[package]\nname="tb-project-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-projektmodule-und-kompilat/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)
result = subprocess.run(['cargo', 'test', '--manifest-path', str(p / 'Cargo.toml'), '--offline', '--test', 'probes', '--', '--nocapture'], env={**os.environ, 'CARGO_TARGET_DIR': str(root / 'target/review-projektmodule')}, timeout=120)
raise SystemExit(result.returncode)
PY
```
**Abnahmeentscheidung:** V1V4 vor Archivierung beheben; V5/V6 ebenfalls in
die vollständige Umsetzung aufnehmen. Keine zusätzlichen Stilvorschläge.

View File

@@ -0,0 +1,266 @@
//! Unabhängige Vertragsproben; Ausführung mit dem temporären Treiber aus review.md.
use tb_frontend::{
forms::FormCatalog,
source::{SourceSegment, SourceUnit},
};
use tb_runtime::{host::CaptureHost, value::Value};
use tb_vm::{
bytecode::CompiledModule,
compile_project,
interp::{RunEvent, Vm},
};
fn units(files: &[(&str, &str)]) -> Vec<SourceUnit> {
files
.iter()
.map(|(name, code)| SourceUnit::new(name, &format!("{name}.bas"), code))
.collect()
}
fn compile(files: &[(&str, &str)]) -> Result<CompiledModule, Vec<tb_frontend::Diagnostic>> {
compile_project("APP", &units(files), &FormCatalog::default(), &[])
}
fn run(module: CompiledModule) -> (RunEvent, String) {
let bytes = module.to_tbc();
let loaded = CompiledModule::from_tbc(&bytes).unwrap();
assert_eq!(bytes, loaded.to_tbc());
let mut vm = Vm::new(loaded);
let event = vm.run(&mut CaptureHost::default());
(event, tb_runtime::snapshot::text(&vm.rt.screen))
}
#[test]
fn v1_zweige_und_schleifen_behalten_eigene_quellorte() {
let mut failures = vec![];
for (name, code, line) in [
(
"ELSEIF",
"IF 0 THEN\nPRINT 1\nELSEIF 1/0 THEN\nPRINT 2\nEND IF",
3,
),
("CASE", "SELECT CASE 1\nCASE 1/0\nPRINT 2\nEND SELECT", 2),
("NEXT", "FOR i%=32767 TO 32767\nPRINT 1\nNEXT", 3),
("LOOP", "DO\nPRINT 1\nLOOP UNTIL 1/0", 3),
] {
let (event, _) = run(compile(&[("MAIN", code)]).unwrap());
if !matches!(event, RunEvent::Error { line: found, .. } if found == line) {
failures.push(format!("{name}: erwartet Zeile {line}, erhalten {event:?}"));
}
}
let source = SourceUnit {
name: "MAIN".into(),
segments: vec![
SourceSegment {
file: "main.bas".into(),
first_line: 1,
text: "IF 0 THEN\nPRINT 1\n".into(),
},
SourceSegment {
file: "cond.bi".into(),
first_line: 1,
text: "ELSEIF 1/0 THEN\nPRINT 2\n".into(),
},
SourceSegment {
file: "main.bas".into(),
first_line: 4,
text: "END IF\n".into(),
},
],
};
let mut vm = Vm::new(compile_project("APP", &[source], &FormCatalog::default(), &[]).unwrap());
let event = vm.run(&mut CaptureHost::default());
if vm.current_file() != "cond.bi" {
failures.push(format!(
"Include: {event:?} aus {} statt cond.bi",
vm.current_file()
));
}
// Das gleiche Problem darf nicht nur durch Umbenennen der Fehlermeldung behoben werden.
let mut vm = Vm::new(
compile(&[("MAIN", "IF 0 THEN\nPRINT 1\nELSEIF 1 THEN\nPRINT 2\nEND IF")]).unwrap(),
);
vm.add_module_breakpoint(0, 3);
let event = vm.run(&mut CaptureHost::default());
if event != (RunEvent::Breakpoint { line: 3 }) {
failures.push(format!("Breakpoint ELSEIF: {event:?}"));
}
assert!(failures.is_empty(), "{}", failures.join("\n"));
}
#[test]
fn v2_importierte_deklarationen_behalten_kontext_und_abhaengigkeiten() {
let cases = [
(
"DEFINT",
"PRINT Doppelt(3)\nEND",
"DEFINT A-Z\nFUNCTION Doppelt(x)\nDoppelt=x*2\nEND FUNCTION",
" 6 \n",
),
(
"CONST",
"CONST A=3\nPRINT B\nEND",
"CONST A=3\nCONST B=A+1",
" 4 \n",
),
(
"TYPE",
"TYPE Inner\nx AS INTEGER\nEND TYPE\nDIM a AS Outer\na.i.x=3\nPRINT a.i.x\nEND",
"TYPE Inner\nx AS INTEGER\nEND TYPE\nTYPE Outer\ni AS Inner\nEND TYPE",
" 3 \n",
),
];
let mut failures = vec![];
for (name, main, lib, output) in cases {
match compile(&[("MAIN", main), ("LIB", lib)]) {
Err(e) => failures.push(format!("{name}: {e:?}")),
Ok(module) => {
let actual = run(module);
if actual != (RunEvent::Ended, output.into()) {
failures.push(format!("{name}: {actual:?}"));
}
}
}
}
assert!(failures.is_empty(), "{}", failures.join("\n"));
}
#[test]
fn v3_form_metabefehle_erzeugen_getrennte_formularobjekte() {
let module = compile(&[
(
"A",
"'$FORM\nCaption=\"a\"\nCALL SetupB\nPRINT Caption\nEND",
),
("B", "'$FORM\nSUB SetupB\nCaption=\"b\"\nEND SUB"),
])
.unwrap();
let names: Vec<_> = module.objects.iter().map(|o| o.name.clone()).collect();
let actual = run(module);
assert_eq!(
actual,
(RunEvent::Ended, "a\n".into()),
"Objekte: {names:?}"
);
}
#[test]
fn v4_common_behaelt_typidentitaet_und_initialisiert_arrays_einmal() {
let mut failures = vec![];
for (name, files, want) in [
(
"Suffixe",
vec![(
"MAIN",
"COMMON SHARED c%, c$\nc%=7\nc$=\"ok\"\nPRINT c%;c$\nEND",
)],
" 7 ok\n",
),
(
"Array",
vec![
("MAIN", "COMMON SHARED a%(2)\na%(1)=7\nCALL F\nEND"),
("LIB", "COMMON SHARED a%(2)\nSUB F\nPRINT a%(1)\nEND SUB"),
],
" 7 \n",
),
] {
match compile(&files) {
Err(e) => failures.push(format!("{name}: {e:?}")),
Ok(module) => {
let actual = run(module);
if actual != (RunEvent::Ended, want.into()) {
failures.push(format!("{name}: {actual:?}"));
}
}
}
}
assert!(failures.is_empty(), "{}", failures.join("\n"));
}
#[test]
fn v5_load_und_unload_loesen_den_expliziten_container_auf() {
use tb_frontend::forms::ObjectClass;
let mut catalog = FormCatalog::default();
for name in ["Form1", "Form2"] {
catalog.add(name, ObjectClass::Form, None, false);
catalog.add("Text1", ObjectClass::TextBox, Some(name), true);
}
let source = units(&[("MAIN", "LOAD Form2!Text1(3)\nForm2!Text1(3).Text=\"b\"\nPRINT Form2!Text1(3).Text\nUNLOAD Form2!Text1(3)\nEND")]);
let module = compile_project("APP", &source, &catalog, &[]).unwrap();
assert_eq!(run(module), (RunEvent::Ended, "b\n".into()));
}
#[test]
fn v6_linkerdiagnose_nennt_den_urspruenglichen_dateiort() {
let errors = compile(&[
("MAIN", "DECLARE SUB F(x%)\nCALL F(1)\nEND"),
("LIB", "SUB F(x$)\nEND SUB"),
])
.unwrap_err();
assert!(
errors
.iter()
.any(|d| d.message.contains("Parameter type mismatch")),
"{errors:?}"
);
assert!(
errors
.iter()
.all(|d| d.file.is_some() && d.pos.line > 0 && d.pos.column > 0),
"{errors:?}"
);
}
#[test]
fn modulbreakpoint_rundlauf_inspektion_und_numerische_erl_bleiben_getrennt() {
let main = format!(
"DIM a%(2)\nTYPE T\nx AS INTEGER\nEND TYPE\nDIM r AS T\na%(1)=7\nr.x=8\n{}CALL F\nEND",
"\n\nn%=1\n"
);
let lib = format!("SUB F\n{}200 ERROR 6\nEND SUB", "\n".repeat(8));
let module = compile(&[("MAIN", &main), ("LIB", &lib)]).unwrap();
let bytes = module.to_tbc();
let loaded = CompiledModule::from_tbc(&bytes).unwrap();
assert_eq!(bytes, loaded.to_tbc());
let mut vm = Vm::new(loaded);
vm.add_module_breakpoint(1, 10);
let mut host = CaptureHost::default();
assert_eq!(vm.run(&mut host), RunEvent::Breakpoint { line: 10 });
assert_eq!(vm.current_module(), 1);
assert_eq!(vm.current_file(), "LIB.bas");
assert!(matches!(
vm.inspect_element("MAIN!a%", &[1]),
Some(Value::Int(7))
));
assert!(matches!(
vm.inspect_field("MAIN!r", &[0]),
Some(Value::Int(8))
));
vm.remove_module_breakpoint(1, 10);
vm.set_step(true);
assert_eq!(vm.run(&mut host), RunEvent::Stepped { line: 10 });
assert_eq!(vm.current_source_pos().column, 5);
vm.set_step(false);
assert!(matches!(
vm.run(&mut host),
RunEvent::Error {
code: 6,
line: 10,
..
}
));
let source = format!("{}ERROR 6", "\n".repeat(41));
assert!(matches!(
run(compile(&[("MAIN", &source)]).unwrap()).0,
RunEvent::Error {
code: 6,
line: 42,
..
}
));
let module = compile(&[(
"MAIN",
"ON ERROR RESUME NEXT\n200 ERROR 6\nPRINT ERR;ERL\nEND",
)])
.unwrap();
assert_eq!(run(module), (RunEvent::Ended, " 6 200 \n".into()));
}

View File

@@ -0,0 +1,79 @@
# Verifikation: projektmodule-und-kompilat
Stand: 05.09.2026, Arbeitsbaum auf Basis von `58b1f62`.
**Keine offenen Befunde: 0 CRITICAL, 0 WARNING, 0 SUGGESTION.**
Die sechs Befunde des [ersten Reviews](review-initial.md) sind behoben.
Weitere bei der Nachprüfung reproduzierte Abweichungen wurden ebenfalls
korrigiert und mit Regressionen abgesichert. Der Change ist abnahmebereit.
| Dimension | Ergebnis |
| --- | --- |
| Vollständigkeit | 12/12 Tasks umgesetzt; alle 7 Requirements und 21 Delta-Szenarien abgeglichen. |
| Korrektheit | 453 Workspace-Tests bestanden, 0 fehlgeschlagen, 1 vorhandener Golden-Generator ignoriert. Die 7 unveränderten ursprünglichen Review-Proben bestehen auch im unabhängigen temporären Treiber. |
| Kohärenz | D1D4 erfüllt: physische Quellorte, getrennte Scopes, selbstständiges TBC 4 und dokumentierte Inline-Instruktionen. |
## Geschlossene Befunde
| Befund | Korrektur und Nachweis |
| --- | --- |
| V1: Zweig-/Schleifenorte | Parser und HIR erhalten ELSEIF-, CASE-, NEXT-, LOOP- und WEND-Positionen. Codegen emittiert die tatsächlichen Anweisungsgrenzen. Fehler, Breakpoints, WHILE-Rücksprung, LOOP-RESUME, NEXT-RESUME NEXT und Include-Enden in Zeile 42/Spalte 3 sind geprüft. Numerische ERL-Labels bleiben getrennt. |
| V2: Importkontext | Exportierte Signaturen erhalten die DEFtype-Typen ihres Ursprungs. Konstanten werden dort gefaltet, einschließlich transitiver Abhängigkeiten über drei Module. TYPE-Abhängigkeiten werden geordnet und bei abweichenden lokalen Layouts intern qualifiziert. Echte lokale Duplikate bleiben Fehler. |
| V3: `$FORM`-Identitäten | FRM- und `$FORM`-Objekte stehen vor jeder Modulübersetzung in einem gemeinsamen Katalog. Getrennte Captions, gegenseitige Referenzen und unterschiedliche Form_Load-Bindungen sind auch für gemischte FRM/BAS-Projekte nach TBC-Rundlauf geprüft. |
| V4: COMMON | HIR übergibt Block, vollständigen Variablenschlüssel, Elementtyp und Arraygrenzen an den Linker. Typen, Ränge und bekannte Grenzen werden geprüft. `CommonArr` initialisiert einmal und prüft spätere dynamische Grenzen ohne Zurücksetzen des Handles oder der Werte. Offene Arraydeklarationen und gerundete Grenzen bleiben unterstützt. |
| V5: LOAD/UNLOAD | Beide Anweisungen verwenden dieselbe explizite Containerauflösung und Indexprüfung wie andere Objektzugriffe. `Form2!Text1(3)` wird geladen, beschrieben, gelesen und entladen, auch wenn Form1 ebenfalls Text1 besitzt. |
| V6: Diagnosen | Der Linker gibt strukturierte Diagnosen an den ursprünglichen Deklarationen zurück; Source-ID, Datei, Zeile und Spalte bleiben erhalten. Signaturkonflikte, COMMON-Konflikte im Include sowie doppelte Module sind geprüft. |
Die erweiterten Proben fanden zusätzlich folgende inzwischen behobene
Abweichungen: transitive Konstantenimports, fremde TYPE-Layouts bei lokal
abweichenden Definitionen, prozedurübergreifendes Durchsickern von DEFtype,
Verwechslung typisierter Debuggernamen, Verwechslung von Formnamen mit
suffixdeklarierten Variablen und fehlende Literalpositionen in Diagnosen.
Letzteres ist durch `CALL F("wrong")` in `args.bi:42:10` abgesichert.
Auch Konflikte erst in der dritten COMMON-Deklaration werden erkannt.
Die [16 dauerhaften Regressionstests](../../../../crates/tb-vm/tests/project_regressions.rs)
enthalten die sieben ursprünglichen Proben mit unveränderten Erwartungen
sowie neun ergänzende Tests mit mehreren verwandten Fällen. Die ursprüngliche
[Probe-Datei](review-probes.rs) wurde nicht geändert. Es wurden keine Goldens
neu erzeugt und keine Fehlererwartungen abgeschwächt.
## Abgleich aller Requirements und Szenarien
| Requirement | Szenarien / Nachweise |
| --- | --- |
| Monomorpher Opcode-Satz | Gemischter Ausdruck und aufgelöste Namen: vorhandene HIR-/Codegentests; numerische Projektverknüpfung. Alle 153 Opcode-Kennungen, Operandenfolgen und Encodingbreiten gegen die Dokumentation geprüft. |
| TBC-Container | Bytegleicher Roundtrip; klare Ablehnung alter/unbekannter Versionen; vollständige Formularwerte und Designarrays. CLI-Projekttests entfernen sämtliche BAS-/BI-/FRM-/MAK-Quellen und führen das TBC selbstständig aus. |
| Quellorte | Fehler in physischer Zeile 42; Fehler in lib.bas:2; verschachtelte Includes; zusätzliche ausführbare Zweig-/Schleifengrenzen und Initialisierungen. |
| Benannte Objekte | Eigenschaften lesen/schreiben; keine Standardeigenschaft; Check1.Value=3 erzeugt Fehler 5; voneinander unabhängige Werte gleichnamiger Controls. Zwei FRM- und gemischte FRM/`$FORM`-Projekte geprüft. |
| Diagnostik | 1-basierte Datei-/Zeilen-/Spaltenangaben in Lexer, Parser, Semantik und Linker; Include-Fehler einschließlich Literalargumenten. |
| Objektgrammatik/-semantik | Unbekanntes Objekt und unbekannte Eigenschaft benennen; Eigenschaftstyp prüfen; TYPEOF; expliziter Form1/Form2-Container bei gleichnamigen Controls. Qualifiziertes LOAD/UNLOAD nutzt dieselbe Auflösung. |
| Unterbrechung/Inspektion | Modulbezogener Breakpoint; scalar-, array- und UDT-Inspektion; Fortsetzen und Einzelschritt. Gleiche physische Zeile in MAIN und LIB bleibt getrennt, explizite Typ-Suffixe unterscheiden Variablen. ERR/ERL bleiben 6/200. |
Die konkreten ursprünglichen Szenario-/Testnamen und weitere Containerproben
stehen im [Implementierungsnachweis](verification.md), den
[VM-Projekttests](../../../../crates/tb-vm/tests/project.rs) und den
[CLI-Projekttests](../../../../crates/tb-cli/tests/project.rs).
## Abschließende Prüfläufe
- `cargo test --workspace`: **453 bestanden, 0 fehlgeschlagen, 1 ignoriert**.
- Unabhängiger Treiber aus [review-initial.md](review-initial.md): **7 bestanden**.
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`: bestanden.
- `cargo fmt --all -- --check`: bestanden.
- `cargo bench -p tb-vm --bench compile`: 508 Zeilen **0,56 ms** (Budget 50 ms);
49.760 Zeilen in 20 verbundenen Modulen **77 ms** (Budget 1000 ms).
- Formatabgleich: **153/153 Opcodes**, Operandentypen und Gesamtbreiten;
**9/9 Abschnittskennungen** stimmen zwischen Writer, Reader und Dokumentation überein.
- `openspec validate projektmodule-und-kompilat --strict`: bestanden.
- `git diff --check`: bestanden.
Die Verifikation prüft den aktuellen Code und die gesamten Change-Artefakte
lokal und headless auf macOS. Ein neuer interaktiver Originalsystemvergleich
oder eine Windows-/Linux-Testmatrix war nicht Teil dieses Prüflaufs.
Die vier betroffenen Hauptspecs wurden am 05.09.2026 synchronisiert und
mit `openspec validate --specs --strict` validiert (15/15 bestanden).
Alle sieben Delta-Requirements stimmen vollständig mit den Hauptspecs
überein; alle zuvor vorhandenen Szenarien und unberührten Requirements
bleiben erhalten. Der Change ist unter
`openspec/changes/archive/2026-09-05-projektmodule-und-kompilat` archiviert.

View File

@@ -0,0 +1,23 @@
## 1. Quellen und Scopes
- [x] 1.1 Quell-/Modulidentitäten durch Include-Expansion und Frontend erhalten; verifizieren mit Compile- und Runtimefehlern aus lib.bas:2 und verschachtelten Includes.
- [x] 1.2 Form-/Prozedurscopes korrekt auflösen; verifizieren mit zwei Form_Load-Prozeduren, zwei Text1-Controls und unterschiedlichen Form1!Text1/Form2!Text1-Werten sowie echten Duplikaten im selben Scope.
## 2. Kompilat und Debugger
- [x] 2.1 Vollständige Forms-Anfangsdaten, Quelltabelle und Prozedursignaturen serialisieren; verifizieren durch bytegleichen Kompilat-Rundlauf und gleiche Ausführung inklusive Designzeit-Control-Arrays.
- [x] 2.2 Modulbezogene Breakpoints/Quellortmeldungen ergänzen; verifizieren mit identischen physischen Zeilennummern in zwei Modulen, Include-Fehlern, Einzelschritt und unverändertem ERR/ERL.
- [x] 2.3 CLI-run für TBC anschließen und Versionsgrenze anheben; verifizieren mit build, Entfernen aller Quellen, run des Kompilats und klarer Ablehnung inkompatibler Versionen.
## 3. Abnahme
- [x] 3.1 Container und vollständige Opcode-/Operandentabelle dokumentieren; verifizieren mit Format-/Opcode-Abgleich, cargo test --workspace und dem Compile-Budget.
- [x] 3.2 Delta-Specs vollständig gegen die erhaltenen Szenarien prüfen; verifizieren mit openspec validate projektmodule-und-kompilat --strict und git diff --check.
## 4. Reviewbefunde vollständig beheben
- [x] 4.1 V1: Physische Quellpositionen aller Zweige und Schleifenenden erhalten; Fehler, Breakpoints und RESUME prüfen.
- [x] 4.2 V2/V6: Importierte Deklarationen im Ursprungskontext auflösen und Linkdiagnosen an Originalstellen melden.
- [x] 4.3 V3/V5: Gemeinsame Formidentitäten und qualifiziertes LOAD/UNLOAD korrigieren.
- [x] 4.4 V4: Vollständige COMMON-Identitäten und kompatible einmalige Arrayinitialisierung sicherstellen.
- [x] 4.5 Unveränderte Reviewproben, ergänzende Nachbarfälle und sämtliche Change-Szenarien erneut prüfen; alle weiteren Befunde beheben.

View File

@@ -0,0 +1,106 @@
# Implementierungsnachweis — 05.09.2026
Change: `projektmodule-und-kompilat`, Ausgangscommit `58b1f62`.
**Abschließende Verifikation:** [review.md](review.md) bestätigt die Behebung
aller sechs ursprünglichen und aller zusätzlich reproduzierten Befunde.
Der [erste Review](review-initial.md) bleibt als historischer Nachweis erhalten.
Alle zwölf Tasks (sieben Implementierungs- und fünf Review-Aufgaben) sind
umgesetzt. F09, F10, F11 und F24 sind im Arbeitsbaum bearbeitet; die
Hauptspec-Synchronisierung und Archivierung sind am 05.09.2026 abgeschlossen. Die Abnahme
umfasst alle sieben Delta-Requirements mit ihren 21 Szenarien.
## Umsetzung
| Task / Befund | Umsetzung und Nachweis |
| --- | --- |
| 1.1 / F10 | `SourceUnit`/`SourceSegment` erhalten Modul, Datei und physische Zeile vor dem Parsen. Lexer- und Parserpositionen werden vor der Semantik den Originalquellen zugeordnet. CLI-Tests prüfen Compile-/Runtimefehler aus `lib.bas:2`, verschachtelten Includes und dem Codeabschnitt eines entfernten FRM. Auch leere Quellen funktionieren. |
| 1.2 / F09 | Module werden getrennt aufgelöst und danach numerisch verbunden. Lokale Prozeduren und Controls haben Vorrang, `Form!Control` sucht direkt im angegebenen Formular. Eltern-IDs ersetzen Namensvergleiche auch bei Frames, Menüs, Optionsgruppen und Geometrie. Zwei Form_Load-Prozeduren initialisieren ihre jeweiligen Text1-Controls unabhängig; echte SUB-/CONST-/TYPE-Duplikate im selben Modul bleiben Fehler. |
| 2.1 / F11 | TBC 4 enthält Module/Quellen, vollständige Parameter- und Rückgabetypen, Locals, Forms-Instanzen mit Eigenschaften, Designindizes und Eltern-IDs sowie das Startformular. `Vm::new` stellt diesen Anfangszustand her. Bytegleicher Rundlauf und Ausführung mit zwei Formularen und Designarrays 0/2 sind geprüft. |
| 2.2 / F10 | `Source` plus `Stmt` liefern Datei/Spalte/physische Zeile. `InitStmt` erhält dieselben Informationen für globale Initialisierungen, ohne vorzeitig Ereignisse zuzustellen. Breakpoints verwenden Modul-ID und Zeile. Einzelschritt, Variableninspektion und Fortsetzen bleiben möglich. Numerische Labels führen separat `SetErl`; DEF FN erhält den tatsächlichen Quellort. |
| 2.3 / F11 | `tbc run` lädt TBC direkt. Der CLI-Test baut ein Projekt, entfernt alle BAS-/BI-/FRM-/MAK-Dateien und vergleicht die Ausgabe des Kompilats mit der Quellausführung (`hello`, `world`, `7`). Ein zweiter Fall erhält nach Entfernen des FRM den Fehlerort `error.frm:6:1`. Versionen 1, 2, 3, 5 und 32767 werden ausdrücklich benannt und abgewiesen. |
| 3.1 / F24 | [TBVM-Format](../../../../docs/tbvm-design.md) dokumentiert alle neun Abschnitte und alle 153 Opcodes einzeln mit Operanden, Encodingbreiten und Kennungen. Der Compile-Benchmark übersetzt und verbindet nun tatsächlich ein Projekt mit 20 Modulen. |
| 3.2 | Alle Delta-Requirement-Blöcke behalten ihre bisherigen Szenarien. Neue Szenarien und die Implementierungsentscheidungen D1D4 wurden gegen die unten genannten Tests und Codepfade abgeglichen. OpenSpec- und Diff-Prüfung bestanden. |
## Projektgrenzen und ergänzende Regressionen
Der Projektlink versetzt Prozedur-, Slot-, TYPE-, String-, DATA- und
Sprungtabellenreferenzen. Hauptprogramminitialisierungen aller Mitglieder
laufen vor der ersten Ereigniszustellung; die übrigen Modulrümpfe folgen der
Projektreihenfolge. Eindeutige externe Prozeduren werden als Deklarationen
importiert, lokale Namen bleiben erhalten. Eindeutige fremde Konstanten und
TYPEs bleiben als Kompatibilitätsregel sichtbar. Es wird kein Quelltext zur
Unterdrückung von Duplikaten gelöscht.
Geprüft sind wiederholt eingebundene Konstanten, gleichnamige lokale SUBs,
modullokales SHARED, gemeinsame COMMON-Skalare und unterschiedliches OPTION
BASE. Modulhandler werden getrennt gespeichert: ON ERROR GOTO 0 in der
Bibliothek deaktiviert den Handler des Aufrufers nicht. Bestehende ERR-/ERL-
und RESUME-Korpustests bestehen unverändert.
Der Signaturtest übergibt ein INTEGER-Array, einen UDT und einen Skalar an
eine Funktion in einem anderen Modul. Er prüft Rückgabetyp, Array-/BYREF-
Merkmale, Ausgabe und Rückwirkung einer UDT-Feldänderung auf den Aufrufer.
Die dabei gefundene Inkonsistenz zwischen UDT-Argument und Parameter wurde
im gemeinsamen Semantikpfad behoben. Bekannte externe Dialogdeklarationen
funktionieren auch mit qualifizierten Prozedurnamen. ISAM-OPEN verwendet mit
`PushUdtId` eine explizit versetzbare TYPE-Referenz; der Test vergleicht sie
nach dem Rundlauf mit dem tatsächlichen UDT-Index.
Der Loader weist abgeschnittene Dateien an jedem Byteoffset, ungültige
Flags/Abschnittsgrößen, doppelte Abschnitte sowie ungültige Quell-, Modul-,
Prozedur- und Elternreferenzen ab. Inkonsistente Signaturen, doppelte
Anfangseigenschaften, falsche Property-Typen und abweichende Designindizes
werden vor dem VM-Start geprüft. Das ersetzt keinen vollständigen
Stackverifizierer für beliebigen fremden Bytecode.
## Requirement- und Szenarioabgleich
Die neuen ausführbaren Nachweise liegen in
[VM-Projekttests](../../../../crates/tb-vm/tests/project.rs) und
[CLI-Projekttests](../../../../crates/tb-cli/tests/project.rs).
Die folgende Tabelle führt auch die erhaltenen Szenarien auf; bestehende
Tests werden durch neue Mehrmodul- und Include-Proben ergänzt.
| Requirement | Szenarien und Belege |
| --- | --- |
| Monomorpher Opcode-Satz | Gemischter Ausdruck: `codegen::tests::ausdruck_monomorph_mit_conv`; aufgelöste Namen: `sema::tests::hir_slots_aufgeloest` und die numerisch verbundenen Projektaufrufe. Vollständigkeit der Dokumentation zusätzlich gegen das `instrs!`-Makro geprüft. |
| .tbc-Containerformat | Roundtrip: mehrere VM-Projekttests vergleichen die gesamten Bytes; unbekannte Version: CLI-Versionstests; Formularwerte: CLI-Ausgabe `hello` und `world` nach Entfernen sämtlicher Quellen. |
| Zeilentabelle für Fehlerortung | Physische Fehlerzeile: Stmt-/Source-Zuordnung und CLI-Fehlerproben; Projektbibliothek: `lib.bas:2:5`, Include: `inner.bi:2:5`; zusätzlich InitStmt-, DEF-FN- und FRM-Codepositionen. |
| Formulare und Steuerelemente als benannte Objekte | Lesen/Schreiben: bestehender VM-Test `objektzugriff_laeuft_ueber_objekt_und_eigenschaftsindex`; keine Standardeigenschaft: `sema::tests::eigenschaftstyp_schreibbarkeit_bang_und_hir_index`; Wertebereich: `forms::tests::defaults_bereich_und_implizites_laden` prüft Check1.Value = 3 → Fehler 5; unabhängige Werte: zwei Formulare mit Text1 und eigenem Form_Load im neuen Projekttest. |
| Diagnostik mit Vorbild-Meldungen | Exakte Position: SourcePos bleibt 1-basiert; neue Tests prüfen Datei, Zeile und Spalte. Include-Diagnose: sowohl direktes SourceSegment als auch verschachtelte CLI-Expansion liefern die ursprüngliche Position des Typfehlers. |
| Objektzugriffe in Grammatik und Semantik | Unbekanntes Objekt/Eigenschaft und Eigenschaftstyp: bestehende Semantiktests für Text9.Text, Text1.Farbe und Text1.Text = 5; TYPEOF: `typeof_form_control_und_form_metabefehl`; gleichnamige Controls: Form1!Text1/Form2!Text1 sowie lokale Text1-Zugriffe beider Form_Load-Rümpfe. |
| Unterbrechbare step()-Ausführung | Breakpoint und Inspektion: vorhandene VM-Tests plus neuer Modulbreakpoint; gleiche Zeile in zwei Modulen: Modul A passiert Zeile 2, Modul B hält dort. Fortsetzen im Einzelschritt erhält `nested.bi:2`, physische Spalte 5 und getrenntes ERL = 200. |
## Ausgeführte Abnahme
- `cargo test --workspace`: **453 bestanden, 0 fehlgeschlagen, 1 ignoriert**.
Der ignorierte Golden-Generator wurde nicht ausgeführt; Sollausgaben blieben unverändert.
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`: bestanden.
- `cargo fmt --all -- --check`: bestanden.
- `cargo bench -p tb-vm --bench compile`: 508 Zeilen **0,56 ms** (Budget 50 ms);
49.760 Zeilen in 20 verbundenen Modulen **77 ms** (Budget 1000 ms),
335.421 Instruktionen. Release-Messung auf diesem Rechner.
- Formatabgleich: **153/153 Opcodezeilen** einschließlich Operandentypen und
Bytebreiten sowie **9/9 Abschnittskennungen** gegen Writer/Reader abgeglichen.
- `openspec validate projektmodule-und-kompilat --strict`: bestanden.
- `git diff --check`: bestanden.
Die Abnahme ist eine lokale Code-/Testprüfung auf macOS; sie ist kein neuer
interaktiver Originalsystemvergleich und keine Windows-/Linux-Testmatrix.
## Reviewkorrekturen
Die ursprünglichen sieben Reviewproben bestehen unverändert, sowohl im
separaten Treiber als auch in der Workspace-Suite. Die dauerhafte Datei
`crates/tb-vm/tests/project_regressions.rs` ergänzt sie um neun Tests mit
verwandten Fällen. [review.md](review.md) ordnet die Korrekturen V1V6 und
alle zusätzlich reproduzierten Abweichungen den Nachweisen zu.
`CommonArr` (`0x3B`) initialisiert gemeinsame Arrays einmal und prüft spätere
Laufzeitgrenzen auf Kompatibilität; vorab bekannte Konflikte meldet der
Linker an der ursprünglichen COMMON-Deklaration. Die neue Instruktion ist
in TBC 4 serialisiert, validiert und vollständig dokumentiert. Typ-Suffixe
bleiben in Debugger-Slotnamen erhalten. AST-Literale und sämtliche ausführbaren
Zweig-/Schleifenteile tragen ihre tatsächlichen Quellpositionen.

View File

@@ -1,15 +0,0 @@
## 1. Quellen und Scopes
- [ ] 1.1 Quell-/Modulidentitäten durch Include-Expansion und Frontend erhalten; verifizieren mit Compile- und Runtimefehlern aus lib.bas:2 und verschachtelten Includes.
- [ ] 1.2 Form-/Prozedurscopes korrekt auflösen; verifizieren mit zwei Form_Load-Prozeduren, zwei Text1-Controls und unterschiedlichen Form1!Text1/Form2!Text1-Werten sowie echten Duplikaten im selben Scope.
## 2. Kompilat und Debugger
- [ ] 2.1 Vollständige Forms-Anfangsdaten, Quelltabelle und Prozedursignaturen serialisieren; verifizieren durch bytegleichen Kompilat-Rundlauf und gleiche Ausführung inklusive Designzeit-Control-Arrays.
- [ ] 2.2 Modulbezogene Breakpoints/Quellortmeldungen ergänzen; verifizieren mit identischen physischen Zeilennummern in zwei Modulen, Include-Fehlern, Einzelschritt und unverändertem ERR/ERL.
- [ ] 2.3 CLI-run für TBC anschließen und Versionsgrenze anheben; verifizieren mit build, Entfernen aller Quellen, run des Kompilats und klarer Ablehnung inkompatibler Versionen.
## 3. Abnahme
- [ ] 3.1 Container und vollständige Opcode-/Operandentabelle dokumentieren; verifizieren mit Format-/Opcode-Abgleich, cargo test --workspace und dem Compile-Budget.
- [ ] 3.2 Delta-Specs vollständig gegen die erhaltenen Szenarien prüfen; verifizieren mit openspec validate projektmodule-und-kompilat --strict und git diff --check.