Решили: переименование сериализованного поля закрывается тремя проверками, а не одной:
FormerlySerializedAs на самом поле, греп по СТРОКОВОМУ имени ("_visual") и греп по рефлексии
(GetField("…")). Компилятор из этих трёх не ловит ни одну.
Почему: при переименовании UnitVisual → AnimationArchetypeData и _visual → _archetype
компиляция прошла с первого раза, а прогон боевых тестов дал 123 падения из 536. Причина —
EffectTestSupport ставил поле по строке (Set(r, "_visual", …)): строку компилятор не проверяет,
и тест падал уже в рантайме, с честным «нет поля _visual в RelicData».
Грабли:
- Вторая находка была страшнее и тест бы её НЕ поймал.
RelicCardVisualRigдоставал удалённоеUnitView._spriteрефлексией:GetFieldвернул быnull, ветка молча пропускалась, и карточка реликвии свалилась бы на фолбэк «первый спрайт в иерархии» — рисуя вместо бойца случайную часть. Ни ошибки, ни падения; нашлось только грепом поGetField("_. Рефлексия по имени поля — это ссылка, которую не видит ни компилятор, ни тест. FormerlySerializedAsобязателен и молчалив. Без него 47 юнит-ассетов потеряли бы архетип не сразу, а при первом сохранении каждого — то есть россыпью, по мере того как кто-то открывает ассеты. С ним ссылки живут: проверено сверкой guid на диске после переименования.- Переименование ассетов через
AssetDatabase.RenameAssetguid сохраняет, и git видит это какrename— история файла не рвётся. Ручное переименование на диске при живом редакторе так не умеет. - Красный тест в общем дереве — не обязательно свой. Параллельно вскрылись два падения про
battle_preset.menu_duel: ассет создан 04.08, а вContentDatabaseего нет ни в одном коммите — кто-то забыл прогнать синхронизацию базы. Отличить чужое от своего удалось только проверкой истории (git show <коммит>:<база> | grep <guid>), а не чтением сообщения теста. - Порядок «удалить → переименовать» имеет значение. Контроллер, который по имени числился боевым, стоял на дев-дуэлянте, а в бою играл «лабораторный». Удаление и переименование сделаны ОДНИМ шагом: между шагами дерево оказалось бы в состоянии, где имя и роль разошлись сильнее прежнего.
Владелец правды: UnitData._archetype (атрибут FormerlySerializedAs — он и есть договор о
переименовании), EffectTestSupport, план tech/40-planning/weapon-system §6.1.