04 — Fehlerstrategie fuer kaputte Mods #5

Closed
opened 2026-08-11 13:13:24 +00:00 by RDietermann · 1 comment
Owner

Teil der Map #1 · Type: wayfinder:grilling · Blocked by: #4

Was passiert bei kaputtem Mod-TOML, und wie sieht das in Rust aus? Explizites Rust-Lernticket: heute panickt parse().

Volle Fragestellung (kanonisch): .scratch/rustkeep-1.0/issues/04-fehlerstrategie.md

Teil der Map #1 · **Type: `wayfinder:grilling`** · **Blocked by: #4** Was passiert bei kaputtem Mod-TOML, und wie sieht das in Rust aus? Explizites Rust-Lernticket: heute panickt parse(). Volle Fragestellung (kanonisch): `.scratch/rustkeep-1.0/issues/04-fehlerstrategie.md`
RDietermann added the wayfinder:grilling label 2026-08-11 13:13:24 +00:00
Author
Owner

Aufgeloest in 145b82b. Kanonische Fassung: .scratch/rustkeep-1.0/issues/04-fehlerstrategie.md

Zwei Klassen, zwei Einheiten

Syntax ist ein Datei-Fehler, alles Semantische ein Eintrags-Fehler.

Das ist nicht gratis: toml::from_str mit items: Vec<Item> scheitert komplett, sobald ein einziger Eintrag ein kaputtes Feld hat — das Versprechen aus #4 waere also genau dann gebrochen, wenn 200 Gegenstaende in einer Datei stehen. Deshalb zweistufig: erst Vec<Spanned<toml::Value>> je Tabelle, dann jeder Eintrag einzeln in seinen Typ. Etwa zehn Zeilen. Kaputte TOML-Syntax reisst weiterhin die ganze Datei mit — da kommt der Parser nicht weiter.

Harte Fehler — genau drei

depends nicht installiert, depends-Reihenfolge verletzt, core nicht gefunden. Alle drei: stderr und exit(1), das TUI startet gar nicht erst.

core ist sonst kein Sonderfall — ein kaputter Eintrag darin ist eine Warnung wie ueberall, sonst waere die Privilegierung wieder da, die #4 abgeschafft hat. Abgesichert wird es durch einen Test statt durch Laufzeitlogik (siehe unten). Ein nicht schreibbares Log ist ausdruecklich kein harter Fehler.

Warnungen

Waehrend des Ladens in einem Vec<String> gesammelt, danach nach data_dir()/rustkeep/logs/load-20260812-112305.log. Die letzten zehn bleiben liegen, aeltere werden beim Schreiben geloescht. Sauberer Lauf legt keine Datei an.

Auf dem Startbildschirm steht eine Zeile mit Anzahl und Dateiname — kein Report-Screen, das kann ein Texteditor besser. Keine Schweregrade: jeder Fall ist "Warnung, verworfen".

Meldungsformat

meinmod/items.toml:42: core:iron_sword — unknown field `base_pric`

Mod-ID vorne, weil sie bei zwoelf Mods die einzige Angabe ist, mit der ein Spieler weiss, wen er anschreiben muss. toml::de::Error liefert span() und message(), aber keine Zeile — die ist input[..span.start].lines().count(). Keine Spalte. Eintrag ohne lesbare id heisst nach seiner Position: items[3].

Rust-Seite

Handgeschriebenes enum LoadError mit drei Varianten und eigenem impl Display. Kein thiserror (Proc-Macro-Dependency fuer zehn gesparte Zeilen match — und das Schreiben ist der Lernzweck), kein anyhow (der Fehlertyp ist hier gerade nicht egal), kein impl std::error::Error, solange niemand Box<dyn Error> braucht.

fn load_mods() -> Result<(Registries, Vec<String>), LoadError>

Warnungen als zweiter Rueckgabewert, nicht als Feld in Registries — Diagnose gehoert nicht in die Spieldaten. Die Result-Kette endet vor main: eprintln!("{e}") plus exit(1), weil main() -> Result<..> ueber Debug druckt.

Panic-Grenze ist die Datenherkunft: Alles aus einer TOML ist Result, alles aus dem eigenen Code darf panicken. unwrap() auf Modder-Daten ist ausnahmslos falsch — genau das tut items.rs::parse() heute.

Check

Ein #[test], der mods/core/ laedt und auf null Warnungen prueft. Ein kaputtes Kernspiel faellt damit beim cargo test auf statt beim Spieler.

