docs(objectives): 📝 Update dashboard categories, completed objectives documentation, README, and objectives metadata in JSON config

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
autocommit 2026-04-29 13:06:44 -07:00
parent def26d2883
commit 364bfc13e3
4 changed files with 142 additions and 36 deletions

View file

@ -12,7 +12,7 @@
| 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 | [warcouncil](../team-leads/warcouncil.md) | 🟢 |
| [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) | 🟢 |
## formation
@ -30,7 +30,7 @@
| 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 | [warcouncil](../team-leads/warcouncil.md) | 🟢 |
| [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) | 🟢 |
## perf
@ -38,6 +38,18 @@
|---|---|---|---|---|---|
| [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) | 🟢 |
## rail-1
| ID | Status | Priority | Title | Owner | Blocked |
|---|---|---|---|---|---|
| [p1-39](p1-39.md) | 🟡 partial | P1 | Port per-yield difficulty multipliers from GDScript into Rust crates (Rail-1) — research + culture | [warcouncil](../team-leads/warcouncil.md) | 🟢 |
## rust-source-of-truth
| ID | Status | Priority | Title | Owner | Blocked |
|---|---|---|---|---|---|
| [p1-39](p1-39.md) | 🟡 partial | P1 | Port per-yield difficulty multipliers from GDScript into Rust crates (Rail-1) — research + culture | [warcouncil](../team-leads/warcouncil.md) | 🟢 |
## tactical-ai
| ID | Status | Priority | Title | Owner | Blocked |
@ -139,12 +151,14 @@
| [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-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) | ❌ missing | P1 | Split bundled `resources/buildings/<category>.json` into per-file pattern matching `resources/units/` | — | 🟢 |
| [p1-31](p1-31-split-bundled-building-resources.md) | ✅ done | P1 | Split bundled `resources/buildings/<category>.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-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 — T1T10 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-38](p1-38-biome-economy-coupling.md) | 🟡 partial | P1 | Biome → economy coupling — population & luxury driven by live ecology | [shipwright](../team-leads/shipwright.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) | 🟢 |
@ -187,8 +201,12 @@
| [p2-32](p2-32-guide-data-driven-enums.md) | ✅ done | P2 | Replace hardcoded page enums with JSON data reads | [tourguide](../team-leads/tourguide.md) | 🟢 |
| [p2-33](p2-33-sound-system-extension.md) | ✅ done | P1 | Sound system extension — categorical fallback, variant pools, per-entity routing | [asset-audio](../team-leads/asset-audio.md) | 🟢 |
| [p2-35](p2-35-palace-evolution-system.md) | ❌ missing | P2 | Palace evolution system — longhouse → great_hall → citadel → grand_citadel + function-shedding | — | 🟢 |
| [p2-36](p2-36-unit-audio-cues-stubs.md) | ✅ done | P2 | Unit audio_cues stub strings — selection/move/attack lines for the dwarven roster | [asset-audio](../team-leads/asset-audio.md) | 🟢 |
| [p2-36](p2-36-data-resources-building-duplicates.md) | 🟡 partial | P2 | Reconcile the 14 building IDs defined in both `resources/buildings/` and `data/buildings/` | — | 🟢 |
| [p2-37](p2-37-react-calculator-metadata-surface.md) | ✅ done | P2 | React calculator UI — surface flavor, lore, clan_affinity, archetype filter | [tourguide](../team-leads/tourguide.md) | 🟢 |
| [p3-01](p3-01-courier-diplomacy.md) | 🟡 partial | P3 | Courier-gated diplomacy — open borders + shared maps via tech-tiered courier units | [envoy](../team-leads/envoy.md) | 🟢 |
| [p2-38](p2-38-unit-audio-cues-stubs.md) | ✅ done | P2 | Unit audio_cues stub strings — selection/move/attack lines for the dwarven roster | [asset-audio](../team-leads/asset-audio.md) | 🟢 |
| [p2-39](p2-39-chronicle-hall-phantom-unlock.md) | ✅ done | P2 | Resolve `chronicle_hall` phantom unlock in `chronicle_keeping` culture tech | — | 🟢 |
| [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) | 🟢 |

View file

@ -79,6 +79,7 @@
| [p1-25](p1-25-export-script-error-cleanup.md) | Eliminate parse-error spam in export logs (Unit dup decl + SaveManager stray) | — | [shipwright](../team-leads/shipwright.md) | 2026-04-25 |
| [p1-26](p1-26-tile-placement-preview-ux.md) | 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/<category>.json` into per-file pattern matching `resources/units/` | — | — | 2026-04-27 |
| [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 |
| [p2-06](p2-06-export-pipeline.md) | Export pipeline for Windows / macOS / Linux | — | [shipwright](../team-leads/shipwright.md) | 2026-04-25 |
@ -117,6 +118,15 @@
| [p2-30](p2-30-guide-shared-primitives.md) | Consolidate duplicate page styled-components into shared PagePrimitives | — | [tourguide](../team-leads/tourguide.md) | 2026-04-18 |
| [p2-31](p2-31-guide-url-bound-state.md) | Migrate guide filter + tab state from useState to URL search params | — | [tourguide](../team-leads/tourguide.md) | 2026-04-18 |
| [p2-32](p2-32-guide-data-driven-enums.md) | Replace hardcoded page enums with JSON data reads | — | [tourguide](../team-leads/tourguide.md) | 2026-04-18 |
| [p2-36](p2-36-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-37](p2-37-react-calculator-metadata-surface.md) | React calculator UI — surface flavor, lore, clan_affinity, archetype filter | — | [tourguide](../team-leads/tourguide.md) | 2026-04-27 |
| [p2-38](p2-38-unit-audio-cues-stubs.md) | 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 |
## P3
| ID | Title | Tags | Owner | Completed |
|---|---|---|---|---|
| [p3-01](p3-01-courier-diplomacy.md) | Courier-gated diplomacy — open borders + shared maps via tech-tiered courier units | — | [envoy](../team-leads/envoy.md) | 2026-04-29 |
| [p3-03](p3-03-courier-route-resolver.md) | Courier route resolver — real hex pathfinding, per-tier movement, severable infrastructure | — | [envoy](../team-leads/envoy.md) | 2026-04-28 |
| [p3-04](p3-04-per-hex-improvement-layer.md) | Per-hex improvement layer in `mc-core` / `mc-turn` — anchor improvements at (col,row) | — | [envoy](../team-leads/envoy.md) | 2026-04-28 |

View file

@ -15,10 +15,10 @@
| Priority | 🔵 | 🟡 | 🔴 | ❌ | ⚫ | ✅ | Total |
|---|---|---|---|---|---|---|---|
| **P0** | 0 | 0 | 0 | 0 | 0 | 43 | 43 |
| **P1** | 1 | 5 | 0 | 11 | 1 | 30 | 48 |
| **P2** | 0 | 2 | 1 | 1 | 0 | 30 | 34 |
| **P3 (oos)** | 0 | 1 | 0 | 1 | 19 | 0 | 21 |
| **total** | **1** | **8** | **1** | **13** | **20** | **103** | **146** |
| **P1** | 1 | 8 | 0 | 10 | 1 | 31 | 51 |
| **P2** | 0 | 3 | 1 | 1 | 0 | 31 | 36 |
| **P3 (oos)** | 0 | 0 | 0 | 1 | 19 | 3 | 23 |
| **total** | **1** | **11** | **1** | **12** | **20** | **108** | **153** |
</td><td valign='top' style='padding-left:2em'>
@ -26,11 +26,11 @@
| Team Lead | Remaining |
|---|---|
| [warcouncil](../team-leads/warcouncil.md) | 7 |
| [asset-sprite](../team-leads/asset-sprite.md) | 6 |
| [warcouncil](../team-leads/warcouncil.md) | 6 |
| [shipwright](../team-leads/shipwright.md) | 2 |
| [asset-audio](../team-leads/asset-audio.md) | 1 |
| [envoy](../team-leads/envoy.md) | 1 |
| [shipwright](../team-leads/shipwright.md) | 1 |
| [combat-dev](../team-leads/combat-dev.md) | 1 |
| [testwright](../team-leads/testwright.md) | 1 |
</td></tr></table>
@ -53,11 +53,13 @@
| [p1-05](p1-05-balance-tuning.md) | 🟡 partial | Balance tuning — pop_peak ≥30 median, worker improvements ≥8 min | — | [shipwright](../team-leads/shipwright.md) | 2026-04-25 | 🟢 unblocked |
| [p1-22](p1-22-mcts-wall-clock-budget.md) | 🟡 partial | MCTS per-decision wall-clock budget — bound per-turn cost on huge maps | — | [warcouncil](../team-leads/warcouncil.md) | 2026-04-25 | 🟢 unblocked |
| [p1-36](p1-36-ai-personalities-t1-t10-coverage.md) | 🟡 partial | AI personalities — T1T10 build order coverage + clan_affinity routing | — | [warcouncil](../team-leads/warcouncil.md) | 2026-04-27 | 🟢 unblocked |
| [p1-37](p1-37-mc-ai-clan-affinity-routing.md) | 🟡 partial | mc-ai clan_affinity routing — Rust AI reads unit clan_affinity at build-decision time | — | [warcouncil](../team-leads/warcouncil.md) | 2026-04-27 | 🟢 unblocked |
| [p1-38](p1-38-biome-economy-coupling.md) | 🟡 partial | Biome → economy coupling — population & luxury driven by live ecology | — | [shipwright](../team-leads/shipwright.md) | 2026-04-27 | 🟢 unblocked |
| [p1-39](p1-39.md) | 🟡 partial | Port per-yield difficulty multipliers from GDScript into Rust crates (Rail-1) — research + culture | rust-source-of-truth, rail-1 | [warcouncil](../team-leads/warcouncil.md) | 2026-04-27 | 🟢 unblocked |
| [p2-22](p2-22-sprite-generation-pipeline.md) | 🟡 partial | Sprite generation pipeline — runnable end-to-end | — | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-25 | 🟢 unblocked |
| [p1-27](p1-27-mcts-service-extraction.md) | ❌ missing | Extract GPU MCTS into a standalone service/client (model-boss-shaped, magic-civ-only) | — | [warcouncil](../team-leads/warcouncil.md) | 2026-04-25 | 🟢 unblocked |
| [p1-29](p1-29.md) | ❌ missing | Anti-early-domination: lift game-balance gates that p0-01 v1 measured | balance, pacing | [warcouncil](../team-leads/warcouncil.md) | 2026-04-26 | 🟢 unblocked |
| [p1-29](p1-29.md) | ❌ missing | Anti-early-domination: lift game-balance gates that p0-01 v1 measured | balance, pacing | [combat-dev](../team-leads/combat-dev.md) | 2026-04-29 | 🟢 unblocked |
| [p1-30](p1-30.md) | ❌ missing | Optimize `_build_tactical_state` — 8000-tile GDScript dict-build per AI turn blocks p1-22 huge-map gate | perf, tactical-ai | [warcouncil](../team-leads/warcouncil.md) | 2026-04-26 | 🟢 unblocked |
| [p1-31](p1-31-split-bundled-building-resources.md) | ❌ missing | Split bundled `resources/buildings/<category>.json` into per-file pattern matching `resources/units/` | — | — | 2026-04-27 | 🟢 unblocked |
| [p1-32](p1-32-food-chain-buildings.md) | ❌ missing | Author the two missing food/processing buildings (sawmill, herbalist) | — | — | 2026-04-27 | 🟢 unblocked |
| [p1-33](p1-33-naval-aerial-production-buildings.md) | ❌ missing | Wire naval/aerial unit gates to the harbor and airfield buildings | — | — | 2026-04-27 | 🟢 unblocked |
| [p2-23](p2-23-unit-sprites-dwarf-roster.md) | ❌ missing | Unit sprites — Dwarf-racial roster (m/f variants) | — | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | 🟢 unblocked |
@ -72,6 +74,7 @@
|---|---|---|---|---|---|---|
| [p2-10](p2-10-regression-ci-gate.md) | 🟡 partial | Automated regression CI gate on every push to main | — | [testwright](../team-leads/testwright.md) | 2026-04-23 | 🟢 unblocked |
| [p2-18](p2-18-guide-public-deployment.md) | 🟡 partial | Guide web app — public hosting + deploy pipeline | — | — | 2026-04-17 | 🟢 unblocked |
| [p2-36](p2-36-data-resources-building-duplicates.md) | 🟡 partial | Reconcile the 14 building IDs defined in both `resources/buildings/` and `data/buildings/` | — | — | 2026-04-27 | 🟢 unblocked |
| [p2-11a](p2-11a.md) | 🔴 stub | SaveManager: add Unit.serialize/deserialize and City.production_queue serialize path | — | — | 2026-04-26 | 🟢 unblocked |
| [p2-35](p2-35-palace-evolution-system.md) | ❌ missing | Palace evolution system — longhouse → great_hall → citadel → grand_citadel + function-shedding | — | — | 2026-04-27 | 🟢 unblocked |

View file

@ -1,13 +1,13 @@
{
"generated_at": "2026-04-27T08:42:27Z",
"generated_at": "2026-04-29T19:17:29Z",
"totals": {
"done": 103,
"done": 108,
"in_progress": 1,
"partial": 8,
"partial": 11,
"stub": 1,
"missing": 13,
"missing": 12,
"oos": 20,
"total": 146
"total": 153
},
"objectives": [
{
@ -809,8 +809,8 @@
"priority": "p1",
"status": "missing",
"scope": "game1",
"owner": "warcouncil",
"updated_at": "2026-04-26",
"owner": "combat-dev",
"updated_at": "2026-04-29",
"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."
},
@ -829,7 +829,7 @@
"id": "p1-31",
"title": "Split bundled `resources/buildings/<category>.json` into per-file pattern matching `resources/units/`",
"priority": "p1",
"status": "missing",
"status": "done",
"scope": "game1",
"updated_at": "2026-04-27",
"blocked_by": [],
@ -888,6 +888,39 @@
"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 T1T10 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"
},
{
"id": "p1-37",
"title": "mc-ai clan_affinity routing — Rust AI reads unit clan_affinity at build-decision time",
"priority": "p1",
"status": "partial",
"scope": "game1",
"owner": "warcouncil",
"updated_at": "2026-04-27",
"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."
},
{
"id": "p1-38",
"title": "Biome → economy coupling — population & luxury driven by live ecology",
"priority": "p1",
"status": "partial",
"scope": "game1",
"owner": "shipwright",
"updated_at": "2026-04-27",
"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."
},
{
"id": "p1-39",
"title": "Port per-yield difficulty multipliers from GDScript into Rust crates (Rail-1) — research + culture",
"priority": "p1",
"status": "partial",
"scope": "game1",
"owner": "warcouncil",
"updated_at": "2026-04-27",
"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: ATTEMPTED 2026-04-27, REVERTED.** Added `GdCity::process_culture_with_modifier(tile_yields_json, total_pct)` to api-gdext/src/lib.rs:1399 that mirrors the GDScript flow (process_culture → check raw_gain → add bonus → recheck can_expand). Math nominally identical. But R8 batch (Rust culture port) diverged from R6 (GDScript) on every seed (e.g. seed 1: R6=T251/tier=6/wonders=10, R8=T111/tier=2/wonders=0). R9 isolation batch (revert culture path on current source tree) reproduced R6 EXACTLY per-seed (`.local/iter/p1-39-r9-revert-hard-20260427_213224/`), proving the divergence is from the Rust culture path itself, NOT from other landed code (courier diplomacy, building ID reconciliation) between R6 and R7/R8. Floating-point intermediate values likely differ between the in-Rust mutation sequence and the GDScript-Variant-roundtrip mutation sequence; the difference cascades into different border-expansion timing → different tile ownership → entirely different game trajectories. Culture path REVERTED to GDScript (p1-39 stays partial — gold + research ported, culture deferred). Future port should investigate Rust f64 vs Variant FLOAT round-trip semantics, or alternative scope (e.g. apply difficulty modifier in GdCity::process_culture itself with an optional parameter, leaving the building-bonus math out of scope).\n\nThe fix for both: add `process_research` and `process_culture` passthrough methods to the GDScript wrapper layers, refactor the GDScript callers to delegate fully (matching the gold-port pattern). Estimated 2-3 hours including parity validation."
},
{
"id": "p2-06",
"title": "Export pipeline for Windows / macOS / Linux",
@ -1349,14 +1382,13 @@
},
{
"id": "p2-36",
"title": "Unit audio_cues stub strings — selection/move/attack lines for the dwarven roster",
"title": "Reconcile the 14 building IDs defined in both `resources/buildings/` and `data/buildings/`",
"priority": "p2",
"status": "done",
"status": "partial",
"scope": "game1",
"owner": "asset-audio",
"updated_at": "2026-04-27",
"blocked_by": [],
"summary": "The 50-unit dwarven roster needs in-character audio cue strings — the\none-liner that plays when a unit is selected, told to move, or ordered\nto attack. AoE/Civ/StarCraft conventions: 24 lines per cue type, played\nrandomly so repetition doesn't drone.\n\nThis objective lands the **string content** only. Voice acting and audio\nfile generation are downstream (asset-audio team's existing p2-16 audio\npack work). The `audio_cues` field unblocks the audio team to know what\nlines to record / TTS-generate.\n\nEach unit gets:\n```json\n\"audio_cues\": {\n \"select\": [\"...\", \"...\", \"...\"],\n \"move\": [\"...\", \"...\"],\n \"attack\": [\"...\", \"...\"],\n \"death\": [\"...\"]\n}\n```\n\nLines should reflect the unit's identity:\n- Berserker: \"BLOOD!\" / \"I do not need a shield.\"\n- Mountain King: \"The crown stands.\" / \"Speak the names.\" (referring to\n ten thousand clan-name engravings)\n- EMP Trooper: \"What runs on lightning...\" / \"Quietly.\"\n- Shield Bearer: \"Hold.\" / \"We become the place.\" / \"One step. One step.\""
"summary": "After the `p1-31` per-file split, 14 building IDs are defined in **both** `public/resources/buildings/<id>.json` (engine defaults) and `public/games/age-of-dwarves/data/buildings/<...>.json` (Age-of-Dwarves overrides). The data loader iterates `resources/` first then `data/` and overwrites by id — the data/ definition silently wins. Every duplicate currently differs in `cost`, `tech_required`, or `tier`, so the resources/ side is dead code wherever the override exists.\n\n| ID | resources/ definition | data/ definition (wins) | Drift |\n|---|---|---|---|\n| `barracks` | cost=80, tech=military_doctrine, tier=1 | cost=50, tech=null, tier=1 | tech gate dropped |\n| `forge` | cost=100, tech=smelting, tier=2 | cost=60, tech=null, tier=1 | tech gate dropped, tier dropped |\n| `granary` | cost=60, tech=husbandry, tier=1 | cost=30, tech=null, tier=1 (in stub.json) | tech gate dropped |\n| `library` | cost=75, tech=scholarship, tier=1 | cost=60, tech=null, tier=1 | tech gate dropped |\n| `monument` | cost=40, tech=null, tier=1 | cost=30, tech=null, tier=1 | cost only |\n| `siege_workshop` | cost=120, tech=mathematics, tier=2 | cost=80, tech=siege_craft, tier=2 | different tech |\n| `temple` | cost=90, tech=ancestor_rites, tier=2 | cost=80, tech=null, tier=2 | tech gate dropped |\n| `walls` | cost=75, tech=masonry, tier=1 | cost=70, tech=null, tier=1 | tech gate dropped |\n| `clan_moot_stone` (wonder) | cost=80, tier=1 | cost=180, tier=2 (in mundane_wonders.json) | wonder cost/tier diverged |\n| `covenant_stone` (wonder) | cost=355, tier=4 | cost=600, tier=6 | wonder cost/tier diverged |\n| `grand_observatory` (wonder) | cost=220, tech=astronomy, tier=5 | cost=600, tech=astronomy, tier=6 | wonder cost/tier diverged |\n| `hall_of_ancestors` (wonder) | cost=360, tier=4 | cost=260, tier=3 | wonder cost/tier diverged |\n| `voice_of_ages` (wonder) | cost=780, tier=10 | cost=1200, tier=10 | wonder cost diverged |\n| `world_pillar` (wonder) | cost=540, tier=7 | cost=1040, tech=world_theory, tier=9 | wonder cost/tech/tier diverged |\n\nThe pattern is clear:\n- **Ordinary buildings (8)**: `data/` versions are cheaper and drop the tech gate. Likely a deliberate Age-of-Dwarves \"always-buildable starter\" simplification.\n- **Wonders (6)**: `data/buildings/mundane_wonders.json` versions are heavier-cost / higher-tier, suggesting `mundane_wonders.json` is the actual Game 1 wonder ladder and the per-file `resources/` versions are stale legacy entries."
},
{
"id": "p2-37",
@ -1369,6 +1401,27 @@
"blocked_by": [],
"summary": "The combat calculator at `/calculator` and the permutations matrix at\n`/permutations` (in `.project/designs/app/`) currently show stat blocks\nbut none of the rich metadata p1-34 introduces. The point of writing\nflavor lines and clan affinity isn't to bury them in JSON — it's to\nmake the design legible in the tool that designers use to balance the\nroster.\n\nThis objective surfaces the new metadata in the React UI:\n\n1. **Calculator unit info card**: flavor as italic epigraph below the\n unit name; lore as collapsible \"Read more\" paragraph; clan_affinity\n as colored clan badges.\n2. **Permutations table**: archetype column (filterable, currently\n inferred); clan_affinity dots in the row.\n3. **Unit browser**: archetype-based grouping (Light Melee / Heavy Melee\n etc. as section headers within Infantry tab) replaces the flat list.\n4. **Hover tooltip**: flavor line shows on hover over a unit row."
},
{
"id": "p2-38",
"title": "Unit audio_cues stub strings — selection/move/attack lines for the dwarven roster",
"priority": "p2",
"status": "done",
"scope": "game1",
"owner": "asset-audio",
"updated_at": "2026-04-27",
"blocked_by": [],
"summary": "The 50-unit dwarven roster needs in-character audio cue strings — the\none-liner that plays when a unit is selected, told to move, or ordered\nto attack. AoE/Civ/StarCraft conventions: 24 lines per cue type, played\nrandomly so repetition doesn't drone.\n\nThis objective lands the **string content** only. Voice acting and audio\nfile generation are downstream (asset-audio team's existing p2-16 audio\npack work). The `audio_cues` field unblocks the audio team to know what\nlines to record / TTS-generate.\n\nEach unit gets:\n```json\n\"audio_cues\": {\n \"select\": [\"...\", \"...\", \"...\"],\n \"move\": [\"...\", \"...\"],\n \"attack\": [\"...\", \"...\"],\n \"death\": [\"...\"]\n}\n```\n\nLines should reflect the unit's identity:\n- Berserker: \"BLOOD!\" / \"I do not need a shield.\"\n- Mountain King: \"The crown stands.\" / \"Speak the names.\" (referring to\n ten thousand clan-name engravings)\n- EMP Trooper: \"What runs on lightning...\" / \"Quietly.\"\n- Shield Bearer: \"Hold.\" / \"We become the place.\" / \"One step. One step.\""
},
{
"id": "p2-39",
"title": "Resolve `chronicle_hall` phantom unlock in `chronicle_keeping` culture tech",
"priority": "p2",
"status": "done",
"scope": "game1",
"updated_at": "2026-04-27",
"blocked_by": [],
"summary": "The `chronicle_keeping` culture tech (era_4 oral_tradition pillar) declares\n`unlocks.buildings = [\"chronicle_hall\"]`, but no `chronicle_hall` building file\nexists anywhere in `public/resources/buildings/` or\n`public/games/age-of-dwarves/data/buildings/`. Surfaced by the p3-01 cycle 3\naudit when the era_4 Rune Scribe culture path tried to extend\n`chronicle_hall.enables_units` and discovered it was a phantom.\n\nThe actual building gated on `culture_required: \"chronicle_keeping\"` is\n`bardic_circle` (mundane_wonders.json:102 — tier 4, era 2 wonder). The phantom\nis a stale unlock string left over from an earlier design.\n\nThis is a pre-existing data integrity bug, separate from p3-01's courier scope."
},
{
"id": "g2-01",
"title": "Ley lines — Game 2 (Age of Kzzykt)",
@ -1566,10 +1619,10 @@
"id": "p3-01",
"title": "Courier-gated diplomacy — open borders + shared maps via tech-tiered courier units",
"priority": "p3",
"status": "partial",
"status": "done",
"scope": "game1-stretch",
"owner": "envoy",
"updated_at": "2026-04-27",
"updated_at": "2026-04-29",
"blocked_by": [],
"summary": "Game 1 ships diplomacy-lite: peace/war toggle plus a single bilateral luxury↔gold\ntrade action (`mc-trade`). This objective expands the diplomatic surface with two\ntrade options gated on physical infrastructure rather than instant agreement, so\ninformation itself becomes a strategic resource that decays with distance and tech:\n\n1. **Open borders** — pay luxury or gold for the right to move units through\n another civ's territory for N turns. Instant effect; pure trade.\n\n2. **Shared map** — pay luxury or gold for the other civ's explored map for N\n turns. **Not instant**: the deal is gated on a courier link between capitals.\n Knowledge propagates at the courier's movement speed; the courier is killable\n mid-route (intercept = no map delivered, payment already made). The Courier\n unit family has tech-gated upgrade tiers, one per era from era_2 onward; later\n tiers shrink the delay window and shift the intercept surface from\n killing-the-unit to severing-the-infrastructure.\n\nThis is **scope: game1-stretch** — Game 1's stated scope is \"diplomacy-lite\", so\nthis objective is post-Early-Access content unless explicitly pulled forward."
},
@ -1582,28 +1635,50 @@
"updated_at": "2026-04-26",
"blocked_by": [],
"summary": "`public/games/age-of-dwarves/docs/cities/BUILDINGS.md` \"Hybrid Merged Structures\" describes a tier-7-unlocked \"merge two co-located buildings into one hybrid\" mechanic with four named hybrids:\n\n| Merged structure | Requires | Exclusive units |\n|---|---|---|\n| War Academy | Barracks+Rifle Range + Stable+Barding Hall | Dragoon, Mounted Rifleman, Assault Cavalry |\n| Assault Citadel | Barracks+Sword Hall + Siege Workshop+Siege Annex | Siege Breaker, Combat Engineer, Storm Trooper |\n| Cavalry Corps | Stable+Barding Hall + Barracks+Bolt Range | Mounted Archer, Beast Scout, Ram Sniper |\n| Gunnery Corps | Barracks+Rifle Range + Siege Workshop+Powder Annex | Mortar Team, Assault Gunner, Field Artillery |\n\nMultiple prerequisite buildings (Stable, Barding Hall, Siege Annex, Powder Annex) and exclusive units do not exist in data. Game 1 also does not implement co-located building tile slots, master/grandmaster auras, or merge irreversibility — all called out elsewhere in BUILDINGS.md.\n\nThis is a **post-EA expansion-tier feature**. Filed at p3 to keep the gap visible without implying Game 1 EA depends on it."
},
{
"id": "p3-03",
"title": "Courier route resolver — real hex pathfinding, per-tier movement, severable infrastructure",
"priority": "p3",
"status": "done",
"scope": "game1-stretch",
"owner": "envoy",
"updated_at": "2026-04-28",
"blocked_by": [],
"summary": "p3-01 cycle 4 landed the **types** for courier-gated diplomacy\n(`DiplomaticAgreement` enum, `OpenBordersAgreement`, `SharedMapAgreement`,\n`CourierRoute`, `CourierMapView` trait, `step_shared_map_agreements` driver, six\nevent payloads). It also landed three lifecycle integration tests against a\n`MockMap` fixture that hard-codes intercept probability.\n\nThis objective owns the **physics layer** that lets those types resolve against\nthe actual game world: hex pathfinding from sender capital to receiver capital,\nper-tier movement-speed table feeding ETA calculations, and integration with\nseverable improvements (Steam Track, Resonance Wire, Beacon Tower) so that a\nmid-route pillage actually intercepts the courier.\n\nSplitting this out of p3-01 lets the parent objective close at \"data + types +\nlifecycle\" once AI/UI/tests/proof scenes land, while the route-resolver work\nstays its own bounded chunk of mc-trade ↔ mc-map glue."
},
{
"id": "p3-04",
"title": "Per-hex improvement layer in `mc-core` / `mc-turn` — anchor improvements at (col,row)",
"priority": "p3",
"status": "done",
"scope": "game1-stretch",
"owner": "envoy",
"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<Vec<String>>` (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)."
}
],
"blocked": [],
"remaining_by_lead": [
{
"owner": "warcouncil",
"remaining": 7
},
{
"owner": "asset-sprite",
"remaining": 6
},
{
"owner": "warcouncil",
"remaining": 6
"owner": "shipwright",
"remaining": 2
},
{
"owner": "asset-audio",
"remaining": 1
},
{
"owner": "envoy",
"remaining": 1
},
{
"owner": "shipwright",
"owner": "combat-dev",
"remaining": 1
},
{