Nacharbeiten aus M1b für die nächsten Pläne #5

Open
opened 2026-10-01 11:40:21 +00:00 by steven · 0 comments
Owner

Die Abschlussprüfung von M1b (#4) hat Brücke und Hülle mit Korrekturen für zusammenführbar erklärt. Die Korrekturen sind im Branch erledigt. Diese Punkte wurden bewusst verschoben, weil sie erst mit den nächsten Plänen wichtig werden oder nur Kleinigkeiten sind. Jeder Plan übernimmt seine Punkte in seine Tasks. Die offenen M1c-Punkte aus #2 gelten weiter.

Für M1c (Gleichschritt im Netz)

  • Gäste starten über World::from_snapshot mit einem eigenen Einstieg in der Brücke. start_loaded meldet alle Spieler ab und würde die Welten von Host und Gast trennen.
  • join_refused nennt keinen Schlüssel, und die Hülle wertet es nicht aus. Ein abgelehnter lokaler Beitritt hinterlässt heute eine Sitzung, in der Graben still nichts bewirkt. In M1c (#9) nennt das Ereignis den Schlüssel; die Auswertung in der Hülle ist nach #8 übernommen.
  • TickClock verwirft nach einem Ruckler den Rest, und die Pause hält nur die eigene Welt an. Beides muss einem gemeinsamen Takt weichen; Pause gibt es nur im Solospiel (Konzept 5).
  • Zwei Instanzen auf einem Rechner teilen sich user:// und damit Spielerschlüssel und Spielstand. Der Zwei-Instanzen-Test von Meilenstein 1 braucht einen Speicherort pro Instanz, zum Beispiel storage_dir aus einem Kommandozeilenargument.
  • Die Reichweite der Spitzhacke prüft nur die sendende Hülle. Der Kern kann sie nicht prüfen, solange Figuren außerhalb des Gleichschritts laufen. Dieses Vertrauensmodell aufschreiben. Steht jetzt in CLAUDE.md; die Bestätigung durch Steven steht in #8.
  • Die Brücke sammelt Befehle unbegrenzt in pending (siehe auch den Punkt „Befehle pro Spieler und Takt begrenzen" in #2). Die Grenze muss stehen, bevor Befehle von anderen Rechnern ankommen.
  • Vorübergehende Dateifehler gelten heute als dauerhaft. player_key() legt bei einem Lesefehler einen neuen Schlüssel an und überschreibt player.key; die Tasche bleibt dann am alten Schlüssel. read_save() liefert bei einem Öffnungsfehler leere Bytes, und _start_from_save legt einen guten Stand beiseite. Lösung: Schlüssel nur anlegen, wenn die Datei fehlt; bei leeren Bytes FileAccess.get_open_error() prüfen und melden, statt zu überschreiben oder beiseitezulegen.
  • Den Panik-Pfad der Brücke (catch_unwind, defekte Sitzung, leere Bytes) automatisch testen: die Logik in eine Funktion ohne Godot-Typen auslagern und in Rust prüfen.

Vor M2 (erste echte Regeln)

  • Aufzeichnung nach einer Kern-Panik oder einem Absturz. Heute entsteht dann keine Aufzeichnung, obwohl Konzept 7.3 verspricht, dass sich ein Fehler aus einem Spieltest genau nachstellen lässt.
    • Eine Kernmethode, die die Aufzeichnung ohne Prüfung des Endzustands kodiert (Kennzeichen im Format, RECORDING_VERSION erhöhen). recording_bytes() liefert sie bei defekter Sitzung; save() bleibt leer. Das Abspielen löst die Panik im selben Takt wieder aus.
    • Bei jedem automatischen Speichern eine Aufzeichnungsdatei pro Sitzung über eine temporäre Datei neu schreiben, damit ein Absturz höchstens zwei Minuten Befehle kostet.
  • Ein kleines Werkzeug, das eine Aufzeichnung aus einem Spieltest abspielt (zum Beispiel ein Beispielprogramm des Kerns mit Recording::verify), und eine Zeile dazu in CLAUDE.md. Im Fragebogen erwähnen, dass eine Aufzeichnung die Welt abspielt, nicht den Weg der Figur.
  • Die Grenze für Wartezeiten in check_restorable hängt an DIG_COOLDOWN_TICKS. Sobald es längere Wartezeiten gibt, in den Skript-Tests nach jedem Schritt from_snapshot(to_snapshot()) prüfen.
  • set_aside_save ersetzt ein älteres world.grw.broken. Beiseitegelegte Stände eindeutig benennen, weil Formatwechsel das Beiseitelegen bald zum Normalfall machen.

Hülle und Spielgefühl

  • Kein Test lässt die Figur gegen eine Wand laufen; fits ist an der nahen Kante nicht direkt getestet.
  • Avatar.walk begrenzt die Länge von direction nicht. Heute unschädlich, weil Input.get_vector höchstens Länge 1 liefert; limit_length(1.0) ergänzen, sobald ein anderer Aufrufer dazukommt.
  • Eine blockierte Achse wird übersprungen, statt die Figur an die Wand zu setzen; der Abstand zur Wand hängt von der Bildzeit ab. Frage 1 des Spieltests klärt, ob das stört.
  • Pause- und Stopp-Hinweis verschwinden nach der nächsten Meldung. Der Stopp-Zustand sollte stehen bleiben; nach SIMULATION_STOPPED läuft die Schleife im selben Bild weiter.
  • _save_blocked fällt nur nach erfolgreichem Laden. Wird das Hindernis außen entfernt und ein späteres F9 legt den Stand beiseite, bleibt das Speichern trotzdem gesperrt. Lösung: _save_blocked = aside.is_empty().
  • play.bat schließt die Konsole nach einem Absturz des Spiels. Den Exit-Code von godot --path game prüfen und mit einer Meldung anhalten.

Prüfwerkzeuge

  • Jeder Prüflauf dreht die Log-Dateien im Benutzerordner weiter (Godot behält fünf). Ein Absturz-Log aus einem Spieltest ist nach wenigen Prüfläufen weg. Prüfläufen eine eigene Log-Datei geben (--log-file) oder debug/file_logging/max_log_files erhöhen.
  • Kein Test bemerkt, wenn core/clippy.toml fehlt.
  • SaveStore.recordings() liest den Ordner recordings/, ohne zu prüfen, ob es ihn gibt; Godot meldet dann einen Engine-Fehler. Im Spielablauf unerreichbar, weil write_recording den Ordner vorher anlegt. Absichern, bevor ein neuer Aufrufer dazukommt, zum Beispiel ein Menü in M1c.
  • Testlücken der Hülle: eine fehlende Zeile in texts.csv, install() von Texten und Tasten, die Tastenbelegung selbst, keine Datei für eine leere Aufzeichnung.
  • Testlücken in test_main.gd: das Entfernen von InputSetup.install(), eine falsche Taktrate, ein fehlendes is_walkable oder der Schutz bei defekter Sitzung fielen nicht auf. Die Grenze tick() <= 5 genau als 1 + TickClock.MAX_TICKS_PER_FRAME schreiben.
  • Der Testläufer hat kein Zeitlimit pro Test.
  • Der Modulkommentar von core/tests/forbidden_apis.rs behauptet noch, Clippy fange gruppierte Importe allgemein ab; Clippy kennt nur die gelisteten Pfade (in core/clippy.toml schon berichtigt).
  • Der Test test_a_save_that_cannot_be_moved_into_place_keeps_the_previous_one setzt die Dateifreigaben von Windows voraus (eine offene Datei lässt sich nicht verschieben). Sobald eine andere Plattform dazukommt, braucht er eine Plattformabfrage.
Die Abschlussprüfung von M1b (#4) hat Brücke und Hülle mit Korrekturen für zusammenführbar erklärt. Die Korrekturen sind im Branch erledigt. Diese Punkte wurden bewusst verschoben, weil sie erst mit den nächsten Plänen wichtig werden oder nur Kleinigkeiten sind. Jeder Plan übernimmt seine Punkte in seine Tasks. Die offenen M1c-Punkte aus #2 gelten weiter. ### Für M1c (Gleichschritt im Netz) - [x] Gäste starten über `World::from_snapshot` mit einem eigenen Einstieg in der Brücke. `start_loaded` meldet alle Spieler ab und würde die Welten von Host und Gast trennen. - [x] `join_refused` nennt keinen Schlüssel, und die Hülle wertet es nicht aus. Ein abgelehnter lokaler Beitritt hinterlässt heute eine Sitzung, in der Graben still nichts bewirkt. In M1c (#9) nennt das Ereignis den Schlüssel; die Auswertung in der Hülle ist nach #8 übernommen. - [x] `TickClock` verwirft nach einem Ruckler den Rest, und die Pause hält nur die eigene Welt an. Beides muss einem gemeinsamen Takt weichen; Pause gibt es nur im Solospiel (Konzept 5). - [x] Zwei Instanzen auf einem Rechner teilen sich `user://` und damit Spielerschlüssel und Spielstand. Der Zwei-Instanzen-Test von Meilenstein 1 braucht einen Speicherort pro Instanz, zum Beispiel `storage_dir` aus einem Kommandozeilenargument. - [x] Die Reichweite der Spitzhacke prüft nur die sendende Hülle. Der Kern kann sie nicht prüfen, solange Figuren außerhalb des Gleichschritts laufen. Dieses Vertrauensmodell aufschreiben. Steht jetzt in `CLAUDE.md`; die Bestätigung durch Steven steht in #8. - [x] Die Brücke sammelt Befehle unbegrenzt in `pending` (siehe auch den Punkt „Befehle pro Spieler und Takt begrenzen" in #2). Die Grenze muss stehen, bevor Befehle von anderen Rechnern ankommen. - [x] Vorübergehende Dateifehler gelten heute als dauerhaft. `player_key()` legt bei einem Lesefehler einen neuen Schlüssel an und überschreibt `player.key`; die Tasche bleibt dann am alten Schlüssel. `read_save()` liefert bei einem Öffnungsfehler leere Bytes, und `_start_from_save` legt einen guten Stand beiseite. Lösung: Schlüssel nur anlegen, wenn die Datei fehlt; bei leeren Bytes `FileAccess.get_open_error()` prüfen und melden, statt zu überschreiben oder beiseitezulegen. - [x] Den Panik-Pfad der Brücke (`catch_unwind`, defekte Sitzung, leere Bytes) automatisch testen: die Logik in eine Funktion ohne Godot-Typen auslagern und in Rust prüfen. ### Vor M2 (erste echte Regeln) - [ ] Aufzeichnung nach einer Kern-Panik oder einem Absturz. Heute entsteht dann keine Aufzeichnung, obwohl Konzept 7.3 verspricht, dass sich ein Fehler aus einem Spieltest genau nachstellen lässt. - Eine Kernmethode, die die Aufzeichnung ohne Prüfung des Endzustands kodiert (Kennzeichen im Format, `RECORDING_VERSION` erhöhen). `recording_bytes()` liefert sie bei defekter Sitzung; `save()` bleibt leer. Das Abspielen löst die Panik im selben Takt wieder aus. - Bei jedem automatischen Speichern eine Aufzeichnungsdatei pro Sitzung über eine temporäre Datei neu schreiben, damit ein Absturz höchstens zwei Minuten Befehle kostet. - [ ] Ein kleines Werkzeug, das eine Aufzeichnung aus einem Spieltest abspielt (zum Beispiel ein Beispielprogramm des Kerns mit `Recording::verify`), und eine Zeile dazu in CLAUDE.md. Im Fragebogen erwähnen, dass eine Aufzeichnung die Welt abspielt, nicht den Weg der Figur. - [ ] Die Grenze für Wartezeiten in `check_restorable` hängt an `DIG_COOLDOWN_TICKS`. Sobald es längere Wartezeiten gibt, in den Skript-Tests nach jedem Schritt `from_snapshot(to_snapshot())` prüfen. - [ ] `set_aside_save` ersetzt ein älteres `world.grw.broken`. Beiseitegelegte Stände eindeutig benennen, weil Formatwechsel das Beiseitelegen bald zum Normalfall machen. ### Hülle und Spielgefühl - [ ] Kein Test lässt die Figur gegen eine Wand laufen; `fits` ist an der nahen Kante nicht direkt getestet. - [ ] `Avatar.walk` begrenzt die Länge von `direction` nicht. Heute unschädlich, weil `Input.get_vector` höchstens Länge 1 liefert; `limit_length(1.0)` ergänzen, sobald ein anderer Aufrufer dazukommt. - [ ] Eine blockierte Achse wird übersprungen, statt die Figur an die Wand zu setzen; der Abstand zur Wand hängt von der Bildzeit ab. Frage 1 des Spieltests klärt, ob das stört. - [ ] Pause- und Stopp-Hinweis verschwinden nach der nächsten Meldung. Der Stopp-Zustand sollte stehen bleiben; nach `SIMULATION_STOPPED` läuft die Schleife im selben Bild weiter. - [ ] `_save_blocked` fällt nur nach erfolgreichem Laden. Wird das Hindernis außen entfernt und ein späteres F9 legt den Stand beiseite, bleibt das Speichern trotzdem gesperrt. Lösung: `_save_blocked = aside.is_empty()`. - [ ] `play.bat` schließt die Konsole nach einem Absturz des Spiels. Den Exit-Code von `godot --path game` prüfen und mit einer Meldung anhalten. ### Prüfwerkzeuge - [ ] Jeder Prüflauf dreht die Log-Dateien im Benutzerordner weiter (Godot behält fünf). Ein Absturz-Log aus einem Spieltest ist nach wenigen Prüfläufen weg. Prüfläufen eine eigene Log-Datei geben (`--log-file`) oder `debug/file_logging/max_log_files` erhöhen. - [ ] Kein Test bemerkt, wenn `core/clippy.toml` fehlt. - [ ] `SaveStore.recordings()` liest den Ordner `recordings/`, ohne zu prüfen, ob es ihn gibt; Godot meldet dann einen Engine-Fehler. Im Spielablauf unerreichbar, weil `write_recording` den Ordner vorher anlegt. Absichern, bevor ein neuer Aufrufer dazukommt, zum Beispiel ein Menü in M1c. - [ ] Testlücken der Hülle: eine fehlende Zeile in `texts.csv`, `install()` von Texten und Tasten, die Tastenbelegung selbst, keine Datei für eine leere Aufzeichnung. - [ ] Testlücken in `test_main.gd`: das Entfernen von `InputSetup.install()`, eine falsche Taktrate, ein fehlendes `is_walkable` oder der Schutz bei defekter Sitzung fielen nicht auf. Die Grenze `tick() <= 5` genau als `1 + TickClock.MAX_TICKS_PER_FRAME` schreiben. - [ ] Der Testläufer hat kein Zeitlimit pro Test. - [ ] Der Modulkommentar von `core/tests/forbidden_apis.rs` behauptet noch, Clippy fange gruppierte Importe allgemein ab; Clippy kennt nur die gelisteten Pfade (in `core/clippy.toml` schon berichtigt). - [ ] Der Test `test_a_save_that_cannot_be_moved_into_place_keeps_the_previous_one` setzt die Dateifreigaben von Windows voraus (eine offene Datei lässt sich nicht verschieben). Sobald eine andere Plattform dazukommt, braucht er eine Plattformabfrage.
steven added this to the M1 Fundament milestone 2026-10-01 11:40:21 +00:00
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: steven/Grovewright#5