Public: anyone can read this; the crew can change it.

forked from trevato/cs

The hub becomes the engine's: a room of any game is opened, stepped, swept and capped by one module behind the door #353

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The hub is the engine's now. `src/engine/rooms.ts` holds what `src/rooms/hub.ts` and `src/rooms/code.ts` held — the rooms one process is holding, the one clock that steps them, the snapshot cadence, the idle sweep, the silent drop, the frame ceiling, the catch-up clamp and the readable room code — and it names no `World`, no `PlayedMap` and no map name: the game arrives as a `RoomGame` and a room'…

shipped production is serving it deploy ae07c2d

opened this

The hub is the engine's now. src/engine/rooms.ts holds what src/rooms/hub.ts and src/rooms/code.ts held — the rooms one process is holding, the one clock that steps them, the snapshot cadence, the idle sweep, the silent drop, the frame ceiling, the catch-up clamp and the readable room code — and it names no World, no PlayedMap and no map name: the game arrives as a RoomGame and a room's options are the game's own opaque value, handed from the caller of Hub.open to the game's own create without being read. Every number arrives in HubOptions with no default, the limiter included, so ROOM_CAP, IDLE_MS, SILENT_MS, MESSAGE_MAX, FRAME_LIMIT, MAX_CATCHUP and the four close codes stay in src/rooms/hub.ts next to the milliseconds of CPU that argue for them. src/server.ts and src/client/main.ts changed in one import line each.

Two things to look at. The table is eleven functions, not the eight the issue counted: the hub also calls helloFor and rosterMessage — what one member is told on arrival, and who is in the room — because it is the hub that delivers both, and logSince is the eleventh. That is exactly what the hub calls today and nothing more, so the seam did not widen, but the count is worth a reviewer's eye. The room code's shape is now a written-out regular expression literal rather than new RegExp built from ALPHABET and LENGTH: a constructor call at module scope is a side effect the minifier will not drop, and scripts/cost.test.ts caught every group behind the door growing by about a hundred bytes of room code it never opens. rooms.test.ts holds the literal against the two constants character by character. The surface moved 0.7.0 → 0.8.0 (eight names arrived, none left).

src/engine/rooms.test.ts hosts a counter with seats — twenty lines of game, importing no game at all — and reads the room cap, the idle collection, the silent drop, both close codes, the catch-up clamp and one clock stepping two rooms off it. src/rooms/hub.test.ts stays as the other half: this game wired to that hub, playing a real round.

Measured over a real socket, two members in one room on this branch, five seconds of both holding W: 75 snapshots each (15.0 Hz against the 16 Hz cadence, which is the 10 ms clock's rounding), 514 bytes a snapshot, 7.5 kB/s a member, and the first snapshot 56–58 ms after the socket opened. bun run test — typecheck and 1396 tests — passes, the purity probe covers the new module, and scripts/pack.ts packs rooms.ts with the rest.

🤖 Generated with Claude Code

Closes #321

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs