Решили: «что сейчас на экране у группы» едет своим каналом (NetChannel.NodeStage) как
состояние с содержимым: вид шага плюс список строковых id вариантов. Первый шаг гость просит сам,
закрытый экран объявляется как Idle.
Почему: совместные экраны (награда, дальше лавка и улучшение) требуют у гостя ТЕХ ЖЕ вариантов, что
у хозяина, а раскат витрины случаен — второй бросок у гостя дал бы другие три реликвии. Поэтому по сети
едет результат раската, а не рецепт.
Отвергнуто поле в ActivityState: место переживает любой экран внутри себя, а шаг узла живёт
короче и несёт содержимое; состояние сравнивается целиком, и состав награды гонялся бы по проводу на
каждое движение фазы боя. Отвергнут приказ «покажи экран»: гость подключается в любой момент и
переживает потери — ему нужен ответ «что сейчас», а не история; применение состояния идемпотентно.
Грабли: равенство шага сравнивает содержимое, а не только вид. Сравнение по виду скрыло бы смену
витрины — вторая награда элитки идёт тем же шагом Reward, и гость остался бы на первой.
Перечисление NodeStageKind только дописывается: номер едет по проводу, и переставленный увёл бы гостя
на другой экран молча. Оборванный список вариантов — отказ целиком: показать один вариант из трёх
значит собрать голос за то, чего игрок не видел.
Владелец правды: Game/Session/Net/NodeStageState.cs, Game/Session/Net/HostNodeStage.cs;
тест NodeStageTests.