Извлечено из замороженного 20-explanation/simulation. Запись существует потому, что решение выглядит нарушением нашего же правила и его тянет «почистить».

Решили: ICombatContext живёт как интерфейс, хотя реализация у него однаCombatSimulation. Это осознанное исключение из правила code-standards §4 («IFooFoo один-к-одному без второй реализации или границы теста не заводить»).

Почему: компоненты эффектов лежат в Combat и обязаны мочь влиять на мир — но не должны знать про конкретный класс CombatSimulation и тем более мутировать его поля. Контекст — это узкий контракт влияния: он перечисляет, что эффекту вообще разрешено сделать с боем, и тем самым ограничивает его, а не открывает доступ. Второе основание — тест: узкий интерфейс мокается, а CombatSimulation целиком нет.

То есть правило не нарушено, а сработало по второму условию: интерфейс здесь — граница, просто граница не для подмены реализации, а для ограничения прав. Убрать его «раз реализация одна» значит открыть каждому компоненту эффекта весь класс симуляции.

Грабли: шов протекает. Часть воздействий (статы и ресурс) ходит мимо ICombatContext напрямую, и это известный хвост — пока контракт не полон, ограничение держится дисциплиной, а не типом. Отдельный заход; не считать существующие протечки разрешением добавлять новые.

Владелец правды: Assets/_Project/Scripts/Combat/ICombatContext.cs и его реализация в CombatSimulation; правило про интерфейсы — Reference - Code Standards §4.