Protocol compatibility
This page defines how Telium servers and clients on different versions talk to each other. The rules are enforced in telium-protocol/src/compat.rs and tested in server/tests/interop.rs.
The protocol version is one integer covering the durable wire formats: the federation API (/_telium/v1/), gateway frames, migration bundles, and signed documents (identity assertions, key documents, promotion and relocation records). It is separate from the release version and from the local database format (STATE_FORMAT_VERSION, see Upgrades).
Version window
Section titled “Version window”| Constant | Value |
|---|---|
PROTOCOL_VERSION |
1 |
MIN_SUPPORTED_PROTOCOL_VERSION |
1 |
Each side advertises its window:
- Discovery:
/.well-known/telium/serverincludesprotocol: { version, min_supported, capabilities }next to the legacyprotocol_versionstring. - Server to server: every signed request carries
X-Telium-Protocol,X-Telium-Min-ProtocolandX-Telium-Capabilities. The receiver records them only after the signature verifies. - Gateway:
HELLOandREADYadvertise the server’s window. The client sends its own in theprotocolblock ofIDENTIFY.
A peer that advertises nothing is treated as version 1, minimum 1, with no capabilities. The minimum is raised only on a major release after a full deprecation cycle.
Change rules
Section titled “Change rules”Compatible, no version bump:
- Adding a field, endpoint, gateway event, error code, or an enum value whose readers ignore unknown values. A missing field must mean the old behaviour.
- Relaxing a limit, rejecting only input no correct peer sends, or local-only changes.
Incompatible, needs a bump:
- Removing, renaming or retyping a field, or changing its units, meaning or which documents count as valid.
- Changing how a signature is computed or what it covers, or the order of a multi-step protocol (such as migration grant, transfer, acknowledge, tombstone).
- Making an optional element required.
The test: a peer on the oldest version in the window must still end up with correct state.
Capabilities
Section titled “Capabilities”Prefer a capability over a version bump. The caller checks for the capability before sending and falls back when it is absent. Unknown tokens are kept as sent.
| Capability | Caller’s fallback when the peer lacks it |
|---|---|
migrate.try_again |
Read the English text of a 409 |
migrate.handoff |
Moving to that peer is not offered |
sync.sealed |
Sealed-only sync keys are not sent |
relocation.announce |
The relocation is discovered at cutover |
onboarding.recommendations |
The peer is not a recommendation target |
federation.curator_feeds |
Its feeds are not polled |
transport.relay |
No “Protect my IP” offer for that home server |
Skew reporting
Section titled “Skew reporting”Per-peer status is one of unknown (never observed, not an error), ok, peer_protocol_too_old or peer_protocol_too_new.
| Endpoint | Shows |
|---|---|
GET /_telium/v1/admin/peers |
Per-peer protocol block (status, version, min_supported, capabilities, message, remedy), plus local and an incompatible count. Incompatible peers sort first |
GET /_telium/v1/admin/peers/{origin} |
Adds local_protocol |
GET /_telium/v1/admin/status |
protocol and incompatible_peers |
The control plane’s Federation pane shows the same data.
Outside the window:
- A client’s gateway connection closes with code
4015before the token is checked. The close reason includes a remedy. - A server-to-server request gets
400with"error": "incompatible_protocol". It is not retried and does not mark the peer as down.
Fixtures
Section titled “Fixtures”server/tests/fixtures/interop/ holds v0-legacy/ (before this contract), v1/ (current) and hypothetical-v2/ (synthetic, for testing refusal). Frozen shapes are never edited; a new version adds a directory. The suite also checks that every key path an older release published is still published.
See Federation for how peer errors reach clients.