Решили: награда носителю за парирование (ParryComponent._onParryReward, у дуэлянта — щит 200 на 3 сек) кладётся в момент открытия окна, вместе с гашением удара-триггера, а не по факту ответного удара. Прибавка «в дуэли» стала отдельным компонентом DuelDamageBonusComponent, а не режимом существующего AllyProximityDamageBonusComponent.

Почему: ответ парирующего — это рекаст, и его можно сорвать станом (так и задумано, 2026-07-31/10). Привяжи награду к ответу — и щит пропадал бы вместе с чужим контролем, хотя отбил носитель уже в момент окна: платили бы дважды за одно попадание. Компонент отдельный по другой причине: «Стая» даёт прибавку ЗА каждого союзника и растёт с числом, дуэль — одну прибавку ПО ПОРОГУ по врагам. Общий компонент потребовал бы двух флагов («союзники или враги» × «за каждого или по порогу») — четыре режима в одной точке вместо двух ясных правил.

Грабли: порог по врагам считается вокруг НОСИТЕЛЯ, и цель в счёт входит — значит «рядом только один враг» это _maxEnemies = 1, а не 0. Ошибка тут не ломает бой, а тихо меняет кит: при пороге 0 бонус не включается никогда, при счёте вокруг цели он включался бы, когда дуэлянт в одиночку влез в чужой строй — ровно наоборот к замыслу. Оба случая из боя не видны, поэтому инвариант ушёл в тест. Второе: величину щита ищет не float, а ScalableValueSetValue на поле роняет ассет-скрипт исключением о типе, а не молча.

Владелец правды: ParryComponent.OnPreDamage (комментарий про момент награды), DuelDamageBonusComponent, тест DuelBonusTests.