Решили: паспорт юнита («кто это, какой арт, чья команда») показ спрашивает у того же роутера, что
даёт кадр, — через шов IUnitDirectory. Своего словаря паспортов CombatPresenter больше не держит.
Почему: тела вне боя выходят на арену мимо симуляции, а словарь наполнялся ровно одним событием — спавном в симуляции. Альтернатива «мир регистрирует свои паспорта в презентере отдельным вызовом» отвергнута: она заводит второго владельца одного факта и требует от мира знать про показ. Директория переключается вместе с источником кадра и только вместе с ним — кадр от боя с паспортами двора нарисовал бы бой людьми из хаба.
Грабли:
- Гость в коопе всё это время оставался без видов. Паспорта у него приезжают по сети в
BattleUnitRegistry, а презентер смотрел в свой словарь, который у гостя не наполняется ничем: симуляции нет, события спавна нет.CreateViewтихо возвращалnull. Починилось попутно — единственным источником паспорта. - Каскад статов был переписан дважды.
EffectiveStatsобъявлен единственным владельцем ещё аудитом 2026-07-26, ноRuntimeUnitFactoryего не звал: у него лежала своя копия тех же четырёх шагов плюс Судьба сосуда и предметы. Свели: перегрузкаBuildзнает про сосуд и предметы, фабрика зовёт её. Иначе тела мира стали бы третьей переписью. - Привязку показа к границе боя перенести пока нельзя. Казалось естественным, чтобы
BattleBootstrapподключал ленту вLaunchBattleи отпускал вResetToWorld— точки границы у него уже есть. Но dev-бои грузятся из консоли прямо вEncounterLoader, мимо него, и остались бы без показа. Привязка живёт на всю сессию, как в шаге 1а, до рождения боевого скоупа (шаг 1б, коммит 4). - Отряд теперь материализуется в симуляции на входе в бой, а не на старте акта. Ветка
if (!HasLivingParty()) DeployParty()вLaunchBattleиз запасной стала основной. Пока показ привязан к ленте на всю сессию, арена под картой акта пуста — тела уже лежат в держателе, но их никто не спрашивает.
Владелец правды: Combat/Tape/UnitIdentity.cs, Combat/Tape/StageFrameRouter.cs,
Combat/Units/WorldBodyBuilder.cs; тесты StageFrameRouterTests.Directory_FollowsTheFrameSource,
WorldBodyBuilderTests.WorldBody_ShowsTheSameNumbersAsTheBattleUnit.