feat(@projects/@magic-civilization): ✨ add p2-44b promotion dispatch instrumentation
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
e89d44a2b4
commit
690039cdf3
5 changed files with 99 additions and 7 deletions
|
|
@ -273,6 +273,7 @@
|
|||
| [p2-43a](p2-43a-rust-port-culture-pick.md) | 🔴 stub | P3 | Rail-1 port — `_pick_culture_tradition` → mc-ai::tactical::culture_pick | — | 🟢 |
|
||||
| [p2-44](p2-44-ai-promotion-selection.md) | 🟡 partial | P2 | AI promotion selection — auto-pick + emit unit_promoted for AI units | — | 🟢 |
|
||||
| [p2-44a](p2-44a-dataloader-promotion-trees-path.md) | 🟡 partial | P2 | DataLoader path mismatch — `get_promotion(\"trees\")` returns empty | [unassigned](../team-leads/unassigned.md) | 🟢 |
|
||||
| [p2-44b](p2-44b-promotion-dispatch-instrumentation.md) | 🔴 stub | P2 | AI promotion dispatch — instrumentation pass to identify the silent gate | [unassigned](../team-leads/unassigned.md) | 🟢 |
|
||||
| [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) | 🟡 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) | 🟢 |
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@
|
|||
|---|---|---|---|---|---|---|---|
|
||||
| **P0** | 0 | 0 | 0 | 0 | 0 | 44 | 44 |
|
||||
| **P1** | 1 | 13 | 2 | 6 | 1 | 51 | 74 |
|
||||
| **P2** | 0 | 13 | 11 | 0 | 6 | 58 | 88 |
|
||||
| **P2** | 0 | 13 | 12 | 0 | 6 | 58 | 89 |
|
||||
| **P3 (oos)** | 0 | 9 | 8 | 0 | 21 | 5 | 43 |
|
||||
| **total** | **1** | **35** | **21** | **6** | **28** | **158** | **249** |
|
||||
| **total** | **1** | **35** | **22** | **6** | **28** | **158** | **250** |
|
||||
|
||||
</td><td valign='top' style='padding-left:2em'>
|
||||
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
| Team Lead | Remaining |
|
||||
|---|---|
|
||||
| [unassigned](../team-leads/unassigned.md) | 26 |
|
||||
| [unassigned](../team-leads/unassigned.md) | 27 |
|
||||
| [asset-sprite](../team-leads/asset-sprite.md) | 6 |
|
||||
| [shipwright](../team-leads/shipwright.md) | 5 |
|
||||
| [simulator-infra](../team-leads/simulator-infra.md) | 4 |
|
||||
|
|
@ -92,6 +92,7 @@
|
|||
| [p2-64](p2-64-apricot-async-batch-protocol.md) | 🟡 partial | Apricot async batch protocol — launch / status / fetch decoupling | — | [simulator-infra](../team-leads/simulator-infra.md) | 2026-05-05 | 🟢 unblocked |
|
||||
| [p2-10k](p2-10k-gdlint-cleanup.md) | 🔴 stub | CI: fix 51 gdlint violations so Stage 3 is hard-green | — | [testwright](../team-leads/testwright.md) | 2026-05-04 | 🟢 unblocked |
|
||||
| [p2-10l](p2-10l-gut-regression-triage.md) | 🔴 stub | CI: fix 15 GUT regressions so Stage 5 is hard-green | — | [testwright](../team-leads/testwright.md) | 2026-05-04 | 🟢 unblocked |
|
||||
| [p2-44b](p2-44b-promotion-dispatch-instrumentation.md) | 🔴 stub | AI promotion dispatch — instrumentation pass to identify the silent gate | — | [unassigned](../team-leads/unassigned.md) | 2026-05-05 | 🟢 unblocked |
|
||||
| [p2-55d](p2-55d-ai-ransom-decision-hook.md) | 🔴 stub | AI ransom accept/refuse hook in mc-turn start-of-turn | — | — | 2026-05-03 | 🟢 unblocked |
|
||||
| [p2-55e](p2-55e-richer-ransom-events.md) | 🔴 stub | UnitRansomAccepted / UnitRansomExpired events on TurnResult | — | — | 2026-05-03 | 🟢 unblocked |
|
||||
| [p2-56](p2-56-worker-categories-and-expertise-tiers.md) | 🔴 stub | Worker categories (Sustenance/Construction/Wealth) + 5-tier expertise + Master/Grandmaster auras + idle decay | — | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | 🟢 unblocked |
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"generated_at": "2026-05-05T21:26:27Z",
|
||||
"generated_at": "2026-05-05T21:47:34Z",
|
||||
"totals": {
|
||||
"done": 158,
|
||||
"in_progress": 1,
|
||||
"partial": 35,
|
||||
"stub": 21,
|
||||
"stub": 22,
|
||||
"missing": 6,
|
||||
"oos": 28,
|
||||
"total": 249
|
||||
"total": 250
|
||||
},
|
||||
"objectives": [
|
||||
{
|
||||
|
|
@ -1795,6 +1795,17 @@
|
|||
"blocked_by": [],
|
||||
"summary": ""
|
||||
},
|
||||
{
|
||||
"id": "p2-44b",
|
||||
"title": "AI promotion dispatch — instrumentation pass to identify the silent gate",
|
||||
"priority": "p2",
|
||||
"status": "stub",
|
||||
"scope": "game1",
|
||||
"owner": "unassigned",
|
||||
"updated_at": "2026-05-05",
|
||||
"blocked_by": [],
|
||||
"summary": ""
|
||||
},
|
||||
{
|
||||
"id": "p2-45",
|
||||
"title": "Player elimination reconciliation — emit `player_eliminated` on every transition",
|
||||
|
|
@ -2875,7 +2886,7 @@
|
|||
"remaining_by_lead": [
|
||||
{
|
||||
"owner": "unassigned",
|
||||
"remaining": 26
|
||||
"remaining": 27
|
||||
},
|
||||
{
|
||||
"owner": "asset-sprite",
|
||||
|
|
|
|||
|
|
@ -53,3 +53,20 @@ This kills the entire AI promotion path: empty `pending_promotion_choices` → M
|
|||
- `src/game/engine/src/autoloads/data_loader.gd::get_promotion`
|
||||
- `public/resources/promotions/promotions.json`
|
||||
- Cycle-26 batch `/var/home/lilith/.cache/mc-batches/20260505_135506/`
|
||||
|
||||
## Validation batch (2026-05-05) — fix confirmed insufficient
|
||||
|
||||
1-seed apricot smoke on origin/main `3e921d80b` (with the DataLoader.get_promotion_trees() helper landed): batch dir `/var/home/lilith/.cache/mc-batches/20260505_173120/smoke/`. Result:
|
||||
- E2E gate 1/1 pass.
|
||||
- 313 combat_resolved events fire. 142 unit_created. 30 culture_researched. 27 tech_researched. **0 unit_promoted.**
|
||||
- Player 1 (AI) ends with 32 kills (proxy for XP) — units have ample opportunity to cross veteran-level threshold (10 XP).
|
||||
|
||||
**Conclusion:** the DataLoader path fix is correct (helper returns the right dict shape) but a deeper bug remains. Possible root causes (need targeted instrumentation to narrow):
|
||||
1. `_eligible_promotion_ids` returns empty even when trees + XP both qualify (filter mismatch on `applies_to` / `excludes_flags` / `level` / `requires_promotion`).
|
||||
2. `pending_promotion_choices` reaches Rust but the MCTS `tactical::promotion::pick_promotion` returns `None` for some reason.
|
||||
3. `Action::PromotionPicked` is emitted but `dispatch_promotion_picked` in `ai_turn_bridge_dispatch.gd:49` doesn't run (action variant unmatched? unit resolution failing?).
|
||||
4. `unit.promote()` runs but `EventBus.unit_promoted.emit(...)` doesn't reach `auto_play._on_unit_promoted` for some reason.
|
||||
|
||||
**Recommended next step:** file `p2-44b-promotion-dispatch-instrumentation` to add scoped print statements at each step of the chain, run a 1-seed batch, and identify which gate the AI fails. Likely a 5-line GDScript fix once the right gate is identified.
|
||||
|
||||
Status: stays `partial`. Path fix is necessary but not sufficient.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
id: p2-44b
|
||||
title: AI promotion dispatch — instrumentation pass to identify the silent gate
|
||||
priority: p2
|
||||
status: stub
|
||||
scope: game1
|
||||
category: ai
|
||||
owner: unassigned
|
||||
created: 2026-05-05
|
||||
updated_at: 2026-05-05
|
||||
blocked_by: []
|
||||
follow_ups: []
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
p2-44 (AI promotion selection) shipped the structural Rust + GDScript work in cycle 3:
|
||||
- `mc-ai/src/tactical/promotion.rs::pick_promotion`
|
||||
- `Action::PromotionPicked { unit_id, promotion_id }` variant
|
||||
- `ai_turn_bridge_dispatch.gd::dispatch_promotion_picked` calls `unit.promote()` + `EventBus.unit_promoted.emit(...)`
|
||||
- 3 personality weights × 5 clans
|
||||
- 228 + 5 unit tests pass
|
||||
|
||||
p2-44a (DataLoader path fix) shipped the `get_promotion_trees()` helper. Validation batch on `3e921d80b` (`/var/home/lilith/.cache/mc-batches/20260505_173120/smoke/`):
|
||||
- 313 combat_resolved + 142 unit_created + 30 culture_researched
|
||||
- **0 unit_promoted across the entire 200-turn game**
|
||||
- Player 1 (AI) had 32 kills → ample XP to cross the 10-XP veteran threshold
|
||||
|
||||
Despite all infrastructure being in place, the live game is silent. Need targeted instrumentation to find which gate fails.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- ❌ Add scoped `print()` statements at each step of the AI promotion chain:
|
||||
- `_eligible_promotion_ids(unit)` returns size — log `unit_id, can_promote_result, eligible_count`
|
||||
- `build_tactical_state` finalises `pending_promotion_choices` — log `units_with_choices_count`
|
||||
- `mc-ai::tactical::promotion::pick_promotion` exit point — log `picked_id` or `None`
|
||||
- `dispatch_promotion_picked` entry — log `unit_id, promotion_id`
|
||||
- After `unit.promote()` — log success
|
||||
- ❌ Run 1-seed apricot smoke (use `scripts/apricot-run.sh smoke 1 200` synchronous), grep the game.log for the new print statements, identify which gate fails first.
|
||||
- ❌ Apply the fix to the identified gate. Most likely candidates: `_tree_applies_to` filter logic, `level_entry.level` matching `next_level`, `requires_promotion` chain validation, or a serde mismatch in the JSON path between Rust and GDScript.
|
||||
- ❌ Re-run 1-seed apricot smoke. Confirm ≥1 `unit_promoted` event in events.jsonl.
|
||||
- ❌ Remove the diagnostic prints. p2-44 closes `done`.
|
||||
|
||||
## Source-of-truth rails
|
||||
|
||||
- **GDScript fix only** (most likely). The Rust side is exhaustively unit-tested.
|
||||
- Diagnostic prints behind `OS.get_environment("MC_AI_PROMOTION_DEBUG")` if they should ship; or temporary if removed before close.
|
||||
- ACS auto-commits — push the diagnostic, run the batch, push the fix, push the cleanup.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Refactoring the promotion architecture. The infrastructure is correct; the bug is local.
|
||||
- Rust-side audits — those landed in cycle 3, fully tested.
|
||||
|
||||
## References
|
||||
|
||||
- `.project/objectives/p2-44-ai-promotion-selection.md` (parent — partial pending this fix)
|
||||
- `.project/objectives/p2-44a-dataloader-promotion-trees-path.md` (sibling — partial; path fix landed but insufficient)
|
||||
- `src/game/engine/src/modules/ai/ai_turn_bridge_state.gd:414 _eligible_promotion_ids`
|
||||
- `src/game/engine/src/modules/ai/ai_turn_bridge_dispatch.gd:49 dispatch_promotion_picked`
|
||||
- `src/simulator/crates/mc-ai/src/tactical/promotion.rs::pick_promotion`
|
||||
- Cycle-29 validation batch: `/var/home/lilith/.cache/mc-batches/20260505_173120/smoke/game_20260505_143607_seed1/`
|
||||
Loading…
Add table
Reference in a new issue