Решили: реактив, требующий ДЕЙСТВИЯ носителя, помечается маркером IRequiresAgencyComponent и не срабатывает, пока юнит выведен контролем; гейт читает СНИМОК дееспособности на начало тика (RuntimeUnit.CanActAtTickStart), а не живой CanAct.

Почему: оглушённый поднимал щит «Оплота» и уходил в кувырок «Изворотливости» — проверялся только IsDead. Отвергли список эффектов, отключающих реактивы: дееспособность уже имеет владельца (CanAct, который EffectSystem собирает из компонентов контроля), и второй список разошёлся бы с ним на первом же новом виде контроля. Маркер на компоненте ставит решение туда, где объявлено поведение, и одна проверка в диспатче заменяет пятнадцать проверок в компонентах. Шипы и вампиризм не помечены намеренно: это свойства, а не действия, и под станом они обязаны работать.

Грабли: две, и обе стоили прогонов. Первая — живой CanAct меняется ПОСРЕДИ тика: RecomputeControl зовётся синхронно при наложении эффекта, а урон проходит раньше фазы эффектов, поэтому реакция стала зависеть от того, чей атакующий раньше в списке юнитов, и зеркальные команды разошлись. Отсюда снимок. Побочное следствие принято как верное: стан, прилетевший тем же тиком, что удар, поднять щит не мешает — как «Оплот» ловит тот самый удар, который его разбудил. Вторая — маркер СЛОМАЛ комбо монаха: его рывок сделан смещением, а смещение снимает дееспособность у летящего, так что гейт отменял фазы собственной способности. Правило: если недееспособность вызвана своей же механикой, маркера быть не должно.

Владелец правды: Assets/_Project/Scripts/Combat/Effects/EffectSystem.cs (гейт в RunPreDamage и в реактивной очереди), Assets/_Project/Scripts/Combat/Effects/IRuntimeEffectComponent.cs (маркер), тесты DefenderSliceTests.Bulwark_DoesNotRaiseTheShieldWhileIncapacitated, DefenderSliceTests.Thorns_StillBiteWhileIncapacitated, AssassinSliceTests.Dodge_DoesNotWorkWhileIncapacitated.