Versioning¶
The real-time protocol is versioned at the subprotocol level and evolved additively at the event level. This page defines compatibility rules, breaking-change policy, deprecation, and event evolution.
Reference: protocol.md · connection.md
Protocol versions¶
The protocol version is negotiated during the handshake via the Sec-WebSocket-Protocol header.
| Subprotocol | Meaning | Status |
|---|---|---|
websocket.v1 | Current protocol version. | Active — use this. |
auction-room.v1 | Legacy auction room protocol. | Accepted for backward compatibility. |
The server accepts websocket.v1 and auction-room.v1. Both may be combined with bearer.<token>:
Negotiation behaviour¶
- The server echoes a supported protocol in the 101 response.
- If the client offers only unknown protocols, the upgrade fails.
- The client must keep sending a supported protocol; a future
websocket.v2will not be accepted by a server that only supportsv1.
Version compatibility¶
Compatibility is defined as follows:
| Change | Compatible? | Policy |
|---|---|---|
| New event type (client or server) | ✅ additive | Old clients ignore unknown server events; the server rejects unknown client events with BAD_REQUEST. |
New optional field in data | ✅ additive | Validators accept extra fields; missing optional fields are fine. |
| New optional envelope field | ✅ additive | Base envelope ignores unknown top-level keys. |
| New permission | ✅ additive | Existing role permission sets grow; old clients unaffected. |
| Changed required fields / renamed events | ❌ breaking | Requires a new protocol version. |
| Changed error codes | ❌ breaking | Requires a new protocol version or a documented migration window. |
| Removed event | ❌ breaking | Deprecate first; remove only in the next major protocol. |
Guiding rule: the server never removes or reshapes a documented event within the same protocol version.
Breaking changes¶
A change is breaking when it can break an existing client:
- removing or renaming an event
type; - making a previously optional field required;
- changing the semantics or units of a field;
- changing an error code or close code meaning;
- reducing a rate limit below client-negotiated expectations;
- changing authentication transport.
How breaking changes are shipped¶
- Introduce the new behaviour behind a new subprotocol (e.g.
websocket.v2). - Keep
websocket.v1functional for the full deprecation window. - Publish migration guides and a cutover date in release notes.
- Remove the legacy version only after the window closes (see Deprecation).
Deprecation policy¶
| Phase | Client behaviour | Server behaviour |
|---|---|---|
| Additive | No action. | Ships new fields/events; old ones unchanged. |
| Deprecation notice | Schedule migration. | Old behaviour still works; logs may flag usage; docs mark it Deprecated. |
| Soft removal | Must migrate. | Old events return a BAD_REQUEST with a deprecation message, or are gated. |
| Hard removal | Upgrade required. | Legacy subprotocol removed from negotiation; old events removed. |
Minimum deprecation window: one major release cycle (announced at least 90 days ahead in the changelog) for public API events.
Event evolution¶
Event evolution follows strict rules to keep both directions safe:
Client → Server (commands)¶
- Additions: new event types, new optional fields, new permissions.
- Deletions: never within a version.
- Field changes: additive only; changing
datashape requires a new version.
Server → Client (pushes)¶
- Additions: new event types are safe — clients must ignore unknown types.
- Payloads: additive fields are safe; removing/renaming requires a new version.
- Clients must treat unknown event types as ignorable but still recover state from the next
auction.snapshot.
Aliased / documented names¶
The documentation lists names such as auction.updated, auction.ended, auction.bid.created, presence.update that map to canonical server events (auction.status_changed, auction.closed, bid.created, presence.changed). These aliases are part of the documented contract, not separate wire events; if a canonical event name ever changes, the alias table in events/auction.md and events/presence.md is updated at the same time.
Request/response versioning¶
- The envelope itself is versioned by the subprotocol; there is no per-message version field.
- A
requestIdis never reused to mean different things across versions. - New envelope fields (like
timestamp) are additive and optional.
Snapshot/replay as a versioning safety net¶
Because clients can always recover from auction.snapshot + lastSequence replay, a dropped or re-shaped server event does not leave a client permanently out of sync. This makes many otherwise-risky event evolutions safe within a version — provided the snapshot schema itself remains compatible.
Release cadence¶
- Additive changes: shipped continuously; no client action required.
- Breaking changes: coordinated through a new subprotocol and a scheduled deprecation window; announced in the changelog and migration guide.
- Removal: only after the deprecation window, with usage telemetry showing legacy clients have migrated.
Related documents¶
- connection.md — subprotocol negotiation.
- protocol.md — envelope and event naming.
- events/auction.md — alias mapping.
- lifecycle.md — reconnect and replay recovery.