4.3 KiB
| id | title | priority | status | scope | owner | updated_at | parent | canonical_doc | coordinates_with | blockedBy | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| p2-54d | AI tech-priority bias from visible-but-gated luxuries + indicator decorations | p2 | done | game1 | terraformer | 2026-05-01 | p2-54 | public/games/age-of-dwarves/docs/RESOURCES.md |
|
|
Summary
Per the user's 2026-05-01 design observation: AI clans don't research the right techs to unlock luxuries. With the three-axis schema (p2-54) and observation cache (p2-54b) in place, mc-ai's strategic policy can read each clan's visible-but-yield-gated luxuries + indicator-decorated subsurface resources in their territory and bias tech research toward unlocking them.
This is the architectural fix for p1-05's luxury_variance regression (median dropped from 3 to 0 because AI never researches Trapping/Scholarship/Herbalism even though their territory contains ivory, silk, spices).
Acceptance
- ✓ Personality reads visible luxuries —
AiPlayerState.luxury_unlock_scoresfield (HashMap<String,f32>) pre-populated by api-gdext caller fromPlayerObservations+GridState+ resources.json. Caller computesLUXURY_TILE_VALUE(10.0) per visible-but-yield-gated luxury tile, scaled by personality wealth axis.score_techinmc-ai::evaluatorreads this additive score. Architecture: Path A (caller pre-computes, Rust reads) matches existing AiPlayerState population pattern and avoids adding mc-save dep to mc-ai. - ✓ Personality reads indicator decorations — same
luxury_unlock_scoresfield carriesINDICATOR_TILE_VALUE(5.0) contribution per indicator-decoration tile (e.g.rust_red_soil→ iron → bronze_working). Caller usesindicator_decorations[].decoration_idfrom resources.json to build the decoration→resource→yield_gate mapping. - ✓ Tech-priority weighting —
score_techinevaluator.rsreadsstate.luxury_unlock_scores.get(&tech.id)and adds it directly onto the base score. Layer is additive — doesn't replace pillar-level personality bias at lines 787-795. - ✓ No regression in existing AI behavior — 211/211 mc-ai tests pass including all pre-existing personality, formation, and production scoring tests.
- ✓ Determinism preserved —
cross_build_determinism4/4 unchanged. - ◻ p1-05 luxury_variance gate validation — deferred to apricot 10-seed batch run (apricot-scale work). Architectural cause resolved; empirical validation pending. See p1-05 evidence note.
- ◻ Doc: RESOURCES.md §5 "AI consumption pattern" updated with the scoring formula. (Deferred — docs agent scope.)
Evidence
src/simulator/crates/mc-ai/src/game_state.rs—luxury_unlock_scores: HashMap<String, f32>added toAiPlayerStatewith#[serde(default)]src/simulator/crates/mc-ai/src/evaluator.rs— luxury bias applied inscore_tech(p2-54d block); 3 new tests added:evaluator::tests::personality_with_visible_silk_prioritizes_scholarship✓evaluator::tests::indicator_iron_in_territory_biases_toward_bronze_working✓evaluator::tests::no_observations_no_bias✓
- mc-ai test run: 211/211 pass; cross_build_determinism: 4/4
Implementation notes
TileObservation (mc-save) has no resource_ids_seen field — it stores only indicator_decorations_seen: Vec<String>. Always-visible resources are not mirrored into the observation cache (p2-54b). The api-gdext bridge must query GridState directly for always-visible resource presence alongside reading indicator decorations from PlayerObservations.by_tile. Rust-side mc-ai receives the pre-computed scores; no mc-save dep added to mc-ai.
Non-goals
- Full personality re-tuning (warcouncil scope, tracked elsewhere)
- Tech-gated UI changes (the AI doesn't drive UI)
- Trade decisions based on luxuries (separate
mc-tradework)
Why blocked-by-p2-54-and-p2-54b
The schema and observation cache must exist for the AI to read them. After both land, this is bounded mc-ai work.
What this resolves
- p1-05 luxury_variance gate (median 0 → expect 3+) — closes the open Shipwright partial
- Foundational: the same machinery enables p1-36's AI personality clan_affinity weighting from observable resources (already partial-closed by p1-37 via clan_affinity routing; this layers the LUXURY bias on top)