Решили: StateChanged кооп-сессии означает «изменилось то, что видит экран», а не «изменилось State». Лобби Steam сообщает о себе тем же событием.

Почему: «Пригласить друга» гасла навсегда, а после перезахода на экран оживала. Причина в порядке: CreateLobby возвращается сразу, лобби приходит от Steam кадры спустя, а сессия становится Hosting раньше него. Экран перечитывает состояние только по StateChanged — то есть ровно один раз, в момент, когда CanInvite ещё честно false. Второго повода перерисоваться не существовало.

Отвергли отдельное событие «доступность приглашения изменилась»: экран спрашивает у сессии четыре вещи, и заводить событие на каждую — это четыре подписки ради одного Refresh(). Событие о том, что пора перерисоваться, здесь честнее, и в интерфейсе так и написано.

Сказано: «Я поднял сессию и кнопка “пригласить друга не стала активной, а при перезаходе - стала, найди баг» (03.08.2026, сессия 272cfad5).

Грабли: событие LobbyEntered в SteamLobbyService существовало, но его никто не слушал — то есть починка выглядела как «подписаться на готовое», а на деле рядом лежал мёртвый код. Заменено на LobbyChanged, которое стреляет ровно на смену наличия лобби: создатель входит в собственное лобби, и Steam сообщает об одном событии дважды. Правка лобби собрана в одну точку (SetLobby), чтобы состояние и событие не могли разъехаться.

Инвариант тестом здесь не закрыт, и это названо намеренно: CoopSession принимает SteamNetTransport и SteamLobbyService конкретными типами, поэтому собрать её в EditMode без запущенного Steam нельзя. Проверяется живым тестом вдвоём (docs/coop-two-machines-checklist.md, шаг 1).

Владелец правды: SteamLobbyService.cs, CoopSession.cs, ICoopSessionControl.cs.