Capsule: wire protocol
Use when adding, removing, or changing any field on a client↔server message, snapshot, or event.
Read first
- docs/design/protocol.md — full wire protocol
- §2.0 Boundary authority and guardrails
- §2.1
ClientMessage - §2.2
ServerMessage - §2.3
startpayload - §2.4
snapshotpayload (per-player, fog-filtered) - §2.4.1 Boundary inventory
- §2.5
Event(transient, one snapshot only) - §2.6 Replay playback state and vision
- §2.7 Observer analysis state
Code map
server/crates/protocol/src/lib.rs— authoritative Rust wire DTOs and compact transportserver/crates/contract/src/lib.rs— shared semantic DTOs re-exported by protocol, including start/snapshot contract records andDEFAULT_FACTION_IDserver/src/protocol.rs— server-shell adapter for typed kind conversion and legacy importsserver/crates/sim/src/protocol.rs— sim-facing adapter for typed kind conversionclient/src/protocol.js— mirror; must agree on every tag, field name, and shapeserver/src/lobby/mod.rs+client/src/config.js—PLAYER_PALETTEcross-surface mirror, guarded bynode tests/protocol_parity.mjs
Current lobby fields to remember
selectMap { map }is the host-only map selector command.lobbycarriesmap(selected stable map name) andmaps[]({name, description}catalog rows). Replay start metadata separately usesmapName.- Lab start payloads carry
labmetadata with the public lab id, operator id, role, full-world vision mode, dirty flag, and operation count. - Start payloads carry recipient-scoped
capabilitiesmetadata for shared room-time, replay-vision, and gameplay-command affordances. The client parser must not infer these from replay/dev/lab mode names. - Start payloads carry recipient-scoped
diagnosticsmetadata when projection policy enables movement-path overlays or observer analysis. Do not infer those affordances from room mode names. LobbyPlayercarriesteamId,factionId,aiProfileId?, andisSpectator; spectators are lobby members but not active match players.
Invariants
- Mirror. Every protocol change touches both files and docs/design/protocol.md in the same commit.
- Parity. Run
node tests/protocol_parity.mjsafter protocol vocabulary, compact code/slot, prediction metadata, start/snapshot/replay DTO, default faction id, or lobby palette changes. - Fog is authoritative. Anything sent per-player (entity views,
target_idtracers, death/ positional events) must be gated on visibility/ownership. Never send a player an entity or position they can’t see. See docs/design/protocol.md §2.4 and docs/design/hardening.md. - Clients are untrusted. Validate and bound everything inbound: dedupe + cap unit lists
(
MAX_UNITS_PER_COMMAND), size-limit frames, range/overflow-check placement coords. See deployment.md and docs/design/hardening.md. rts-protocoldepends only onrts-contractamong workspace crates. Kind conversion that needs rules/sim vocabulary belongs in adapter modules.
Cross-capsule triggers
- Adding a snapshot field consumed by rendering → client-ui.md.
- Changing event emission from the sim → server-sim.md.