Решили: «Геомант» вычищен из данных — кит стал relic.hemomancer (Кровомант, как в карточке с 2026-07-30), эффект effect.stone_titheeffect.tithe, класс StoneTitheComponentTitheComponent, вместе с AI-пресетом, тегом кита и лок-ключами.

Почему: опечатка жила только в именах ассетов и id, а карточка полтора месяца называла кита иначе. Расхождение имени в данных и в дизайне — тот же дефект единственного владельца: по relic.geomancer искать нечего, а по «Десятине» не находится ассет.

Сказано: «никакого КАМЕННЫЙ, у нас геомант был ОПЕЧАТКОЙ, убери это» (2026-08-03, сессия 87bf8fd2).

Грабли:

  • [SerializeReference] хранит ИМЯ КЛАССА внутри ассета (references.RefIds[].type.class). Переименование класса без [UnityEngine.Scripting.APIUpdating.MovedFrom(true, sourceClassName: …)] превращает компонент в null молча: ассет открывается, эффект существует, а механики в нём больше нет. Прецедент атрибута в проекте уже был — BlockComponentBulwarkComponent.
  • Порядок обязателен: сначала правится и компилируется КОД (класс + атрибут), и только потом трогаются ассеты. Наоборот — Unity успевает переварить ассет без известного ей типа.
  • Проверять надо в редакторе, а не по диффу. managedReferenceFullTypename у элемента массива показывает, каким типом он резолвится сейчас; git-дифф ассета при удачном MovedFrom вообще пустой, и «ничего не изменилось» одинаково выглядит и при успехе, и при потере компонента.
  • Id живут в трёх местах на одну сущность: сам ассет, его AI-пресет и тег кита в _tags. Плюс лок-ключи, которые едут за id и без переноса остаются сиротами.

Владелец правды: TitheComponent.cs (атрибут), Hemomancer.asset, Tithe.asset, тест DataDrivenPayloadRulesTests.