Решили: предел живых призывов проверяется гейтом каста в AbilitySystem.TryPlan, а тест на него
переписан так, чтобы падать при отсутствии гейта.
Почему: AbilityData.SummonLimit было объявлено в данных, описано в карточке Bonewright («лимит
живых скелетов — 8») и закреплено решением Макса («предел — гейт каста: мана и кулдаун целы, игрок
видит предел глазами»). Читать его при этом не читала ни одна строка боевой логики: единственный
потребитель SummonSystem.CountLiveSummons вызывался только из теста. Некромант копил скелетов,
пока хватало маны.
Грабли: поле, объявленное в данных и не прочитанное кодом, ничем себя не выдаёт — ни ошибкой, ни предупреждением. Инспектор его показывает, карточка его обещает, тест его упоминает; отсутствует только исполнение. Хуже того, тест был ложнозелёным по чужой причине: у призывателя было 100 маны при цене каста 40, поэтому третий призыв отсекала цена, а не предел. Тест проходил и при полностью отсутствующем гейте — то есть охранял инвариант только на словах. Признак такого теста: его числа сходятся ровно на границе, и граница эта — не та, что он проверяет.
Владелец правды: AbilitySystem.TryPlan (гейт с комментарием), тест
SummonTests.SummonLimit_BlocksTheCastEntirely_KeepingManaAndCooldown.