Решение принято в Фазе 1, точная дата не зафиксирована; запись извлечена из замороженного
20-explanation/di-events.
Решили: боевая сборка не знает про MessagePipe. Combat — нижний слой, наружу отдаёт голые
C#-события (десяток: спавн и смерть юнита, урон, лечение, уклонение, начало и конец боя). В шину их
ретранслирует CombatPresenter, уже в слое презентации — оттуда их слушают Audio, VFX и UI.
Почему: сборка, лежащая ниже всех, не должна тянуть за собой пакет ради развязки тех, кто выше.
Голое C#-событие — это ноль зависимостей и ноль настройки, а подписчикам всё равно нужен слой, который
знает и про сим, и про Unity. Заодно снят статический доступ к шине: провайдер GlobalMessagePipe
удалён, потому что его никто не звал, а глобальная поверхность жила и приглашала ею воспользоваться.
Грабли: инвариант держится соглашением, а не тестом — проверяется тем, что using MessagePipe
не встречается в Scripts/Combat ни разу. Первый, кто напишет там using, ничего не сломает и ничего
не заметит. По нашему же правилу («инвариант между файлами идёт в тест») здесь нужен guard-тест на
границу сборок; занесён в Meta - Tech Debt §5.6.
Владелец правды: Assets/_Project/Scripts/Combat/ (отсутствие зависимости) и
Assets/_Project/Scripts/Presentation/CombatPresenter.cs (ретрансляция в шину); правило слоёв —
CLAUDE.md.