diff --git a/.project/objectives/p1-42-ai-full-building-catalog.md b/.project/objectives/p1-42-ai-full-building-catalog.md index ddff5b60..141a30ec 100644 --- a/.project/objectives/p1-42-ai-full-building-catalog.md +++ b/.project/objectives/p1-42-ai-full-building-catalog.md @@ -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 diff --git a/.project/objectives/p1-42a-personality-priors-building-priors-field.md b/.project/objectives/p1-42a-personality-priors-building-priors-field.md new file mode 100644 index 00000000..e81cdf58 --- /dev/null +++ b/.project/objectives/p1-42a-personality-priors-building-priors-field.md @@ -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` diff --git a/.project/objectives/p2-60-weather-lens-godot-ui.md b/.project/objectives/p2-60-weather-lens-godot-ui.md index 4ee22394..87d265fe 100644 --- a/.project/objectives/p2-60-weather-lens-godot-ui.md +++ b/.project/objectives/p2-60-weather-lens-godot-ui.md @@ -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__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