Решили: гость получает состояние забега снимком, а команды только отправляет хосту. Своего держателя, лога команд и обработчика у него нет вовсе.

Почему: очевидной альтернативой было «гость применяет тот же лог команд у себя» — красиво на бумаге и ровно так описан реконнект («снимок плюс хвост»). Но сегодня четыре транзакции идут мимо шины (TrySpendGold, TryAddRelic, TrySpendRestart, IncreaseCapacity — они отвечают «вышло ли» синхронно, и их переезд это отложенный шаг транзакций, ТЗ кооп-вертикали §10). Применяющий лог гость потерял бы ровно эти изменения — и узнал бы об этом не сразу, а через час игры, разъехавшимся золотом. Снимок же несёт состояние целиком и мимо шины проехать не может по устройству.

Вторая причина — это уже принятая у нас модель: гость не тикает симуляцию, а смотрит ленту. Забег устроен так же, и одинаковость тут дороже экономии трафика.

Цена названа честно: снимок уезжает целиком на каждое изменение, это несколько килобайт. Дельта имела бы смысл при десятках снимков в секунду, а их единицы за узел.

Снимок уходит там же, где пишется сейв. Точки совпадают намеренно: гость получает ровно то, что легло бы на диск, поэтому «у нас разные состояния» и «состояние разошлось с сейвом» — один баг, а не два. Отсюда же общий владелец правил сериализации SaveJson: вторая копия настроек Newtonsoft разошлась бы молча, а без конвертера Vector2 сериализатор вообще уходит в рекурсию — то есть вешал бы отправку на первой позиции слота.

Грабли: роль выбирает состав — значит наружу из сеанса торчат два контракта, и оба пришлось назвать отдельно (ISessionRunCommands, ISessionRunState). Причина не в красоте: под теми же интерфейсами в корне стоят вечные роутеры, и спроси роутер свой же интерфейс — резолв ушёл бы вверх по контейнеру и вернулся к нему самому.

Вторые грабли, стоившие прогона: Enum.IsDefined для байтового перечисления бросает на int — приведение к (int) в проверке вида команды роняло разбор целиком.

Владелец правды: Game/Session/Net/ (GuestRunState, RemoteRunCommands, RunStateBroadcast, кодеки), тест GuestRunSyncTests.