diff --git a/.project/objectives/DASHBOARD_CATEGORIES.md b/.project/objectives/DASHBOARD_CATEGORIES.md
index cd88d7bc..e5c8d9bd 100644
--- a/.project/objectives/DASHBOARD_CATEGORIES.md
+++ b/.project/objectives/DASHBOARD_CATEGORIES.md
@@ -206,7 +206,7 @@
| [p1-41](p1-41-game-pack-subscription-manifest.md) | β
done | P1 | Game-pack subscription manifest + loader filter (Phase B of resources/ unification) | β | π’ |
| [p1-42](p1-42-ai-full-building-catalog.md) | π‘ partial | P1 | AI must consider the full 155-building catalog, not the hardcoded 8-id ladder | β | π’ |
| [p1-43](p1-43-building-stacking-upgrade.md) | π‘ partial | P1 | Building stacking β per-category upgrade chains (military / science / culture / production / etc.) | β | π’ |
-| [p1-44](p1-44-buildings-as-producers.md) | β missing | P1 | Buildings produce units, not the city center β per-building production queues | β | π’ |
+| [p1-44](p1-44-buildings-as-producers.md) | π‘ partial | P1 | Buildings produce units, not the city center β per-building production queues | β | π’ |
| [p1-46](p1-46-design-lab-terrain-dimensions.md) | β
done | P1 | Terrain Dimensions Lab β fix ridginess, bind 149 flora species, add Whittaker plot | [terraformer](../team-leads/terraformer.md) | π’ |
| [p1-47](p1-47-river-hydrology-network.md) | β
done | P1 | River hydrology β D6 flow analysis, hydraulic erosion, multi-hex lakes, cross-tile rivers | [terraformer](../team-leads/terraformer.md) | π’ |
| [p1-48](p1-48-flora-species-renderer.md) | β
done | P1 | Flora species renderer β bind 149 species to world-map tile rendering (single source of truth) | [terraformer](../team-leads/terraformer.md) | π’ |
@@ -241,6 +241,8 @@
| [p2-10h](p2-10h-sprite-renderer-build-key.md) | β
done | P2 | UnitRenderer: implement _build_sprite_key() helper and fix cache key test | β | π’ |
| [p2-10i](p2-10i-tile-tooltip-scene.md) | β
done | P2 | TileTooltip: fix scene node name mismatches and collectibles text formatting | β | π’ |
| [p2-10j](p2-10j-fog-vision-scout-move.md) | β
done | P2 | FogOfWar: fix recalculate_vision to not re-reveal already-seen tiles on move | β | π’ |
+| [p2-10k](p2-10k-gdlint-cleanup.md) | π΄ stub | P2 | CI: fix 51 gdlint violations so Stage 3 is hard-green | [testwright](../team-leads/testwright.md) | π’ |
+| [p2-10l](p2-10l-gut-regression-triage.md) | π΄ stub | P2 | CI: fix 15 GUT regressions so Stage 5 is hard-green | [testwright](../team-leads/testwright.md) | π’ |
| [p2-11](p2-11-version-about-screen.md) | β
done | P2 | Version string + About screen | [shipwright](../team-leads/shipwright.md) | π’ |
| [p2-11a](p2-11a.md) | β
done | P2 | SaveManager: add Unit.serialize/deserialize and City.production_queue serialize path | β | π’ |
| [p2-12](p2-12-apricot-weston-install.md) | β
done | P2 | Install weston on apricot RUN host β unblock display-server smoke tests | [shipwright](../team-leads/shipwright.md) | π’ |
diff --git a/.project/objectives/README.md b/.project/objectives/README.md
index 497fa97e..287b911e 100644
--- a/.project/objectives/README.md
+++ b/.project/objectives/README.md
@@ -1,10 +1,10 @@
# Objectives β Dashboard
-> **Generated by `tools/objectives-report.py` β do not hand-edit.** Source of truth is per-file YAML frontmatter in this directory.
+> **Generated by `@lilith/mcp-objectives` β do not hand-edit.** Source of truth is per-file YAML frontmatter in this directory. Completed: [DASHBOARD_COMPLETED.md](DASHBOARD_COMPLETED.md) Β· By category: [DASHBOARD_CATEGORIES.md](DASHBOARD_CATEGORIES.md).
## Legend
-β
done Β· π΅ in-progress Β· π‘ partial Β· π΄ stub Β· β missing Β· β« out-of-scope (Game 2 / Game 3)
+π΅ in-progress Β· π‘ partial Β· π΄ stub Β· β missing Β· β« out-of-scope Β· β
done Β· β»οΈ superseded
## Totals
@@ -12,13 +12,13 @@
**By Priority**
-| Priority | β
| π΅ | π‘ | π΄ | β | β« | Total |
+| Priority | π΅ | π‘ | π΄ | β | β« | β
| Total |
|---|---|---|---|---|---|---|---|
-| **P0** | 43 | 0 | 0 | 0 | 0 | 0 | 43 |
-| **P1** | 48 | 1 | 14 | 2 | 6 | 1 | 72 |
-| **P2** | 57 | 0 | 10 | 12 | 0 | 6 | 85 |
-| **P3 (oos)** | 3 | 0 | 0 | 18 | 1 | 21 | 43 |
-| **total** | **151** | **1** | **24** | **32** | **7** | **28** | **243** |
+| **P0** | 0 | 0 | 0 | 0 | 0 | 43 | 43 |
+| **P1** | 1 | 15 | 2 | 5 | 1 | 48 | 72 |
+| **P2** | 0 | 10 | 12 | 0 | 6 | 58 | 86 |
+| **P3 (oos)** | 0 | 0 | 18 | 1 | 21 | 3 | 43 |
+| **total** | **1** | **25** | **32** | **6** | **28** | **152** | **244** |
@@ -28,8 +28,8 @@
|---|---|
| [unassigned](../team-leads/unassigned.md) | 28 |
| [asset-sprite](../team-leads/asset-sprite.md) | 6 |
-| [warcouncil](../team-leads/warcouncil.md) | 5 |
| [shipwright](../team-leads/shipwright.md) | 5 |
+| [warcouncil](../team-leads/warcouncil.md) | 5 |
| [simulator-infra](../team-leads/simulator-infra.md) | 3 |
| [testwright](../team-leads/testwright.md) | 3 |
| [combat-dev](../team-leads/combat-dev.md) | 2 |
@@ -37,255 +37,111 @@
|
-## P0 β Blockers for "completely playable"
+## π΅ In Progress
-| ID | Status | Title | Owner | Updated |
+> Actively claimed by a team lead. Grouped by owner.
+
+### [asset-audio](../team-leads/asset-audio.md)
+
+| ID | Priority | Title | Updated | Blocked |
|---|---|---|---|---|
-| [p0-01](p0-01-mcts-wiring.md) | β
done | Wire MCTS into gameplay AI | [warcouncil](../team-leads/warcouncil.md) | 2026-04-26 |
-| [p0-02](p0-02-clan-personalities.md) | β
done | Five AI clan personalities drive distinct playstyles | [warcouncil](../team-leads/warcouncil.md) | 2026-04-26 |
-| [p0-03](p0-03-pvp-in-turn.md) | β
done | PvP combat resolved inside the authoritative turn processor | β | 2026-04-17 |
-| [p0-04](p0-04-wonder-tracking.md) | β
done | World wonder tracking in PlayerState and score victory | β | 2026-04-17 |
-| [p0-05](p0-05-culture-and-borders.md) | β
done | Culture generation and border expansion | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p0-06](p0-06-economy-integration.md) | β
done | Fold gold income / upkeep / improvement yields into turn loop | β | 2026-04-17 |
-| [p0-07](p0-07-tech-research-costs.md) | β
done | Tech research costs and science pool pacing | β | 2026-04-17 |
-| [p0-08](p0-08-domination-victory.md) | β
done | Domination victory path in mc-turn::victory | [warcouncil](../team-leads/warcouncil.md) | 2026-04-18 |
-| [p0-09](p0-09-ui-completeness.md) | β
done | City-screen UI completeness (citizen assign, queue controls, promotion picker) | β | 2026-04-16 |
-| [p0-10](p0-10-completion-stability.md) | β
done | Game-completion stability β β₯7/10 seeds declare a winner | β | 2026-04-17 |
-| [p0-11](p0-11-mystery-item-authoring.md) | β
done | Author the four T8βT10 mystery item drops | β | 2026-04-16 |
-| [p0-12](p0-12-save-load-autosave.md) | β
done | Save / load + autosave on quit | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p0-13](p0-13-fog-of-war-exploration.md) | β
done | Fog of war and exploration / scout loop | β | 2026-04-17 |
-| [p0-14](p0-14-map-generation-balanced-starts.md) | β
done | Map generation, resource placement, and balanced fair starts | [shipwright](../team-leads/shipwright.md) | 2026-04-16 |
-| [p0-15](p0-15-happiness-golden-age.md) | β
done | Happiness pool and Golden Age mechanics end-to-end | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p0-16](p0-16-worker-improvement-loop.md) | β
done | Worker / tile-improvement build loop | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p0-17](p0-17-wild-creature-lair-loop.md) | β
done | Wild creature and lair clearing loop | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p0-18](p0-18-strategic-resource-gate.md) | β
done | Strategic resources gate unit production (empire ledger) | β | 2026-04-17 |
-| [p0-19](p0-19-biome-economy-integration.md) | β
done | Biome-driven collectibles β tile yields β happiness end-to-end | β | 2026-04-16 |
-| [p0-21](p0-21-audio-system-capability.md) | β
done | Audio system capability β manifest + autoload + EventBus wiring | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p0-22](p0-22-ultimate-ai-stress-test.md) | β
done | "Ultimate AI stress test β 5 clans, huge map, deep lookahead" | [warcouncil](../team-leads/warcouncil.md) | 2026-04-25 |
-| [p0-23](p0-23-sprite-rendering-capability.md) | β
done | Sprite rendering capability β replace procedural draw_* with texture rendering | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p0-24](p0-24-difficulty-calibrated-ai-progression.md) | β
done | Difficulty-calibrated AI progression β Easy / Normal / Hard tier-peak distributions | [warcouncil](../team-leads/warcouncil.md) | 2026-04-19 |
-| [p0-25](p0-25-game-quality-metrics-instrumentation.md) | β
done | Game-quality metrics instrumentation β tier_peak, peak_unit_tier, wonder_count | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p0-26](p0-26-ai-tactical-rust-port.md) | β
done | Port tactical AI from GDScript to mc-ai (Rail-1 compliance) | [warcouncil](../team-leads/warcouncil.md) | 2026-04-18 |
-| [p0-27](p0-27-gd-culture-bridge.md) | β
done | GdCulture bridge β live game delegates culture to mc-culture | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p0-28](p0-28-gd-economy-bridge.md) | β
done | GdEconomy bridge β live game delegates gold/upkeep to mc-economy | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p0-29](p0-29-gd-tech-bridge.md) | β
done | GdTechWeb bridge β live game delegates research to mc-tech | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p0-30](p0-30-ecology-double-tick-fix.md) | β
done | Remove duplicate GDScript ecology tick (single Rust source) | [shipwright](../team-leads/shipwright.md) | 2026-04-18 |
-| [p0-31](p0-31-climate-rust-path-restore.md) | β
done | Restore Rust ecology path β fix ClimateScript bugs + re-enable per-turn tick | [shipwright](../team-leads/shipwright.md) | 2026-04-18 |
-| [p0-32](p0-32-weather-climate-effects-restore.md) | β
done | Restore WeatherScript + ClimateEffectsScript β per-turn weather and climate-effects | [shipwright](../team-leads/shipwright.md) | 2026-04-18 |
-| [p0-33](p0-33-world-map-input-and-panel-wiring.md) | β
done | World-map input wiring β unit selection panel, city click, ESC/F10 menu, panel close | [wireguard](../team-leads/wireguard.md) | 2026-04-19 |
-| [p0-34](p0-34-freepeople-tribe-founding.md) | β
done | Freepeople tribe-founding cinematic β turn -1 / 0 / 1 start sequence and Dwarf Tribe founder unit | [shipwright](../team-leads/shipwright.md) | 2026-04-18 |
-| [p0-37](p0-37-personality-emergent-tactical-thresholds.md) | β
done | Personality-emergent tactical thresholds (lift 7 hardcoded constants into axis-derived functions) | [warcouncil](../team-leads/warcouncil.md) | 2026-04-18 |
-| [p0-38](p0-38-mcts-personality-priors.md) | β
done | Inject personality-utility scores as MCTS UCB1 priors | [warcouncil](../team-leads/warcouncil.md) | 2026-04-24 |
-| [p0-39](p0-39-ai-tier-progression-unit-selection.md) | β
done | AI tier-progression unit selection β production.rs picks tier-2+ units once tech unlocks | [warcouncil](../team-leads/warcouncil.md) | 2026-04-18 |
-| [p0-40](p0-40-iron-ore-resource-density.md) | β
done | Iron-ore strategic resource density β unblock tier 3-6 unit chain | [shipwright](../team-leads/shipwright.md) | 2026-04-24 |
-| [p0-41](p0-41.md) | β
done | Building rally points β produced units auto-deploy to a designated hex | [shipwright](../team-leads/shipwright.md) | 2026-04-24 |
-| [p0-41a](p0-41a-rally-smoke.md) | β
done | Rally-point smoke β produced unit gets PatrolOrder toward rally hex | [shipwright](../team-leads/shipwright.md) | 2026-04-25 |
-| [p0-42](p0-42.md) | β
done | Formation aggregation β adjacent units link into a shaped formation with terrain reflow | [shipwright](../team-leads/shipwright.md) | 2026-04-25 |
-| [p0-42a](p0-42a-formation-smoke.md) | β
done | Formation aggregation smoke β formations form and evolve at runtime | [shipwright](../team-leads/shipwright.md) | 2026-04-25 |
-| [p0-43](p0-43.md) | β
done | "Formation AI β MCTS plans at formation level, not per-unit" | [warcouncil](../team-leads/warcouncil.md) | 2026-04-25 |
-| [p0-44](p0-44-movement-mode-ux.md) | β
done | Movement mode UX β Move button, path preview, right-click confirm, fog-aware pathing | [wireguard](../team-leads/wireguard.md) | 2026-04-19 |
+| [p2-16](p2-16-audio-assets.md) | P1 | Audio assets β in-theme OSS launch pack + source ledger | 2026-05-03 | π’ unblocked |
## P1 β Ship-readiness
-| ID | Status | Title | Owner | Updated |
-|---|---|---|---|---|
-| [p0-20](p0-20-gpu-mcts-rollouts.md) | π‘ partial | GPU-accelerated MCTS rollouts for look-ahead decision-making | [warcouncil](../team-leads/warcouncil.md) | 2026-05-04 |
-| [p0-35](p0-35-ecology-telemetry-instrumentation.md) | β
done | Ecology telemetry instrumentation β flora canopy / undergrowth fields in turn_stats.jsonl | [shipwright](../team-leads/shipwright.md) | 2026-04-18 |
-| [p0-36](p0-36-weather-event-telemetry.md) | β
done | Weather / climate-effects event telemetry β events.jsonl + turn_stats aggregates | [shipwright](../team-leads/shipwright.md) | 2026-04-18 |
-| [p1-01](p1-01-diplomacy-lite.md) | β
done | Diplomacy-lite β peace/war toggle plus one trade action | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p1-02](p1-02-strategic-resource-yields.md) | β
done | Strategic resource yields feed into production bonuses | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p1-03](p1-03-tutorial-overlay.md) | β
done | First-run tutorial / onboarding overlay | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p1-05](p1-05-balance-tuning.md) | π‘ partial | Balance tuning β pop_peak β₯30 median, worker improvements β₯8 min | [shipwright](../team-leads/shipwright.md) | 2026-05-01 |
-| [p1-06](p1-06-options-polish.md) | β
done | Options screen polish | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p1-07](p1-07-chronicle-coverage.md) | β
done | Chronicle notifications coverage | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p1-08](p1-08-victory-screen-content.md) | β
done | Victory/defeat screen content β recap, banner, replay seed | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p1-09](p1-09-determinism-gate.md) | β
done | Determinism gate β same seed produces byte-identical runs | [testwright](../team-leads/testwright.md) | 2026-04-19 |
-| [p1-10](p1-10-game-setup-ux.md) | β
done | Game setup UX β new-game dialog, difficulty, clan preview | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p1-11](p1-11-build-output-src-purge.md) | β
done | Purge build output from src/ β wasm-pack moves to .local/build/wasm/ | [tourguide](../team-leads/tourguide.md) | 2026-04-17 |
-| [p1-12](p1-12-build-output-docs-alignment.md) | β
done | Align every doc reference to the relocated wasm-pack output | [tourguide](../team-leads/tourguide.md) | 2026-04-17 |
-| [p1-13](p1-13-guide-dev-route-coverage.md) | β
done | Guide dev server boots on plum with zero-error route coverage | [tourguide](../team-leads/tourguide.md) | 2026-04-17 |
-| [p1-15](p1-15-guide-next-deploy-infra.md) | β
done | Deploy dev guide to https://mc.next.black.local | [tourguide](../team-leads/tourguide.md) | 2026-04-17 |
-| [p1-16](p1-16-guide-game1-scope-hygiene.md) | β
done | Purge Game 2/3 scope bleed from user-visible Game 1 guide copy | [tourguide](../team-leads/tourguide.md) | 2026-04-18 |
-| [p1-17](p1-17-guide-next-auto-deploy.md) | β
done | Forgejo workflow auto-deploys dev guide on push to main | [tourguide](../team-leads/tourguide.md) | 2026-04-18 |
-| [p1-18](p1-18-village-discovery-feedback.md) | β
done | Village discovery β world-map feedback (notification, reward popup, minimap ping) | [wireguard](../team-leads/wireguard.md) | 2026-04-19 |
-| [p1-19](p1-19-tutorial-opt-in.md) | β
done | Tutorial opt-in β HUD button, disappears after turn 5, starts from Step 1 | [wireguard](../team-leads/wireguard.md) | 2026-04-19 |
-| [p1-20](p1-20-unit-action-capability-registry.md) | β
done | Unit action capability registry β one source of truth for "what can this unit do right now?" | [wireguard](../team-leads/wireguard.md) | 2026-04-19 |
-| [p1-21](p1-21-unit-patrol-orders.md) | β
done | Unit patrol orders β standing order to loop between waypoint tiles | [wireguard](../team-leads/wireguard.md) | 2026-04-19 |
-| [p1-22](p1-22-mcts-wall-clock-budget.md) | π‘ partial | MCTS per-decision wall-clock budget β bound per-turn cost on huge maps | [warcouncil](../team-leads/warcouncil.md) | 2026-04-25 |
-| [p1-23](p1-23-stats-tracker-restore.md) | β
done | Restore StatsTracker β demographics overview broken in shipped builds | [shipwright](../team-leads/shipwright.md) | 2026-04-25 |
-| [p1-24](p1-24-windows-path-separator.md) | β
done | ai_personalities.json fails to load from packed builds (all platforms) β pass JSON contents not path | [shipwright](../team-leads/shipwright.md) | 2026-04-25 |
-| [p1-25](p1-25-export-script-error-cleanup.md) | β
done | Eliminate parse-error spam in export logs (Unit dup decl + SaveManager stray) | [shipwright](../team-leads/shipwright.md) | 2026-04-25 |
-| [p1-26](p1-26-tile-placement-preview-ux.md) | β
done | "Tile-placement UX with effect preview β Civ7-style \\\"where does this go and what changes\\\"" | [shipwright](../team-leads/shipwright.md) | 2026-04-26 |
-| [p1-27](p1-27-mcts-service-extraction.md) | π‘ partial | Extract GPU MCTS into a standalone service/client (model-boss-shaped, magic-civ-only) | [warcouncil](../team-leads/warcouncil.md) | 2026-05-03 |
-| [p1-28](p1-28-culture-research-tree.md) | β
done | "Culture research tree β real graph, bridge, UI" | [shipwright](../team-leads/shipwright.md) | 2026-04-26 |
-| [p1-29](p1-29.md) | π‘ partial | "Anti-early-domination: lift game-balance gates that p0-01 v1 measured" | [combat-dev](../team-leads/combat-dev.md) | 2026-05-03 |
-| [p1-29a](p1-29a-last-stand-defense.md) | π‘ partial | Last-stand defense β combat-strength multiplier when defender is at last city | [combat-dev](../team-leads/combat-dev.md) | 2026-05-04 |
-| [p1-30](p1-30.md) | β
done | "Optimize `_build_tactical_state` β 8000-tile GDScript dict-build per AI turn blocks p1-22 huge-map gate" | [warcouncil](../team-leads/warcouncil.md) | 2026-05-04 |
-| [p1-30b](p1-30b-parallel-mcts-rollouts.md) | π΄ stub | "Parallel MCTS rollouts for huge-map decisive games (closes p1-22's huge-map sub-gate)" | [warcouncil](../team-leads/warcouncil.md) | 2026-05-03 |
-| [p1-31](p1-31-split-bundled-building-resources.md) | β
done | Split bundled `resources/buildings/.json` into per-file pattern matching `resources/units/` | β | 2026-04-27 |
-| [p1-32](p1-32-food-chain-buildings.md) | β
done | Author the two missing food/processing buildings (sawmill, herbalist) | β | 2026-05-03 |
-| [p1-33](p1-33-naval-aerial-production-buildings.md) | β
done | Wire naval/aerial unit gates to the harbor and airfield buildings | β | 2026-05-03 |
-| [p1-34](p1-34-unit-metadata-expansion.md) | β
done | "Unit metadata expansion β flavor, archetype, promotion_tree, clan_affinity fields" | [shipwright](../team-leads/shipwright.md) | 2026-04-27 |
-| [p1-35](p1-35-unit-lore-paragraphs.md) | β
done | "Per-unit lore paragraphs β historical/cultural context for the dwarven roster" | [shipwright](../team-leads/shipwright.md) | 2026-04-27 |
-| [p1-36](p1-36-ai-personalities-t1-t10-coverage.md) | β
done | "AI personalities β T1βT10 build order coverage + clan_affinity routing" | [warcouncil](../team-leads/warcouncil.md) | 2026-05-03 |
-| [p1-37](p1-37-mc-ai-clan-affinity-routing.md) | β
done | "mc-ai clan_affinity routing β Rust AI reads unit clan_affinity at build-decision time" | [warcouncil](../team-leads/warcouncil.md) | 2026-05-01 |
-| [p1-38](p1-38-biome-economy-coupling.md) | π‘ partial | Biome β economy coupling β population & luxury driven by live ecology | [shipwright](../team-leads/shipwright.md) | 2026-05-03 |
-| [p1-39](p1-39.md) | π‘ partial | Port per-yield difficulty multipliers from GDScript into Rust crates (Rail-1) β research + culture | [warcouncil](../team-leads/warcouncil.md) | 2026-05-04 |
-| [p1-40](p1-40-single-source-of-truth-resources.md) | β
done | Collapse data// override layer into single source of truth at resources/ | β | 2026-04-29 |
-| [p1-41](p1-41-game-pack-subscription-manifest.md) | β
done | Game-pack subscription manifest + loader filter (Phase B of resources/ unification) | β | 2026-04-29 |
-| [p1-42](p1-42-ai-full-building-catalog.md) | π‘ partial | "AI must consider the full 155-building catalog, not the hardcoded 8-id ladder" | β | 2026-05-04 |
-| [p1-43](p1-43-building-stacking-upgrade.md) | π‘ partial | Building stacking β per-category upgrade chains (military / science / culture / production / etc.) | β | 2026-05-04 |
-| [p1-44](p1-44-buildings-as-producers.md) | β missing | Buildings produce units, not the city center β per-building production queues | β | 2026-04-29 |
-| [p1-45](p1-45-batch-binary-freshness.md) | β
done | "Batch binary freshness: rebuild GDExt before every autoplay batch" | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-03 |
-| [p1-46](p1-46-design-lab-terrain-dimensions.md) | β
done | Terrain Dimensions Lab β fix ridginess, bind 149 flora species, add Whittaker plot | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p1-47](p1-47-river-hydrology-network.md) | β
done | River hydrology β D6 flow analysis, hydraulic erosion, multi-hex lakes, cross-tile rivers | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p1-48](p1-48-flora-species-renderer.md) | β
done | Flora species renderer β bind 149 species to world-map tile rendering (single source of truth) | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p1-49](p1-49-fauna-species-renderer.md) | β
done | Fauna species renderer β 61 Game-1 species visible on encounter and lair tiles | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p1-50](p1-50-tectonic-prepass.md) | β
done | Tectonic prepass β voronoi plates + boundary classification seeding elevation | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p1-51](p1-51-worldgen-canonical-design-docs.md) | β
done | Worldgen canonical design docs β author the spec before any Rust | [terraformer](../team-leads/terraformer.md) | 2026-04-30 |
-| [p1-52](p1-52-api-wasm-build-fix.md) | β
done | api-wasm build fix β unblock WASM bundle for design-lab WASM consumption | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p1-53](p1-53-worldgen-layer-pages.md) | β
done | "Worldgen layer pages β one playground per canonical doc, mirroring the layered Earth model" | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p1-54](p1-54-hex-direction-rust-ts-mapping.md) | β
done | Hex direction-index translation β Rust pointy-top axial vs design-app flat-top canvas | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p1-55](p1-55-tech-culture-domain-propagation.md) | π‘ partial | "Tech & Culture domain field β propagate categorization through Rust, Godot UI, and player analysis" | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-04 |
-| [p1-56](p1-56-civics-buildings-and-great-works.md) | π‘ partial | "Civics buildings, Great Works, Specialists, Great People β wire authored data into Rust + Godot" | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-04 |
-| [p1-57](p1-57-diplomacy-tribute-treaties.md) | π΄ stub | "Diplomacy: tribute, treaty lifecycle, magical-terrain episode gating" | [unassigned](../team-leads/unassigned.md) | 2026-05-03 |
-| [p1-58](p1-58-ecology-cognitive-system.md) | π‘ partial | "Ecology cognition: terrain affinity, food web, grudge memory, apex tier-10 fauna/flora" | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-04 |
-| [p2-06](p2-06-export-pipeline.md) | β
done | Export pipeline for Windows / macOS / Linux | [shipwright](../team-leads/shipwright.md) | 2026-04-25 |
-| [p2-16](p2-16-audio-assets.md) | π΅ in_progress | Audio assets β in-theme OSS launch pack + source ledger | [asset-audio](../team-leads/asset-audio.md) | 2026-05-03 |
-| [p2-22](p2-22-sprite-generation-pipeline.md) | π‘ partial | Sprite generation pipeline β runnable end-to-end | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-25 |
-| [p2-23](p2-23-unit-sprites-dwarf-roster.md) | β missing | Unit sprites β Dwarf-racial roster (m/f variants) | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 |
-| [p2-24](p2-24-unit-sprites-wild-creatures.md) | β missing | Unit sprites β wild creatures & fauna (generic, no race/sex) | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 |
-| [p2-25](p2-25-building-sprites-base-coverage.md) | β missing | Building sprites β base game coverage (non-wonder) | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 |
-| [p2-26](p2-26-mundane-wonder-sprites.md) | β missing | Mundane-wonder sprites β 24 distinct, higher-fidelity art | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 |
-| [p2-27](p2-27-city-population-tier-sprites.md) | β missing | City population-tier sprites β city_q1 through city_q5 | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 |
-| [p2-28](p2-28-sprite-provenance-ledger.md) | β
done | Sprite provenance ledger β LICENSES.md per-file attribution | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-25 |
-| [p2-33](p2-33-sound-system-extension.md) | β
done | "Sound system extension β categorical fallback, variant pools, per-entity routing" | [asset-audio](../team-leads/asset-audio.md) | 2026-04-27 |
+| ID | Status | Title | Tags | Owner | Updated | Blocked |
+|---|---|---|---|---|---|---|
+| [p0-20](p0-20-gpu-mcts-rollouts.md) | π‘ partial | GPU-accelerated MCTS rollouts for look-ahead decision-making | β | [warcouncil](../team-leads/warcouncil.md) | 2026-05-04 | π’ unblocked |
+| [p1-05](p1-05-balance-tuning.md) | π‘ partial | Balance tuning β pop_peak β₯30 median, worker improvements β₯8 min | β | [shipwright](../team-leads/shipwright.md) | 2026-05-01 | π’ unblocked |
+| [p1-22](p1-22-mcts-wall-clock-budget.md) | π‘ partial | MCTS per-decision wall-clock budget β bound per-turn cost on huge maps | β | [warcouncil](../team-leads/warcouncil.md) | 2026-04-25 | π’ unblocked |
+| [p1-27](p1-27-mcts-service-extraction.md) | π‘ partial | Extract GPU MCTS into a standalone service/client (model-boss-shaped, magic-civ-only) | β | [warcouncil](../team-leads/warcouncil.md) | 2026-05-03 | π’ unblocked |
+| [p1-29](p1-29.md) | π‘ partial | Anti-early-domination: lift game-balance gates that p0-01 v1 measured | balance, pacing | [combat-dev](../team-leads/combat-dev.md) | 2026-05-03 | π’ unblocked |
+| [p1-29a](p1-29a-last-stand-defense.md) | π‘ partial | Last-stand defense β combat-strength multiplier when defender is at last city | balance, combat, pacing | [combat-dev](../team-leads/combat-dev.md) | 2026-05-04 | π’ unblocked |
+| [p1-38](p1-38-biome-economy-coupling.md) | π‘ partial | Biome β economy coupling β population & luxury driven by live ecology | β | [shipwright](../team-leads/shipwright.md) | 2026-05-03 | π’ unblocked |
+| [p1-39](p1-39.md) | π‘ partial | Port per-yield difficulty multipliers from GDScript into Rust crates (Rail-1) β research + culture | rust-source-of-truth, rail-1 | [warcouncil](../team-leads/warcouncil.md) | 2026-05-04 | π’ unblocked |
+| [p1-42](p1-42-ai-full-building-catalog.md) | π‘ partial | AI must consider the full 155-building catalog, not the hardcoded 8-id ladder | β | β | 2026-05-04 | π’ unblocked |
+| [p1-43](p1-43-building-stacking-upgrade.md) | π‘ partial | Building stacking β per-category upgrade chains (military / science / culture / production / etc.) | β | β | 2026-05-04 | π’ unblocked |
+| [p1-44](p1-44-buildings-as-producers.md) | π‘ partial | Buildings produce units, not the city center β per-building production queues | β | β | 2026-05-04 | π’ unblocked |
+| [p1-55](p1-55-tech-culture-domain-propagation.md) | π‘ partial | Tech & Culture domain field β propagate categorization through Rust, Godot UI, and player analysis | β | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-04 | π’ unblocked |
+| [p1-56](p1-56-civics-buildings-and-great-works.md) | π‘ partial | Civics buildings, Great Works, Specialists, Great People β wire authored data into Rust + Godot | β | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-04 | π’ unblocked |
+| [p1-58](p1-58-ecology-cognitive-system.md) | π‘ partial | Ecology cognition: terrain affinity, food web, grudge memory, apex tier-10 fauna/flora | β | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-04 | π’ unblocked |
+| [p2-22](p2-22-sprite-generation-pipeline.md) | π‘ partial | Sprite generation pipeline β runnable end-to-end | β | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-25 | π’ unblocked |
+| [p1-30b](p1-30b-parallel-mcts-rollouts.md) | π΄ stub | Parallel MCTS rollouts for huge-map decisive games (closes p1-22's huge-map sub-gate) | perf, mcts, tactical-ai | [warcouncil](../team-leads/warcouncil.md) | 2026-05-03 | π’ unblocked |
+| [p1-57](p1-57-diplomacy-tribute-treaties.md) | π΄ stub | Diplomacy: tribute, treaty lifecycle, magical-terrain episode gating | β | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | π’ unblocked |
+| [p2-23](p2-23-unit-sprites-dwarf-roster.md) | β missing | Unit sprites β Dwarf-racial roster (m/f variants) | β | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | π’ unblocked |
+| [p2-24](p2-24-unit-sprites-wild-creatures.md) | β missing | Unit sprites β wild creatures & fauna (generic, no race/sex) | β | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | π’ unblocked |
+| [p2-25](p2-25-building-sprites-base-coverage.md) | β missing | Building sprites β base game coverage (non-wonder) | β | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | π’ unblocked |
+| [p2-26](p2-26-mundane-wonder-sprites.md) | β missing | Mundane-wonder sprites β 24 distinct, higher-fidelity art | β | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | π’ unblocked |
+| [p2-27](p2-27-city-population-tier-sprites.md) | β missing | City population-tier sprites β city_q1 through city_q5 | β | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | π’ unblocked |
## P2 β Polish
-| ID | Status | Title | Owner | Updated |
-|---|---|---|---|---|
-| [p2-01](p2-01-minimap-improvements.md) | β
done | Minimap β fog reflection and unit markers | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p2-02](p2-02-hud-tooltips.md) | β
done | Tooltips on all HUD elements | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p2-03](p2-03-hotkey-cheat-sheet.md) | β
done | Hotkey cheat sheet (F1 / ?) | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p2-04](p2-04-localization-audit.md) | β
done | Localization audit β no hardcoded strings | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p2-05](p2-05-turn-latency.md) | β
done | Sub-second single-player turn latency | β | 2026-04-23 |
-| [p2-06b](p2-06b-windows-runner.md) | β
done | Cross-compile Windows .exe + .dll from Linux via cargo-xwin (no Windows host) | [shipwright](../team-leads/shipwright.md) | 2026-04-25 |
-| [p2-07](p2-07-credits-screen.md) | β
done | Credits screen accessible from main menu | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p2-08](p2-08-accessibility.md) | β
done | Accessibility baseline β colorblind palette + keyboard navigation | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p2-09](p2-09-guide-web-deploy.md) | β
done | Player guide web app β builds clean from source | β | 2026-04-17 |
-| [p2-10](p2-10-regression-ci-gate.md) | π‘ partial | Automated regression CI gate on every push to main | [testwright](../team-leads/testwright.md) | 2026-05-04 |
-| [p2-10a](p2-10a-gdlint-ungate.md) | β
done | "CI: gdlint stage un-gated" | [testwright](../team-leads/testwright.md) | 2026-04-25 |
-| [p2-10b](p2-10b-gut-ungate.md) | β
done | "CI: headless GUT stage un-gated" | [testwright](../team-leads/testwright.md) | 2026-04-26 |
-| [p2-10c](p2-10c-diplomacy-luxury-ids.md) | β
done | "Diplomacy: implement _collect_unique_luxury_ids() in happiness.gd" | β | 2026-04-26 |
-| [p2-10d](p2-10d-legacy-unit-json.md) | β
done | "Data: strip legacy flags/can_found_city/can_build_improvements from unit JSON" | β | 2026-04-26 |
-| [p2-10e](p2-10e-data-integrity.md) | β
done | "Data: resolve duplicate IDs and dangling unlock refs in game data" | β | 2026-04-26 |
-| [p2-10f](p2-10f-save-manager-typed-arrays.md) | β
done | "SaveManager: fix typed array property assignment on Player/Unit deserialization" | β | 2026-04-26 |
-| [p2-10g](p2-10g-city-bridge-production-cost.md) | β
done | "CityBridge: add production_cost field to items JSON fixture" | β | 2026-04-26 |
-| [p2-10h](p2-10h-sprite-renderer-build-key.md) | β
done | "UnitRenderer: implement _build_sprite_key() helper and fix cache key test" | β | 2026-04-26 |
-| [p2-10i](p2-10i-tile-tooltip-scene.md) | β
done | "TileTooltip: fix scene node name mismatches and collectibles text formatting" | β | 2026-04-26 |
-| [p2-10j](p2-10j-fog-vision-scout-move.md) | β
done | "FogOfWar: fix recalculate_vision to not re-reveal already-seen tiles on move" | β | 2026-04-26 |
-| [p2-10k](p2-10k-gdlint-cleanup.md) | π΄ stub | "CI: fix 51 gdlint violations so Stage 3 is hard-green" | [testwright](../team-leads/testwright.md) | 2026-05-04 |
-| [p2-10l](p2-10l-gut-regression-triage.md) | π΄ stub | "CI: fix 15 GUT regressions so Stage 5 is hard-green" | [testwright](../team-leads/testwright.md) | 2026-05-04 |
-| [p2-11](p2-11-version-about-screen.md) | β
done | Version string + About screen | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
-| [p2-11a](p2-11a.md) | β
done | "SaveManager: add Unit.serialize/deserialize and City.production_queue serialize path" | β | 2026-05-04 |
-| [p2-12](p2-12-apricot-weston-install.md) | β
done | Install weston on apricot RUN host β unblock display-server smoke tests | [shipwright](../team-leads/shipwright.md) | 2026-04-25 |
-| [p2-18](p2-18-guide-public-deployment.md) | π‘ partial | Guide web app β public hosting + deploy pipeline | β | 2026-04-17 |
-| [p2-19](p2-19-guide-progress-report-page.md) | β
done | Guide progress report page β dynamic dashboard + missing assets | β | 2026-04-17 |
-| [p2-20](p2-20-guide-sim-cache-pnpm-resolve.md) | β
done | Fix simCachePlugin pre-warm worker β tsx can't resolve @magic-civ/physics-rs through pnpm symlink | [tourguide](../team-leads/tourguide.md) | 2026-04-17 |
-| [p2-21](p2-21-guide-simcache-static-bake.md) | β
done | Bake pre-computed sim-cache frames into the static build | [tourguide](../team-leads/tourguide.md) | 2026-04-18 |
-| [p2-29](p2-29-guide-welcome-homepage-theme-alignment.md) | β
done | Welcome modal + HomePage lore + guide theme align to the player's chosen race/gender | [tourguide](../team-leads/tourguide.md) | 2026-04-18 |
-| [p2-30](p2-30-guide-shared-primitives.md) | β
done | Consolidate duplicate page styled-components into shared PagePrimitives | [tourguide](../team-leads/tourguide.md) | 2026-04-18 |
-| [p2-31](p2-31-guide-url-bound-state.md) | β
done | Migrate guide filter + tab state from useState to URL search params | [tourguide](../team-leads/tourguide.md) | 2026-04-18 |
-| [p2-32](p2-32-guide-data-driven-enums.md) | β
done | Replace hardcoded page enums with JSON data reads | [tourguide](../team-leads/tourguide.md) | 2026-04-18 |
-| [p2-35](p2-35-palace-evolution-system.md) | β
done | Palace evolution system β longhouse β great_hall β citadel β grand_citadel + function-shedding | β | 2026-05-04 |
-| [p2-36](p2-36-data-resources-building-duplicates.md) | β
done | Reconcile the 14 building IDs defined in both `resources/buildings/` and `data/buildings/` | β | 2026-04-29 |
-| [p2-37](p2-37-react-calculator-metadata-surface.md) | β
done | "React calculator UI β surface flavor, lore, clan_affinity, archetype filter" | [tourguide](../team-leads/tourguide.md) | 2026-04-27 |
-| [p2-38](p2-38-unit-audio-cues-stubs.md) | β
done | "Unit audio_cues stub strings β selection/move/attack lines for the dwarven roster" | [asset-audio](../team-leads/asset-audio.md) | 2026-04-27 |
-| [p2-39](p2-39-chronicle-hall-phantom-unlock.md) | β
done | Resolve `chronicle_hall` phantom unlock in `chronicle_keeping` culture tech | β | 2026-04-27 |
-| [p2-43](p2-43-culture-research-completion-event.md) | π‘ partial | "Culture research live-game pipeline β per-turn GDExt bridge + `culture_researched` emit" | β | 2026-05-04 |
-| [p2-44](p2-44-ai-promotion-selection.md) | π‘ partial | AI promotion selection β auto-pick + emit unit_promoted for AI units | β | 2026-05-04 |
-| [p2-45](p2-45-elimination-reconciliation.md) | β
done | "Player elimination reconciliation β emit `player_eliminated` on every transition" | β | 2026-04-30 |
-| [p2-46](p2-46-past-games-archive-replay-viewer.md) | π‘ partial | Past-games archive & replay viewer β `mc-replay` crate, on-disk archive, projection-based playback | [shipwright](../team-leads/shipwright.md) | 2026-05-03 |
-| [p2-47](p2-47-in-game-statistics-screens.md) | π‘ partial | In-game statistics screens β Civ-style 5-tab modal (Demographics / Graphs / Rankings / Replay / Histories) | [shipwright](../team-leads/shipwright.md) | 2026-05-03 |
-| [p2-48](p2-48-end-of-game-summary-screen.md) | π‘ partial | End-of-game summary screen β outcome banner, standings, score graph, awards, timeline, footer actions | [shipwright](../team-leads/shipwright.md) | 2026-05-03 |
-| [p2-49](p2-49-climate-axes-latitude-continentality.md) | β
done | Climate axes refactor β latitude + continentality + zonal winds as first-class per-hex inputs | [terraformer](../team-leads/terraformer.md) | 2026-04-30 |
-| [p2-50](p2-50-rng-determinism-pin.md) | β
done | Deterministic RNG + seed-derivation pin across mc-mapgen / mc-climate / mc-ecology | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p2-51](p2-51-world-shape-knobs.md) | β
done | Player-facing world-shape parameters on new-game screen | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p2-52](p2-52-substrate-flora-cover-ontology-split.md) | β
done | Split terrain enum into substrate Γ flora-cover layers (resolve biome ontology) | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p2-53](p2-53-action-vocabulary-design-game-gap.md) | β
done | Action vocabulary β gap analysis between design page and shipped Rust/Godot game | [wireguard](../team-leads/wireguard.md) | 2026-05-03 |
-| [p2-53a](p2-53a-sentry-guard-action-kind.md) | β
done | Sentry/Guard ActionKind β add Sentry/Unsentry to mc-core with wake-on-vision | [wireguard](../team-leads/wireguard.md) | 2026-05-01 |
-| [p2-53b](p2-53b-building-action-registry.md) | β
done | Building action registry β `BuildingActionKind`, `building_actions.json`, `GdBuildingActions` bridge | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-01 |
-| [p2-53c](p2-53c-rally-vocabulary-expansion.md) | β
done | Rally vocabulary expansion β Hold / Fortify / JoinFormation + two-waypoint Patrol | [shipwright](../team-leads/shipwright.md) | 2026-05-01 |
-| [p2-53d](p2-53d-building-specifics.md) | β
done | Building specifics β Garrison, Repair, Toggle Active + 18 archetype-specific actions | [shipwright](../team-leads/shipwright.md) | 2026-05-03 |
-| [p2-53e](p2-53e-siege-pillage-embark.md) | β
done | Siege handlers (Pack/Deploy/Bombard) + Pillage UI wiring + Embark/Disembark handlers | [combat-dev](../team-leads/combat-dev.md) | 2026-05-03 |
-| [p2-53f](p2-53f-infantry-specifics.md) | β
done | Infantry specifics β Shield Wall, Brace, Shove, Rage, Cleave, War Cry | [combat-dev](../team-leads/combat-dev.md) | 2026-05-01 |
-| [p2-53g](p2-53g-ranged-specifics.md) | β
done | Ranged specifics β Volley, Aimed Shot, Fire Arrows | [combat-dev](../team-leads/combat-dev.md) | 2026-05-03 |
-| [p2-53h](p2-53h-cavalry-specifics.md) | β
done | Cavalry specifics β Charge, Pursue, Wheel | [combat-dev](../team-leads/combat-dev.md) | 2026-05-03 |
-| [p2-53i](p2-53i-engineer-pioneer-medic-scout.md) | β
done | Support specifics β Engineer, Pioneer, Medic, Scout | [shipwright](../team-leads/shipwright.md) | 2026-05-03 |
-| [p2-54](p2-54-resource-visibility-three-axis.md) | β
done | Resource visibility β three-axis (visibility/yield_gate/improvement_gate) refactor | [terraformer](../team-leads/terraformer.md) | 2026-05-02 |
-| [p2-54a](p2-54a-deposits-three-axis-migration.md) | β
done | Migrate deposits/*.json to three-axis visibility schema | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p2-54b](p2-54b-player-observation-cache.md) | β
done | Per-player tile observation cache β flora/fauna last-observed state | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p2-54c](p2-54c-renderer-observations-and-indicators.md) | β
done | Renderer reads observations + indicator decorations for tech-gated resources | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p2-54d](p2-54d-ai-tech-priority-from-visibility.md) | β
done | AI tech-priority bias from visible-but-gated luxuries + indicator decorations | [terraformer](../team-leads/terraformer.md) | 2026-05-01 |
-| [p2-55](p2-55-civilian-capture-system.md) | π‘ partial | "Civilian Capture / Destroy / Ransom" | β | 2026-05-03 |
-| [p2-55d](p2-55d-ai-ransom-decision-hook.md) | π΄ stub | "AI ransom accept/refuse hook in mc-turn start-of-turn" | β | 2026-05-03 |
-| [p2-55e](p2-55e-richer-ransom-events.md) | π΄ stub | "UnitRansomAccepted / UnitRansomExpired events on TurnResult" | β | 2026-05-03 |
-| [p2-56](p2-56-worker-categories-and-expertise-tiers.md) | π΄ stub | "Worker categories (Sustenance/Construction/Wealth) + 5-tier expertise + Master/Grandmaster auras + idle decay" | [unassigned](../team-leads/unassigned.md) | 2026-05-03 |
-| [p2-56a](p2-56a-worker-category-types.md) | β
done | Worker category types β Sustenance / Construction / Wealth taxonomy | [unassigned](../team-leads/unassigned.md) | 2026-05-04 |
-| [p2-56b](p2-56b-expertise-tier-progression.md) | β
done | Expertise tier progression β 5-tier specialist XP ladder | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-04 |
-| [p2-56c](p2-56c-master-grandmaster-auras.md) | π‘ partial | Master / Grandmaster auras β adjacent-slot yield propagation | [unassigned](../team-leads/unassigned.md) | 2026-05-04 |
-| [p2-57](p2-57-production-chain-typed-resources.md) | π΄ stub | "Production-chain typed resources β raw β processed pipelines wired into mc-city" | [unassigned](../team-leads/unassigned.md) | 2026-05-03 |
-| [p2-57a](p2-57a-typed-resource-stockpile.md) | π‘ partial | Typed resource stockpile β raw vs processed taxonomy | [unassigned](../team-leads/unassigned.md) | 2026-05-04 |
-| [p2-57b](p2-57b-consume-produce-edges.md) | π΄ stub | "Building consume/produce edges β stockpile coupled to unit quality" | [unassigned](../team-leads/unassigned.md) | 2026-05-03 |
-| [p2-58](p2-58-ambient-encounter-rolls.md) | π΄ stub | "Ambient encounter rolls per tile moved β fauna_density Γ ecology_tier" | [unassigned](../team-leads/unassigned.md) | 2026-05-03 |
-| [p2-59](p2-59-pioneer-escort-mechanic.md) | π΄ stub | "Pioneer escort mechanic β protection rules vs ambient encounters" | [unassigned](../team-leads/unassigned.md) | 2026-05-03 |
-| [p2-60](p2-60-weather-lens-godot-ui.md) | π΄ stub | "Weather / observation lens switcher in the Godot HUD" | [unassigned](../team-leads/unassigned.md) | 2026-05-03 |
-| [p2-61](p2-61-observation-recording-gates-from-tech.md) | π΄ stub | "Bind mc-observation gate_bits to player tech state β recording gates per-field" | [unassigned](../team-leads/unassigned.md) | 2026-05-03 |
-| [p2-62](p2-62-procedural-unit-and-building-renderer.md) | β
done | Procedural unit/building renderer β alpha-only visual substitute | [asset-sprite](../team-leads/asset-sprite.md) | 2026-05-04 |
-| [p2-63](p2-63-mc-flora-biome-substrate-migration.md) | π΄ stub | "mc-flora generation: migrate biome filter to substrate_climate-aware path" | [unassigned](../team-leads/unassigned.md) | 2026-05-04 |
+| ID | Status | Title | Tags | Owner | Updated | Blocked |
+|---|---|---|---|---|---|---|
+| [p2-10](p2-10-regression-ci-gate.md) | π‘ partial | Automated regression CI gate on every push to main | β | [testwright](../team-leads/testwright.md) | 2026-05-04 | π’ unblocked |
+| [p2-18](p2-18-guide-public-deployment.md) | π‘ partial | Guide web app β public hosting + deploy pipeline | β | β | 2026-04-17 | π’ unblocked |
+| [p2-43](p2-43-culture-research-completion-event.md) | π‘ partial | Culture research live-game pipeline β per-turn GDExt bridge + `culture_researched` emit | β | β | 2026-05-04 | π’ unblocked |
+| [p2-44](p2-44-ai-promotion-selection.md) | π‘ partial | AI promotion selection β auto-pick + emit unit_promoted for AI units | β | β | 2026-05-04 | π’ unblocked |
+| [p2-46](p2-46-past-games-archive-replay-viewer.md) | π‘ partial | Past-games archive & replay viewer β `mc-replay` crate, on-disk archive, projection-based playback | β | [shipwright](../team-leads/shipwright.md) | 2026-05-03 | π’ unblocked |
+| [p2-47](p2-47-in-game-statistics-screens.md) | π‘ partial | In-game statistics screens β Civ-style 5-tab modal (Demographics / Graphs / Rankings / Replay / Histories) | β | [shipwright](../team-leads/shipwright.md) | 2026-05-03 | π’ unblocked |
+| [p2-48](p2-48-end-of-game-summary-screen.md) | π‘ partial | End-of-game summary screen β outcome banner, standings, score graph, awards, timeline, footer actions | β | [shipwright](../team-leads/shipwright.md) | 2026-05-03 | π’ unblocked |
+| [p2-55](p2-55-civilian-capture-system.md) | π‘ partial | Civilian Capture / Destroy / Ransom | β | β | 2026-05-03 | π’ unblocked |
+| [p2-56c](p2-56c-master-grandmaster-auras.md) | π‘ partial | Master / Grandmaster auras β adjacent-slot yield propagation | β | [unassigned](../team-leads/unassigned.md) | 2026-05-04 | π’ unblocked |
+| [p2-57a](p2-57a-typed-resource-stockpile.md) | π‘ partial | Typed resource stockpile β raw vs processed taxonomy | β | [unassigned](../team-leads/unassigned.md) | 2026-05-04 | π’ unblocked |
+| [p2-10k](p2-10k-gdlint-cleanup.md) | π΄ stub | CI: fix 51 gdlint violations so Stage 3 is hard-green | β | [testwright](../team-leads/testwright.md) | 2026-05-04 | π’ unblocked |
+| [p2-10l](p2-10l-gut-regression-triage.md) | π΄ stub | CI: fix 15 GUT regressions so Stage 5 is hard-green | β | [testwright](../team-leads/testwright.md) | 2026-05-04 | π’ unblocked |
+| [p2-55d](p2-55d-ai-ransom-decision-hook.md) | π΄ stub | AI ransom accept/refuse hook in mc-turn start-of-turn | β | β | 2026-05-03 | π’ unblocked |
+| [p2-55e](p2-55e-richer-ransom-events.md) | π΄ stub | UnitRansomAccepted / UnitRansomExpired events on TurnResult | β | β | 2026-05-03 | π’ unblocked |
+| [p2-56](p2-56-worker-categories-and-expertise-tiers.md) | π΄ stub | Worker categories (Sustenance/Construction/Wealth) + 5-tier expertise + Master/Grandmaster auras + idle decay | β | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | π’ unblocked |
+| [p2-57](p2-57-production-chain-typed-resources.md) | π΄ stub | Production-chain typed resources β raw β processed pipelines wired into mc-city | β | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | π’ unblocked |
+| [p2-58](p2-58-ambient-encounter-rolls.md) | π΄ stub | Ambient encounter rolls per tile moved β fauna_density Γ ecology_tier | β | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | π’ unblocked |
+| [p2-60](p2-60-weather-lens-godot-ui.md) | π΄ stub | Weather / observation lens switcher in the Godot HUD | β | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | π’ unblocked |
+| [p2-61](p2-61-observation-recording-gates-from-tech.md) | π΄ stub | Bind mc-observation gate_bits to player tech state β recording gates per-field | β | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | π’ unblocked |
+| [p2-63](p2-63-mc-flora-biome-substrate-migration.md) | π΄ stub | mc-flora generation: migrate biome filter to substrate_climate-aware path | β | [unassigned](../team-leads/unassigned.md) | 2026-05-04 | π’ unblocked |
+| [p2-57b](p2-57b-consume-produce-edges.md) | π΄ stub | Building consume/produce edges β stockpile coupled to unit quality | β | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | π p2-57a |
+| [p2-59](p2-59-pioneer-escort-mechanic.md) | π΄ stub | Pioneer escort mechanic β protection rules vs ambient encounters | β | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | π p2-58 |
-## Out of Scope (Game 2 / Game 3)
+## Out of Scope
-> These objectives are explicitly future-scope. **Game 2 (Age of Kzzykt)** items introduce leylines, the Green school, and spacefaring. **Game 3 (Age of Elves)** items cover the full five-school magic system, Archons, and Arcane Ascension. None are part of the Game 1 Early Access release.
+> These objectives are explicitly deferred. They are tracked for visibility but not blocking the current release.
-| ID | Status | Title | Owner | Updated |
-|---|---|---|---|---|
-| [p1-14](p1-14-guide-magic-school-scope-drift.md) | β« oos | Gate Game 2/3/4 magic-school content behind EpisodeGate (future-game scope) | β | 2026-04-17 |
-| [g2-05](g2-05-tectonics-lithology-oos.md) | β« oos | Tectonics + lithology axes for procedural map generation (Game 2) | β | 2026-04-30 |
-| [g2-06](g2-06-soil-derivation-oos.md) | β« oos | Soil derivation layer β emergent soil order from rock + climate + slope (Game 2) | β | 2026-04-30 |
-| [g2-07](g2-07-flora-lifecycle-transitions-oos.md) | β« oos | Flora lifecycle transitions β climate-driven succession over turns (Game 2) | β | 2026-05-01 |
-| [g2-08](g2-08-fauna-population-dynamics-oos.md) | β« oos | Fauna population dynamics β habitat_min, carrying_capacity, prey availability (Game 2) | β | 2026-05-01 |
-| [g2-09](g2-09-flora-tolerance-driven-selection-oos.md) | β« oos | Flora tolerance-driven selection β drought / fire / cold tolerances feed selector (Game 2) | β | 2026-05-01 |
-| [g2-10](g2-10-fauna-migration-paths-oos.md) | β« oos | Fauna migration paths β seasonal range shifts, reintroduction propagation (Game 2) | β | 2026-05-01 |
-| [g2-01](g2-01-leylines-oos.md) | β« oos | Ley lines β Game 2 (Age of Kzzykt) | β | 2026-04-17 |
-| [g2-02](g2-02-additional-races-oos.md) | β« oos | Kzzykt playable race β Game 2 (Age of Kzzykt) | β | 2026-04-17 |
-| [g2-03](g2-03-green-school-oos.md) | β« oos | Kzzykt Green school of magic β Game 2 (Age of Kzzykt) | β | 2026-04-17 |
-| [g2-04](g2-04-multi-gpu-batch-simulate-oos.md) | β« oos | Multi-GPU sharding for batch_simulate_gpu β out-of-scope (Game 2) | [warcouncil](../team-leads/warcouncil.md) | 2026-04-17 |
-| [g2-11](g2-11-vertical-city-floor-stack-oos.md) | β« oos | "Vertical city floor stack (Game 2) β OOS" | [unassigned](../team-leads/unassigned.md) | 2026-05-03 |
-| [g2-12](g2-12-underground-layer-stack-oos.md) | β« oos | "Underground layer stack (Game 2) β OOS" | [unassigned](../team-leads/unassigned.md) | 2026-05-03 |
-| [g3-01](g3-01-archons-oos.md) | β« oos | Archons β Game 3 (Age of Elves) | β | 2026-04-17 |
-| [g3-02](g3-02-life-school-oos.md) | β« oos | Life school spellbook β Game 3 (Age of Elves) | β | 2026-04-17 |
-| [g3-03](g3-03-death-school-oos.md) | β« oos | Death school spellbook β Game 3 (Age of Elves) | β | 2026-04-17 |
-| [g3-04](g3-04-chaos-school-oos.md) | β« oos | Chaos school spellbook β Game 3 (Age of Elves) | β | 2026-04-17 |
-| [g3-05](g3-05-aether-school-oos.md) | β« oos | Aether school spellbook β Game 3 (Age of Elves) | β | 2026-04-17 |
-| [g3-06](g3-06-arcane-ascension-oos.md) | β« oos | Arcane Ascension victory β Game 3 (Age of Elves) | β | 2026-04-17 |
-| [g4-01](g4-01-terran-race-oos.md) | β« oos | Terran (Human) playable species β Game 4 (Age of Terrans) | β | 2026-04-17 |
-| [g4-02](g4-02-psionics-oos.md) | β« oos | Psionics ability system β Game 4 (Age of Terrans) | β | 2026-04-17 |
-| [g4-03](g4-03-religious-victory-oos.md) | β« oos | Religious victory condition β Game 4 (Age of Terrans) | β | 2026-04-17 |
-| [g5-01](g5-01-phantasma-oos.md) | β« oos | Phantasma playable species β Game 5 (Age of Ascension) | β | 2026-04-17 |
-| [g5-02](g5-02-flugel-oos.md) | β« oos | FlΓΌgel playable species β Game 5 (Age of Ascension) | β | 2026-04-17 |
-| [g5-03](g5-03-gith-oos.md) | β« oos | Gith playable species (Githyanki + Githzerai) β Game 5 (Age of Ascension) | β | 2026-04-17 |
-| [g5-04](g5-04-demonia-oos.md) | β« oos | Demonia playable species β Game 5 (Age of Ascension) | β | 2026-04-17 |
-| [g6-01](g6-01-naval-combat-oos.md) | β« oos | Naval combat β out-of-scope (post-v10) | β | 2026-04-26 |
-| [g6-02](g6-02-caravan-trade-routes-oos.md) | β« oos | Caravan trade routes β out-of-scope (post-v10) | β | 2026-04-26 |
+| ID | Status | Title | Tags | Owner | Updated | Blocked |
+|---|---|---|---|---|---|---|
+| [p1-14](p1-14-guide-magic-school-scope-drift.md) | β« oos | Gate Game 2/3/4 magic-school content behind EpisodeGate (future-game scope) | β | β | 2026-04-17 | π’ unblocked |
+| [g2-05](g2-05-tectonics-lithology-oos.md) | β« oos | Tectonics + lithology axes for procedural map generation (Game 2) | β | β | 2026-04-30 | π’ unblocked |
+| [g2-06](g2-06-soil-derivation-oos.md) | β« oos | Soil derivation layer β emergent soil order from rock + climate + slope (Game 2) | β | β | 2026-04-30 | π’ unblocked |
+| [g2-07](g2-07-flora-lifecycle-transitions-oos.md) | β« oos | Flora lifecycle transitions β climate-driven succession over turns (Game 2) | β | β | 2026-05-01 | π’ unblocked |
+| [g2-08](g2-08-fauna-population-dynamics-oos.md) | β« oos | Fauna population dynamics β habitat_min, carrying_capacity, prey availability (Game 2) | β | β | 2026-05-01 | π’ unblocked |
+| [g2-09](g2-09-flora-tolerance-driven-selection-oos.md) | β« oos | Flora tolerance-driven selection β drought / fire / cold tolerances feed selector (Game 2) | β | β | 2026-05-01 | π’ unblocked |
+| [g2-10](g2-10-fauna-migration-paths-oos.md) | β« oos | Fauna migration paths β seasonal range shifts, reintroduction propagation (Game 2) | β | β | 2026-05-01 | π’ unblocked |
+| [g2-01](g2-01-leylines-oos.md) | β« oos | Ley lines β Game 2 (Age of Kzzykt) | β | β | 2026-04-17 | π’ unblocked |
+| [g2-02](g2-02-additional-races-oos.md) | β« oos | Kzzykt playable race β Game 2 (Age of Kzzykt) | β | β | 2026-04-17 | π’ unblocked |
+| [g2-03](g2-03-green-school-oos.md) | β« oos | Kzzykt Green school of magic β Game 2 (Age of Kzzykt) | β | β | 2026-04-17 | π’ unblocked |
+| [g2-04](g2-04-multi-gpu-batch-simulate-oos.md) | β« oos | Multi-GPU sharding for batch_simulate_gpu β out-of-scope (Game 2) | β | [warcouncil](../team-leads/warcouncil.md) | 2026-04-17 | π’ unblocked |
+| [g2-11](g2-11-vertical-city-floor-stack-oos.md) | β« oos | Vertical city floor stack (Game 2) β OOS | β | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | π g2-12 |
+| [g2-12](g2-12-underground-layer-stack-oos.md) | β« oos | Underground layer stack (Game 2) β OOS | β | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | π’ unblocked |
+| [g3-01](g3-01-archons-oos.md) | β« oos | Archons β Game 3 (Age of Elves) | β | β | 2026-04-17 | π’ unblocked |
+| [g3-02](g3-02-life-school-oos.md) | β« oos | Life school spellbook β Game 3 (Age of Elves) | β | β | 2026-04-17 | π’ unblocked |
+| [g3-03](g3-03-death-school-oos.md) | β« oos | Death school spellbook β Game 3 (Age of Elves) | β | β | 2026-04-17 | π’ unblocked |
+| [g3-04](g3-04-chaos-school-oos.md) | β« oos | Chaos school spellbook β Game 3 (Age of Elves) | β | β | 2026-04-17 | π’ unblocked |
+| [g3-05](g3-05-aether-school-oos.md) | β« oos | Aether school spellbook β Game 3 (Age of Elves) | β | β | 2026-04-17 | π’ unblocked |
+| [g3-06](g3-06-arcane-ascension-oos.md) | β« oos | Arcane Ascension victory β Game 3 (Age of Elves) | β | β | 2026-04-17 | π’ unblocked |
+| [g4-01](g4-01-terran-race-oos.md) | β« oos | Terran (Human) playable species β Game 4 (Age of Terrans) | β | β | 2026-04-17 | π’ unblocked |
+| [g4-02](g4-02-psionics-oos.md) | β« oos | Psionics ability system β Game 4 (Age of Terrans) | β | β | 2026-04-17 | π’ unblocked |
+| [g4-03](g4-03-religious-victory-oos.md) | β« oos | Religious victory condition β Game 4 (Age of Terrans) | β | β | 2026-04-17 | π’ unblocked |
+| [g5-01](g5-01-phantasma-oos.md) | β« oos | Phantasma playable species β Game 5 (Age of Ascension) | β | β | 2026-04-17 | π’ unblocked |
+| [g5-02](g5-02-flugel-oos.md) | β« oos | FlΓΌgel playable species β Game 5 (Age of Ascension) | β | β | 2026-04-17 | π’ unblocked |
+| [g5-03](g5-03-gith-oos.md) | β« oos | Gith playable species (Githyanki + Githzerai) β Game 5 (Age of Ascension) | β | β | 2026-04-17 | π’ unblocked |
+| [g5-04](g5-04-demonia-oos.md) | β« oos | Demonia playable species β Game 5 (Age of Ascension) | β | β | 2026-04-17 | π’ unblocked |
+| [g6-01](g6-01-naval-combat-oos.md) | β« oos | Naval combat β out-of-scope (post-v10) | β | β | 2026-04-26 | π’ unblocked |
+| [g6-02](g6-02-caravan-trade-routes-oos.md) | β« oos | Caravan trade routes β out-of-scope (post-v10) | β | β | 2026-04-26 | π’ unblocked |
## Superseded
-> These objectives were split into narrower children. Files are retained as index stubs so external references don't 404. The `superseded_by:` frontmatter field names the replacement IDs.
+> These objectives were split into narrower children. Files are retained as index stubs so external references do not 404.
-| ID | Status | Title | Owner | Updated |
-|---|---|---|---|---|
-| [p1-27d](p1-27d-additive-value-estimate.md) | β»οΈ superseded | Add `value_estimate_abstract` GdMcTreeController method β non-lossy MCTS service caller | [warcouncil](../team-leads/warcouncil.md) | 2026-04-25 |
-| [p2-17](p2-17-sprite-assets.md) | β»οΈ superseded | Sprite assets β superseded index (split into p2-22 β¦ p2-28) | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 |
+| ID | Status | Title | Tags | Owner | Updated | Blocked |
+|---|---|---|---|---|---|---|
+| [p1-27d](p1-27d-additive-value-estimate.md) | β»οΈ superseded | Add `value_estimate_abstract` GdMcTreeController method β non-lossy MCTS service caller | β | [warcouncil](../team-leads/warcouncil.md) | 2026-04-25 | π’ unblocked |
+| [p2-17](p2-17-sprite-assets.md) | β»οΈ superseded | Sprite assets β superseded index (split into p2-22 β¦ p2-28) | β | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | π’ unblocked |
diff --git a/.project/objectives/objectives.json b/.project/objectives/objectives.json
index 0908aa4a..9e7f3ccc 100644
--- a/.project/objectives/objectives.json
+++ b/.project/objectives/objectives.json
@@ -1,13 +1,13 @@
{
- "generated_at": "2026-05-04T07:43:53Z",
+ "generated_at": "2026-05-04T08:17:10Z",
"totals": {
"done": 152,
"in_progress": 1,
- "partial": 24,
- "stub": 30,
- "missing": 7,
+ "partial": 25,
+ "stub": 32,
+ "missing": 6,
"oos": 28,
- "total": 242
+ "total": 244
},
"objectives": [
{
@@ -987,9 +987,9 @@
"id": "p1-44",
"title": "Buildings produce units, not the city center β per-building production queues",
"priority": "p1",
- "status": "missing",
+ "status": "partial",
"scope": "game1",
- "updated_at": "2026-04-29",
+ "updated_at": "2026-05-04",
"blocked_by": [],
"summary": "User direction (2026-04-29): \"it would make sense to build those units in the appropriate buildings rather than the city center.\"\n\nToday every city has **one** production queue (`city.gd:57 production_queue: Array`) where the player picks \"warrior\", \"barracks\", \"wonder\", anything goes through the same FIFO. Building selection just gates the menu β the building doesn't actually *do* anything when production happens.\n\nThe user's model β and the model `PRODUCTION_CHAIN.md` already describes β is that buildings are **producers**:\n\n> Every citizen is a resource pulled between three competing demands:\n> - **Construction** β builds new buildings, upgrades existing ones (investment)\n> - **Buildings** β produces units, research, culture, equipment (output)\n> - **Tiles** β produces food, raw materials, gold (sustenance)\n\nConcretely:\n- **Barracks** has its own queue producing infantry / armory / military_academy lineage units.\n- **Stable** queues cavalry units.\n- **Siege Workshop** queues siege units.\n- **Library** queues sages / cartographers / engineers (science civilians) and accumulates research per turn.\n- **Temple** queues battle priests and accumulates culture/happiness.\n- **Harbor** queues naval units (and gates them β see `p1-33`).\n- **Airfield** queues aerial units.\n- **Construction queue** (city-level, distinct from building queues) builds NEW buildings and upgrades existing ones.\n\nEach producer building runs its queue independently per turn. Citizens / production allocation gets split across buildings (per `PRODUCTION_CHAIN.md` \"Three-Way Tension\"). The city's single global queue dies; build-vs-train becomes a structural distinction not a queue-item distinction.\n\nThis is a major engine refactor. Touches: `mc-city`, `mc-turn`, `city.gd`, `city_screen.gd`, `city_buildable_helper.gd`, save schema, AI's `production.rs` (now picks per producer-building, not per city), and the new themed-unit catalog (battle_priest, sage, bard, merchant, etc. β see `p1-43` open question 1)."
},
@@ -1424,7 +1424,7 @@
"status": "partial",
"scope": "game1",
"owner": "testwright",
- "updated_at": "2026-04-23",
+ "updated_at": "2026-05-04",
"blocked_by": [],
"summary": "This project ships via direct commits to `main` on a self-hosted forge\nat `http://10.0.0.11:3000/magicciv/magicciv` (Forgejo, port 3000).\nThere is no PR workflow β `git log --oneline` shows zero \"Merge pull\nrequest\" commits, no feature branches, no review gate. Forgejo Actions\n(drone-compatible, files live in `.forgejo/workflows/`) plus a\nself-hosted apricot runner enforces the test suite on every push to\n`main`, matching the two-host workflow (CLAUDE.md: EDIT host commits, RUN\nhost executes β apricot already is the RUN host).\n\n**State as of 2026-04-17 PM**: the pipeline is operational end-to-end. apricot runner `act_runner v12.8.0` is registered at org scope, systemd user unit is linger-enabled, PATH-patched for fnm-managed node. Every push to main produces a commit status visible on the forge commit page. The Rust workspace (~700 tests, 11 crates) hard-gates the commit; GDExtension now builds as part of CI so Godot's GDScript parse resolves bridge types.\n\nTwo stages remain `continue-on-error: true` (advisory) with in-workflow comments documenting the cleanup owner and un-gating trigger: gdlint (7 structural violations β file-splitting required) and headless GUT (39 pre-existing failures out of 439). The third advisory stage (autoplay smoke / Stage 9) was un-gated 2026-04-24 after the `_finalize_run()` write race fix. These are tracked via `advisory_backlog_tracked` in the audit block above; un-gating the remaining two is the path to closing this objective from π‘ to β
.\n\n**gdlint status (2026-04-23):** Reduced from 88 β 7 violations via mechanical fixes (class-definitions-order in tile.gd, max-line-length in save_manager/event_bus/auto_play, duplicated-load in auto_play, function-variable-name in turn_processor/turn_processor_helpers). Remaining 7 are structural and cannot be fixed without file-splitting:\n- `max-file-lines`: unit_renderer.gd (634 lines), game_state.gd (556), city.gd (568), auto_play.gd (2238), turn_processor.gd (635), ai_turn_bridge.gd (722)\n- `max-returns`: auto_play.gd `_maybe_prioritize_worker` (>6 return statements β refactor changes game logic)\nCI Stage 3 remains `continue-on-error: true` until file-splitting is scheduled."
},
@@ -1538,6 +1538,28 @@
"blocked_by": [],
"summary": "The two tests were `pending()` placeholders. The production code (`world_map_vision.gd:recalculate_vision()`) is correct β it demotes visibleβstale then re-promotes in-range tiles, which is standard fog-of-war behavior with no return value. The fix was implementing real test bodies using the existing `_expand_vision()` helper, which already counts staleβvisible transitions correctly.\n\n- `test_move_scout_expands_known_count`: reveals 37 tiles on first call; after 1-hex move, asserts `< 37` new tiles (already-visible tiles stay visible)\n- `test_seeded_t10_scout_move_reveals_exact_k_tiles`: asserts exactly `2*sight_range+1 = 7` new tiles from a 1-hex axial move (the leading-edge slice formula)"
},
+ {
+ "id": "p2-10k",
+ "title": "CI: fix 51 gdlint violations so Stage 3 is hard-green",
+ "priority": "p2",
+ "status": "stub",
+ "scope": "game1",
+ "owner": "testwright",
+ "updated_at": "2026-05-04",
+ "blocked_by": [],
+ "summary": "As of 2026-05-04, `gdlint src/game/engine/src/` reports 51 violations across\n17 files. The CI YAML comment claiming \"Hard-gated 2026-04-25\" was aspirational\ndocumentation; the rule was never verified to pass on apricot.\n\nParent: p2-10 (regression CI gate)."
+ },
+ {
+ "id": "p2-10l",
+ "title": "CI: fix 15 GUT regressions so Stage 5 is hard-green",
+ "priority": "p2",
+ "status": "stub",
+ "scope": "game1",
+ "owner": "testwright",
+ "updated_at": "2026-05-04",
+ "blocked_by": [],
+ "summary": "As of 2026-05-04, `bash tools/gut-headless.sh` reports 15 failing tests\n(500 total, 477 passing, 8 pending). The CI YAML comment claiming\n\"Hard-gated 2026-04-26 (p2-10b)\" was aspirational; the stage was never\nverified clean on apricot.\n\nParent: p2-10 (regression CI gate). Previous child objectives p2-10c\nthrough p2-10j are all `status: done` β these 15 failures are new\nregressions introduced after those were closed."
+ },
{
"id": "p2-11",
"title": "Version string + About screen",
@@ -2819,6 +2841,10 @@
"owner": "simulator-infra",
"remaining": 3
},
+ {
+ "owner": "testwright",
+ "remaining": 3
+ },
{
"owner": "combat-dev",
"remaining": 2
@@ -2826,10 +2852,6 @@
{
"owner": "asset-audio",
"remaining": 1
- },
- {
- "owner": "testwright",
- "remaining": 1
}
]
}
diff --git a/.project/objectives/p1-44-buildings-as-producers.md b/.project/objectives/p1-44-buildings-as-producers.md
index fcfb8a4d..46900049 100644
--- a/.project/objectives/p1-44-buildings-as-producers.md
+++ b/.project/objectives/p1-44-buildings-as-producers.md
@@ -1,12 +1,22 @@
---
id: p1-44
-title: Buildings produce units, not the city center β per-building production queues
+title: "Buildings produce units, not the city center β per-building production queues"
priority: p1
-status: missing
+status: partial
scope: game1
-updated_at: 2026-04-29
+updated_at: 2026-05-04
+evidence:
+ - "src/simulator/crates/mc-core/src/production_origin.rs:18 typed ProductionOrigin enum (CityCenter | Building(BuildingId)) with 3 round-trip tests"
+ - "src/simulator/crates/mc-core/src/ids.rs:62 typed UnitId string newtype (#[serde(transparent)])"
+ - "src/simulator/crates/mc-city/src/production.rs:114 UnitDef.requires_building: Option + UnitRegistry (BTreeMap)"
+ - "src/simulator/crates/mc-city/src/city.rs City::enqueue_unit gates on requires_building (uses has_building, returns ProductionOrigin)"
+ - "src/simulator/crates/mc-ai/src/tactical/state.rs:291 TacticalUnitSpec.requires_building retyped Option -> Option"
+ - "src/simulator/crates/mc-ai/src/tactical/production.rs:551 AI catalog filter respects requires_building (typed)"
+ - src/simulator/api-gdext/src/lib.rs queue_snapshot emits kind + origin_kind + origin_building_id for GDScript UI
+ - "public/resources/units/caravan_master.json:27 requires_building: marketplace per brief example"
+ - cargo test -p mc-core 190 passed; mc-city 143 passed (8 new); mc-turn + mc-ai green; cargo check --workspace green
+ - "5 of 10 acceptance bullets remain deferred (queue split taxonomy, allocator, save migration, UI, AI per-building action, full themed civilian roster, GUT, batch) β documented in objective remaining-work section"
---
-
## Summary
User direction (2026-04-29): "it would make sense to build those units in the appropriate buildings rather than the city center."
@@ -73,6 +83,120 @@ This is the largest single architectural change still on the Game 1 board. Three
User decision needed.
+## Progress β 2026-05-04 (cycle 8) β typed `ProductionOrigin` + unit `requires_building` gate
+
+**EA-scope decision (Option 2 β hybrid).** The runtime now honours the
+producer-building gate for unit training; the per-building "split queue"
+allocator + UI rework + AI per-building emission are deferred. Rationale:
+Option 2 is the minimum architectural change that lets future objectives
+(p1-43 stacking, p1-33 naval/aerial) operate against typed origin data
+rather than `Option` shims, and it lets `p1-42` AI scoring
+continue running unchanged because the existing AI gate already filtered on
+`requires_building`. Option 1 (defer) would have left the AI gate as the
+only enforcement point and the engine would happily accept queue orders
+the AI politely declined to issue. Option 3 (full Civ-6 split queues + UI)
+remains the right end-state but does not block any p1 milestone today.
+
+**Closed bullets.**
+
+- β `Building` schema gains `produces` field analog *via inverse direction*:
+ unit JSON declares `requires_building: ` (already present on 20 naval
+ / aerial / civilian unit files; `caravan_master` updated this cycle to
+ declare `requires_building: marketplace` per the brief example) at
+ `public/resources/units/caravan_master.json:27`. The bidirectional
+ `building.produces[]` mirror remains β (out of scope this cycle β it is
+ authoring redundancy that the validator rules in p1-43 already enforce
+ one-way). Engine gate added at
+ `src/simulator/crates/mc-city/src/city.rs::City::enqueue_unit` (typed
+ [`mc_core::ProductionOrigin`] return value) +
+ `src/simulator/crates/mc-city/src/production.rs::UnitDef::requires_building`
+ (typed `Option`).
+- β AI rework subset: `mc-ai/tactical/production.rs:551` already filters
+ the unit catalog by `requires_building`. This cycle retyped
+ `TacticalUnitSpec::requires_building` from `Option` β
+ `Option` at
+ `src/simulator/crates/mc-ai/src/tactical/state.rs:291` (JSON wire format
+ unchanged β `BuildingId` is `#[serde(transparent)]`). Per-building
+ emission of distinct `Action::SetProduction` per turn (the brief's
+ *building_id* enum extension) remains β β gated on the queue split
+ refactor.
+- β Buildable filter respects ownership *for units*: enforced inside
+ `City::enqueue_unit` (returns `QueueError::MissingProducer` when the
+ required building is absent β same error variant items already use, so
+ callers handle a single uniform rejection path).
+
+**Bullets still β (deferred to a sibling p1-44b runtime-flip objective).**
+
+- β `city.production_queue: Array` retired in favour of a split
+ `construction_queue` + `building_queues` dictionary. The current model is
+ *already* per-building queues for items / units, so the literal
+ acceptance bullet is moot β but the ConstructionQueue / BuildingQueue
+ taxonomy split (buildings vs units vs items into distinct families)
+ remains unimplemented.
+- β Production tick allocator (even split + UI weight overrides).
+- β Save schema migration for legacy single-queue saves.
+- β City UI rework with one panel per producer building.
+- β AI emits `Action::SetProduction { building_id: Option }`
+ per non-empty queue per turn.
+- β Themed civilian units authored across the full table from
+ `PRODUCTION_CHAIN.md` (sage, bard, merchant, loremaster, β¦). Only
+ `caravan_master` was data-touched this cycle.
+- β Headless GUT tests for the per-building UI flow.
+- β 10-seed regression batch showing AI cities producing different units
+ in the same turn from distinct producer buildings.
+
+**New crate primitives this cycle.**
+
+- `mc_core::ProductionOrigin` (`mc-core/src/production_origin.rs`) β typed
+ enum `CityCenter | Building(BuildingId)`, serde tagged
+ (`{"kind":"city_center"}` / `{"kind":"building","building_id":"..."}`).
+ 3 unit tests cover both variants + the `is_building` / `building_id`
+ discriminators.
+- `mc_core::UnitId` (`mc-core/src/ids.rs:62`) β string newtype mirroring
+ the existing `BuildingId` pattern; `#[serde(transparent)]` so JSON wire
+ format is unchanged. Distinct from the `mc_economy::UnitId` runtime
+ `u32` entity handle (which is *per-instance*, not *content*).
+- `mc_city::UnitDef` / `mc_city::UnitRegistry`
+ (`mc-city/src/production.rs`) β production-relevant projection of the
+ per-unit JSON. Uses `BTreeMap` per the brief.
+- `mc_city::QueueEntry::origin` and `mc_city::CompletedEntry::origin` β
+ every queued / completed entry now carries its origin tag, with
+ `#[serde(default)]` so pre-p1-44 saves load unchanged (defaults to
+ `CityCenter`).
+- `mc_city::CITY_CENTER_QUEUE_ID` β reserved queue key (`__city_center__`)
+ for entries with `ProductionOrigin::CityCenter`. Distinct from any
+ authored snake_case building id; `tick_building` accepts it as a
+ first-class queue.
+
+**GDExtension bridge.** `GdCity::queue_snapshot` now emits `kind` (`item` /
+`wonder` / `unit`) and `origin_kind` (`city_center` / `building`) +
+`origin_building_id` per entry so GDScript UI can route panels by origin
+without re-querying the registry.
+
+**Tests added (mc-city + mc-core).**
+
+- `mc_core::production_origin::tests::city_center_round_trips_serde`.
+- `mc_core::production_origin::tests::building_origin_round_trips_serde`.
+- `mc_core::production_origin::tests::helpers_discriminate_origin_kind`.
+- `mc_city::production::tests::test_unit_requires_building_blocks_queue`
+ (the brief's named test).
+- `mc_city::production::tests::test_production_origin_round_trip_serde`
+ (the brief's named test).
+- `mc_city::production::tests::unit_without_building_gate_routes_to_city_center`.
+- `mc_city::production::tests::unit_tech_gate_blocks_atomically`.
+- `mc_city::production::tests::legacy_queue_entry_without_origin_defaults_to_city_center`.
+
+**Verification.**
+
+- `cargo test -p mc-core` β 190 passed.
+- `cargo test -p mc-city` β 143 passed (was 135; +8 from this cycle).
+- `cargo test -p mc-turn -p mc-ai` β all green (retype was wire-compatible).
+- `cargo check --workspace` β green.
+
+**Status decision.** `partial` β 3 of the 10 acceptance bullets fully
+closed, 1 partial, 6 deferred to a sibling p1-44b. Remaining work below
+stays as authored.
+
## Remaining work (2026-05-03)
All ten acceptance bullets remain β (status: missing). This is the largest single architectural change still on the Game-1 board per the existing "Note on EA scope". Per the task brief: this objective depends on **p2-35 (palace)** and **p2-43 (culture event)** for the production-queue split per category (palace defines the city-center construction-queue baseline; culture event drives the temple/library science+culture producer semantics).