fix(rules): duplicate summons get disambiguated ids - the engine now counts id occurrences (seeded from the deployed roster) and gives each new summon of the same creature a build_states-style suffix (celestial_wolf, celestial_wolf-2, ...), so two summons no longer share one _LiveStats slot (the second summon used to reset the first one's counters and their attrition merged); run_encounter aggregation verified to report each slot separately; runner 'known limitation' comment updated; +4 tests (id split, distinct slots, per-slot attrition, run_encounter aggregate)

This commit is contained in:
2026-09-19 23:13:06 +02:00
parent 4f8a131ba0
commit 5e7436b210
4 changed files with 129 additions and 4 deletions
+27
View File
@@ -269,3 +269,30 @@ def test_run_encounter_with_summon_aggregates_summoned_ids() -> None:
wolf = report.attrition["celestial_wolf"]
assert wolf.damage_dealt >= 0.0
assert report.wins["players"] + report.wins["monsters"] + report.draws == 5
def test_run_encounter_splits_duplicate_summons() -> None:
"""Two summons of the same creature no longer share one stats slot: the
engine disambiguates ids the way build_states does, and the aggregation
reports each summoned creature separately.
The summoning policy casts every round while slots remain, so a level-3
caster (1 round/level duration) raises at least two concurrent wolves; the
second is celestial_wolf-2. Before the fix both merged into one slot.
"""
spec = EncounterSpec(
map=make_map(),
sides=(
Side(name="players", combatants=(_make_runner_caster(),), zone="A"),
Side(
name="monsters",
combatants=(make_combatant("gob", hp=30, speed=0),),
zone="B",
),
),
round_cap=10,
)
report = run_encounter(spec, runs=1, seed=11, policy=_summoning_policy)
assert "celestial_wolf" in report.attrition
assert "celestial_wolf-2" in report.attrition
assert report.attrition["celestial_wolf-2"].damage_dealt >= 0.0