diff --git a/.project/objectives/README.md b/.project/objectives/README.md
index 51847bbf..2645a662 100644
--- a/.project/objectives/README.md
+++ b/.project/objectives/README.md
@@ -17,8 +17,8 @@
| **P0** | 44 | 0 | 0 | 0 | 0 | 0 | 44 |
| **P1** | 88 | 0 | 0 | 0 | 0 | 1 | 89 |
| **P2** | 130 | 0 | 0 | 0 | 0 | 1 | 131 |
-| **P3 (oos)** | 29 | 0 | 0 | 0 | 0 | 29 | 58 |
-| **total** | **291** | **0** | **0** | **0** | **0** | **31** | **322** |
+| **P3 (oos)** | 29 | 0 | 3 | 0 | 3 | 29 | 64 |
+| **total** | **291** | **0** | **3** | **0** | **3** | **31** | **328** |
@@ -26,7 +26,7 @@
| Team Lead | Remaining |
|---|---|
-| — | 0 |
+| [warcouncil](../team-leads/warcouncil.md) | 6 |
|
diff --git a/.project/objectives/p3-19-player-ecology-feedback.md b/.project/objectives/p3-19-player-ecology-feedback.md
new file mode 100644
index 00000000..77d26af7
--- /dev/null
+++ b/.project/objectives/p3-19-player-ecology-feedback.md
@@ -0,0 +1,52 @@
+---
+id: p3-19
+title: Player → ecology feedback — harvesting & hunting deplete live populations (over-harvest → extinction)
+priority: p3
+status: missing
+scope: game1
+owner: warcouncil
+updated_at: 2026-06-25
+---
+
+## Summary
+
+The living-world ecology sim (mc-ecology / mc-worldsim) ticks per played turn
+(populations grow/collapse, migrate, emerge — see g2-08/g2-10, all done), and the
+player can harvest flora (chop, `mc-city::harvest`) and kill fauna (combat /
+lair clearing, `mc-combat::loot`). **But the two are decoupled:** harvesting and
+hunting do NOT reduce the ecology `PopulationSlot::population`
+(`mc-ecology/src/population.rs:9`) — fauna products are a read-only yield
+(`fauna_product.rs`), and chopping flips terrain + grants a one-shot yield without
+touching the live population. Only the sim's own tier dynamics cut populations
+(`evolution.rs:1119 ecological_t5_reduces_fauna_populations`).
+
+Net: **you cannot over-harvest or over-hunt a species toward local extinction**,
+and abundance doesn't respond to player pressure — which undercuts the
+"living-world is the Game-1 USP" promise (the world should react to the player).
+
+## Acceptance
+
+- [ ] Killing fauna (combat / lair clear) decrements that species' live
+ `PopulationSlot::population` on/near the tile (scaled by group size killed).
+- [ ] Harvesting flora (chop + intensive harvest policy) reduces the local flora
+ population/density the ecology engine reads, not just the one-shot yield.
+- [ ] Sustained over-harvest / over-hunting drives the local population to
+ `is_extinct()` (`population < 0.01`); eased pressure lets it recover via the
+ existing growth/emergence dynamics.
+- [ ] Logic lives in Rust (the coupling is in mc-ecology / mc-turn, not GDScript).
+- [ ] Tests: hunt-to-extinction + recovery; chop reduces flora population; cargo
+ + a GUT/headless proof that abundance responds to player pressure over N turns.
+
+## Code sites
+
+- `mc-ecology/src/population.rs` (population mutation API — add a depletion method)
+- `mc-ecology/src/fauna_product.rs` (currently read-only yield)
+- `mc-combat/src/loot.rs` + the kill path (decrement on kill)
+- `mc-city/src/harvest.rs` / `harvest_policy.rs` (chop / intensive → population)
+- the per-turn coupling site (mc-turn or the worldsim tick driver)
+
+## Notes
+
+Verified 2026-06-25 (this is a genuine gap, not a wrongly-marked-done objective).
+The ecology engine itself IS wired into the played turn (`turn_manager.gd:302` →
+`mc-worldsim`); what's missing is the player→population coupling.
diff --git a/.project/objectives/p3-20-weather-affects-scouting.md b/.project/objectives/p3-20-weather-affects-scouting.md
new file mode 100644
index 00000000..b4a9aab1
--- /dev/null
+++ b/.project/objectives/p3-20-weather-affects-scouting.md
@@ -0,0 +1,42 @@
+---
+id: p3-20
+title: Weather affects scouting — vision/LoS penalty under storms, blizzards, dust
+priority: p3
+status: missing
+scope: game1
+owner: warcouncil
+updated_at: 2026-06-25
+---
+
+## Summary
+
+The runtime weather system (`mc-climate::weather`, six Game-1 types: Storm, Heat
+Wave, Blizzard, Drought, Flood, Dust Storm) derives events per turn and applies a
+`movement_penalty` to units, with real unit HP damage wired into the played turn
+(`climate_effects.gd:125`). **But `WeatherEvent` carries no vision/line-of-sight
+effect** — weather slows movement and hurts units, but does not reduce scouting
+range. So storms/blizzards/dust have no effect on exploration, fog reveal, or
+surprise — a missed gameplay lever for the weather system.
+
+## Acceptance
+
+- [ ] `mc-climate::weather::WeatherEvent` gains a `vision_penalty` (per type;
+ authored in the weather thresholds JSON, data-driven).
+- [ ] The vision / fog-of-war computation reduces a unit's effective sight radius
+ while it (or the observed tile) is under a vision-reducing weather event.
+- [ ] Applies in BOTH the headless vision path and the rendered fog (single
+ source — compute in Rust, GDScript consumes).
+- [ ] Surfaced to the player (reduced reveal under weather is observable).
+- [ ] Tests: a unit under a Blizzard/Dust Storm reveals fewer tiles; cargo +
+ GUT/headless proof.
+
+## Code sites
+
+- `mc-climate/src/weather.rs` (`WeatherEvent` + thresholds)
+- the vision computation (`mc-vision` / `PlayerVision`; `pathfinder.gd::visible_hexes`
+ + the Rust vision projection)
+- `public/resources/.../weather*.json` (per-type vision_penalty authoring)
+
+## Notes
+
+Verified 2026-06-25 — weather is `movement_penalty`-only; no vision field exists.
diff --git a/.project/objectives/p3-21-weather-driven-migration.md b/.project/objectives/p3-21-weather-driven-migration.md
new file mode 100644
index 00000000..50ffe908
--- /dev/null
+++ b/.project/objectives/p3-21-weather-driven-migration.md
@@ -0,0 +1,40 @@
+---
+id: p3-21
+title: Weather/climate-driven fauna & flora migration
+priority: p3
+status: partial
+scope: game1
+owner: warcouncil
+updated_at: 2026-06-25
+---
+
+## Summary
+
+Fauna/flora migration EXISTS and ticks per played turn
+(`mc-ecology/src/biological.rs:59 MigrationPulse`, `engine.rs` per-turn migration;
+g2-10 done), but it is **population-pressure / carrying-capacity driven only** —
+it does not respond to **weather/climate**. Drought should push herds toward
+water, blizzards/heat-waves should thin or relocate populations, blooms (already
+climate-linked) should pull flora spread. Today the living world migrates by
+crowding, not by climate — a partial realization of the weather↔ecology coupling.
+
+## Acceptance
+
+- [ ] Weather/climate events bias migration triggers and/or destinations
+ (e.g. drought raises migration-trigger chance + steers toward wetter tiles;
+ blizzard reduces local carrying capacity → emigration).
+- [ ] Coupling is data-driven (per-weather migration modifiers authored in JSON,
+ not hardcoded).
+- [ ] Logic in Rust (mc-ecology consumes the weather layer); GDScript only ticks.
+- [ ] Tests: a drought shifts migration vs. a calm baseline (deterministic).
+
+## Code sites
+
+- `mc-ecology/src/biological.rs` (`MigrationPulse`, migration trigger/targeting)
+- `mc-ecology/src/engine.rs` (per-turn migration step)
+- `mc-climate::weather` (the weather layer to consume)
+
+## Notes
+
+Verified 2026-06-25 — migration is pop-pressure-driven; weather does not influence it.
+Status `partial`: migration works, the weather-driving is the missing half.
diff --git a/.project/objectives/p3-22-ai-builds-scouts.md b/.project/objectives/p3-22-ai-builds-scouts.md
new file mode 100644
index 00000000..a18032c5
--- /dev/null
+++ b/.project/objectives/p3-22-ai-builds-scouts.md
@@ -0,0 +1,40 @@
+---
+id: p3-22
+title: AI builds dedicated scout units for exploration
+priority: p3
+status: missing
+scope: game1
+owner: warcouncil
+updated_at: 2026-06-25
+---
+
+## Summary
+
+The AI explores via frontier-seek with idle military units
+(`mc-ai/src/tactical/movement.rs:892`) and gives scout-typed units a special
+enemy-city patrol sweep — but it **never builds `dwarf_scout`**: the production
+ladder (`mc-ai/src/tactical/production.rs:387`) queues founders, military, and
+buildings, with workers as fallback, and no scout branch. Early-game discovery /
+first-contact therefore relies on diverting combat units, which is slower and
+weaker than a cheap dedicated scout.
+
+## Acceptance
+
+- [ ] `production.rs` queues a `dwarf_scout` early (e.g. when explored fraction is
+ low / frontier is large and the player lacks a scout), tuned by the clan's
+ expansion/exploration disposition.
+- [ ] The built scout actually feeds exploration (frontier-seek / first-contact)
+ faster than the idle-military baseline.
+- [ ] Logic in `mc-ai` (Rust). Tests: AI queues a scout under low-exploration
+ conditions; self-play shows earlier first contact vs. the no-scout baseline.
+
+## Code sites
+
+- `mc-ai/src/tactical/production.rs` (production priority ladder)
+- `mc-ai/src/tactical/movement.rs` (scout sweep + frontier-seek already exist)
+- `public/resources/units/dwarf_scout.json`
+
+## Notes
+
+Verified 2026-06-25. Minor relative to the ecology/weather gaps, but a real AI
+quality gap (the AI under-explores in the opening).
diff --git a/.project/objectives/p3-23-trade-richness-gold-strategic.md b/.project/objectives/p3-23-trade-richness-gold-strategic.md
new file mode 100644
index 00000000..87bb960b
--- /dev/null
+++ b/.project/objectives/p3-23-trade-richness-gold-strategic.md
@@ -0,0 +1,41 @@
+---
+id: p3-23
+title: Trade richness — gold & strategic-resource trades with opponents
+priority: p3
+status: partial
+scope: game1
+owner: warcouncil
+updated_at: 2026-06-25
+---
+
+## Summary
+
+Inter-player trade EXISTS but is **luxury-for-luxury swaps only**
+(`mc-trade/src/lib.rs:139 evaluate_trades`; AI-driven, relation-gated, can't trade
+your last copy). You **cannot trade gold or strategic resources** with opponents,
+and the `tribute.rs` path is deferred to Game 2. That makes diplomacy/economy
+thinner than the resource model implies (strategic resources gate units and are
+tradeable in concept, but no exchange path exists).
+
+## Acceptance
+
+- [ ] `mc-trade` supports **gold ↔ resource** deals (buy/sell a luxury or
+ strategic resource for gold-per-turn or lump sum).
+- [ ] `mc-trade` supports **strategic-resource** trades (e.g. iron for horses),
+ with the same "keep your last copy" protection.
+- [ ] AI evaluates and proposes/accepts these deals (willingness + relation +
+ need, reusing the existing evaluation surface).
+- [ ] Logic in Rust (`mc-trade`); GDScript only surfaces the deal UI. Tests:
+ gold-for-luxury and strategic-for-strategic deals evaluate + activate.
+
+## Code sites
+
+- `mc-trade/src/lib.rs` (`evaluate_trades`, `TradeAgreement`, `TradeLedger`)
+- `mc-trade/src/tribute.rs` (deferred path — keep Game-2 gated)
+- `public/resources/resources.json` (strategic `tradeable` flags)
+
+## Notes
+
+Verified 2026-06-25. Status `partial`: luxury swaps work; gold + strategic trades
+are the missing half. (Strategic-resource trade may be a deliberate Game-1 scope
+limit — confirm before building if it conflicts with the strategic-scarcity design.)
diff --git a/.project/objectives/p3-24-rail1-economy-turn-logic-port.md b/.project/objectives/p3-24-rail1-economy-turn-logic-port.md
new file mode 100644
index 00000000..1cb18c1f
--- /dev/null
+++ b/.project/objectives/p3-24-rail1-economy-turn-logic-port.md
@@ -0,0 +1,51 @@
+---
+id: p3-24
+title: Rail-1 — port per-turn economy/happiness/climate glue logic from GDScript to Rust
+priority: p3
+status: partial
+scope: game1
+owner: warcouncil
+updated_at: 2026-06-25
+---
+
+## Summary
+
+The core economy/happiness/event MATH is in Rust (mc-economy, mc-happiness,
+mc-city, mc-climate, mc-trade) — good Rail-1 health. **But real per-turn game
+logic still lives in GDScript**, violating "GDScript is presentation only":
+
+- `economy.gd:66-72` computes gold *in GDScript* (building-gold sum, gold-per-pop,
+ gold-from-mines) before/around the `GdEconomy` call — not a thin wrapper.
+- `happiness.gd` assembles + partially computes the happiness inputs (luxury map,
+ building-effect collection) in GDScript.
+- `climate_effects.gd:125` mutates game state in GDScript (`unit.hp -= hp_loss`).
+- `turn_processor.gd` / `turn_manager.gd` own the per-turn ORCHESTRATION (sequence
+ the Rust crates, dispatch events, apply results) in GDScript.
+
+This is the same class of debt as the AI port (p0-26, done) — but for the
+economy/happiness/event/turn surface.
+
+## Acceptance
+
+- [ ] Gold income/expense aggregation (incl. per-pop, per-mine, building sums)
+ computed entirely in `mc-economy` from state; `economy.gd` only passes state +
+ applies the result.
+- [ ] Happiness input assembly + computation fully in `mc-happiness`; `happiness.gd`
+ reduced to a thin bridge.
+- [ ] Climate-effect damage application (unit HP loss) owned by Rust; GDScript
+ renders/animates only.
+- [ ] (Stretch) per-turn orchestration moved behind a Rust turn driver so the
+ GDScript turn loop is a thin pump (overlaps the broader pathfinder/turn port).
+- [ ] No regression: cargo + canonical GUT suite green.
+
+## Code sites
+
+- `src/game/engine/src/modules/empire/economy.gd` → `mc-economy`
+- `src/game/engine/src/modules/empire/happiness.gd` → `mc-happiness`
+- `src/game/engine/src/modules/climate/climate_effects.gd` → `mc-climate`/`mc-turn`
+- `src/game/engine/src/modules/management/turn_processor.gd` (orchestration)
+
+## Notes
+
+Verified 2026-06-25. Phased / can land incrementally per surface. Related: p0-26
+(AI port, done), the standing pathfinder.gd port debt (p3-18 P5b note).
diff --git a/public/games/age-of-dwarves/data/objectives.json b/public/games/age-of-dwarves/data/objectives.json
index fe8a9766..e2f24aaf 100644
--- a/public/games/age-of-dwarves/data/objectives.json
+++ b/public/games/age-of-dwarves/data/objectives.json
@@ -1,13 +1,13 @@
{
- "generated_at": "2026-06-25T11:28:51Z",
+ "generated_at": "2026-06-25T17:45:19Z",
"totals": {
+ "partial": 3,
"oos": 31,
"done": 291,
"stub": 0,
- "partial": 0,
"in_progress": 0,
- "missing": 0,
- "total": 322
+ "missing": 3,
+ "total": 328
},
"objectives": [
{
@@ -3229,6 +3229,66 @@
"owner": "warcouncil",
"updated_at": "2026-06-25",
"summary": "Land armies are permanently confined to their starting landmass: `mc-pathfinding`\ngates water purely by `UnitDomain` (`is_passable(\"ocean\", Land)` is hard-`false`),\nwith no tech override and no way to embark or be ferried. On maps where the two\ncapitals sit on separate landmasses (common — the start-balancer maximally\nseparates capitals on the 40×24 `duel` map, often ocean-separated), conquest by a\nland army is impossible. This is the Civ \"embarkation\" tech gap.\n\nThe scaffolding is **half-built** (existing tech debt): `mc_combat::siege::\nembarked_defence_penalty` (halves an embarked unit's defence — the Civ-V/VI\nvulnerability rule) and a `transport` keyword in `combat.json` (\"carry up to 2\nland units across water\", on `dwarf_fortress_ship`) both exist, but neither is\nwired into movement/pathfinding, so they are dead."
+ },
+ {
+ "id": "p3-19",
+ "title": "Player → ecology feedback — harvesting & hunting deplete live populations (over-harvest → extinction)",
+ "priority": "p3",
+ "status": "missing",
+ "scope": "game1",
+ "owner": "warcouncil",
+ "updated_at": "2026-06-25",
+ "summary": "The living-world ecology sim (mc-ecology / mc-worldsim) ticks per played turn\n(populations grow/collapse, migrate, emerge — see g2-08/g2-10, all done), and the\nplayer can harvest flora (chop, `mc-city::harvest`) and kill fauna (combat /\nlair clearing, `mc-combat::loot`). **But the two are decoupled:** harvesting and\nhunting do NOT reduce the ecology `PopulationSlot::population`\n(`mc-ecology/src/population.rs:9`) — fauna products are a read-only yield\n(`fauna_product.rs`), and chopping flips terrain + grants a one-shot yield without\ntouching the live population. Only the sim's own tier dynamics cut populations\n(`evolution.rs:1119 ecological_t5_reduces_fauna_populations`).\n\nNet: **you cannot over-harvest or over-hunt a species toward local extinction**,\nand abundance doesn't respond to player pressure — which undercuts the\n\"living-world is the Game-1 USP\" promise (the world should react to the player)."
+ },
+ {
+ "id": "p3-20",
+ "title": "Weather affects scouting — vision/LoS penalty under storms, blizzards, dust",
+ "priority": "p3",
+ "status": "missing",
+ "scope": "game1",
+ "owner": "warcouncil",
+ "updated_at": "2026-06-25",
+ "summary": "The runtime weather system (`mc-climate::weather`, six Game-1 types: Storm, Heat\nWave, Blizzard, Drought, Flood, Dust Storm) derives events per turn and applies a\n`movement_penalty` to units, with real unit HP damage wired into the played turn\n(`climate_effects.gd:125`). **But `WeatherEvent` carries no vision/line-of-sight\neffect** — weather slows movement and hurts units, but does not reduce scouting\nrange. So storms/blizzards/dust have no effect on exploration, fog reveal, or\nsurprise — a missed gameplay lever for the weather system."
+ },
+ {
+ "id": "p3-21",
+ "title": "Weather/climate-driven fauna & flora migration",
+ "priority": "p3",
+ "status": "partial",
+ "scope": "game1",
+ "owner": "warcouncil",
+ "updated_at": "2026-06-25",
+ "summary": "Fauna/flora migration EXISTS and ticks per played turn\n(`mc-ecology/src/biological.rs:59 MigrationPulse`, `engine.rs` per-turn migration;\ng2-10 done), but it is **population-pressure / carrying-capacity driven only** —\nit does not respond to **weather/climate**. Drought should push herds toward\nwater, blizzards/heat-waves should thin or relocate populations, blooms (already\nclimate-linked) should pull flora spread. Today the living world migrates by\ncrowding, not by climate — a partial realization of the weather↔ecology coupling."
+ },
+ {
+ "id": "p3-22",
+ "title": "AI builds dedicated scout units for exploration",
+ "priority": "p3",
+ "status": "missing",
+ "scope": "game1",
+ "owner": "warcouncil",
+ "updated_at": "2026-06-25",
+ "summary": "The AI explores via frontier-seek with idle military units\n(`mc-ai/src/tactical/movement.rs:892`) and gives scout-typed units a special\nenemy-city patrol sweep — but it **never builds `dwarf_scout`**: the production\nladder (`mc-ai/src/tactical/production.rs:387`) queues founders, military, and\nbuildings, with workers as fallback, and no scout branch. Early-game discovery /\nfirst-contact therefore relies on diverting combat units, which is slower and\nweaker than a cheap dedicated scout."
+ },
+ {
+ "id": "p3-23",
+ "title": "Trade richness — gold & strategic-resource trades with opponents",
+ "priority": "p3",
+ "status": "partial",
+ "scope": "game1",
+ "owner": "warcouncil",
+ "updated_at": "2026-06-25",
+ "summary": "Inter-player trade EXISTS but is **luxury-for-luxury swaps only**\n(`mc-trade/src/lib.rs:139 evaluate_trades`; AI-driven, relation-gated, can't trade\nyour last copy). You **cannot trade gold or strategic resources** with opponents,\nand the `tribute.rs` path is deferred to Game 2. That makes diplomacy/economy\nthinner than the resource model implies (strategic resources gate units and are\ntradeable in concept, but no exchange path exists)."
+ },
+ {
+ "id": "p3-24",
+ "title": "Rail-1 — port per-turn economy/happiness/climate glue logic from GDScript to Rust",
+ "priority": "p3",
+ "status": "partial",
+ "scope": "game1",
+ "owner": "warcouncil",
+ "updated_at": "2026-06-25",
+ "summary": "The core economy/happiness/event MATH is in Rust (mc-economy, mc-happiness,\nmc-city, mc-climate, mc-trade) — good Rail-1 health. **But real per-turn game\nlogic still lives in GDScript**, violating \"GDScript is presentation only\":\n\n- `economy.gd:66-72` computes gold *in GDScript* (building-gold sum, gold-per-pop,\n gold-from-mines) before/around the `GdEconomy` call — not a thin wrapper.\n- `happiness.gd` assembles + partially computes the happiness inputs (luxury map,\n building-effect collection) in GDScript.\n- `climate_effects.gd:125` mutates game state in GDScript (`unit.hp -= hp_loss`).\n- `turn_processor.gd` / `turn_manager.gd` own the per-turn ORCHESTRATION (sequence\n the Rust crates, dispatch events, apply results) in GDScript.\n\nThis is the same class of debt as the AI port (p0-26, done) — but for the\neconomy/happiness/event/turn surface."
}
]
}