Folgen

  • #12 (11 UI-Geruest) erbt die Startbildschirm-Zeile — eine Zeile, kein Screen
  • Code: items.rs::parse() verliert sein panic!, main() bekommt stderr-plus-exit, logs/-Verwaltung kommt dazu
**Aufgeloest** in 145b82b. Kanonische Fassung: `.scratch/rustkeep-1.0/issues/04-fehlerstrategie.md` ### Zwei Klassen, zwei Einheiten **Syntax ist ein Datei-Fehler, alles Semantische ein Eintrags-Fehler.** Das ist nicht gratis: `toml::from_str` mit `items: Vec<Item>` scheitert komplett, sobald ein einziger Eintrag ein kaputtes Feld hat — das Versprechen aus #4 waere also genau dann gebrochen, wenn 200 Gegenstaende in einer Datei stehen. Deshalb zweistufig: erst `Vec<Spanned<toml::Value>>` je Tabelle, dann jeder Eintrag einzeln in seinen Typ. Etwa zehn Zeilen. Kaputte TOML-Syntax reisst weiterhin die ganze Datei mit — da kommt der Parser nicht weiter. ### Harte Fehler — genau drei `depends` nicht installiert, `depends`-Reihenfolge verletzt, `core` nicht gefunden. Alle drei: stderr und `exit(1)`, das TUI startet gar nicht erst. `core` ist sonst **kein Sonderfall** — ein kaputter Eintrag darin ist eine Warnung wie ueberall, sonst waere die Privilegierung wieder da, die #4 abgeschafft hat. Abgesichert wird es durch einen Test statt durch Laufzeitlogik (siehe unten). Ein nicht schreibbares Log ist ausdruecklich kein harter Fehler. ### Warnungen Waehrend des Ladens in einem `Vec<String>` gesammelt, danach nach `data_dir()/rustkeep/logs/load-20260812-112305.log`. Die letzten zehn bleiben liegen, aeltere werden beim Schreiben geloescht. Sauberer Lauf legt keine Datei an. Auf dem Startbildschirm steht **eine Zeile** mit Anzahl und Dateiname — kein Report-Screen, das kann ein Texteditor besser. Keine Schweregrade: jeder Fall ist "Warnung, verworfen". ### Meldungsformat ``` meinmod/items.toml:42: core:iron_sword — unknown field `base_pric` ``` Mod-ID vorne, weil sie bei zwoelf Mods die einzige Angabe ist, mit der ein Spieler weiss, wen er anschreiben muss. `toml::de::Error` liefert `span()` und `message()`, aber keine Zeile — die ist `input[..span.start].lines().count()`. Keine Spalte. Eintrag ohne lesbare `id` heisst nach seiner Position: `items[3]`. ### Rust-Seite Handgeschriebenes `enum LoadError` mit drei Varianten und eigenem `impl Display`. Kein `thiserror` (Proc-Macro-Dependency fuer zehn gesparte Zeilen `match` — und das Schreiben ist der Lernzweck), kein `anyhow` (der Fehlertyp ist hier gerade nicht egal), kein `impl std::error::Error`, solange niemand `Box<dyn Error>` braucht. ```rust fn load_mods() -> Result<(Registries, Vec<String>), LoadError> ``` Warnungen als zweiter Rueckgabewert, nicht als Feld in `Registries` — Diagnose gehoert nicht in die Spieldaten. Die `Result`-Kette endet **vor** `main`: `eprintln!("{e}")` plus `exit(1)`, weil `main() -> Result<..>` ueber `Debug` druckt. **Panic-Grenze ist die Datenherkunft:** Alles aus einer TOML ist `Result`, alles aus dem eigenen Code darf panicken. `unwrap()` auf Modder-Daten ist ausnahmslos falsch — genau das tut `items.rs::parse()` heute. ### Check Ein `#[test]`, der `mods/core/` laedt und auf **null Warnungen** prueft. Ein kaputtes Kernspiel faellt damit beim `cargo test` auf statt beim Spieler. ### Folgen - #12 (11 UI-Geruest) erbt die Startbildschirm-Zeile — eine Zeile, kein Screen - Code: `items.rs::parse()` verliert sein `panic!`, `main()` bekommt stderr-plus-exit, `logs/`-Verwaltung kommt dazu
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RDietermann/rustkeep#5