From 8d9eb02d99bd4cda973fa3a583f28213367a4705 Mon Sep 17 00:00:00 2001 From: autocommit Date: Wed, 29 Apr 2026 13:06:44 -0700 Subject: [PATCH] =?UTF-8?q?chore(objectives):=20=F0=9F=94=A7=20Update=20p1?= =?UTF-8?q?-39-md=20milestone=20documentation=20and=20configuration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .project/objectives/p1-39-md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .project/objectives/p1-39-md diff --git a/.project/objectives/p1-39-md b/.project/objectives/p1-39-md new file mode 100644 index 00000000..13199837 --- /dev/null +++ b/.project/objectives/p1-39-md @@ -0,0 +1,35 @@ +--- +id: p1-39 +title: Port per-yield difficulty multipliers from GDScript into Rust crates (Rail-1) +priority: p1 +status: missing +scope: game1 +tags: [rust-source-of-truth, rail-1] +owner: warcouncil +updated_at: 2026-04-27 +--- +## Summary + +During p1-29 Round 3-4, warcouncil added a per-yield difficulty multiplier framework (gold_mult, culture_mult, luxury_mult, research_mult, production_mult, yield_per_turn_growth) plus a symmetric player handicap (Easy = player gets Hard-AI bonuses). The framework SHAPE is validated — R4 batch shows median tier_peak climbed from 4-5 to 6 with the wiring active. + +But the APPLICATION sites are in GDScript (`turn_processor.gd::_process_research`, `_process_culture`, `economy.gd::process_turn`) which violates Rail-1 (Rust = simulation source of truth). The user flagged this as "B — finish R4 validation first, then port" 2026-04-27. + +This objective covers the port: + +1. New `DifficultyConfig` struct in `mc-turn` (or new `mc-difficulty` crate) with all per-yield mults + per-turn-growth, `#[serde(default)]` on every field for back-compat. +2. `TurnProcessor` gains `pub difficulty: DifficultyConfig` field — default = no-op (1.0/0.0). `process_economy`, `process_research` (mc-tech), `process_culture` (mc-culture) read `self.difficulty.X_mult(turn, is_human)` and apply inline. +3. GDExtension surface: `GdTurnProcessor::set_difficulty(json)` — GDScript reads `difficulty.json`, serializes to JSON, calls setter at game start. +4. `GameState.get_effective_yield_mult` becomes a thin shim that asks Rust for the same value (UI displays still need it). +5. Delete the GDScript multiplication call sites (turn_processor.gd:56, 154; economy.gd:47-50; turn_processor.gd:368-372). + +`difficulty.json` schema + `GameState.ai_X_modifier` fields stay where they are. The port changes WHERE the multiply happens, not WHAT it does — R4 evidence already validates correctness. + +Reference batch for parity check: `.local/iter/p1-29-r4-hard-20260427_023500/` should reproduce identically (same seeds → same outcomes) once the Rust port is the active path. + +## Acceptance + +- ❌ mc-turn::DifficultyConfig struct + TurnProcessor.difficulty field; cargo test -p mc-turn --lib --locked passes +- ❌ GdTurnProcessor::set_difficulty(json) #[func] exposed; GDScript reads difficulty.json + sends JSON at game start +- ❌ GDScript application sites (turn_processor.gd:56,154; economy.gd:47-50; turn_processor.gd:368-372) deleted; comments cite this objective for the port +- ❌ Replay parity: re-run .local/iter/p1-29-r4-hard-20260427_023500 seeds with new binary; per-game tier_peak/turn outcomes within 5% (deterministic seeds → deterministic outputs) +- ❌ GameState.get_effective_yield_mult kept as thin Rust-asking shim (UI still needs it)