Решили: инвариант «каждая часть тела умеет вспыхивать» держит ТЕСТ (BodyFlashMaterialTests), а
не редакторная кнопка. Кнопка «поставить материал вспышки» осталась как лечение, но сторожем быть
перестала.
Почему: у сторибук-юнита не вспыхивали волосы, кисть, гарда и рукоять — эти четыре части сидели
на Sprite-Lit-Default, который не знает _FlashAmount. Код при этом писал вспышку во ВСЕ части,
выборочности в нём нет: property block уходил в свойство, которого у шейдера не существует, и эффект
исчезал молча. Той же дорогой у этих частей не работали голограмма смерти и контур каста.
Материал раздавала кнопка в инспекторе тела — и была единственным хранителем инварианта. То есть держался он тем, что человек не забыл нажать. Четыре части забыли, и узнать об этом можно было только глазами, на конкретном эффекте, спустя недели. Это ровно тот случай, который правило «инвариант между файлами идёт в тест» и описывает: комментарий и кнопка видны одной стороне шва, а нарушает его вторая.
Список частей тест берёт ТОТ ЖЕ, по которому ходит рантайм (приватный _parts), а не обходом
иерархии: адресация эффектов идёт по индексу в нём, и проверка по иерархии проверяла бы не то, чем
пользуется бой.
Сказано: «смерть вспышка не работает на волосы, другиче части тела (гарда и рука), изучи механизм, у нас там где-то костыль очень плохой, надо единый источник правды» (2026-08-06, сессия d760c178). Костыль он предположил не глядя в код — и оказался прав.
Грабли: отсутствие свойства в шейдере — самый тихий вид поломки, какой бывает.
MaterialPropertyBlock не жалуется на запись в несуществующее свойство, поэтому «эффект не
показался» и «эффекта не было» выглядят одинаково, а искать начинают в коде эффекта, где всё верно.
Владелец правды: Assets/_Project/Tests/EditMode/Presentation/BodyFlashMaterialTests.cs.