feat(@projects/@magic-civilization): ✨ update culture pick objective status
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
bf9295a5d9
commit
febfaf4cb9
3 changed files with 42 additions and 17 deletions
|
|
@ -2,13 +2,14 @@
|
|||
id: p2-43a
|
||||
title: "Rail-1 port — `_pick_culture_tradition` → mc-ai::tactical::culture_pick"
|
||||
priority: p3
|
||||
status: stub
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-05-03
|
||||
updated_at: 2026-05-14
|
||||
evidence:
|
||||
- "src/game/engine/scenes/tests/auto_play.gd:1297-1351 (Phase A GDScript picker)"
|
||||
- "src/simulator/crates/mc-ai/src/tactical/promotion.rs (reference shape)"
|
||||
- "src/simulator/crates/mc-ai/src/policy.rs:140-156 (PersonalityPriors slot for culture weights)"
|
||||
- "src/simulator/crates/mc-ai/src/tactical/culture_pick.rs (Rust port + 5 tests, all green)"
|
||||
- "src/simulator/api-gdext/src/ai.rs:516+ (GdAiController::pick_culture_tradition bridge)"
|
||||
- "src/game/engine/scenes/tests/auto_play.gd:1352+ (call site annotated; scoring mirrored, see note)"
|
||||
- "cargo test -p mc-ai --lib tactical::culture_pick → 5/5 passed"
|
||||
assigned_by: shipwright
|
||||
---
|
||||
## Summary
|
||||
|
|
@ -35,14 +36,24 @@ Mirror the shape of `mc-ai::tactical::pick_promotion`:
|
|||
|
||||
## Acceptance
|
||||
|
||||
- [ ] `mc-ai::tactical::culture_pick::pick_culture_tradition` lands with
|
||||
personality-driven scoring and pillar weights.
|
||||
- [ ] `GdAiController::pick_culture_tradition` bridge method added.
|
||||
- [x] `mc-ai::tactical::culture_pick::pick_culture_tradition` lands with
|
||||
personality-driven scoring (mercantile blend on wealth +
|
||||
trade_willingness axes; pillar weights deferred — no `culture` axis
|
||||
yet, see Out of scope).
|
||||
- [x] `GdAiController::pick_culture_tradition` bridge method added
|
||||
(`api-gdext/src/ai.rs`, accepts `available_json` + `axes_json`).
|
||||
- [ ] `auto_play.gd::_pick_culture_tradition` body collapses to one
|
||||
bridge call; the GDScript scoring loop is deleted.
|
||||
- [ ] `cargo test -p mc-ai` green; `cargo check --workspace` green.
|
||||
bridge call. **Blocked:** `auto_play.gd` cannot instantiate
|
||||
`GdAiController` (per CLAUDE.md § 'AI exception'). Same constraint
|
||||
that holds `_pick_research` inline. Resolves when auto_play.gd
|
||||
grows a controller via the same wiring path p0-26 lands for the
|
||||
tactical bridge. Scoring is mirrored 1:1 and annotated.
|
||||
- [x] `cargo test -p mc-ai --lib tactical::culture_pick` green
|
||||
(5/5 passed, 2026-05-14). `cargo check -p magic-civ-physics-gdext`
|
||||
clean.
|
||||
- [ ] 1-seed apricot smoke continues to fire `culture_researched` at
|
||||
least once per 200-turn run.
|
||||
least once per 200-turn run — not re-run; GDScript scoring is
|
||||
byte-identical to pre-port so behaviour unchanged.
|
||||
|
||||
## Out of scope
|
||||
|
||||
|
|
|
|||
|
|
@ -257,3 +257,13 @@ Full plan with the 20 numbered file items, locked decisions, and verification ma
|
|||
- Acceptance gate: `owner:` populated.
|
||||
|
||||
Bullets remaining: 18 (16 implementation + 2 admin: follow-ups + owner).
|
||||
|
||||
### 2026-05-14 status (combat-dev re-dispatch — `defender_capturable` PvP wiring)
|
||||
|
||||
- **PvP wiring landed** at `mc-turn/src/processor.rs:2186-2243` (queued attack path in `resolve_single_pvp_attack`) and `:2936-2990` (proximity-discovery loop in `process_pvp_combat`). Both sites read `(capturable, ransom_multiplier, build_cost)` from `state.units_catalog`, resolve attacker posture via `capture::resolve_posture`, and pass all four fields into `CombatParams`. Non-capturable defenders keep `defender_capturable=false` and fall through to `Killed`/`Survived` unchanged.
|
||||
- **Verification:** `cargo test -p mc-turn --test capture_pvp_end_to_end` — 3 of 4 tests green (Capture posture, Destroy posture, unknown-unit-id fallthrough). The Ransom posture test (`ransom_posture_pvp_enqueues_offer_with_priced_unit`) fails — but the failure is downstream of the wiring, not in the wiring itself.
|
||||
- **Ransom test failure is a separate followup, not a wiring gap.** Diagnostics: the queued path enqueues the offer correctly (`UnitRansomOffered` event with `offer_id=0, price=140, expires_turn=4` is emitted, `enqueue_ransom_offer` runs). Then `process_ai_ransom_decisions` (invoked once per `step` at line 575) silently auto-refuses with `PersonalityPriors::default()` because the test seat has empty `clan_id` — the auto-refuse drains the queue and `apply_refuse_from_offer` moves the unit to the captor. The proximity-discovery loop at `:2936` then also re-engages any unit still on the warrior's tile because there is no `captive_of.is_some()` skip guard. The compound effect explains the observed state: queue empty, worker no longer on p1's vec, and a stray `UnitKilled` event in the stream.
|
||||
- **Followup needed (not blocking p2-55 wiring, blocking p2-55d smoke gate):**
|
||||
- Add `captive_of.is_some()` skip in the proximity-discovery loop (`process_pvp_combat`, ~line 2879 attacker_snaps filter and ~line 2896 `find_enemy_nearby` defender side) so captive units cannot be re-engaged in the same turn they are pinned.
|
||||
- Either gate `process_ai_ransom_decisions` to skip empty-`clan_id` seats (treat as "no AI lives here, leave the offer for the human/test"), or make the test fixture set `clan_id` to a personality that holds the offer for at least one turn.
|
||||
- These two changes are sufficient to flip the Ransom PvP test green and unblock the p2-55d 30-turn smoke gate.
|
||||
|
|
|
|||
|
|
@ -1350,13 +1350,17 @@ func _pick_research(player: RefCounted) -> void:
|
|||
|
||||
|
||||
func _pick_culture_tradition(player: RefCounted) -> void:
|
||||
## p2-43 Phase A: GDScript-side culture-tradition picker.
|
||||
## p2-43a: scoring logic ported to `mc-ai::tactical::culture_pick`.
|
||||
##
|
||||
## Selects the cheapest available tradition (1000/cost), nudged by a
|
||||
## mercantile blend ((wealth + trade_willingness) / 2) so goldvein-flavoured
|
||||
## clans bias toward culture mildly. Personalities have no `culture` axis
|
||||
## today; this is intentionally simple. Rail-1 port of the picker into
|
||||
## `mc-ai::tactical::culture_pick` is tracked as `p2-43a-rust-port`.
|
||||
## The canonical scoring function is
|
||||
## `mc_ai::tactical::culture_pick::pick_culture_tradition` and the bridge
|
||||
## is `GdAiController::pick_culture_tradition(available_json, axes_json)`.
|
||||
## This test-harness path matches the Rust scoring inline because
|
||||
## `auto_play.gd` does not hold a `GdAiController` instance (per
|
||||
## CLAUDE.md § 'AI exception': `ClassDB.instantiate('GdAiController')` is
|
||||
## blocked). Production AI consumers route through the bridge — same
|
||||
## pattern as `_pick_research` above. Any change to the scoring formula
|
||||
## here MUST be mirrored in `culture_pick.rs` (and vice versa).
|
||||
##
|
||||
## Prereq filtering delegates to `CultureWeb.get_available_traditions(...)`
|
||||
## (Rust GDExt) — never reimplement the prereq graph in GDScript.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue