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.
Security:
- roomcode PUT now requires instance ownership (any player could plant
or relocate codes on foreign private instances)
- /platformid/{accountId} requires auth (anonymous Steam/Oculus id
enumeration oracle)
- request tracing no longer captures successful /thread bodies by
default (chat messages landed unredacted in logs); opt in via
Trace__SuccessBodyPaths
- anonymous action-link renewal clamped to 720h per consume
Data integrity:
- buyPurchaseReminder upserts its objective sentinel (second purchase
threw UNIQUE after the wallet was debited)
- progression reward gift + idempotency sentinel commit in one
transaction (crash between them double-minted the reward)
- ClubPermissionsGalleryAndModeration migration defaults corrected to
the entity contract (CommentsJson '[]', ClubChatEnabled true); new
one-shot ClubChatDefaultRepair migration fixes databases that
applied the wrong defaults; bootstrap repairs '' CommentsJson rows
- admin subroom-maxplayers audit entry commits with the mutation
- account purge covers CustomAvatarItems (ownership deleted, created
items reassigned to the system account)
- duplicate photo reports ignored while one is unresolved
Stability:
- bootstrap only swallows the expected duplicate-column error; locked
databases and schema failures now fail startup instead of the first
endpoint
- clone blob write failure degrades to an empty sub-room instead of a
500 after the clone row committed
- resumed photo-feed cursor stamped DateTimeKind.Utc (Npgsql rejects
Unspecified for timestamptz)
- unreadcounts queries per requested room instead of materialising the
whole comment keyspace
Tests:
- destroys-the-probe-session template guard is case-insensitive
74/74 tests pass.
Fourteen agents worked one server file each over the audit's open findings,
re-verifying every claim against the client binary before changing anything.
Route+verb coverage against the recovered client inventory is now 474/522
(90.8%), up from 86.2% when the harness was first wired up.
Adds ClientRouteCoverageTests, which turns "are we compliant?" into a number
instead of an opinion. It reads data/client-routes-2023.tsv — every request the
2023-03-21 client can issue, recovered from the binary — and asserts each one
has a handler under the verb the client actually uses, separating "no handler"
from "handler exists, wrong verb" since those have different fixes. Remaining
gaps live in KnownGaps, which is expected to shrink and never grow.
Also fixes a real blind spot in EndpointContractDiscovery: it only collected
HttpMethodAttribute, so an action carrying a bare [Route] with no verb attribute
was invisible to it. The CDN's unity_assets handler is exactly that shape, which
had been showing up as a phantom gap.
Notable findings from this pass:
- The club permissions envelope key is literally "Type", not "MembershipType"
as the audit's suggested fix guessed. Read off the generated reader, then
cross-checked against the 2020 decompile — the int bitmask we were emitting
was wrong for BOTH client generations, not just 2023.
- Room-consumable purchase responses carry OperationResult as an OBJECT
{ Status, InventoryItem }; the scalar operation enum belongs in
BalanceUpdateResult. The base type OKHNOPLBOFP holds a single BGHBAILNNJJ,
which exposes exactly those two properties. A test asserting the old scalar
shape was corrected rather than the code.
- buyProgressionEventXpBoost blind-inserted an ObjectiveProgress row whose
(PlayerId, Key) is unique, so a second purchase of the same boost threw
"UNIQUE constraint failed" and 500'd AFTER taking the player's currency.
Now an upsert.
Agents were forbidden from faking fixes they could not complete in their own
file, and several correctly refused: club role permissions, club additional
image slots, announcement meta, MinLevel/ClubChatEnabled, currency purchase
offer ordering, and room-key image/currency columns all need new entities or
columns. Those are deliberately left for a single coherent schema change rather
than stubbed out here.
- Implemented ProgressionEventsController to handle progression event retrieval and active events.
- Created RoomConsumablesController for listing and purchasing room consumables.
- Developed RoomCurrenciesController for managing room currencies, including creation, updates, and balance retrieval.
- Added RoomEarningsDistributionsController to fetch earnings distribution data for rooms.
- Introduced ScreenShareReportsController for reporting screen share incidents.
- Established SubscriptionSeasonsController to provide current subscription season details and rewards.
- Launched UgcPurchasablesController for managing user-generated content purchasables, including bulk operations.
- Added new data entities for customization and room economy, including custom avatar items, room currencies, and UGC purchasables.
Targets Rec Room 2020.12.18 client.
Re-import after adding:
- DorkNet.ClientMod/dorknet-clientmod.json.template — config schema
the launcher's manifest-driven patcher renders into UserData/.
- tools/build-patcher-zip.ps1 — produces the dorknet-clientpatch-{key}.zip
Release asset the launcher fetches.
- .github/workflows/release.yml — auto-publishes both Release assets
on v1-december-* tag push.
Scrubbed via maintainer-side scrub-for-public.ps1: same drop rules as
the prior import, plus build-patcher-zip.ps1 added to the tools/
allow-list so it survives the scrub.