magicciv/.project/objectives/p1-42b-playerstate-priors-plumbing.md
Natalie c5062822ed docs(@projects/@magic-civilization): update playerstate priors acceptance criteria
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-05-14 23:14:06 -07:00

4.6 KiB

id title priority status scope category owner created updated_at blocked_by follow_ups parent
p1-42b Plumb per-personality building_category_weights + wonder_priorities through mc-turn PlayerState + GDScript bridge p2 done game1 ai warcouncil 2026-05-14 2026-05-14
p1-42

Context

p1-42 cycle 5 shipped the catalog-driven AI building scorer (mc-ai/tactical/production.rs::score_building) with RawAxes-driven multipliers (production/wealth/aggression). The scorer reads BuildingPriors off TacticalPlayerState, but the bridge does not yet push per-personality JSON weights into PlayerStateproject_player seeds BuildingPriors::default() (neutral) so the scorer falls through to axis multipliers.

This stub tracks the remaining plumbing to wire authored JSON priors through to the Rust scorer.

Out-of-scope items lifted from p1-42

  1. Personality JSON building_category_weights — extend each public/games/age-of-dwarves/resources/ai_personalities/*.json with building_category_weights: { production, infrastructure, military, knowledge, religious, wonder, naval } and surface them on mc-turn::PlayerState so project_player can populate TacticalPlayerState::building_priors from the player's personality.

  2. Per-personality wonder_priorities — same plumbing: extend ai_personalities/*.json with wonder_priorities: { the_great_forge: f32, undermount_vault: f32, ... }, project into TacticalPlayerState, consume in production.rs::score_building (replace the flat +5.0 wonder bonus at production.rs:489-493).

Files in scope (domain-isolated from p1-42)

  • src/simulator/crates/mc-turn/src/state.rs (PlayerState extension)
  • src/simulator/crates/mc-player-api/src/projection.rs (project_player → BuildingPriors)
  • src/game/engine/src/modules/ai/ai_turn_bridge_state.gd (push JSON weights)
  • public/games/age-of-dwarves/resources/ai_personalities/*.json (author weights)

Acceptance

  • PlayerState carries building_category_weights + wonder_priorities.
    • Evidence: src/simulator/crates/mc-turn/src/game_state.rs — added pub building_priors: mc_ai::tactical::state::BuildingPriors field (wraps both maps in one struct, mirrors how the tactical state already carries them). #[serde(default)] keeps pre-p1-42b saves loading.
  • project_player (i.e. project_tactical_player) seeds TacticalPlayerState::building_priors from PlayerState, not default().
    • Evidence: src/simulator/crates/mc-player-api/src/projection.rs:1158-1166 now reads player.building_priors.clone() straight through. Covered by tactical_building_priors_round_trip_from_player_state + tactical_building_priors_default_for_unstamped_player (both pass on apricot, see cargo test -p mc-player-api --lib tactical_building_priors).
    • Bridge wiring: api-gdext/src/lib.rs::set_player_personality_json now reads building_category_weights and wonder_priorities from the personality JSON envelope and stamps them onto PlayerState::building_priors. Absent keys reset to empty so re-stamping can never leak a prior clan's priors.
  • All 5 clan personality JSONs author non-neutral weights.
    • Evidence: public/games/age-of-dwarves/data/ai_personalities.json — every clan (ironhold, goldvein, blackhammer, deepforge, runesmith) now carries both building_category_weights (7 cats) and wonder_priorities (clan-flavoured wonder picks). Schema accepts via additionalProperties: true. JSON validates (python3 -c "import json; ...").
  • mc-ai/tests/personality_building_bias.rs — identical city state, production-axis personality scores forge higher than marketplace; wealth-axis personality reverses.
    • Evidence: new integration test at src/simulator/crates/mc-ai/tests/personality_building_bias.rs. Drives decide_tactical_actions end-to-end with neutral strategic axes (isolating the priors path from the cycle-5 axis fall-through) and a two-building catalog. Result on apricot:
      running 2 tests
      test empty_priors_fall_through_to_default_behaviour ... ok
      test production_priors_pick_forge_wealth_priors_pick_marketplace ... ok
      test result: ok. 2 passed; 0 failed
      
  • Headless regression check — cargo test -p mc-turn --lib (220 passed), cargo test -p mc-player-api --lib (91 passed), cargo test -p mc-ai (full suite green incl. ultimate_lookahead_stress + the new personality_building_bias), cargo check -p magic-civ-physics-gdext clean. No regressions touched.