Решили: «что сейчас на экране у группы» едет своим каналом (NetChannel.NodeStage) как состояние с содержимым: вид шага плюс список строковых id вариантов. Первый шаг гость просит сам, закрытый экран объявляется как Idle.

Почему: совместные экраны (награда, дальше лавка и улучшение) требуют у гостя ТЕХ ЖЕ вариантов, что у хозяина, а раскат витрины случаен — второй бросок у гостя дал бы другие три реликвии. Поэтому по сети едет результат раската, а не рецепт. Отвергнуто поле в ActivityState: место переживает любой экран внутри себя, а шаг узла живёт короче и несёт содержимое; состояние сравнивается целиком, и состав награды гонялся бы по проводу на каждое движение фазы боя. Отвергнут приказ «покажи экран»: гость подключается в любой момент и переживает потери — ему нужен ответ «что сейчас», а не история; применение состояния идемпотентно.

Грабли: равенство шага сравнивает содержимое, а не только вид. Сравнение по виду скрыло бы смену витрины — вторая награда элитки идёт тем же шагом Reward, и гость остался бы на первой. Перечисление NodeStageKind только дописывается: номер едет по проводу, и переставленный увёл бы гостя на другой экран молча. Оборванный список вариантов — отказ целиком: показать один вариант из трёх значит собрать голос за то, чего игрок не видел.

Владелец правды: Game/Session/Net/NodeStageState.cs, Game/Session/Net/HostNodeStage.cs; тест NodeStageTests.