Rail-1 city-model unification, step 2: give the headless/bench simulation real,
growing territory so view_json carries it (toward "simulator provides everything").
- mc_city::CityState gains owned_tiles: Vec<(i32,i32)> (serde default; backward-compat).
- mc-turn::process_culture: the culture-ready list from CulturePool::tick_all was
previously DROPPED (let _ready = ...). Now each ready city claims one contiguous,
in-bounds frontier tile per turn into owned_tiles — real border expansion in Rust.
Deterministic pick (lowest col,row among the unclaimed frontier); city centre owned
implicitly via city_positions, materialised on first expansion; consume_expansion
advances the threshold. Grid dims read before the &mut player borrow.
- mc-player-api projection: CityView.owned_tiles (schema field that existed but was
stubbed Vec::new()) now projects CityState.owned_tiles, with a centre fallback so
every city reports at least the tile it sits on.
- Fixed a pre-existing broken test (serde_roundtrip HappinessInput literal missing the
building_happiness_effects/happiness_per_city_effects fields p3-24 added).
Verified: cargo test mc-city + mc-turn + mc-player-api 725/0, incl. new
culture_expansion_claims_frontier_tiles + projection_surfaces_city_owned_tiles. Rust-only
headless-path change; live game (presentation_cities) unaffected. Unblocks step 4
(trade sourcing from owned-tile resources). p3-25 steps 1-2 done; 3-6 remain.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>