diff --git a/.project/objectives/DASHBOARD_CATEGORIES.md b/.project/objectives/DASHBOARD_CATEGORIES.md index 7637d4f5..8f298561 100644 --- a/.project/objectives/DASHBOARD_CATEGORIES.md +++ b/.project/objectives/DASHBOARD_CATEGORIES.md @@ -12,25 +12,26 @@ | ID | Status | Priority | Title | Owner | Blocked | |---|---|---|---|---|---| -| [p1-29](p1-29.md) | โŒ missing | P1 | Anti-early-domination: lift game-balance gates that p0-01 v1 measured | [combat-dev](../team-leads/combat-dev.md) | ๐ŸŸข | +| [p1-29](p1-29.md) | ๐ŸŸก partial | P1 | Anti-early-domination: lift game-balance gates that p0-01 v1 measured | [combat-dev](../team-leads/combat-dev.md) | ๐ŸŸข | +| [p1-29a](p1-29a-last-stand-defense.md) | ๐Ÿ”ด stub | P1 | Last-stand defense โ€” combat-strength multiplier when defender is at last city | [combat-dev](../team-leads/combat-dev.md) | ๐ŸŸข | ## batch | ID | Status | Priority | Title | Owner | Blocked | |---|---|---|---|---|---| -| [p1-45](p1-45-batch-binary-freshness.md) | โŒ missing | P1 | Batch binary freshness: rebuild GDExt before every autoplay batch | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | +| [p1-45](p1-45-batch-binary-freshness.md) | โœ… done | P1 | Batch binary freshness: rebuild GDExt before every autoplay batch | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | ## ci | ID | Status | Priority | Title | Owner | Blocked | |---|---|---|---|---|---| -| [p1-45](p1-45-batch-binary-freshness.md) | โŒ missing | P1 | Batch binary freshness: rebuild GDExt before every autoplay batch | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | +| [p1-45](p1-45-batch-binary-freshness.md) | โœ… done | P1 | Batch binary freshness: rebuild GDExt before every autoplay batch | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | ## combat | ID | Status | Priority | Title | Owner | Blocked | |---|---|---|---|---|---| -| [p2-55](p2-55-civilian-capture-system.md) | โšช pending | P2 | Civilian Capture / Destroy / Ransom | โ€” | ๐ŸŸข | +| [p1-29a](p1-29a-last-stand-defense.md) | ๐Ÿ”ด stub | P1 | Last-stand defense โ€” combat-strength multiplier when defender is at last city | [combat-dev](../team-leads/combat-dev.md) | ๐ŸŸข | ## formation @@ -42,25 +43,28 @@ | ID | Status | Priority | Title | Owner | Blocked | |---|---|---|---|---|---| -| [p1-45](p1-45-batch-binary-freshness.md) | โŒ missing | P1 | Batch binary freshness: rebuild GDExt before every autoplay batch | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | +| [p1-45](p1-45-batch-binary-freshness.md) | โœ… done | P1 | Batch binary freshness: rebuild GDExt before every autoplay batch | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | ## mcts | ID | Status | Priority | Title | Owner | Blocked | |---|---|---|---|---|---| | [p0-43](p0-43.md) | โœ… done | P0 | Formation AI โ€” MCTS plans at formation level, not per-unit | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | +| [p1-30b](p1-30b-parallel-mcts-rollouts.md) | ๐Ÿ”ด stub | P1 | Parallel MCTS rollouts for huge-map decisive games (closes p1-22's huge-map sub-gate) | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | ## pacing | ID | Status | Priority | Title | Owner | Blocked | |---|---|---|---|---|---| -| [p1-29](p1-29.md) | โŒ missing | P1 | Anti-early-domination: lift game-balance gates that p0-01 v1 measured | [combat-dev](../team-leads/combat-dev.md) | ๐ŸŸข | +| [p1-29](p1-29.md) | ๐ŸŸก partial | P1 | Anti-early-domination: lift game-balance gates that p0-01 v1 measured | [combat-dev](../team-leads/combat-dev.md) | ๐ŸŸข | +| [p1-29a](p1-29a-last-stand-defense.md) | ๐Ÿ”ด stub | P1 | Last-stand defense โ€” combat-strength multiplier when defender is at last city | [combat-dev](../team-leads/combat-dev.md) | ๐ŸŸข | ## perf | ID | Status | Priority | Title | Owner | Blocked | |---|---|---|---|---|---| -| [p1-30](p1-30.md) | โŒ missing | P1 | Optimize `_build_tactical_state` โ€” 8000-tile GDScript dict-build per AI turn blocks p1-22 huge-map gate | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | +| [p1-30](p1-30.md) | ๐ŸŸก partial | P1 | Optimize `_build_tactical_state` โ€” 8000-tile GDScript dict-build per AI turn blocks p1-22 huge-map gate | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | +| [p1-30b](p1-30b-parallel-mcts-rollouts.md) | ๐Ÿ”ด stub | P1 | Parallel MCTS rollouts for huge-map decisive games (closes p1-22's huge-map sub-gate) | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | ## rail-1 @@ -78,13 +82,14 @@ | ID | Status | Priority | Title | Owner | Blocked | |---|---|---|---|---|---| -| [p1-30](p1-30.md) | โŒ missing | P1 | Optimize `_build_tactical_state` โ€” 8000-tile GDScript dict-build per AI turn blocks p1-22 huge-map gate | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | +| [p1-30](p1-30.md) | ๐ŸŸก partial | P1 | Optimize `_build_tactical_state` โ€” 8000-tile GDScript dict-build per AI turn blocks p1-22 huge-map gate | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | +| [p1-30b](p1-30b-parallel-mcts-rollouts.md) | ๐Ÿ”ด stub | P1 | Parallel MCTS rollouts for huge-map decisive games (closes p1-22's huge-map sub-gate) | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | ## tooling | ID | Status | Priority | Title | Owner | Blocked | |---|---|---|---|---|---| -| [p1-45](p1-45-batch-binary-freshness.md) | โŒ missing | P1 | Batch binary freshness: rebuild GDExt before every autoplay batch | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | +| [p1-45](p1-45-batch-binary-freshness.md) | โœ… done | P1 | Batch binary freshness: rebuild GDExt before every autoplay batch | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | ## (untagged) @@ -100,6 +105,8 @@ | [g2-08](g2-08-fauna-population-dynamics-oos.md) | โšซ oos | P2 | Fauna population dynamics โ€” habitat_min, carrying_capacity, prey availability (Game 2) | โ€” | ๐ŸŸข | | [g2-09](g2-09-flora-tolerance-driven-selection-oos.md) | โšซ oos | P2 | Flora tolerance-driven selection โ€” drought / fire / cold tolerances feed selector (Game 2) | โ€” | ๐ŸŸข | | [g2-10](g2-10-fauna-migration-paths-oos.md) | โšซ oos | P2 | Fauna migration paths โ€” seasonal range shifts, reintroduction propagation (Game 2) | โ€” | ๐ŸŸข | +| [g2-11](g2-11-vertical-city-floor-stack-oos.md) | โšซ oos | P3 | Vertical city floor stack (Game 2) โ€” OOS | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ g2-12 | +| [g2-12](g2-12-underground-layer-stack-oos.md) | โšซ oos | P3 | Underground layer stack (Game 2) โ€” OOS | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | | [g3-01](g3-01-archons-oos.md) | โšซ oos | P3 | Archons โ€” Game 3 (Age of Elves) | โ€” | ๐ŸŸข | | [g3-02](g3-02-life-school-oos.md) | โšซ oos | P3 | Life school spellbook โ€” Game 3 (Age of Elves) | โ€” | ๐ŸŸข | | [g3-03](g3-03-death-school-oos.md) | โšซ oos | P3 | Death school spellbook โ€” Game 3 (Age of Elves) | โ€” | ๐ŸŸข | @@ -185,30 +192,34 @@ | [p1-24](p1-24-windows-path-separator.md) | โœ… done | P1 | ai_personalities.json fails to load from packed builds (all platforms) โ€” pass JSON contents not path | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | | [p1-25](p1-25-export-script-error-cleanup.md) | โœ… done | P1 | Eliminate parse-error spam in export logs (Unit dup decl + SaveManager stray) | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | | [p1-26](p1-26-tile-placement-preview-ux.md) | โœ… done | P1 | Tile-placement UX with effect preview โ€” Civ7-style \\\"where does this go and what changes\\\" | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | -| [p1-27](p1-27-mcts-service-extraction.md) | โŒ missing | P1 | Extract GPU MCTS into a standalone service/client (model-boss-shaped, magic-civ-only) | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | +| [p1-27](p1-27-mcts-service-extraction.md) | ๐ŸŸก partial | P1 | Extract GPU MCTS into a standalone service/client (model-boss-shaped, magic-civ-only) | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | | [p1-28](p1-28-culture-research-tree.md) | โœ… done | P1 | Culture research tree โ€” real graph, bridge, UI | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | | [p1-31](p1-31-split-bundled-building-resources.md) | โœ… done | P1 | Split bundled `resources/buildings/.json` into per-file pattern matching `resources/units/` | โ€” | ๐ŸŸข | -| [p1-32](p1-32-food-chain-buildings.md) | โŒ missing | P1 | Author the two missing food/processing buildings (sawmill, herbalist) | โ€” | ๐ŸŸข | -| [p1-33](p1-33-naval-aerial-production-buildings.md) | โŒ missing | P1 | Wire naval/aerial unit gates to the harbor and airfield buildings | โ€” | ๐ŸŸข | +| [p1-32](p1-32-food-chain-buildings.md) | โœ… done | P1 | Author the two missing food/processing buildings (sawmill, herbalist) | โ€” | ๐ŸŸข | +| [p1-33](p1-33-naval-aerial-production-buildings.md) | โœ… done | P1 | Wire naval/aerial unit gates to the harbor and airfield buildings | โ€” | ๐ŸŸข | | [p1-34](p1-34-unit-metadata-expansion.md) | โœ… done | P1 | Unit metadata expansion โ€” flavor, archetype, promotion_tree, clan_affinity fields | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | | [p1-35](p1-35-unit-lore-paragraphs.md) | โœ… done | P1 | Per-unit lore paragraphs โ€” historical/cultural context for the dwarven roster | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | -| [p1-36](p1-36-ai-personalities-t1-t10-coverage.md) | ๐ŸŸก partial | P1 | AI personalities โ€” T1โ€“T10 build order coverage + clan_affinity routing | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | -| [p1-37](p1-37-mc-ai-clan-affinity-routing.md) | ๐ŸŸก partial | P1 | mc-ai clan_affinity routing โ€” Rust AI reads unit clan_affinity at build-decision time | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | +| [p1-36](p1-36-ai-personalities-t1-t10-coverage.md) | โœ… done | P1 | AI personalities โ€” T1โ€“T10 build order coverage + clan_affinity routing | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | +| [p1-37](p1-37-mc-ai-clan-affinity-routing.md) | โœ… done | P1 | mc-ai clan_affinity routing โ€” Rust AI reads unit clan_affinity at build-decision time | [warcouncil](../team-leads/warcouncil.md) | ๐ŸŸข | | [p1-38](p1-38-biome-economy-coupling.md) | ๐ŸŸก partial | P1 | Biome โ†’ economy coupling โ€” population & luxury driven by live ecology | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | | [p1-40](p1-40-single-source-of-truth-resources.md) | โœ… done | P1 | Collapse data// override layer into single source of truth at resources/ | โ€” | ๐ŸŸข | | [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) | โŒ missing | P1 | AI must consider the full 155-building catalog, not the hardcoded 8-id ladder | โ€” | ๐ŸŸข | -| [p1-43](p1-43-building-stacking-upgrade.md) | โŒ missing | P1 | Building stacking โ€” per-category upgrade chains (military / science / culture / production / etc.) | โ€” | ๐ŸŸข | +| [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-46](p1-46-design-lab-terrain-dimensions.md) | ๐ŸŸก partial | 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) | ๐ŸŸก partial | 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) | ๐ŸŸก partial | P1 | Flora species renderer โ€” bind 149 species to world-map tile rendering (single source of truth) | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | -| [p1-49](p1-49-fauna-species-renderer.md) | ๐ŸŸก partial | P1 | Fauna species renderer โ€” 61 Game-1 species visible on encounter and lair tiles | [terraformer](../team-leads/terraformer.md) | ๐Ÿ”’ p1-47 | -| [p1-50](p1-50-tectonic-prepass.md) | ๐ŸŸก partial | P1 | Tectonic prepass โ€” voronoi plates + boundary classification seeding elevation | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | +| [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) | ๐ŸŸข | +| [p1-49](p1-49-fauna-species-renderer.md) | โœ… done | P1 | Fauna species renderer โ€” 61 Game-1 species visible on encounter and lair tiles | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | +| [p1-50](p1-50-tectonic-prepass.md) | โœ… done | P1 | Tectonic prepass โ€” voronoi plates + boundary classification seeding elevation | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | | [p1-51](p1-51-worldgen-canonical-design-docs.md) | โœ… done | P1 | Worldgen canonical design docs โ€” author the spec before any Rust | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | | [p1-52](p1-52-api-wasm-build-fix.md) | โœ… done | P1 | api-wasm build fix โ€” unblock WASM bundle for design-lab WASM consumption | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | | [p1-53](p1-53-worldgen-layer-pages.md) | โœ… done | P1 | Worldgen layer pages โ€” one playground per canonical doc, mirroring the layered Earth model | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | | [p1-54](p1-54-hex-direction-rust-ts-mapping.md) | โœ… done | P1 | Hex direction-index translation โ€” Rust pointy-top axial vs design-app flat-top canvas | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | +| [p1-55](p1-55-tech-culture-domain-propagation.md) | ๐Ÿ”ต in_progress | P1 | Tech & Culture domain field โ€” propagate categorization through Rust, Godot UI, and player analysis | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | +| [p1-56](p1-56-civics-buildings-and-great-works.md) | ๐Ÿ”ต in_progress | P1 | Civics buildings, Great Works, Specialists, Great People โ€” wire authored data into Rust + Godot | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | +| [p1-57](p1-57-diplomacy-tribute-treaties.md) | ๐Ÿ”ด stub | P1 | Diplomacy: tribute, treaty lifecycle, magical-terrain episode gating | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p1-58](p1-58-ecology-cognitive-system.md) | ๐ŸŸก partial | P1 | Ecology cognition: terrain affinity, food web, grudge memory, apex tier-10 fauna/flora | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | | [p2-01](p2-01-minimap-improvements.md) | โœ… done | P2 | Minimap โ€” fog reflection and unit markers | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | | [p2-02](p2-02-hud-tooltips.md) | โœ… done | P2 | Tooltips on all HUD elements | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | | [p2-03](p2-03-hotkey-cheat-sheet.md) | โœ… done | P2 | Hotkey cheat sheet (F1 / ?) | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | @@ -231,7 +242,7 @@ | [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-11](p2-11-version-about-screen.md) | โœ… done | P2 | Version string + About screen | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | -| [p2-11a](p2-11a.md) | ๐Ÿ”ด stub | P2 | SaveManager: add Unit.serialize/deserialize and City.production_queue serialize path | โ€” | ๐ŸŸข | +| [p2-11a](p2-11a.md) | ๐ŸŸก partial | 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) | ๐ŸŸข | | [p2-16](p2-16-audio-assets.md) | ๐Ÿ”ต in_progress | P1 | Audio assets โ€” in-theme OSS launch pack + source ledger | [asset-audio](../team-leads/asset-audio.md) | ๐ŸŸข | | [p2-18](p2-18-guide-public-deployment.md) | ๐ŸŸก partial | P2 | Guide web app โ€” public hosting + deploy pipeline | โ€” | ๐ŸŸข | @@ -258,16 +269,64 @@ | [p2-43](p2-43-culture-research-completion-event.md) | โŒ missing | P2 | Culture research live-game pipeline โ€” per-turn GDExt bridge + `culture_researched` emit | โ€” | ๐ŸŸข | | [p2-44](p2-44-ai-promotion-selection.md) | โŒ missing | P2 | AI promotion selection โ€” auto-pick + emit unit_promoted for AI units | โ€” | ๐ŸŸข | | [p2-45](p2-45-elimination-reconciliation.md) | โœ… done | P2 | Player elimination reconciliation โ€” emit `player_eliminated` on every transition | โ€” | ๐ŸŸข | -| [p2-46](p2-46-past-games-archive-replay-viewer.md) | โŒ missing | P2 | Past-games archive & replay viewer โ€” `mc-replay` crate, on-disk archive, projection-based playback | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | -| [p2-47](p2-47-in-game-statistics-screens.md) | โŒ missing | P2 | In-game statistics screens โ€” Civ-style 5-tab modal (Demographics / Graphs / Rankings / Replay / Histories) | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | -| [p2-48](p2-48-end-of-game-summary-screen.md) | โŒ missing | P2 | End-of-game summary screen โ€” outcome banner, standings, score graph, awards, timeline, footer actions | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | -| [p2-49](p2-49-climate-axes-latitude-continentality.md) | ๐ŸŸก partial | P2 | Climate axes refactor โ€” latitude + continentality + zonal winds as first-class per-hex inputs | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | -| [p2-50](p2-50-rng-determinism-pin.md) | ๐ŸŸก partial | P2 | Deterministic RNG + seed-derivation pin across mc-mapgen / mc-climate / mc-ecology | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | -| [p2-51](p2-51-world-shape-knobs.md) | ๐ŸŸก partial | P2 | Player-facing world-shape parameters on new-game screen | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | -| [p2-52](p2-52-substrate-flora-cover-ontology-split.md) | ๐ŸŸก partial | P2 | Split terrain enum into substrate ร— flora-cover layers (resolve biome ontology) | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | -| [p2-55](p2-55-civilian-capture-system.md) | โšช pending | P2 | Civilian Capture / Destroy / Ransom | โ€” | ๐ŸŸข | +| [p2-46](p2-46-past-games-archive-replay-viewer.md) | ๐ŸŸก partial | P2 | Past-games archive & replay viewer โ€” `mc-replay` crate, on-disk archive, projection-based playback | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | +| [p2-47](p2-47-in-game-statistics-screens.md) | ๐ŸŸก partial | P2 | In-game statistics screens โ€” Civ-style 5-tab modal (Demographics / Graphs / Rankings / Replay / Histories) | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | +| [p2-48](p2-48-end-of-game-summary-screen.md) | ๐ŸŸก partial | P2 | End-of-game summary screen โ€” outcome banner, standings, score graph, awards, timeline, footer actions | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | +| [p2-49](p2-49-climate-axes-latitude-continentality.md) | โœ… done | P2 | Climate axes refactor โ€” latitude + continentality + zonal winds as first-class per-hex inputs | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | +| [p2-50](p2-50-rng-determinism-pin.md) | โœ… done | P2 | Deterministic RNG + seed-derivation pin across mc-mapgen / mc-climate / mc-ecology | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | +| [p2-51](p2-51-world-shape-knobs.md) | โœ… done | P2 | Player-facing world-shape parameters on new-game screen | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | +| [p2-52](p2-52-substrate-flora-cover-ontology-split.md) | โœ… done | P2 | Split terrain enum into substrate ร— flora-cover layers (resolve biome ontology) | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | +| [p2-53](p2-53-action-vocabulary-design-game-gap.md) | โœ… done | P2 | Action vocabulary โ€” gap analysis between design page and shipped Rust/Godot game | [wireguard](../team-leads/wireguard.md) | ๐ŸŸข | +| [p2-53a](p2-53a-sentry-guard-action-kind.md) | โœ… done | P2 | Sentry/Guard ActionKind โ€” add Sentry/Unsentry to mc-core with wake-on-vision | [wireguard](../team-leads/wireguard.md) | ๐ŸŸข | +| [p2-53a1](p2-53a1-sentry-bridge-state-pipe.md) | โœ… done | P2 | Sentry bridge state pipe โ€” extend `GdUnitActions` signature to pass `is_sentrying` | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | +| [p2-53b](p2-53b-building-action-registry.md) | โœ… done | P2 | Building action registry โ€” `BuildingActionKind`, `building_actions.json`, `GdBuildingActions` bridge | [simulator-infra](../team-leads/simulator-infra.md) | ๐ŸŸข | +| [p2-53c](p2-53c-rally-vocabulary-expansion.md) | โœ… done | P2 | Rally vocabulary expansion โ€” Hold / Fortify / JoinFormation + two-waypoint Patrol | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | +| [p2-53d](p2-53d-building-specifics.md) | โœ… done | P2 | Building specifics โ€” Garrison, Repair, Toggle Active + 18 archetype-specific actions | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | +| [p2-53e](p2-53e-siege-pillage-embark.md) | โœ… done | P2 | Siege handlers (Pack/Deploy/Bombard) + Pillage UI wiring + Embark/Disembark handlers | [combat-dev](../team-leads/combat-dev.md) | ๐ŸŸข | +| [p2-53f](p2-53f-infantry-specifics.md) | โœ… done | P2 | Infantry specifics โ€” Shield Wall, Brace, Shove, Rage, Cleave, War Cry | [combat-dev](../team-leads/combat-dev.md) | ๐ŸŸข | +| [p2-53g](p2-53g-ranged-specifics.md) | โœ… done | P2 | Ranged specifics โ€” Volley, Aimed Shot, Fire Arrows | [combat-dev](../team-leads/combat-dev.md) | ๐ŸŸข | +| [p2-53h](p2-53h-cavalry-specifics.md) | โœ… done | P2 | Cavalry specifics โ€” Charge, Pursue, Wheel | [combat-dev](../team-leads/combat-dev.md) | ๐ŸŸข | +| [p2-53i](p2-53i-engineer-pioneer-medic-scout.md) | โœ… done | P2 | Support specifics โ€” Engineer, Pioneer, Medic, Scout | [shipwright](../team-leads/shipwright.md) | ๐ŸŸข | +| [p2-54](p2-54-resource-visibility-three-axis.md) | โœ… done | P2 | Resource visibility โ€” three-axis (visibility/yield_gate/improvement_gate) refactor | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | +| [p2-54a](p2-54a-deposits-three-axis-migration.md) | โœ… done | P2 | Migrate deposits/*.json to three-axis visibility schema | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | +| [p2-54b](p2-54b-player-observation-cache.md) | โœ… done | P2 | Per-player tile observation cache โ€” flora/fauna last-observed state | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | +| [p2-54c](p2-54c-renderer-observations-and-indicators.md) | โœ… done | P2 | Renderer reads observations + indicator decorations for tech-gated resources | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | +| [p2-54d](p2-54d-ai-tech-priority-from-visibility.md) | โœ… done | P2 | AI tech-priority bias from visible-but-gated luxuries + indicator decorations | [terraformer](../team-leads/terraformer.md) | ๐ŸŸข | +| [p2-55](p2-55-civilian-capture-system.md) | ๐ŸŸก partial | P2 | Civilian Capture / Destroy / Ransom | โ€” | ๐ŸŸข | +| [p2-55d](p2-55d-ai-ransom-decision-hook.md) | ๐Ÿ”ด stub | P2 | AI ransom accept/refuse hook in mc-turn start-of-turn | โ€” | ๐ŸŸข | +| [p2-55e](p2-55e-richer-ransom-events.md) | ๐Ÿ”ด stub | P2 | UnitRansomAccepted / UnitRansomExpired events on TurnResult | โ€” | ๐ŸŸข | +| [p2-55f](p2-55f-ransom-duration-from-json.md) | ๐Ÿ”ด stub | P3 | Read ransom_offer_duration_turns from combat_balance.json | โ€” | ๐ŸŸข | +| [p2-56](p2-56-worker-categories-and-expertise-tiers.md) | ๐Ÿ”ด stub | P2 | Worker categories (Sustenance/Construction/Wealth) + 5-tier expertise + Master/Grandmaster auras + idle decay | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p2-35 | +| [p2-56a](p2-56a-worker-category-types.md) | ๐Ÿ”ด stub | P2 | Worker category types โ€” Sustenance / Construction / Wealth taxonomy | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p2-35 | +| [p2-56b](p2-56b-expertise-tier-progression.md) | ๐Ÿ”ด stub | P2 | Expertise tier progression โ€” 5-tier specialist XP ladder | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p2-56a | +| [p2-56c](p2-56c-master-grandmaster-auras.md) | ๐Ÿ”ด stub | P2 | Master / Grandmaster auras โ€” adjacent-slot yield propagation | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p2-56b | +| [p2-57](p2-57-production-chain-typed-resources.md) | ๐Ÿ”ด stub | P2 | Production-chain typed resources โ€” raw โ†’ processed pipelines wired into mc-city | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p2-57a](p2-57a-typed-resource-stockpile.md) | ๐Ÿ”ด stub | P2 | Typed resource stockpile โ€” raw vs processed taxonomy | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p2-57b](p2-57b-consume-produce-edges.md) | ๐Ÿ”ด stub | P2 | Building consume/produce edges โ€” stockpile coupled to unit quality | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p2-57a | +| [p2-58](p2-58-ambient-encounter-rolls.md) | ๐Ÿ”ด stub | P2 | Ambient encounter rolls per tile moved โ€” fauna_density ร— ecology_tier | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p2-59](p2-59-pioneer-escort-mechanic.md) | ๐Ÿ”ด stub | P2 | Pioneer escort mechanic โ€” protection rules vs ambient encounters | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p2-58 | +| [p2-60](p2-60-weather-lens-godot-ui.md) | ๐Ÿ”ด stub | P2 | Weather / observation lens switcher in the Godot HUD | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p2-61](p2-61-observation-recording-gates-from-tech.md) | ๐Ÿ”ด stub | P2 | Bind mc-observation gate_bits to player tech state โ€” recording gates per-field | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p2-62](p2-62-procedural-unit-and-building-renderer.md) | ๐Ÿ”ด stub | P2 | Procedural unit/building renderer โ€” alpha-only visual substitute | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | | [p3-01](p3-01-courier-diplomacy.md) | โœ… done | P3 | Courier-gated diplomacy โ€” open borders + shared maps via tech-tiered courier units | [envoy](../team-leads/envoy.md) | ๐ŸŸข | | [p3-02](p3-02-hybrid-merged-structures.md) | โŒ missing | P3 | Hybrid merged structures โ€” war_academy, assault_citadel, cavalry_corps, gunnery_corps | โ€” | ๐ŸŸข | | [p3-03](p3-03-courier-route-resolver.md) | โœ… done | P3 | Courier route resolver โ€” real hex pathfinding, per-tier movement, severable infrastructure | [envoy](../team-leads/envoy.md) | ๐ŸŸข | | [p3-04](p3-04-per-hex-improvement-layer.md) | โœ… done | P3 | Per-hex improvement layer in `mc-core` / `mc-turn` โ€” anchor improvements at (col,row) | [envoy](../team-leads/envoy.md) | ๐ŸŸข | +| [p3-05a](p3-05a-civic-state-wrapper-and-game-state.md) | ๐Ÿ”ด stub | P3 | Civic state wrapper โ€” typed CivicState added to PlayerState | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p3-05b](p3-05b-authority-axis-catalog.md) | ๐Ÿ”ด stub | P3 | Authority axis civics catalog | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p3-05a | +| [p3-05c](p3-05c-labor-axis-catalog.md) | ๐Ÿ”ด stub | P3 | Labor axis civics catalog | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p3-05a | +| [p3-05d](p3-05d-economy-axis-catalog.md) | ๐Ÿ”ด stub | P3 | Economy axis civics catalog | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p3-05a | +| [p3-05e](p3-05e-civic-modifier-propagation.md) | ๐Ÿ”ด stub | P3 | Civic modifier propagation โ€” apply civic effects to per-city yields | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p3-05b, p3-05c, p3-05d | +| [p3-06](p3-06-civic-anarchy-and-axis-switching.md) | ๐Ÿ”ด stub | P3 | Civic anarchy โ€” 5-turn anarchy on axis switch | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p3-05a | +| [p3-07a](p3-07a-cv-wealth-and-authority-amplifier.md) | ๐Ÿ”ด stub | P3 | CV-of-wealth + Authority amplifier โ†’ inequality stat | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p3-05b | +| [p3-07b](p3-07b-four-damage-channels.md) | ๐Ÿ”ด stub | P3 | Four damage channels โ€” Land/Water/Magic/Air emission from inequality | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p3-07a | +| [p3-10a](p3-10a-lair-assault-mode.md) | ๐Ÿ”ด stub | P3 | Lair assault mode โ€” enter-and-clear | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p3-10b](p3-10b-lair-siege-mode.md) | ๐Ÿ”ด stub | P3 | Lair siege mode โ€” multi-turn pressure from adjacent | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p3-10a | +| [p3-10c](p3-10c-lair-raid-mode.md) | ๐Ÿ”ด stub | P3 | Lair raid mode โ€” grab-and-exit | [unassigned](../team-leads/unassigned.md) | ๐Ÿ”’ p3-10a | +| [p3-11](p3-11-pioneer-engineer-action-points.md) | ๐Ÿ”ด stub | P3 | Pioneer & Engineer action-point pool | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p3-12](p3-12-fauna-stat-derivation-from-traits.md) | ๐Ÿ”ด stub | P3 | Fauna combat stat derivation โ€” regenerate from traits | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p3-13a](p3-13a-extend-meteorological-events.md) | ๐Ÿ”ด stub | P3 | Extend meteorological events โ€” drought, flood, dust_storm | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p3-13b](p3-13b-geological-events.md) | ๐Ÿ”ด stub | P3 | Geological events โ€” earthquake, volcanic_eruption, landslide | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p3-13c](p3-13c-biological-events.md) | ๐Ÿ”ด stub | P3 | Biological events โ€” plague, bloom, migration_pulse | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | +| [p3-13d](p3-13d-anomalous-events.md) | ๐Ÿ”ด stub | P3 | Anomalous events โ€” aurora, fog_bank, thermal_anomaly | [unassigned](../team-leads/unassigned.md) | ๐ŸŸข | diff --git a/.project/objectives/DASHBOARD_COMPLETED.md b/.project/objectives/DASHBOARD_COMPLETED.md index a112ca7b..d78c4795 100644 --- a/.project/objectives/DASHBOARD_COMPLETED.md +++ b/.project/objectives/DASHBOARD_COMPLETED.md @@ -80,10 +80,20 @@ | [p1-26](p1-26-tile-placement-preview-ux.md) | Tile-placement UX with effect preview โ€” Civ7-style \\\"where does this go and what changes\\\" | โ€” | [shipwright](../team-leads/shipwright.md) | 2026-04-26 | | [p1-28](p1-28-culture-research-tree.md) | Culture research tree โ€” real graph, bridge, UI | โ€” | [shipwright](../team-leads/shipwright.md) | 2026-04-26 | | [p1-31](p1-31-split-bundled-building-resources.md) | Split bundled `resources/buildings/.json` into per-file pattern matching `resources/units/` | โ€” | โ€” | 2026-04-27 | +| [p1-32](p1-32-food-chain-buildings.md) | Author the two missing food/processing buildings (sawmill, herbalist) | โ€” | โ€” | 2026-05-03 | +| [p1-33](p1-33-naval-aerial-production-buildings.md) | Wire naval/aerial unit gates to the harbor and airfield buildings | โ€” | โ€” | 2026-05-03 | | [p1-34](p1-34-unit-metadata-expansion.md) | 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) | 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) | 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) | mc-ai clan_affinity routing โ€” Rust AI reads unit clan_affinity at build-decision time | โ€” | [warcouncil](../team-leads/warcouncil.md) | 2026-05-01 | | [p1-40](p1-40-single-source-of-truth-resources.md) | Collapse data// override layer into single source of truth at resources/ | โ€” | โ€” | 2026-04-29 | | [p1-41](p1-41-game-pack-subscription-manifest.md) | Game-pack subscription manifest + loader filter (Phase B of resources/ unification) | โ€” | โ€” | 2026-04-29 | +| [p1-45](p1-45-batch-binary-freshness.md) | Batch binary freshness: rebuild GDExt before every autoplay batch | tooling, batch, gdext, ci | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-03 | +| [p1-46](p1-46-design-lab-terrain-dimensions.md) | 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) | 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) | 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) | 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) | 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) | 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) | 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) | Worldgen layer pages โ€” one playground per canonical doc, mirroring the layered Earth model | โ€” | [terraformer](../team-leads/terraformer.md) | 2026-05-01 | @@ -129,6 +139,26 @@ | [p2-38](p2-38-unit-audio-cues-stubs.md) | 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) | Resolve `chronicle_hall` phantom unlock in `chronicle_keeping` culture tech | โ€” | โ€” | 2026-04-27 | | [p2-45](p2-45-elimination-reconciliation.md) | Player elimination reconciliation โ€” emit `player_eliminated` on every transition | โ€” | โ€” | 2026-04-30 | +| [p2-49](p2-49-climate-axes-latitude-continentality.md) | 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) | 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) | 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) | 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) | 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) | Sentry/Guard ActionKind โ€” add Sentry/Unsentry to mc-core with wake-on-vision | โ€” | [wireguard](../team-leads/wireguard.md) | 2026-05-01 | +| [p2-53a1](p2-53a1-sentry-bridge-state-pipe.md) | Sentry bridge state pipe โ€” extend `GdUnitActions` signature to pass `is_sentrying` | โ€” | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-01 | +| [p2-53b](p2-53b-building-action-registry.md) | 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) | Rally vocabulary expansion โ€” Hold / Fortify / JoinFormation + two-waypoint Patrol | โ€” | [shipwright](../team-leads/shipwright.md) | 2026-05-01 | +| [p2-53d](p2-53d-building-specifics.md) | 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) | 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) | 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) | Ranged specifics โ€” Volley, Aimed Shot, Fire Arrows | โ€” | [combat-dev](../team-leads/combat-dev.md) | 2026-05-03 | +| [p2-53h](p2-53h-cavalry-specifics.md) | Cavalry specifics โ€” Charge, Pursue, Wheel | โ€” | [combat-dev](../team-leads/combat-dev.md) | 2026-05-03 | +| [p2-53i](p2-53i-engineer-pioneer-medic-scout.md) | Support specifics โ€” Engineer, Pioneer, Medic, Scout | โ€” | [shipwright](../team-leads/shipwright.md) | 2026-05-03 | +| [p2-54](p2-54-resource-visibility-three-axis.md) | 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) | Migrate deposits/*.json to three-axis visibility schema | โ€” | [terraformer](../team-leads/terraformer.md) | 2026-05-01 | +| [p2-54b](p2-54b-player-observation-cache.md) | 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) | 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) | AI tech-priority bias from visible-but-gated luxuries + indicator decorations | โ€” | [terraformer](../team-leads/terraformer.md) | 2026-05-01 | ## P3 diff --git a/.project/objectives/README.md b/.project/objectives/README.md index 903ac8a3..a84d3a68 100644 --- a/.project/objectives/README.md +++ b/.project/objectives/README.md @@ -15,10 +15,10 @@ | Priority | โœ… | ๐Ÿ”ต | ๐ŸŸก | ๐Ÿ”ด | โŒ | โšซ | Total | |---|---|---|---|---|---|---|---| | **P0** | 43 | 0 | 0 | 0 | 0 | 0 | 43 | -| **P1** | 47 | 4 | 10 | 3 | 7 | 1 | 72 | +| **P1** | 47 | 3 | 11 | 3 | 7 | 1 | 72 | | **P2** | 52 | 0 | 7 | 14 | 3 | 6 | 82 | | **P3 (oos)** | 3 | 0 | 0 | 18 | 1 | 21 | 43 | -| **total** | **145** | **4** | **17** | **35** | **11** | **28** | **240** | +| **total** | **145** | **3** | **18** | **35** | **11** | **28** | **240** | @@ -149,7 +149,7 @@ | [p1-55](p1-55-tech-culture-domain-propagation.md) | ๐Ÿ”ต in_progress | "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) | ๐Ÿ”ต in_progress | "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) | ๐Ÿ”ต in_progress | "Ecology cognition: terrain affinity, food web, grudge memory, apex tier-10 fauna/flora" | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-04 | +| [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 | diff --git a/.project/objectives/objectives.json b/.project/objectives/objectives.json index f11eff29..7f18e820 100644 --- a/.project/objectives/objectives.json +++ b/.project/objectives/objectives.json @@ -1,13 +1,13 @@ { - "generated_at": "2026-05-01T06:14:38Z", + "generated_at": "2026-05-04T04:39:55Z", "totals": { - "done": 116, - "in_progress": 1, - "partial": 19, - "stub": 1, - "missing": 21, - "oos": 26, - "total": 184 + "done": 146, + "in_progress": 3, + "partial": 18, + "stub": 35, + "missing": 11, + "oos": 28, + "total": 241 }, "objectives": [ { @@ -546,7 +546,7 @@ "status": "partial", "scope": "game1", "owner": "shipwright", - "updated_at": "2026-04-25", + "updated_at": "2026-05-01", "blocked_by": [], "summary": "Post-p0-16 batch (`.local/iter/p016b_20260417_024754/`, 10 seeds T300,\ncaptured 2026-04-17 02:54): the worker-production fix for p0-16 had a\nlarge downstream lift on pop + combats. Per-seed p0_pop_peak =\n[58,46,76,65,77,74,53,113,73,36]; median **69**, min 36, max 113. Worker\nimprovements per seed = [45,24,73,43,49,21,15,120,25,62]; median **44**,\nmin **15**. Combats median **808**, techs median **39**. All four primary\nacceptance metrics now clear their thresholds decisively โ€” the 29.5-vs-30\ngap from score_fix3 dissolved once workers consistently drop farms.\n\nShipwright passes applied:\n- `farm.json` food yield **2 โ†’ 3** (prior tune, validated in p016b where\n per-seed farm counts 3-20 drive pop_peak 36-113).\n- Worker AI surfaced in both `auto_play.gd::_maybe_prioritize_worker` and\n `simple_heuristic_ai.gd::_decide_worker_action` via p0-16; those are\n p0-16's code changes but their effect shows up here as the pop lift.\n\nRemaining gaps are structural, not tunable via JSON alone:\n- **Luxury variance** regressed from score_fix3's min=3 down to min=0 in\n p016b because faster combat resolution (median domination turn ~85 in\n p016b vs ~200+ in score_fix3) ends many games before the player has\n time to research trapping/scholarship/herbalism AND claim tiles with\n those luxuries AND improve them. 14 of 15 luxuries are tech-gated in\n `resources.json`. Tuning would need to either un-gate early-luxuries\n (ivory/furs/salt) or slow combat โ€” both are cross-cutting changes\n (p0-06 economy + p0-08 domination tempo) that exceed p1-05's\n tuning-only scope.\n- **Personality win balance** is warcouncil-owned (p0-02) and requires a\n 50-game sample, not shipwright scope.\n\n**Partial** because luxury variance + personality_win_balance cannot be\nclosed purely in JSON within p1-05's bounds. Other 4 primary metrics are\ndone.\n\n**2026-04-17 ecology handoff from p0-30:** duplicate GDScript ecology tick\n(`ecosystem.gd` + `flora.gd`) deleted; ecology is dormant until\n`ClimateScript.process_turn` is re-enabled, at which point\n`GdEcologyPhysics::process_step` becomes the sole canonical tick. Any\nwilds/food/lair knobs tuned against the previous 1ร— GDScript rate may\nneed re-tuning against the Rust rate in a follow-up pass." }, @@ -785,10 +785,10 @@ "id": "p1-27", "title": "Extract GPU MCTS into a standalone service/client (model-boss-shaped, magic-civ-only)", "priority": "p1", - "status": "missing", + "status": "partial", "scope": "game1", "owner": "warcouncil", - "updated_at": "2026-04-25", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "Today the GPU MCTS path lives **inside** the `mc-ai` crate (`gpu/inner.rs`, `gpu/rollout.wgsl`, `gpu/cpu_reference.rs`) and runs in-process via the GDExtension (`GdMcTreeController`). That couples GPU lifecycle (device init, queue submission, buffer pooling, fence waits) to the game's per-turn decision call.\n\nPer user directive 2026-04-25: extract this into its own **MCTS service/client** that\n\n1. Lives **inside @magic-civilization** (not in @model-boss / not in any other repo) โ€” it's game-specific.\n2. Lives **independently** of the in-process GDExtension โ€” long-lived process the game talks to via IPC (Unix socket / TCP / shared memory).\n3. **Borrows patterns** from `@model-boss` (job submission, queue, batched dispatch, GPU lifecycle isolation) but doesn't take a dependency on it. Magic-civ's MCTS workload is narrow enough to warrant its own focused implementation.\n\nWhy a service vs in-process:\n- GPU init + warm-up amortized once per session, not per AI turn\n- Game can keep playing turns while a deep search is in flight (async)\n- Crash isolation โ€” a wgpu/driver fault doesn't take the game down\n- One service can serve multiple game clients (autoplay-batch parallel runs hit one warm GPU instead of N cold inits)\n- Future: out-of-process service can run on a different host (apricot has GPU, dev mac doesn't)" }, @@ -807,24 +807,46 @@ "id": "p1-29", "title": "Anti-early-domination: lift game-balance gates that p0-01 v1 measured", "priority": "p1", - "status": "missing", + "status": "partial", "scope": "game1", "owner": "combat-dev", - "updated_at": "2026-04-29", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "Split out from p0-01's original v1 sub-gates that the AI-layer cycles (1, 2, 3) could not move because they measure emergent game-balance dynamics, not AI quality. p0-01 closed `done` 2026-04-26 against Gate v2 (3/5 v1 sub-gates pass cleanly: tier_peak=4, wonders 7/10, combats=255). The 2 v1 sub-gates that v2 reframed away need a real owner:\n\n- `tier_peak_gap โ‰ค 4` median: in surviving-pair games at end, one player tech-monopolizes (tp=6) while the other stagnates (tp=0), giving gap=5-6. Even with the alive-aware metric, the gap holds. Root cause: capture/combat dynamics let one player snowball without the other catching up. Loser stays alive but undeveloped.\n- `peak_unit_tier โ‰ฅ 3 in โ‰ฅ7/10 games` absolute: 5/10 currently. 4 of the 5 fails are early-domination games (T48-T121) where tier-3 tech hasn't unlocked yet. The AI does deploy tier-3 units when available (80% of seeds reaching tp โ‰ฅ3 also reach unit โ‰ฅ3), but games end before tier-3 unlocks in half the seeds.\n\nCycle-3 attempted multiple AI-layer levers and confirmed they DON'T move these gates:\n- Tactical `DOMINANCE_FACTOR` bump (production.rs 1.25โ†’2.0): no effect on outcome\n- Tactical dominance lerp bump (thresholds.rs 1.5โ†’2.0/2.5 baseline): caused REGRESSION on tier_peak (faster opportunist wins)\n- Both reverted because the strategic MCTS doesn't pick attack actions โ€” it only picks `SpawnUnit/FoundCity/Idle` per `mc-turn/src/snapshot.rs:204-214 action_prior`. The capture/development tempo is governed by mc-turn capture mechanics + mc-economy growth rates, NOT by AI scoring weights.\n\nReal levers (cross-team scope):\n- **mc-combat / mc-turn capture mechanics**: increase city HP, lengthen siege duration, add capital-recapture cost, weaken early-rush combat math.\n- **mc-economy growth rates**: faster baseline tech research, lower tier-3 prereq cost, give players tech catch-up bonus when behind.\n- **mc-turn turn-limit floor**: refuse to award domination victory before T150 (force games to mid-game minimum).\n\nPick one or compose multiple. Each requires the corresponding team-lead's involvement." }, + { + "id": "p1-29a", + "title": "Last-stand defense โ€” combat-strength multiplier when defender is at last city", + "priority": "p1", + "status": "stub", + "scope": "game1", + "owner": "combat-dev", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "Filed by p1-29 cycle 5 close-out as the combat-side intervention that should close p1-29's `tier_peak_gap โ‰ค4` gate. Three consecutive cycles of research-side levers (catch-up tech-pick mult, catch-up tech-output mult, loss-tolerance lever) landed durably but failed to move the gate across three batches. The failure is structural: p1 (the losing AI) loses cities faster than research output can unlock era-2+ techs. Research-side levers multiply a tiny base into a tiny base. The gate is a **territory problem**, not a research problem.\n\nThis objective addresses the territory problem by giving the defender (when reduced to their last city) a combat-strength bonus that scales with how many cities they've lost โ€” buying enough turns for the existing research-side levers to finally fire and unlock era-2+ techs." + }, { "id": "p1-30", "title": "Optimize `_build_tactical_state` โ€” 8000-tile GDScript dict-build per AI turn blocks p1-22 huge-map gate", "priority": "p1", - "status": "missing", + "status": "partial", "scope": "game1", "owner": "warcouncil", - "updated_at": "2026-04-26", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "Split out from p1-22 (MCTS per-decision wall-clock budget). p1-22 closed `partial` after cycles 2-3 shipped strategic + tactical Rust budgets (`mcts_tree::simulate_parallel` + all 5 `mc-ai/src/tactical/` submodules + `GdAiController::set_budget_ms`, 186/186 lib tests). Strategic budget verified working: p1-22-cycle-2 batch had seeds 9 and 10 reach T500 victories at max_tier=10 and 7. Tactical budget verified bounded by unit test `tactical::tests::tactical_budget_respected`.\n\nBut the huge-map โ‰ฅ5/10 victories sub-gate FAILED at 2/10 in the cycle-2 batch because seeds 1-8 hung at low turn counts (T43-T236). The Rust paths are bounded; the hang is in GDScript. Specifically: `src/game/engine/src/modules/ai/ai_turn_bridge.gd:248-250` (`_build_tactical_state`) iterates `width ร— height` tiles (112ร—72 = 8064 on a huge map) building a Dictionary per tile to serialize as JSON to feed `GdAiController::decide_actions`. That serialization runs every AI turn per player.\n\n5 AI players ร— ~8000 tile-dicts ร— ~T100 turns = ~4 million GDScript dict allocations per game. Each dict allocation is microseconds but compounds. The Rust `MCTS_DECISION_BUDGET_MS=2000` doesn't bound this โ€” by the time Rust gets the JSON, the GDScript serialization has already chewed through the wall-clock budget for the turn.\n\nThe fix has two reasonable shapes:\n1. **Delta serialization**: only serialize tiles whose state changed since last AI turn. Cache per-player. ~10ร— speedup.\n2. **Move tile state into mc-turn**: have Rust own the tile catalog (already partial via `TacticalMap`), pass an opaque handle from GDScript instead of full JSON. Eliminates the GDScript dict-build entirely. Aligns with Rail-1.\n\nOption 2 is more correct (Rail-1) but bigger surface. Option 1 is the quick win." }, + { + "id": "p1-30b", + "title": "Parallel MCTS rollouts for huge-map decisive games (closes p1-22's huge-map sub-gate)", + "priority": "p1", + "status": "stub", + "scope": "game1", + "owner": "warcouncil", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "Filed by p1-30 cycle 5 close-out as the home for the gameplay-outcome gate that p1-30 inherited from p1-22 but cannot close in its current scope.\n\np1-30's stated scope is `_build_tactical_state` GDScript-side perf. Cycle 5 verified the Rail-1 ephemerals handoff at the Rust level (criterion bench `tactical_state_build`: 17.6ฮผs serialize, 36.9ฮผs roundtrip on 112ร—72 huge-map fixture). But the **gameplay-outcome gate** that originally lived under p1-30 โ€” \"huge-map-5clan 10-seed batch achieves โ‰ฅ5/10 victories with โ‰ฅ2 distinct winners\" โ€” is constrained by MCTS **rollout efficiency**, not by `_build_tactical_state` perf. Cycle-2 and cycle-3 evidence (in `p1-30.md`) shows the gate is two-sided unreachable by knob retuning alone:\n\n- 2000ms MCTS_DECISION_BUDGET_MS โ†’ 0/10 decisive (every seed `outcome=in_progress` at 1800s timeout)\n- 500ms MCTS_DECISION_BUDGET_MS โ†’ 3/4 deadlock (per-decision floor breached)\n\nThe bottleneck is `mc-ai/src/mcts.rs` rollout cost, currently single-threaded. The fix is a structural rewrite to support parallel rollouts (rayon-based fan-out from `mcts_tree::simulate_parallel`, or a smaller-action-space MCTS, or a different decision algorithm entirely)." + }, { "id": "p1-31", "title": "Split bundled `resources/buildings/.json` into per-file pattern matching `resources/units/`", @@ -839,9 +861,9 @@ "id": "p1-32", "title": "Author the two missing food/processing buildings (sawmill, herbalist)", "priority": "p1", - "status": "missing", + "status": "done", "scope": "game1", - "updated_at": "2026-04-27", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "`public/games/age-of-dwarves/docs/cities/PRODUCTION_CHAIN.md` describes a stockpile-based processing economy with six processing buildings: `granary`, `mill`, `brewery`, `tannery`, `sawmill`, `herbalist`. Audit confirms the first four exist in `resources/buildings/` bundles (`economy.json` carries granary/mill/brewery; `crafting_producers.json` carries tannery). The remaining two are truly missing.\n\n| Building | Designed source | Status |\n|---|---|---|\n| `granary` | Husbandry tech, food storage | โœ“ in `resources/buildings/economy.json` |\n| `mill` | Husbandry tech, grain โ†’ flour | โœ“ in `resources/buildings/economy.json` |\n| `brewery` | Brewing tech, ale (happiness + trade) | โœ“ in `resources/buildings/economy.json` |\n| `tannery` | Tanning tech, hides โ†’ leather | โœ“ in `resources/buildings/crafting_producers.json` |\n| `sawmill` | Logging tech, timber โ†’ lumber | **missing** โ€” closest is `lumber_camp` (production_advanced.json, different concept) |\n| `herbalist` | Herbalism tech, reagents โ†’ academy | **missing** โ€” closest are `alchemist_workshop` / `alchemist_bench` (different concept) |\n\nThis objective authors only the two genuinely missing buildings. The naming question โ€” should `sawmill` reuse the existing `lumber_camp` slot, and should `herbalist` reuse `alchemist_workshop`? โ€” needs a design decision before content is authored." }, @@ -849,9 +871,9 @@ "id": "p1-33", "title": "Wire naval/aerial unit gates to the harbor and airfield buildings", "priority": "p1", - "status": "missing", + "status": "done", "scope": "game1", - "updated_at": "2026-04-27", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "The buildings `harbor` (`resources/buildings/naval_buildings.json`, `enables_naval` effect, `requires_coastal: true`) and `airfield` (`resources/buildings/infrastructure_advanced.json`) already exist and are loaded by the engine. The gating problem is upstream of the buildings:\n\n- The 14 dwarf naval units (`dwarf_river_galley` โ†’ `dwarf_fortress_ship`) carry only a `tech_required` field. None reference `harbor` or `requires_building`. A landlocked city the moment `shipbuilding` is researched can build a `dwarf_dreadnought`.\n- The 7 dwarf aerial units (`dwarf_gyrocopter` โ†’ `dwarf_sky_fortress`) similarly do not reference `airfield`. Any city with `mechanical_flight` can build a sky_fortress on a mountaintop with no infrastructure.\n\nThe `harbor` building's effect `enables_naval: true` is suggestive of an intended gate, but no Rust or GDScript code consumes that effect. Naval / aerial unit eligibility is determined entirely by tech.\n\nThis objective wires the gate." }, @@ -881,10 +903,10 @@ "id": "p1-36", "title": "AI personalities โ€” T1โ€“T10 build order coverage + clan_affinity routing", "priority": "p1", - "status": "partial", + "status": "done", "scope": "game1", "owner": "warcouncil", - "updated_at": "2026-04-27", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "`public/games/age-of-dwarves/data/ai_personalities.json` currently lists\nhardcoded early build orders that reference only the old 10-unit roster\n(warrior / forge / walls / dwarf_founder). The new T1โ€“T10 roster (50 new\nunits) is invisible to all five AI clans โ€” they cannot build a Shield\nBearer, a Ballista Crew, a Boar Scout, or any T7+ unit.\n\nCombined with `clan_affinity` (added by p1-34), this objective wires the\nfive AI personalities to actually feel distinct in the units they build:\n\n- **Ironhold** (production 9, aggressive 6) โ€” heavy melee anchored\n defender lines, walls, anvil_guard at T6, mountain_king late game\n- **Goldvein** (wealth 9, trade 9) โ€” cheap cost-efficient units, mercenary\n archers, defensive pikemen, light_field_gun for cavalry counter\n- **Blackhammer** (aggression 9) โ€” light melee rush, hearth_raiders,\n berserkers, war_rams for cavalry pressure, doomsoul end-game\n- **Deepforge** (production 8, isolationist) โ€” siege + walker focus,\n forge_titan, rail_cannon, adamantine_tank, ancestral_walker\n- **Runesmith** (balanced) โ€” runic units, rune_spears, marksmen, mixed\n army with one of each archetype" }, @@ -892,10 +914,10 @@ "id": "p1-37", "title": "mc-ai clan_affinity routing โ€” Rust AI reads unit clan_affinity at build-decision time", "priority": "p1", - "status": "partial", + "status": "done", "scope": "game1", "owner": "warcouncil", - "updated_at": "2026-04-27", + "updated_at": "2026-05-01", "blocked_by": [], "summary": "p1-36 landed the data side: every unit JSON has a `clan_affinity` array (per p1-34's\nschema expansion), and `ai_personalities.json` now has tiered build orders (early /\nmid / late) per clan that respect clan affinity. But the **decision loop that picks\nunits doesn't yet read either field** โ€” it still selects from a flat priority list,\nso all five clans build similarly-statted armies and the Ironhold-vs-Blackhammer\ngameplay difference doesn't surface in actual matches.\n\nPer **Rail #1** (Rust is the simulation source of truth), this work lands in\n`src/simulator/crates/mc-ai/`, NOT in any GDScript file. The completed p0-26 port\nestablished the `GdAiController` bridge; this objective extends the build-order /\nunit-selection path inside `mc-ai` to consume `clan_affinity` data." }, @@ -906,7 +928,7 @@ "status": "partial", "scope": "game1", "owner": "shipwright", - "updated_at": "2026-04-27", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "Population growth and luxury supply have been decoupled from the live ecology\nsimulation since `mc-flora` was wired up. Cities read static per-terrain food\nyields (`grassland.food=2`, `plains.food=1`); 70 fauna species exist purely\nas combat encounters with no contribution to the city economy; the\n`mc-happiness::get_growth_modifier` tiering (1.25 / 1.00 / 0.50 / 0.00) was\ncomputed but unused on the GDScript side. This objective re-couples the\ncity economy to the ecology layer in four phases (C โ†’ A โ†’ B โ†’ D), each\nsized to land independently with its own balance regression risk.\n\nThe four phases were approved together as a single `p1` objective in plan\n`~/.claude/plans/hi-so-in-valiant-mango.md` (2026-04-27), but ship in\nsequence so `p1-05`'s baseline bands (median `pop_peak=69`, batch\n`p016b_20260417_024754`) are not disturbed." }, @@ -917,7 +939,7 @@ "status": "partial", "scope": "game1", "owner": "warcouncil", - "updated_at": "2026-04-29", + "updated_at": "2026-05-01", "blocked_by": [], "summary": "During p1-29 Round 3-5, warcouncil added a per-yield difficulty multiplier framework (gold_mult, culture_mult, luxury_mult, research_mult, production_mult, yield_per_turn_growth) plus a symmetric player handicap (Easy = player gets Hard-AI bonuses). Per Rail-1, the multiplier APPLICATION should live in Rust crates, not in GDScript turn_processor.gd / economy.gd / turn_processor_helpers.gd.\n\n**Gold yield port: DONE 2026-04-27.** `EconomyParams.yield_mult` field added to `api-gdext/src/lib.rs:2962-2992` with serde default 1.0; `GdEconomy::process_turn` now scales gross income before netting expenses. GDScript `economy.gd::_build_params_json` injects `yield_mult` from `GameState.get_effective_yield_mult(player, \"gold\")`; the GDScript-side multiplication is deleted. Validated via 10-seed Hard batch `.local/iter/p1-31-r5-hard-20260427_044618/` โ€” 4/5 quality gates PASS (up from 3/5), clan diversity up from 3 to 5 distinct winners.\n\n**Research yield port: DONE 2026-04-27.** Added `process_research(player_json, yield_json, sci_modifier)` passthrough at `knowledge_web.gd:152` (delegates to `_bridge.call(\"process_research\", ...)`) and exposed at `tech_web.gd:39`. Refactored `turn_processor.gd::_process_research:143` to delegate fully โ€” assembles JSON inputs (player_dict + per-city yields_arr), calls `tw.process_research()`, only handles completion side-effects (school_locked emit, _form_high_archon, tech_researched signal, resource reveals). No Rust rebuild needed (GdTechWeb::process_research already had sci_modifier as a direct parameter; only the wrapper-layer plumbing was missing).\n\nValidation: `.local/iter/p1-39-r6-hard-20260427_054348/` (10-seed Hard batch). 4/5 quality gates PASS: median winner_tier_peak=4.5 PASS (was 3 FAIL in R5 โ€” research port LIFTED this), tier_peak_gap=5.0 FAIL (was 3.5 PASS โ€” gates alternate, total still 4/5), max_peak_unit 10/10 PASS, wonders 7/10 PASS, combats 454 PASS. **All 10 games completed (vs 8/10 in R5)**, **6 distinct winners** (max diversity for 5-clan game).\n\n**Culture yield port: COMPLETED 2026-04-29.** Root cause of R7/R8 divergence was NOT floating-point semantics. Two bugs caused the apparent divergence:\n\n1. **Stale GDExtension binary on apricot** โ€” R7 and R8 batches ran against an old `.so` that lacked `process_culture_with_modifier`. Godot emitted `SCRIPT ERROR: Invalid call. Nonexistent function 'process_culture_with_modifier'` on every culture call per turn, culture never accumulated, games ended at T111 vs R6/R9's T251. Evidence: `game.log` in both R7 and R8 dirs contains this exact error; R9 (reverted to `process_culture`) worked because that symbol WAS in the old binary.\n\n2. **Missing GDScript bridge wrappers** โ€” `city.gd` and `city_rust_bridge.gd` delegated `process_culture` but had no `process_culture_with_modifier` method. The delegation chain from `turn_processor.gd` โ†’ `city.gd` โ†’ `city_rust_bridge.gd` โ†’ `_gd_city.call(...)` was incomplete.\n\nThe \"f64 vs Variant FLOAT round-trip\" hypothesis in the revert comment was incorrect. Godot 4 Variant FLOAT is f64 (lossless), and the Rust math is algebraically identical to the original GDScript.\n\nFix (2026-04-29): added `process_culture_with_modifier` wrappers to `city.gd` and `city_rust_bridge.gd`; switched `turn_processor.gd::_process_culture` to call `c.process_culture_with_modifier(tile_json, total_pct)`; rebuilt GDExtension on apricot (binary dated 2026-04-29 21:43). R12 validation run: zero `process_culture_with_modifier` errors. Games terminate at T22 due to an unrelated AI regression (`set_map`/`captured_turn` errors from p1-29 changes) not from culture.\n\nAll three yield types (gold, research, culture) are now ported to Rust. The one remaining open acceptance bullet is replay parity โ€” blocked on unrelated p1-29 AI regressions, not on the culture port itself." }, @@ -955,9 +977,9 @@ "id": "p1-43", "title": "Building stacking โ€” per-category upgrade chains (military / science / culture / production / etc.)", "priority": "p1", - "status": "missing", + "status": "partial", "scope": "game1", - "updated_at": "2026-04-29", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "User direction (2026-04-29): \"all the buildings should be buildable and some buildings can be built on top of each other (double barracks - infantry) ... what about comboing other buildings ... science stack, culture stack\".\n\nToday every building is binary: a city either has it or doesn't. The mechanic the user wants: queueing a building on top of an existing one upgrades the slot in place โ€” `barracks` + another `barracks` build = `infantry` (a stronger military producer). The same primitive applies to every category: science stacks (library โ†’ scriptorium โ†’ academy), culture stacks (monument โ†’ bardic_circle โ†’ great_hall), production stacks (forge โ†’ iron_forge โ†’ grand_forge), etc. This is distinct from the BUILDINGS.md \"Hybrid Merged Structures\" mechanic (which combines TWO different buildings + Synthesis tech into a hybrid). Stacking is the simpler primitive: same-category Lv1 โ†’ Lv2 โ†’ Lv3 chains within one slot.\n\nThe existing data already implies category-tier chains via the `tier` + `category` fields:\n\n| Category | Lv1 (no tech) | Lv2 (mid tech) | Lv3+ (late tech) |\n|---|---|---|---|\n| Production | `forge` t1 | (gap โ€” `iron_forge` doesn't exist) | `dwarf_deep_forge` t3, `tempering_forge` t6, `steam_forge` t7, `adamantine_foundry` t10 |\n| Science | `library` t1 | `university` t3, `observatory` t3 | `academy_of_sciences` t5, `climate_institute` t9 |\n| Culture | `monument` t1 | `great_hall` t3, `gathering_hall` t2 | `ancestor_hall` t10 |\n| Military | `barracks` t1 | (gap โ€” `infantry` doesn't exist) | `armory` t3, `military_academy` t6, `command_citadel` t10 |\n| Food | `granary` t1 | `mill` t2, `brewery` t2, `watermill` t2 | `great_granary` t2 (wonder) |\n| Defense | `walls` t1 | `watchtower` t1 | `castle` t3 |\n| Wealth | `marketplace` t2, `market` t2 (DUPLICATE) | `guild_hall` t4 | (none) |\n| Religion | `temple` t2 | `temple_of_the_ancestor` t5 (wonder) | (none) |\n\nThe stacking schema makes these chains explicit and queryable. Where a Lv2 successor doesn't exist yet (e.g. `infantry`, `iron_forge`, `scriptorium`), this objective authors the missing intermediates.\n\nThree design questions need user sign-off before authoring:\n\n1. **Successor identity**: is `infantry` a NEW building (needs authoring) or an existing one (e.g. reuse `armory` as the \"barracks Lv2\" slot)?\n2. **Mechanic shape**:\n - **(a) Replacement**: building barracks twice consumes both, slot becomes `infantry`. Original gone.\n - **(b) Levelled**: building stays \"barracks\" but carries a `level: 2` field with stacked effects.\n - **(c) Per-tile**: two barracks on same tile merge (only relevant if `placement_tile_required: true`).\n3. **Schema**: declare on the lower tier (`barracks.json::stacks_into: \"infantry\"`) or on the upper (`infantry.json::requires_existing: \"barracks\"` + `consumes_existing: true`)? The latter keeps the relationship bidirectional readable.\n\nRecommendation: option **(a) Replacement** with declaration on the upper tier (`requires_existing` + `consumes_existing`). Matches civ-style upgrade slots, reads naturally in the city UI (\"Upgrade Barracks โ†’ Infantry\"), avoids per-tile placement complexity for a v1." }, @@ -975,10 +997,10 @@ "id": "p1-45", "title": "Batch binary freshness: rebuild GDExt before every autoplay batch", "priority": "p1", - "status": "missing", + "status": "done", "scope": "game1", "owner": "simulator-infra", - "updated_at": "2026-04-30", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "Autoplay batches (`tools/autoplay-batch.sh`) run Godot against the installed GDExtension binary\n(`engine/addons/magic_civ_physics/libmagic_civ_physics.x86_64.so`). When multiple agents or\ndevelopers land Rust changes between batches, the `.so` silently goes stale โ€” the GDScript wrappers\ncall methods that don't exist yet in the binary, producing cryptic errors like:\n\n```\nInvalid call. Nonexistent function 'process_culture_with_modifier' in base 'RefCounted (City)'.\n```\n\nThis was observed on 2026-04-30 during the p1-29 anti-snowball batch cycle when the culture-port\nteammate's `process_culture_with_modifier` and p1-30's `set_map`/`update_tile` GDExt methods were\nlanded after the last build, causing R12 test failures at T22." }, @@ -986,7 +1008,7 @@ "id": "p1-46", "title": "Terrain Dimensions Lab โ€” fix ridginess, bind 149 flora species, add Whittaker plot", "priority": "p1", - "status": "partial", + "status": "done", "scope": "game1", "owner": "terraformer", "updated_at": "2026-05-01", @@ -997,7 +1019,7 @@ "id": "p1-47", "title": "River hydrology โ€” D6 flow analysis, hydraulic erosion, multi-hex lakes, cross-tile rivers", "priority": "p1", - "status": "partial", + "status": "done", "scope": "game1", "owner": "terraformer", "updated_at": "2026-05-01", @@ -1008,10 +1030,10 @@ "id": "p1-48", "title": "Flora species renderer โ€” bind 149 species to world-map tile rendering (single source of truth)", "priority": "p1", - "status": "partial", + "status": "done", "scope": "game1", "owner": "terraformer", - "updated_at": "2026-04-30", + "updated_at": "2026-05-01", "blocked_by": [], "summary": "`public/resources/ecology/flora/species/*.json` defines **149 species**\nwith rich schema:\n\n- `biomes[]` โ€” which terrain types support the species\n- `tags[]` including layer (`layer_canopy` / `layer_understory` /\n `layer_ground` / `layer_fungal`) and structure (`structure_woody` /\n `conifer` / `broadleaf` / `evergreen`)\n- `lineage` โ€” taxonomic group (`conifers`, `broadleaf_trees`,\n `tropical_broadleaf`, `cacti`, `palms`, `aquatic_plants`,\n `mosses_lichens`, etc.)\n- `quality_tier` (0โ€“10), `canopy_contribution`,\n `undergrowth_contribution`, `fungi_contribution`\n- `drought_tolerance`, `fire_resistance`, `growth_rate`\n\nWave C landed the Rust selector, WASM + GDExt bridges, and integration tests.\nThe visual-proof bullets (tooltip, lab integration) are Wave-E work โ€” relocated\nto p1-46. The TS twin (`floraSpecies.ts`) was deleted; `Lab.tsx` has\n`TODO(p1-46)` markers where the WASM calls will be wired in.\n\n**Single source of truth (Rail 1):** the selector is implemented ONCE\nin `mc-ecology` (Rust), exposed to Godot via GDExtension and to the\ndesign-lab via WASM. NO TypeScript twin." }, @@ -1019,7 +1041,7 @@ "id": "p1-49", "title": "Fauna species renderer โ€” 61 Game-1 species visible on encounter and lair tiles", "priority": "p1", - "status": "partial", + "status": "done", "scope": "game1", "owner": "terraformer", "updated_at": "2026-05-01", @@ -1032,7 +1054,7 @@ "id": "p1-50", "title": "Tectonic prepass โ€” voronoi plates + boundary classification seeding elevation", "priority": "p1", - "status": "partial", + "status": "done", "scope": "game1", "owner": "terraformer", "updated_at": "2026-05-01", @@ -1083,6 +1105,50 @@ "blocked_by": [], "summary": "Two related hex-direction bugs surfaced after p1-53 Stage 2 wired the\nHydrology page to live Rust output:\n\n**Bug 1 โ€” `Hydrology.tsx` flow-arrow rendering (lines 11โ€“13):**\n```typescript\nconst FLOW_DX = [1, 1, 0, -1, -1, 0];\nconst FLOW_DY_EVEN = [0, -1, -1, 0, 1, 1];\nconst FLOW_DY_ODD = [0, -1, -1, 0, 1, 1];\n```\n`FLOW_DY_EVEN` and `FLOW_DY_ODD` are identical. For any odd-q offset\ngrid they MUST differ โ€” that's the entire point of the parity table.\nResult: flow-arrow overlay points to the wrong neighbour for half the\nhexes (whichever parity wasn't hand-checked when the values were\ncopied).\n\n**Bug 2 โ€” Rust โ†” TS direction-label mismatch:**\n`mc-core/algorithms/hex.rs::AXIAL_DIRECTIONS` documents directions\n0โ€“5 as `E, NE, NW, W, SW, SE` โ€” the pointy-top axial convention with\nE and W as neighbour directions. But the design-app canvas uses\n**flat-top** geometry (`hexCorners` places corners at angles 0ยฐ, 60ยฐ,\nโ€ฆ, 300ยฐ โ†’ corners at E and W, edges/neighbours at NE/SE/S/SW/NW/N).\n\nSo when `WasmGrid::tile_hydrology(col, row).flow_out` returns `0`\n(\"E\" in Rust), the design-app canvas should interpret that as the\nflat-top **SE** direction (Rust's \"E\" is `(col+1, row)` axial, which\nin flat-top with odd cols shifted DOWN lands SE of the source cell\nfor even cols).\n\nThe two conventions need a documented translation table that both the\ncanvas and any future TS consumer of WASM hex output reads from.\n\n`hexCanvas.ts::EDGE_CORNERS` and `neighborCoords` were corrected\n2026-05-01 (out of band, before this objective existed) to use\nflat-top semantics โ€” that fix is correct for design-app-only logic\nthat doesn't cross the WASM bridge. The remaining gap is the\n**bridge-crossing** label translation." }, + { + "id": "p1-55", + "title": "Tech & Culture domain field โ€” propagate categorization through Rust, Godot UI, and player analysis", + "priority": "p1", + "status": "in_progress", + "scope": "game1", + "owner": "simulator-infra", + "updated_at": "2026-05-04", + "blocked_by": [], + "summary": "The designs app at `.project/designs/app/` now drives `/tech-tree` and\n`/culture-tree` from real JSON data with a 10-domain categorization\n(Military / Economy / Industry / Agriculture / Governance / Culture /\nScience / Exploration / Engineering / Medicine), authored as\n`tech.domain` directly in `public/resources/techs/*.json`. Culture\npolicies use the `pillar` field as their tab axis.\n\nThis objective propagates that categorization through the rest of the\nsystem โ€” the Rust simulator, the Godot gameplay UI (`knowledge_tree`,\n`tech_tree`, `culture_tree`), and player data analysis surfaces โ€” so\nevery consumer reads the same Single Source of Truth.\n\nThe shared TreeView component (`.project/designs/app/src/components/tree/`)\nis the reference implementation. Other surfaces should match its UX:\ndomain tab bar, matching-tab-floats-to-top sort, inline unlocks on each\nnode." + }, + { + "id": "p1-56", + "title": "Civics buildings, Great Works, Specialists, Great People โ€” wire authored data into Rust + Godot", + "priority": "p1", + "status": "in_progress", + "scope": "game1", + "owner": "simulator-infra", + "updated_at": "2026-05-04", + "blocked_by": [], + "summary": "A large body of city-management data was authored in the 2026-05-03 design\nsession. The JSON content + designs-app pages exist as the canonical\nspecification. Rust simulator and Godot UI consumers must now be wired\nto actually run the systems in-game." + }, + { + "id": "p1-57", + "title": "Diplomacy: tribute, treaty lifecycle, magical-terrain episode gating", + "priority": "p1", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "Three diplomacy-related systems were authored in JSON. Rust wire-up\npending." + }, + { + "id": "p1-58", + "title": "Ecology cognition: terrain affinity, food web, grudge memory, apex tier-10 fauna/flora", + "priority": "p1", + "status": "partial", + "scope": "game1", + "owner": "simulator-infra", + "updated_at": "2026-05-04", + "blocked_by": [], + "summary": "A unifying ecology-cognition layer was authored across flora, fauna, and\nwild-creature units. Adds shared `combat_profile`, `cognitive_profile`,\n`terrain_affinity`, and `loot_table` fields. Brings the Civ5 \"tier-10 apex\npredator owns the map\" experience to dwarven gameplay." + }, { "id": "p2-06", "title": "Export pipeline for Windows / macOS / Linux", @@ -1101,7 +1167,7 @@ "status": "in_progress", "scope": "game1", "owner": "asset-audio", - "updated_at": "2026-04-27", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "The audio capability shipped as **p0-21** โ€” `AudioManager`, manifest,\nsignal wiring, volume sliders all work. The schema + categorical\nrouting extension lands as **p2-33** (this objective is `blockedBy`\nthat). What's missing is the actual `.ogg` files plus the source\nledger that proves their licenses are clean.\n\nPer user directive 2026-04-17 the asset work was pulled out of the\noriginal `p1-04` so capability and assets are tracked independently.\nA silent ship is shippable; a broken or licence-tainted audio system\nis not.\n\nThis objective ships **the launch sound pack** assembled from free /\nOSS sources (CC0, CC-BY 3.0/4.0, royalty-free commercial; no\nShareAlike, no NonCommercial). Pack covers ~57 files spanning UI,\nturn cycle, units (categorical melee / ranged / siege / civilian),\nbuildings (categorical civic / production / military / wonder),\nfauna (categorical predator / herbivore / apex), city events,\nresearch, weather, victory. ~50 SFX + 7 music tracks." }, @@ -1487,9 +1553,9 @@ "id": "p2-11a", "title": "SaveManager: add Unit.serialize/deserialize and City.production_queue serialize path", "priority": "p2", - "status": "stub", + "status": "partial", "scope": "game1", - "updated_at": "2026-04-26", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "Unit has no serialize()/deserialize() methods โ€” infusions, equipped_items, promo_ids, keywords and other typed arrays cannot round-trip through SaveManager. City.production_queue is a GDScript-side Array with no serialize path; the Rust-backed City.to_json() does not include it. These gaps were deferred from p2-10f, which narrowed its tests to the Player serialize surface only." }, @@ -1678,10 +1744,10 @@ "id": "p2-46", "title": "Past-games archive & replay viewer โ€” `mc-replay` crate, on-disk archive, projection-based playback", "priority": "p2", - "status": "missing", + "status": "partial", "scope": "game1-stretch", "owner": "shipwright", - "updated_at": "2026-04-30", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "Persistent local archive of finished games, accessible from the main menu, with three surfaces:\n\n1. **Past Games index** โ€” card grid (newest first), filters (outcome / map / version / date), per-card actions (Open Summary ยท Watch Replay ยท Rename ยท Export ยท Delete).\n2. **Replay viewer** โ€” turn-by-turn playback against the live renderer, **projection-based not re-simulated** (reads pre-recorded snapshots + events), scrubber, speed selector, event ticker, optional stats overlay.\n3. **Compare view** โ€” multi-select 2โ€“4 games โ†’ overlapping score-graph + final-standings delta.\n\nFoundational for `p3-06` (statistics screens) and `p3-07` (end-of-game summary), both of which read the same `GameHistory` artefact this objective owns. **Ships first** of the three.\n\nDesign doc: [.project/designs/past-games-replays.md](../designs/past-games-replays.md)." }, @@ -1689,10 +1755,10 @@ "id": "p2-47", "title": "In-game statistics screens โ€” Civ-style 5-tab modal (Demographics / Graphs / Rankings / Replay / Histories)", "priority": "p2", - "status": "missing", + "status": "partial", "scope": "game1-stretch", "owner": "shipwright", - "updated_at": "2026-04-30", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "Civ-style mid-game statistics modal opened from the HUD info button (or `F9`). Five tabs in one scene, all read-only views over the per-turn `TurnSnapshot` log produced by `mc-replay` (p3-05):\n\n1. **Demographics** โ€” sortable single-turn table of every met clan.\n2. **Graphs** โ€” multi-line chart, Y-axis selector (score / pop / cities / army / gold-per-turn / culture-per-turn / tech-count / land-area), X = turn.\n3. **Rankings** โ€” top-N leaderboard for the selected metric, with trend arrow vs. previous turn.\n4. **Replay** โ€” in-game preview of the post-game replay viewer (p3-05 surface), scoped to the current game's history.\n5. **Histories** โ€” per-clan chronicle (founding turn, wars, wonders, eras, leaders).\n\nComposite score is recomputed every turn-end from JSON-driven weights, used for Rankings default and end-game ordering.\n\nDesign doc: [.project/designs/stats-screens.md](../designs/stats-screens.md)." }, @@ -1700,10 +1766,10 @@ "id": "p2-48", "title": "End-of-game summary screen โ€” outcome banner, standings, score graph, awards, timeline, footer actions", "priority": "p2", - "status": "missing", + "status": "partial", "scope": "game1-stretch", "owner": "shipwright", - "updated_at": "2026-04-30", + "updated_at": "2026-05-03", "blocked_by": [], "summary": "Full-screen summary triggered when the game ends โ€” by victory condition, last-clan-standing, turn-limit, or player resignation. Replaces the world-map HUD with:\n\n- **Hero strip** โ€” outcome banner + winning-clan card + player's-clan card (player-second slot stable across victory/defeat).\n- **Section 1 โ€” Final standings** โ€” Demographics table from p3-06 frozen at final turn, plus `Outcome` and `Score breakdown` columns.\n- **Section 2 โ€” Score graph** โ€” full-game chart from p3-06's Graphs widget with event markers forced on.\n- **Section 3 โ€” Awards** โ€” JSON-driven per-category superlatives.\n- **Section 4 โ€” Timeline** โ€” Histories from p3-06 with fog lifted (every clan visible).\n- **Footer** โ€” View Map ยท Watch Replay ยท Save to Archive ยท Export JSON ยท Main Menu.\n\nDesign doc: [.project/designs/end-game-summary.md](../designs/end-game-summary.md)." }, @@ -1711,7 +1777,7 @@ "id": "p2-49", "title": "Climate axes refactor โ€” latitude + continentality + zonal winds as first-class per-hex inputs", "priority": "p2", - "status": "partial", + "status": "done", "scope": "game1", "owner": "terraformer", "updated_at": "2026-04-30", @@ -1722,10 +1788,10 @@ "id": "p2-50", "title": "Deterministic RNG + seed-derivation pin across mc-mapgen / mc-climate / mc-ecology", "priority": "p2", - "status": "partial", + "status": "done", "scope": "game1", "owner": "terraformer", - "updated_at": "2026-04-30", + "updated_at": "2026-05-01", "blocked_by": [], "summary": "Every terraformer-owned objective claims \"deterministic from seed\", but\nno objective specifies (a) which RNG, (b) the seed-mixing function,\n(c) the version pin that survives `cargo update`. Today, the worldgen\npipeline calls `rand::thread_rng()` and `StdRng::seed_from_u64(seed)`\ninconsistently across crates. `StdRng` is explicitly documented as\n**not stable across rand versions** โ€” saves break silently on dep\nbumps.\n\nThis objective pins a versioned RNG and a single seed-derivation\nfunction for all worldgen โ€” tectonics, hydrology, climate, species\nselection. Lands as a small infrastructure objective so Wave A of the\nterraformer schedule (p1-50, p2-49) is built on a stable foundation,\nnot retrofitted later." }, @@ -1733,10 +1799,10 @@ "id": "p2-51", "title": "Player-facing world-shape parameters on new-game screen", "priority": "p2", - "status": "partial", + "status": "done", "scope": "game1", "owner": "terraformer", - "updated_at": "2026-04-30", + "updated_at": "2026-05-01", "blocked_by": [], "summary": "The terraformer pipeline now exposes ~15 internal parameters\n(plate count, tectonic strength, fbm octaves, sea level, latitude\ngradient, continentality decay, rain-shadow factor, erosion\niterations, drainage threshold, etc.). Designers tune these in the\nforest lab; **players see none of them**. The new-game screen ships\n\"Map Size\" and not much else.\n\nIndustry baseline (Civ 6, Old World, Songs of Conquest) exposes 4โ€“6\nhigh-level shape knobs. Each knob is a *preset* that derives several\ninternal parameters at once. This objective wires that surface from\nJSON presets through `mc-mapgen` parameters into the Godot game-setup\nscene." }, @@ -1744,23 +1810,371 @@ "id": "p2-52", "title": "Split terrain enum into substrate ร— flora-cover layers (resolve biome ontology)", "priority": "p2", - "status": "partial", + "status": "done", "scope": "game1", "owner": "terraformer", "updated_at": "2026-05-01", "blocked_by": [], "summary": "The current `terrain.json` enum (16 IDs) conflates three orthogonal\necological layers into a single field:\n\n| Layer | Examples currently in terrain enum | Should live where |\n|---|---|---|\n| **Substrate** (geological / hydrological) | `mountains`, `hills`, `ocean`, `coast`, `lake`, `inland_sea`, `volcano`, `ice`, `snow` | terrain (correct) |\n| **Flora-cover** (emergent from species) | `forest`, `jungle`, `boreal_forest`, `grassland`, `swamp` | derived from flora selector |\n| **Substrate ร— climate composite** | `desert`, `tundra`, `plains` | derived label, not authored |\n\nThe `feature_type: \"foliage\"` field on `forest`/`jungle`/`boreal_forest`\nin `public/games/age-of-dwarves/data/terrain/land_forest.json` is the\ndata layer admitting these are flora cover masquerading as terrain.\n\nThis conflation propagates everywhere:\n- Flora species `biomes[]` arrays list flora-cover types as locking\n conditions (a beech tree's `biomes = [temperate_forest, forest]` โ€”\n both are flora-cover labels, not substrates)\n- Climate classifier (`mc-climate::derive::classify_terrain_whittaker`)\n emits flora-cover names from T/P bands directly, skipping the\n substrate axis\n- Terrain blends (`terrain_blends.json`) mix substrate edges\n (`coast+plains โ†’ shore`) with flora-cover edges\n (`forest+plains โ†’ grass_fringe`) on equal footing\n\nThis objective restructures the data model into three independent layers\nthat the renderer composes into a final visual:\n\n```\nSubstrate โ† Tectonics + Hydrology output\n ร— Climate โ† (t_band, p_band, riparian_distance)\n ร— Flora-cover โ† Ecology selector output (canopy/understory/ground/bare)\n = Biome label โ† Display name only, derived not stored\n```" }, + { + "id": "p2-53", + "title": "Action vocabulary โ€” gap analysis between design page and shipped Rust/Godot game", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "wireguard", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "The design page at `/unit-actions` (`.project/designs/app/src/pages/UnitActions.tsx`) curates an exemplar per unit/building category and lists per-archetype action vocabularies. Cross-checking that vocabulary against the shipped Rust action registry (`mc-core/src/action.rs::ActionKind`), the JSON capability map (`unit_actions.json`), and the Godot panel (`scenes/hud/unit_panel.gd`) reveals four classes of gap. This objective is the gap analysis only โ€” implementation work splits out into child objectives once the design vocabulary is ratified." + }, + { + "id": "p2-53a", + "title": "Sentry/Guard ActionKind โ€” add Sentry/Unsentry to mc-core with wake-on-vision", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "wireguard", + "updated_at": "2026-05-01", + "blocked_by": [], + "summary": "Gap 1 from p2-53: The design page at `.project/designs/app/src/pages/UnitActions.tsx` proposes Guard (sentry posture, no stat bonus, wakes on enemy entering vision range) as distinct from Fortify (cumulative dig-in, wakes only on adjacency). The shipped game had only `Fortify`/`Unfortify`. Decision: add `ActionKind::Sentry` / `ActionKind::Unsentry` with wake-on-vision predicate in `processor.rs` turn-end phase.\n\nThis is the **canonical template objective** for p2-53. The pattern established here โ€” Rust enum variant + `DisabledReason` + `UnitCapability` field + `legal_actions()` gate + `UnitState` field + turn-phase hook + JSON keyword map + GDScript signal + action handler + tests + objective file โ€” is the exact pattern followed by every downstream child (53f, 53g, 53h, 53i).\n\nMechanical definition:\n- `Sentry`: unit enters sentry posture. No stat bonus (unlike Fortify's cumulative defense). Consumes movement. Mutually exclusive with Fortify and Patrol.\n- `Unsentry`: manual exit from sentry posture. Always enabled while sentrying.\n- **Wake-on-vision**: at turn-end phase (after fauna encounters, before PvP combat โ€” Phase 5a-sentry), any sentrying unit with an enemy unit within 2 hex radius automatically wakes (`is_sentrying โ†’ false`). This is the load-bearing distinction from Fortify." + }, + { + "id": "p2-53a1", + "title": "Sentry bridge state pipe โ€” extend `GdUnitActions` signature to pass `is_sentrying`", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "simulator-infra", + "updated_at": "2026-05-01", + "blocked_by": [], + "summary": "p2-53a shipped the Sentry/Unsentry ActionKind end-to-end EXCEPT the GDExtension bridge: `api-gdext/src/action.rs:58` and `:96` hardcode `is_sentrying: false` with TODO comments. This means the unit panel in Godot cannot show the Unsentry button (it never thinks the unit is sentrying), only the Sentry button, regardless of actual state.\n\nThis sub-objective closes the loop. Tiny scope โ€” one signature extension, one GDScript caller update, one test." + }, + { + "id": "p2-53b", + "title": "Building action registry โ€” `BuildingActionKind`, `building_actions.json`, `GdBuildingActions` bridge", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "simulator-infra", + "updated_at": "2026-05-01", + "blocked_by": [], + "summary": "Buildings have no action registry analogous to the unit pipeline (p1-20). Today, building-level player actions are scattered across `city_screen.gd` (Set Rally button), `world_map.gd` (production-queue clicks), and ad-hoc per-screen controls. There is no `BuildingActionKind` enum, no `building_actions.json` capability map, no `GdBuildingActions` bridge, and the unit panel has no visual analogue for buildings.\n\nThis objective lands the canonical building-action surface โ€” exactly mirroring the unit-action pipeline (p1-20) so the patterns are uniform. After landing, every subsequent building action (Garrison, Repair, Toggle Active, Drill, Auto-Promote, Murder Holes, Gate, Raze, Annex, Stockpile, Overdrive, Research Aid, Invoke Ancestor, Inscribe Hero, Pack & March, Supply Aura, Claim Territory, Light Beacon โ€” see p2-53d) ships as one enum variant + one keyword mapping + one handler + one signal." + }, + { + "id": "p2-53c", + "title": "Rally vocabulary expansion โ€” Hold / Fortify / JoinFormation + two-waypoint Patrol", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "shipwright", + "updated_at": "2026-05-01", + "blocked_by": [], + "summary": "`BuildingRallyPoint.command` (p0-41, `mc-turn/src/game_state.rs`) and `_FORMATION_COMMANDS` (`unit_panel.gd:56`) currently support three orders by name: `defend`, `patrol`, `advance`. The named `\"patrol\"` is a marker string โ€” it does NOT carry the two-waypoint config the unit-side Patrol uses (p1-21 `IssuePatrol`/`EditPatrol`). Treat current rally-Patrol as a stub: `try_spawn_unit` issues a `PatrolOrder` PingPong from spawn-hex to rally-hex, with no way to configure the second waypoint.\n\nThis objective:\n1. Upgrades rally-Patrol to a real two-waypoint config matching unit-side Patrol.\n2. Adds three new rally orders: **Hold** (skip-turn idle, no engagement), **Fortify** (auto-fortify on arrival), **JoinFormation** (skip PatrolOrder issuance; rely on `auto_join` to link into destination hex's formation).\n3. Parks **Reinforce** until an army-identity primitive exists (open question; outside scope)." + }, + { + "id": "p2-53d", + "title": "Building specifics โ€” Garrison, Repair, Toggle Active + 18 archetype-specific actions", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "shipwright", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "Once `p2-53b` lands the building action registry, this objective fills in the per-archetype handlers. Each follows the 12-touchpoint pipeline (BuildingActionKind variant + handler + JSON keyword + bridge + signal + vocab + tests)." + }, + { + "id": "p2-53e", + "title": "Siege handlers (Pack/Deploy/Bombard) + Pillage UI wiring + Embark/Disembark handlers", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "combat-dev", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "Three Rust `ActionKind` variants (`PackSiege`, `DeploySiege`, `Bombard`) are defined in `mc-core/src/action.rs:32` but explicitly annotated *\"no handler wired\"*. They appear in `unit_actions.json` for the `siege` keyword but `action_handlers.rs::invoke()` returns `Err(WrongTerrain)` for all three. `Embark`/`Disembark` for amphibious units are similarly stubbed. `PillageFriendly` has a handler stub but is not in `unit_panel.gd::_KIND_TO_SIGNAL`, so the button never renders.\n\nThis objective ships the full feature for these five existing-but-stubbed actions. They share a structural pattern: state-toggle action that gates other actions (Deployed siege can Bombard, Packed cannot move-and-fire, etc.). After landing, players can actually use catapults / ballistas / cannon crews against walls; pillage is a clickable action; coastal units cross water." + }, + { + "id": "p2-53f", + "title": "Infantry specifics โ€” Shield Wall, Brace, Shove, Rage, Cleave, War Cry", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "combat-dev", + "updated_at": "2026-05-01", + "blocked_by": [ + "p2-53a" + ], + "summary": "Six new `ActionKind` variants gating on archetype keyword (`infantry_line` for Defender, `infantry_shock` for Berserker). Each is a per-action handler + combat hook." + }, + { + "id": "p2-53g", + "title": "Ranged specifics โ€” Volley, Aimed Shot, Fire Arrows", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "combat-dev", + "updated_at": "2026-05-03", + "blocked_by": [ + "p2-53a" + ], + "summary": "Three new `ActionKind` variants gating on `keywords: [\"ranged\"]`:\n\n- **Volley** โ€” area attack: hits target hex's centre + 2 random edge slots; lower per-target damage, more chances to hit\n- **Aimed Shot** โ€” skip-turn that ignores 50% of target's defence on next attack; sets `aimed_shot_pending = true`\n- **Fire Arrows** โ€” toggle posture; ranged attacks ignite tile (uses Fire system from `mc-ecology` if available); persistent damage, smoke obscures vision" + }, + { + "id": "p2-53h", + "title": "Cavalry specifics โ€” Charge, Pursue, Wheel", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "combat-dev", + "updated_at": "2026-05-03", + "blocked_by": [ + "p2-53a" + ], + "summary": "Three new `ActionKind` variants gating on `keywords: [\"cavalry\"]`:\n\n- **Charge** โ€” move 2+ hexes in straight line, then attack: +30% damage; may push target back; cancellable by Brace (p2-53f)\n- **Pursue** โ€” if target dies/routs, advance into its hex without spending movement (passive trigger; manual confirm if multiple options)\n- **Wheel** โ€” reorient to a new edge slot without leaving the hex; useful to dodge first-strike" + }, + { + "id": "p2-53i", + "title": "Support specifics โ€” Engineer, Pioneer, Medic, Scout", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "shipwright", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "Largest specifics child (15 actions across 4 archetypes). Most action effects already have system support somewhere in `mc-turn` / `mc-tech` / `mc-ecology` and just need the action surface." + }, + { + "id": "p2-54", + "title": "Resource visibility โ€” three-axis (visibility/yield_gate/improvement_gate) refactor", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "terraformer", + "updated_at": "2026-05-02", + "blocked_by": [], + "summary": "Replace the binary `revealed_by_tech` field on resources with three orthogonal axes\n(`visibility` / `yield_gate` / `improvement_gate`) plus forward-compatible schema\nextensions for environmental indicator decorations and a per-player observation cache.\n\nMulti-cycle objective. This cycle (p2-54) delivers the schema + data + Rust struct.\nFollow-on cycles handle rendering, AI, and the observation cache.\n\n---" + }, + { + "id": "p2-54a", + "title": "Migrate deposits/*.json to three-axis visibility schema", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "terraformer", + "updated_at": "2026-05-01", + "blocked_by": [], + "summary": "`public/resources/resources.json` has been migrated to the three-axis schema\n(`visibility` / `yield_gate` / `improvement_gate`). However, the 30 individual deposit\nfiles in `public/resources/deposits/*.json` โ€” which are the actual source read by\nGDScript (via `DataLoader`) and the guide-web (via Vite `import.meta.glob`) โ€” still use\n`revealed_by_tech`.\n\nUntil this migration is done, all consumer code falls back to `revealed_by_tech` via\nthe dual-read fallback paths installed in p2-54. The new three-axis field path is\nforward-compatible but inert.\n\nThis is the **blocking precondition** for p2-54b (observation cache), p2-54c (renderer\ndecorations), and p2-54d (AI tech-priority hints) to work correctly.\n\n---" + }, + { + "id": "p2-54b", + "title": "Per-player tile observation cache โ€” flora/fauna last-observed state", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "terraformer", + "updated_at": "2026-05-01", + "blocked_by": [], + "summary": "Per the user's 2026-05-01 design decision: flora and fauna are NOT omniscient-always-visible. Each player remembers what their scout/unit last saw, not the simulator's current state. Since flora evolves (forests grow/regress, swamps drain) and fauna migrates (populations shift, herds move), the displayed map for a player reflects their **last observation**, not ground truth.\n\nThis adds a per-player per-tile observation cache, persisted in saves via the mc-save crate (p2-50)." + }, + { + "id": "p2-54c", + "title": "Renderer reads observations + indicator decorations for tech-gated resources", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "terraformer", + "updated_at": "2026-05-01", + "blocked_by": [], + "summary": "After the three-axis schema (p2-54) and per-player observation cache (p2-54b) land, the renderer must:\n1. Render flora/fauna from the **player's PlayerObservations**, not the simulator's current state\n2. Render `indicator_decorations` on tech-gated resource tiles (rust-red iron-oxide soil for iron, malachite stains for copper, etc.) โ€” these are visual cues that exist before the resource's HUD icon is unlocked\n3. Render the explicit resource icon when the player's tech satisfies `yield_gate`\n\nAffects both the design app's `MapCanvas` (TS/WASM consumer) and Godot's `hex_renderer.gd`." + }, + { + "id": "p2-54d", + "title": "AI tech-priority bias from visible-but-gated luxuries + indicator decorations", + "priority": "p2", + "status": "done", + "scope": "game1", + "owner": "terraformer", + "updated_at": "2026-05-01", + "blocked_by": [], + "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.\n\nThis 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)." + }, { "id": "p2-55", "title": "Civilian Capture / Destroy / Ransom", "priority": "p2", - "status": "pending", + "status": "partial", "scope": "game1", "owner": "", "updated_at": "2026-05-03", "blocked_by": [], - "summary": "Civ-5-inspired capture mechanic for 0-attack civilians (worker, founder, dwarf_founder). Three resolutions โ€” Capture / Destroy / Ransom โ€” driven by a posture system with per-civ default + per-unit override + new-player prompt. Adds `CombatOutcome::{Captured, RansomOffered, Destroyed}` to `mc-combat`, a ransom queue with 3-turn expiry in `mc-turn`, AI scoring across all three options in `mc-ai/tactical/combat_predict`, and UI surfaces (combat preview row, ransom_offers modal, posture dropdowns on diplomacy + unit panels). Engineers, caravan_master, and freepeople capture deferred to follow-ups p2-55a/b/c. Plan: `~/.claude/plans/in-the-game-civilization-elegant-popcorn.md`." + "summary": "" + }, + { + "id": "p2-55d", + "title": "AI ransom accept/refuse hook in mc-turn start-of-turn", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, + { + "id": "p2-55e", + "title": "UnitRansomAccepted / UnitRansomExpired events on TurnResult", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, + { + "id": "p2-56", + "title": "Worker categories (Sustenance/Construction/Wealth) + 5-tier expertise + Master/Grandmaster auras + idle decay", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p2-35" + ], + "summary": "" + }, + { + "id": "p2-56a", + "title": "Worker category types โ€” Sustenance / Construction / Wealth taxonomy", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p2-35" + ], + "summary": "" + }, + { + "id": "p2-56b", + "title": "Expertise tier progression โ€” 5-tier specialist XP ladder", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p2-56a" + ], + "summary": "" + }, + { + "id": "p2-56c", + "title": "Master / Grandmaster auras โ€” adjacent-slot yield propagation", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p2-56b" + ], + "summary": "" + }, + { + "id": "p2-57", + "title": "Production-chain typed resources โ€” raw โ†’ processed pipelines wired into mc-city", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, + { + "id": "p2-57a", + "title": "Typed resource stockpile โ€” raw vs processed taxonomy", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, + { + "id": "p2-57b", + "title": "Building consume/produce edges โ€” stockpile coupled to unit quality", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p2-57a" + ], + "summary": "" + }, + { + "id": "p2-58", + "title": "Ambient encounter rolls per tile moved โ€” fauna_density ร— ecology_tier", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, + { + "id": "p2-59", + "title": "Pioneer escort mechanic โ€” protection rules vs ambient encounters", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p2-58" + ], + "summary": "" + }, + { + "id": "p2-60", + "title": "Weather / observation lens switcher in the Godot HUD", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, + { + "id": "p2-61", + "title": "Bind mc-observation gate_bits to player tech state โ€” recording gates per-field", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, + { + "id": "p2-62", + "title": "Procedural unit/building renderer โ€” alpha-only visual substitute", + "priority": "p2", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" }, { "id": "g2-01", @@ -1803,6 +2217,30 @@ "blocked_by": [], "summary": "`mc-ai::gpu::inner::GpuContext::shared()` (at `src/simulator/crates/mc-ai/src/gpu/inner.rs:189`) picks exactly ONE adapter via `instance.request_adapter(PowerPreference::HighPerformance)`. On multi-GPU hosts this leaves every adapter past #0 idle from our compute perspective.\n\napricot has 2ร— NVIDIA RTX 3090. Right now `batch_simulate_gpu` uses one of them (whichever wgpu selects โ€” typically GPU0). GPU1 sits at 0% compute util from our workload. p0-20 wall-time comparisons are therefore measured against a halved ceiling." }, + { + "id": "g2-11", + "title": "Vertical city floor stack (Game 2) โ€” OOS", + "priority": "p3", + "status": "oos", + "scope": "game2", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "g2-12" + ], + "summary": "" + }, + { + "id": "g2-12", + "title": "Underground layer stack (Game 2) โ€” OOS", + "priority": "p3", + "status": "oos", + "scope": "game2", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, { "id": "g3-01", "title": "Archons โ€” Game 3 (Age of Elves)", @@ -1955,6 +2393,17 @@ "blocked_by": [], "summary": "Persistent trade-route units (caravans, traders) that travel between owned cities OR between own-city and foreign-city, generate per-turn gold/resource yields tied to distance and city-pair characteristics, and can be plundered by enemy units. Distinct from p1-01's instantaneous luxury-for-gold trade modal." }, + { + "id": "p2-55f", + "title": "Read ransom_offer_duration_turns from combat_balance.json", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, { "id": "p3-01", "title": "Courier-gated diplomacy โ€” open borders + shared maps via tech-tiered courier units", @@ -1997,6 +2446,217 @@ "updated_at": "2026-04-28", "blocked_by": [], "summary": "Improvements ship as data files (`public/resources/improvements/*.json`) but the\nsimulation has no per-hex anchor for them. Improvements currently live on\n`PlayerState.city_improvements: Vec>` (per-player / per-city,\nunanchored). The grid's per-tile struct stores terrain only โ€” no improvement\nslot.\n\nThis blocks p3-03 acceptance bullets 4 (severance: pillaging Steam Track at hex\n(c,r) intercepts a courier whose route includes (c,r)), 5 (Hold-Network reroute\nwhen a Steam Track is severed), and the infrastructure-gating half of bullet 2\n(Steam Messenger requires Steam Track tiles on its route, Resonance\nTelegrapher requires Resonance Wire tiles).\n\nThis is also a foundational gap that will block other Game-1-stretch features\nbeyond couriers (tile-improvement pillaging, road network bonuses,\nfortification ZOC, defensive towers)." + }, + { + "id": "p3-05a", + "title": "Civic state wrapper โ€” typed CivicState added to PlayerState", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, + { + "id": "p3-05b", + "title": "Authority axis civics catalog", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p3-05a" + ], + "summary": "" + }, + { + "id": "p3-05c", + "title": "Labor axis civics catalog", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p3-05a" + ], + "summary": "" + }, + { + "id": "p3-05d", + "title": "Economy axis civics catalog", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p3-05a" + ], + "summary": "" + }, + { + "id": "p3-05e", + "title": "Civic modifier propagation โ€” apply civic effects to per-city yields", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p3-05b", + "p3-05c", + "p3-05d" + ], + "summary": "" + }, + { + "id": "p3-06", + "title": "Civic anarchy โ€” 5-turn anarchy on axis switch", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p3-05a" + ], + "summary": "" + }, + { + "id": "p3-07a", + "title": "CV-of-wealth + Authority amplifier โ†’ inequality stat", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p3-05b" + ], + "summary": "" + }, + { + "id": "p3-07b", + "title": "Four damage channels โ€” Land/Water/Magic/Air emission from inequality", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p3-07a" + ], + "summary": "" + }, + { + "id": "p3-10a", + "title": "Lair assault mode โ€” enter-and-clear", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p0-17" + ], + "summary": "" + }, + { + "id": "p3-10b", + "title": "Lair siege mode โ€” multi-turn pressure from adjacent", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p3-10a" + ], + "summary": "" + }, + { + "id": "p3-10c", + "title": "Lair raid mode โ€” grab-and-exit", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p3-10a" + ], + "summary": "" + }, + { + "id": "p3-11", + "title": "Pioneer & Engineer action-point pool", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, + { + "id": "p3-12", + "title": "Fauna combat stat derivation โ€” regenerate from traits", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, + { + "id": "p3-13a", + "title": "Extend meteorological events โ€” drought, flood, dust_storm", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [ + "p0-36" + ], + "summary": "" + }, + { + "id": "p3-13b", + "title": "Geological events โ€” earthquake, volcanic_eruption, landslide", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, + { + "id": "p3-13c", + "title": "Biological events โ€” plague, bloom, migration_pulse", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" + }, + { + "id": "p3-13d", + "title": "Anomalous events โ€” aurora, fog_bank, thermal_anomaly", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "unassigned", + "updated_at": "2026-05-03", + "blocked_by": [], + "summary": "" } ], "blocked": [ @@ -2005,35 +2665,163 @@ "blockedBy": [ "p1-47" ] + }, + { + "id": "p2-53f", + "blockedBy": [ + "p2-53a" + ] + }, + { + "id": "p2-53g", + "blockedBy": [ + "p2-53a" + ] + }, + { + "id": "p2-53h", + "blockedBy": [ + "p2-53a" + ] + }, + { + "id": "p2-56", + "blockedBy": [ + "p2-35" + ] + }, + { + "id": "p2-56a", + "blockedBy": [ + "p2-35" + ] + }, + { + "id": "p2-56b", + "blockedBy": [ + "p2-56a" + ] + }, + { + "id": "p2-56c", + "blockedBy": [ + "p2-56b" + ] + }, + { + "id": "p2-57b", + "blockedBy": [ + "p2-57a" + ] + }, + { + "id": "p2-59", + "blockedBy": [ + "p2-58" + ] + }, + { + "id": "g2-11", + "blockedBy": [ + "g2-12" + ] + }, + { + "id": "p3-05b", + "blockedBy": [ + "p3-05a" + ] + }, + { + "id": "p3-05c", + "blockedBy": [ + "p3-05a" + ] + }, + { + "id": "p3-05d", + "blockedBy": [ + "p3-05a" + ] + }, + { + "id": "p3-05e", + "blockedBy": [ + "p3-05b", + "p3-05c", + "p3-05d" + ] + }, + { + "id": "p3-06", + "blockedBy": [ + "p3-05a" + ] + }, + { + "id": "p3-07a", + "blockedBy": [ + "p3-05b" + ] + }, + { + "id": "p3-07b", + "blockedBy": [ + "p3-07a" + ] + }, + { + "id": "p3-10a", + "blockedBy": [ + "p0-17" + ] + }, + { + "id": "p3-10b", + "blockedBy": [ + "p3-10a" + ] + }, + { + "id": "p3-10c", + "blockedBy": [ + "p3-10a" + ] + }, + { + "id": "p3-13a", + "blockedBy": [ + "p0-36" + ] } ], "remaining_by_lead": [ { - "owner": "terraformer", - "remaining": 9 - }, - { - "owner": "warcouncil", - "remaining": 7 + "owner": "unassigned", + "remaining": 30 }, { "owner": "asset-sprite", "remaining": 6 }, + { + "owner": "warcouncil", + "remaining": 6 + }, { "owner": "shipwright", "remaining": 5 }, { - "owner": "asset-audio", - "remaining": 1 + "owner": "simulator-infra", + "remaining": 3 }, { "owner": "combat-dev", - "remaining": 1 + "remaining": 2 }, { - "owner": "simulator-infra", + "owner": "asset-audio", "remaining": 1 }, { diff --git a/.project/objectives/p1-55-tech-culture-domain-propagation.md b/.project/objectives/p1-55-tech-culture-domain-propagation.md index 53f1c595..39650774 100644 --- a/.project/objectives/p1-55-tech-culture-domain-propagation.md +++ b/.project/objectives/p1-55-tech-culture-domain-propagation.md @@ -6,7 +6,9 @@ status: in_progress scope: game1 owner: simulator-infra updated_at: 2026-05-04 -evidence: [] +evidence: + - "src/simulator/crates/mc-core/src/tech.rs" + - "src/simulator/crates/mc-tech/src/web.rs" assigned_by: simulator-infra --- ## Summary @@ -30,10 +32,25 @@ node. ## Acceptance -- [ ] **Rust** โ€” `mc-tech::Tech` carries `domain: String` deserialised - from JSON. Schema test in `mc-data` asserts every authored tech has - a non-empty domain belonging to the 10-value enum. `cargo test -p - mc-tech -p mc-culture -p mc-data` passes. +- [x] **Rust** โ€” `mc-tech::TechDefinition` now carries + `domain: Option` (typed enum, not `String`); `TechDomain` + lives in `mc-core/src/tech.rs:20` with all 10 canonical variants and + serde round-trips PascalCase. Schema test + (`src/simulator/crates/mc-tech/src/web.rs:399` โ€” + `all_authored_techs_have_valid_domain`) confirms every authored tech + has `Some(_)` after deserialisation; serde itself rejects unknown + strings, so enum-membership and non-empty are enforced together. + Determinism aid `TechWeb::techs_by_domain_map() -> BTreeMap<...>` + added at `web.rs:248`. `cargo test -p mc-core -p mc-tech` green + (12 + 28 tests; including new `domain_field_round_trips_via_json`, + `domain_field_defaults_to_none_when_absent`, + `invalid_domain_string_is_rejected`); `cargo test -p mc-culture + -p mc-turn` green; `cargo check --workspace` green. `mc-data` crate + does not exist in this workspace; the schema test was placed in + `mc-tech` where the deserialisation lives. (mc-culture re-exports + `TechDefinition` as `CultureNode`; the enum field defaults to `None` + for culture data, matching the design note that culture uses `pillar` + as its tab axis.) - [ ] **GDExtension** โ€” `GdTechWeb` exposes `domains() -> PackedStringArray` and `techs_by_domain(domain) -> Array`. diff --git a/.project/objectives/p1-58-ecology-cognitive-system.md b/.project/objectives/p1-58-ecology-cognitive-system.md index 95f09f9d..c8320fe2 100644 --- a/.project/objectives/p1-58-ecology-cognitive-system.md +++ b/.project/objectives/p1-58-ecology-cognitive-system.md @@ -2,11 +2,19 @@ id: p1-58 title: "Ecology cognition: terrain affinity, food web, grudge memory, apex tier-10 fauna/flora" priority: p1 -status: in_progress +status: partial scope: game1 owner: simulator-infra updated_at: 2026-05-04 -evidence: [] +evidence: + - "src/simulator/crates/mc-ecology/src/species.rs:107-288 โ€” apex profile types CombatProfile/CognitiveProfile/BreathWeapon/PackBehavior/LootTable/Devastation wired into Species" + - "src/simulator/crates/mc-ecology/src/species.rs:651-665 โ€” RawSpeciesJson reads combat_profile/cognitive_profile/terrain_affinity/loot_table/devastation/food_consumption_per_turn" + - "src/simulator/crates/mc-ecology/src/species.rs:1444-1483 โ€” test_all_authored_species_deserialize: 592 fauna files parse with no panic" + - "src/simulator/crates/mc-ecology/src/species.rs:1487-1509 โ€” test_ancient_red_dragon_profile_fields validates apex profile contents" + - "src/simulator/crates/mc-ecology/src/species.rs:1129-1135 โ€” true_dragon lineage exempt from T7 cap" + - "src/simulator/crates/mc-flora/src/generation.rs:340-369 โ€” AuthoredSpeciesFile accepts apex flora (optional traits/biomes)" + - "src/simulator/crates/mc-flora/src/generation.rs:779-825 โ€” all_authored_flora_species_deserialize: 153 flora files parse, โ‰ฅ4 apex" + - "public/games/age-of-dwarves/docs/FAUNA_COMBAT_STATS.md:143-176 โ€” apex profile schema documented" assigned_by: simulator-infra --- ## Summary @@ -76,9 +84,15 @@ domain, trophic_level): ## Acceptance โ€” Rust wire-up -- [ ] `mc-ecology::Species` (or shared parent type) deserializes the new +- [โœ“] `mc-ecology::Species` (or shared parent type) deserializes the new fields: `combat_profile`, `cognitive_profile`, `terrain_affinity`, `loot_table`, `devastation`, `prey` (already deserialized). + Fauna: `species.rs:651-665` (RawSpeciesJson) + `species.rs:1444-1509` tests + (592 fauna parse; ancient_red_dragon profile asserted). Flora: apex tier-10 + parses without panic via `mc-flora::generation::AuthoredSpeciesFile` defaults + (`generation.rs:340-369`); test `all_authored_flora_species_deserialize` + (`generation.rs:779-825`) walks 153 flora files, โ‰ฅ4 apex flora deserialise. + `cargo test -p mc-ecology -p mc-core` green; `cargo check --workspace` green. - [ ] `mc-ecology::dynamics`: when a unit attacks a creature with `cognitive_profile.intelligence >= 3` and survives, register a grudge entry on the creature: `{ player_id, turn_recorded, expires_turn: @@ -213,4 +227,7 @@ domain, trophic_level): - Dependencies: all Rust bullets. - Acceptance gate: `godot --headless --test ...` green; screenshot showing populated tile inspector + grudge badge approved per `phase-gate-protocol.md`. -Bullets remaining: 9. +Bullets remaining: 8 (deserialise gate โœ“ as of 2026-05-04). Remaining: grudge +dynamics, devastation in combat, Lotka-Volterra prey shifts, food drain, generation +refactor (terrain_affinity-indexed pool), loot rolling, Godot UI bridge, +GUT tests + proof screenshot. diff --git a/public/games/age-of-dwarves/data/objectives.json b/public/games/age-of-dwarves/data/objectives.json index ee971b75..29d777ac 100644 --- a/public/games/age-of-dwarves/data/objectives.json +++ b/public/games/age-of-dwarves/data/objectives.json @@ -1,12 +1,12 @@ { - "generated_at": "2026-05-04T03:17:51Z", + "generated_at": "2026-05-04T04:41:32Z", "totals": { - "partial": 17, - "in_progress": 4, + "in_progress": 3, "missing": 11, - "stub": 35, - "done": 145, + "partial": 18, "oos": 28, + "done": 145, + "stub": 35, "total": 240 }, "objectives": [ @@ -1054,7 +1054,7 @@ "id": "p1-58", "title": "\"Ecology cognition: terrain affinity, food web, grudge memory, apex tier-10 fauna/flora\"", "priority": "p1", - "status": "in_progress", + "status": "partial", "scope": "game1", "owner": "simulator-infra", "updated_at": "2026-05-04",