feat(@projects/@magic-civilization): add personality priors field alignment stub

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-05-14 18:22:47 -07:00
parent 4b359c56f9
commit 8e7014e3da
3 changed files with 98 additions and 5 deletions

View file

@ -56,7 +56,16 @@ Verification:
- `cargo test -p mc-player-api` — green.
Consumer-side block in `p1-56-civics-buildings-and-great-works.md` now
clears. No `p1-42a-projection-building-priors` stub needed.
clears (cycle 46 re-verified the `.so` link path is unblocked).
**Test-side compile gap (separate from the projection.rs fix):**
`cargo check -p mc-ai --test capture_scoring` still fails with three
E0560 errors at `crates/mc-ai/tests/capture_scoring.rs:37,55,73` — the
test constructs `PersonalityPriors { building_priors: … }` but
`BuildingPriors` lives on `TacticalPlayerState`, not on
`PersonalityPriors` (`crates/mc-ai/src/policy.rs:116-121`). Tracked
separately under `p1-42a-personality-priors-building-priors-field.md`
*not* a regression of this objective's cycle-5 fix.
## Out of scope

View file

@ -0,0 +1,80 @@
---
id: p1-42a
title: "Reconcile capture_scoring.rs ↔ PersonalityPriors — building_priors field location"
priority: p2
status: stub
scope: game1
category: ai
owner: warcouncil
created: 2026-05-14
updated_at: 2026-05-14
blocked_by: []
follow_ups: []
parent: p1-42
---
## Context
The cycle 5 fix on `p1-42` resolved the `projection.rs:1138` compile blocker
by seeding `TacticalPlayerState { building_priors: BuildingPriors::default() }`
in the `project_player` constructor. `cargo check -p mc-player-api` and
`cargo test -p mc-ai --lib` both come back green.
However, **`cargo check -p mc-ai --test capture_scoring`** still fails:
```
crates/mc-ai/tests/capture_scoring.rs:37:9: error[E0560]:
struct `PersonalityPriors` has no field named `building_priors`
crates/mc-ai/tests/capture_scoring.rs:55:9: error[E0560]: ...
crates/mc-ai/tests/capture_scoring.rs:73:9: error[E0560]: ...
```
The test at lines 24/41/59 constructs `PersonalityPriors { …, building_priors:
mc_ai::tactical::state::BuildingPriors::default() }`, but the actual
`PersonalityPriors` definition in `crates/mc-ai/src/policy.rs:116-121` carries
no such field — `BuildingPriors` lives on `TacticalPlayerState`, not on the
personality struct.
The test was written assuming a different home for the priors than what
`p1-42` cycle 5 actually shipped. Either:
- (a) Add `building_priors: BuildingPriors` to `PersonalityPriors` and
thread it through `personality.rs` JSON load + `Default` impl, OR
- (b) Remove the three `building_priors:` lines from `capture_scoring.rs`
(they have no semantic effect today — the test doesn't read them back).
Option (b) is the minimum surgical fix; option (a) is what the test's
*intent* implies (per-personality building scoring weights, which is also
called out as deferred in `p1-42`'s acceptance bullet on personality JSON
weights).
## Acceptance
- [ ] `cargo check -p mc-ai --tests` green (no E0560 on `building_priors`).
- [ ] `cargo test -p mc-ai --test capture_scoring` runs and passes its 6
existing assertions.
- [ ] Decision recorded in this objective body — option (a) keeps the door
open for personality-driven building scoring; option (b) lets the
catch-up test compile today and defers per-personality priors to a
separate JSON authoring pass.
## Source-of-truth rails
- **Rust crate**: `mc-ai::policy::PersonalityPriors` (option a only).
- **No JSON change** required unless option (a) is chosen and per-clan
weights are authored in the same pass.
## Out of scope
- Authoring per-clan `building_category_weights` JSON (still parked under
`p1-42` acceptance bullet 3).
- Wonder priority weights JSON (still parked under `p1-42` acceptance
bullet 5).
## References
- Parent: `.project/objectives/p1-42-ai-full-building-catalog.md`
- Test: `src/simulator/crates/mc-ai/tests/capture_scoring.rs:37,55,73`
- Struct: `src/simulator/crates/mc-ai/src/policy.rs:116-121`
- Sibling struct (current home of `BuildingPriors`):
`src/simulator/crates/mc-ai/src/tactical/state.rs::BuildingPriors`

View file

@ -2,15 +2,19 @@
id: p2-60
title: "Weather / observation lens switcher in the Godot HUD"
priority: p2
status: partial
status: done
scope: game1
category: ui
owner: godot-ui
created: 2026-05-03
updated_at: 2026-05-14
blocked_by: []
follow_ups:
- "Capture one screenshot per lens via tools/screenshot.sh against res://engine/scenes/tests/lens_switcher_proof.tscn — phase-gate evidence for bullet 6."
follow_ups: []
proof:
- "scripts/p2-60-lens-proof.sh — weston-headless flatpak Godot driver for the proof scene; produced 20 PNGs (1 default + 19 lenses) on apricot from origin/main d5a5e9c4e."
- ".local/proof/p2-60-lens-switcher/lens_none_2026-05-14_18-17-29.png — default state, no active lens, full 19-button strip visible."
- ".local/proof/p2-60-lens-switcher/lens_temperature_2026-05-14_18-17-30.png — Temperature highlighted (green active-state tint) while remaining 18 buttons stay neutral; proves set_active_lens highlight tracking."
- ".local/proof/p2-60-lens-switcher/lens_{rivers,terrain,climate_cycles,delta,moisture,ocean_currents,wind_pressure,aquifer_mapping,biosphere_health,canopy_undergrowth,fungi_network,marine_health,tile_quality,wildlife_habitat,atmospheric_chemistry,sulfate_aerosol,tectonic_activity,weather_prediction}_2026-05-14_18-17-30.png — one PNG per remaining lens, each cycled by the proof scene."
---
## Context
@ -26,7 +30,7 @@ This objective ships the Godot UI side: a lens switcher widget + the renderer ho
- ✓ Renderer reads the active lens through the existing `EventBus.map_overlay_changed(mode)` bridge (compat-emitted alongside the new `lens_changed`). `hex_overlay_renderer.gd` already consumes the matching mode strings (`temperature`, `moisture`, `pressure`, `humidity`, …). Additive only — no renderer refactoring.
- ✓ Hotkey cycling: actions `ui_map_lens_next` (Tab) and `ui_map_lens_prev` (Shift+Tab) registered in `project.godot`. The `ui_map_` prefix is auto-picked up by the `p2-03` `hotkey_sheet.gd` bucket rule, so the cheat sheet surfaces the new keys without further wiring. `lens_switcher.gd::_unhandled_input()` handles them.
- ✓ EventBus signal `lens_changed(lens_id: String)` added in `event_bus.gd`; widget emits it (and the legacy `map_overlay_changed`) on every switch.
- ❌ Proof scene `src/game/engine/scenes/tests/lens_switcher_proof.tscn` (+ `.gd`) exists and is wired to capture one screenshot per loaded lens, but the screenshot run itself (via `tools/screenshot.sh` on the headless host) has not been performed in this session. Phase-gate evidence pending.
- ✓ Proof scene `src/game/engine/scenes/tests/lens_switcher_proof.tscn` (+ `.gd`) captures one screenshot per loaded lens. Captured 2026-05-14 on apricot under weston-headless flatpak Godot (origin/main `d5a5e9c4e`, GDExt rebuilt fresh, class cache pre-populated) via `scripts/p2-60-lens-proof.sh`. 20 PNGs landed at `.local/proof/p2-60-lens-switcher/lens_<id>_2026-05-14_18-17-{29,30}.png` on the SCREENSHOT_HOST (plum). `lens_none` shows the full 19-button strip with no active highlight; `lens_temperature` shows the same strip with the Temperature button rendered in the active-state green tint — visual confirmation of the JSON-driven button list and the `set_active_lens` highlight bridge.
- ✓ `--headless` GUT test `src/game/engine/tests/unit/test_lens_switcher.gd` asserts the lens registry parses (at least one lens, `temperature` present) and that both `EventBus.lens_changed` and the compat `EventBus.map_overlay_changed` fire on `set_active_lens` (including the empty-string clear case).
## Source-of-truth rails