Решение принято в Фазе 1 (до 19.06.2026), точная дата не зафиксирована; запись извлечена из замороженного 20-explanation/simulation.

Решили: RuntimeUnit — POCO с публичными изменяемыми полями, без свойств и инкапсуляции. Никакого MonoBehaviour/ScriptableObject: юнит живёт один бой и хранит HP, щит, позицию (и PreviousPosition для интерполяции вида), цель, кулдаун атаки, эффекты, флаги контроля.

Почему: сознательный размен в пользу скорости и простоты, Data-Oriented стиль — системы читают и пишут эти поля много раз за тик. Инкапсуляция дала бы геттеры на горячем пути и ничего не защитила бы: дисциплина «мутирует только такая-то система» всё равно держится соглашением, потому что систем много и все они внутри одной сборки. Цена честная — компилятор дисциплину не навязывает, нужна аккуратность; выгода — ноль аллокаций и ноль вызовов на пути тика.

Это же решение — причина, по которой инвариант «вид только читает» держится не типами, а правилом (IUnitBodyVisual и презентационный шов). Открытый пункт H7 в Meta - Tech Debt — про ту самую цену.

Грабли: создавать RuntimeUnit только через RuntimeUnitFactory — там единая точка сборки со значимым порядком: дефолты статов → моды реликвии → таланты → пассивки → способности → CurrentHP = MaxHP. Порядок не косметика: пассивка на +MaxHP обязана примениться до инициализации CurrentHP, иначе юнит выходит в бой не с полным здоровьем. Собранный руками юнит молча получает неверное HP.

Владелец правды: Assets/_Project/Scripts/Combat/Units/RuntimeUnit.cs и RuntimeUnitFactory рядом с ним.