- Room roles: list the creator as Creator (255), not CoOwner (30). The
client takes the local role from the Roles list and only lets a player
edit roles below their own (Creator excepted), so the creator could not
edit Co-Owner and Creator permissions. Enforce the role ladder on the
server (RoomRoleRules), let invitees accept (PUT roles/{me} role=30) and
reject (PUT roles/{me}/invite role=0), send message Types 62/60/61, and
push RoomUpdate after every role change.
- Permissions: persist PUT subrooms/{sub}/permissions cells in a new
RoomRolePermissions table, serve them from photon_access_token (plus a
roomserver/ twin) and push PhotonAccessToken to the sub-room.
- Publish: player-owned rooms are never IsRRO on the wire; the client
hides Publish and every room setting for an RRO.
- Sub-rooms: wire SubRoomId = OrderIndex + 1 (the client will not load a
sub-room with id 0), new rooms always get a named Home sub-room, and a
startup pass repairs rooms without one.
- Instance browser: per-room Redis presence index, live players only,
private instances for the people allowed in, real IsFull.
- Room/sub-room settings: creator or accepted co-owner everywhere.
Most pushes were still shaped for the 2020 watch, so the 2023 client
parsed them as empty or dropped them without any error.
- RelationshipChanged carries the relationship row, to both players, on
friend request / accept / remove / add and on favorite / mute / ignore.
Friend requests and accepts also land in the notifications inbox.
- ModerationKick uses the client's flat moderation block, with the
reason in VoteKickReason (the only field the dialog shows).
- Bans, account deletion, password resets and second-session takeover
are a Logout with a numeric reason instead of a kick to the dorm; the
old string reason failed the client's parse.
- SubscribeToPlayers is honoured: each connection joins a presence group
per subscribed player, and presence (only presence) reaches subscribers
as well as friends. The hub allows 180 s of client silence, since the
client reconnects at most 3 times per login.
- Admin broadcast sends its text as a coach message and can start the
client's own maintenance countdown; ServerMaintenance only reads
StartsInMinutes.
- ConsumableMapping, StorefrontBalance, gift, player event, level-up,
RoomUpdate, profile-image and PlayerLeftChat pushes carry the client's
DTOs. "Join rejected" is the client's RequestGameInvite message.
Contract in docs/recroom-2023-notifications.md; push frames are checked
by NotificationContractTests through a capturing hub context.