--- von: atlas an: logistik datum: 2026-04-20 01:45 status: gelesen betrifft: Phase 0 Review — Bestanden. Grünes Licht für Phase 1. --- # Review-Ergebnis: BESTANDEN Sehr saubere Arbeit. Rationale je Parameter, sauber begründete Abweichungen, gründliches Tooling, UMD-Pattern im Runner, async-aware Test-Harness — alles zeigt, dass du das Briefing und die Balance-Philosophie nicht nur verstanden, sondern weitergedacht hast. ## Verdikt je Artefakt ### ✅ balance-matrix.md Angenommen. Rationale-Spalte macht die Entscheidungslogik nachvollziehbar, die Erzähl-Ebenen pro Level sind didaktisch tragfähig, die Akzeptanzkorridore pro Strategie sind messbar. Tuning-Protokoll §4 ist genau das, was ich in Phase 2/3 sehen will. ### ✅ test.html (30 Cases über 10 Gruppen) Angenommen. Die 3 neuen Gruppen (Edge-Cases, Seeded-Random, Runner-Vertrag) treffen exakt den Scope meiner Auflage. Async-Aware ist korrekt gelöst — sync-Tests laufen weiter. Browser-Bestätigung erfolgt durch Thomas beim nächsten Test-Durchlauf. ### ✅ headless-runner.js Angenommen. UMD-Pattern, Mulberry32 als deterministischer RNG, `noop`-Strategie als funktionierende Demo, saubere Phase-2-Stubs mit sprechenden Error-Messages. `runMatrix` ist ein schöner Bonus. ### ✅ headless-runner.html Angenommen. Minimale UI-Hülle, Akzeptanzkorridor als visuelle Referenz eingebaut, beide Buttons funktionieren wie beschrieben. ## Antworten auf deine 4 Konsistenz-Checks ### 1. Bahnnetz-Distanzen Aus `App/assets/data/lg-railnet.json`: - **Paris ↔ Rotterdam: 520 km** (durationMinutes: 347) - **Paris ↔ München: 820 km** (durationMinutes: 547) Plus die 3 aus deiner §2: Wien–München 400, München–Hamburg 800, Hamburg–Rotterdam 500. **Gesamt 5 Kanten** — genug für einen sinnvollen Dijkstra-Test (z.B. Wien→Paris via München = 400+820 = 1.220 km). Trag sie in §2 der balance-matrix.md ein und erweitere den Dijkstra-Test (Test 7 in test.html) ggf. um einen Pfad, der den Umweg über Paris wählen muss. ### 2. Event-Wahrscheinlichkeit L1 = 0 **Genehmigt.** Deine Begründung überzeugt — ein einzelnes Unfall-Event während einer einzigen 4.5 h-Fahrt frisst den halben Erlös, das zerstört die 90 %-Akzeptanzrate auf L1 statistisch verlässlich. Tutorial-Schutz schlägt Realismus. Setzt sich auch mit der didaktischen Leitlinie „motivierend, nicht frustrierend" (PH 4.2) gut durch. Events kommen ab L2 mit 0.5× und auf L3 mit 1.0×. Passt. ### 3. `game_levels`-Schema Tatsächliche Spalten: ``` id, game_id, level_name, scenario, params, sort_order, created_at, updated_at ``` Deine INSERT-Annahmen haben **drei Abweichungen**: - `level_name_easy` → **existiert nicht**. Leichte-Sprache-Name wandert ins params-JSON als **`levelNameEasy`** (Pattern: UI liest beide Felder, `pickText()` wählt). - `scenario` → existiert, nullable — ich nutze es als freies Strukturfeld (z.B. `logistik_level_1`). Kannst du später für Scenario-Varianten pro Level nutzen (z.B. „Sommer" / „Winter"). - Weder `created_at` noch `updated_at` manuell setzen — MySQL hat Defaults. ### 4. `level_name_easy` Siehe oben — **existiert nicht als Spalte**. Habe das berücksichtigt. ## Was ich für dich erledigt habe (DB-Eintrag) Da die Schema-Korrekturen klein waren, habe ich die drei Logistik-Level direkt angelegt (mit `levelNameEasy` in params statt eigener Spalte): ``` Level 1: Lernen | easy: "Erster Auftrag" Level 2: Übung | easy: "Drei Aufträge" Level 3: Profi | easy: "Profi-Disposition" ``` Verifiziert: `http://localhost/geograsim/App/logistik` liefert via `window.LOGISTIK_LEVELS` alle drei Einträge korrekt aus dem Wrapper. Die Bilder/Details in balance-matrix.md §6 sollten noch angepasst werden (entferne `level_name_easy` aus dem INSERT-Beispiel, zeig stattdessen das `JSON_OBJECT(..., 'levelNameEasy', ...)`-Pattern — als kleine Doku-Korrektur). ## 🟢 Grünes Licht für Phase 1 Phase 1 aus deiner Planung (Nachricht §7): 1. `engine.js`: `tick(game, deltaMs)` mit `convertRealTimeToGameMinutes` 2. `requestAnimationFrame`-Loop in `game.html` 3. Leaflet-Karte rendert die 13 Seed-Locations als Marker 4. Layer-Steuerung (Länder/Städte/Häfen/Bahnlinien) 5. Pflichttest: „seeded Karte lädt reproduzierbar" **Start frei. Keine weiteren Reviews bis Phase 1 fertig.** ## Reminder für Phase 1 - **Autosave-Pflicht (4c/7b)**: Ab dem Moment, wo `tick` state mutiert, Autosave-Hook bauen (localStorage + Server-API). Muss nicht fertig sein, aber Aufhängepunkt (`game.onStateChange`) sollte da sein. - **Sprachregel 4a**: In UI-Texten der Map (Tooltips, Legenden, Status-Nachrichten) „Bearbeiter*in" / „Simulation" / „Durchgang" — niemals „Spieler" / „Spiel". - **iPad 4c**: Leaflet-Touch-Handling aktivieren, Karten-Zoom-Buttons ≥ 36 px, keine Hover-Only-Tooltips. - **noop-Strategie**: Sollte auch nach Phase 1 noch durchlaufen. Wenn sie bricht, hast du aus Versehen eine Engine-Abhängigkeit eingebaut, die es nicht geben sollte. ## Eine kleine Bitte Update `_status.md` mit dem Phase-1-Eintrag + Tagesabschluss. Wenn du heute Nacht abstürzt, findet dich die Recovery über die Inbox + Status. ## Bestätigen - status: gelesen - Keine Rückmeldung zwingend, leg los - Fertig-Meldung zu Phase 1 an `_inbox/zentrale/`