Validation, errors, and conformance
Protocol validation protects routing, correlation, storage, and extension boundaries. A conforming implementation validates before it mutates state, preserves identities when a safe retry is possible, and reports malformed input without claiming more execution evidence than it has.
Identifier and stream rules
Protocol identifiers are non-empty strings with bounded length. General identifiers are at most 256 characters and use the safe character set accepted by the paired Python and TypeScript validators. Application code should treat them as opaque values, not embed authorization decisions in their spelling.
A client-provided stream key is a suffix. It may contain path separators for application organization, but it may not contain principal syntax such as : or @. The server combines the authenticated principal with that suffix. This prevents a body field from selecting a different user or tenant namespace.
Canonical user and tenant IDs have stricter UUID-based formats described in Canonical identities and authentication.
JSON and payload shape
Command parameters, targets, trace data, capture options, returned payloads, error details, and state snapshots have family-specific object requirements. Ordinary progress and result payloads may also be explicitly null or absent. JSON arrays and primitive values are not ordinary result payloads even if the handler's host language can serialize them.
Numbers and timestamps must satisfy their positive or non-negative constraints. Response sequence numbers begin at one. response.mode is exactly rpc or none. Message-family discriminators are likewise closed sets; an implementation should not silently reinterpret an unknown kind as a known one.
Reserved keys and payload references
Keys beginning with the reserved __cheetah_ namespace belong to protocol facilities. The server recursively rejects user-supplied reserved keys in command parameters, capture options, and parser definitions after Unicode NFKC normalization. Normalization prevents visually similar key spellings from bypassing the rule.
Large-payload references use an explicitly validated server-produced marker. The fact that a valid reference contains a reserved key does not permit application data to manufacture an arbitrary reserved object. Implementations should call the shared validators rather than maintaining a looser private allowlist.
Recoverable malformed return
An ordinary HTTP return can sometimes be malformed while still carrying trustworthy-enough correlation fields. When the service can safely extract and validate the principal-scoped client, runtime, stream, message, and command identities, it fences the runtime and appends a synthetic terminal malformed_message error. It notifies readers and resolves a local waiter only after that error is durably accepted by history, then raises a validation error for the host to map.
This behavior gives the application a retained terminal explanation instead of an unexplained timeout. It is not applied when identifiers cannot be recovered safely. An oversized body uses the same bounded recovery path when possible, but its raw content is redacted rather than copied into error details.
State reports use a stricter mutation rule. Platform-specific conversion and validation must succeed before history, deduplication, or topology changes. A bad report raises without a partial current-state update.
WebSocket protocol errors
Before handshake acceptance, invalid JSON, the wrong first family, malformed hello fields, unsupported version, transport mismatch, and authentication failure are explicit rejection paths. After acceptance, a malformed or unknown application frame does not become a command or change route identity. Current server implementations trace or ignore unsupported post- handshake frames according to the specific family; clients must not assume that every such mistake produces a disconnect.
The reference client validates a delivered command before acknowledgement. An identifiable invalid command produces a correlated wire_validation_error; an unidentifiable one produces wire_validation_error_unidentified on _cheetah/errors. Neither path sends an ACK.
Cross-language conformance checklist
A custom server adapter, client transport, or protocol implementation should demonstrate all of the following against the same protocol version:
- exact hello and hello-ack compatibility, including rejected version and transport posture;
- stable logical-client identity across a transport reconnect and a new runtime identity after real runtime replacement;
- command envelope validation and conversion into the normalized runtime shape;
- ACK only after valid dispatch admission and fencing to the attempted runtime;
- ordinary result validation for every kind, including null payloads and terminal errors;
- retry deduplication by message identity and response-chain deduplication by command and sequence;
- independently authenticated HTTP return and server-side principal prefixing;
- stale-instance rejection, late return after socket loss, and replacement behavior;
- complete state-report validation before any topology projection;
- rejection of nested reserved keys and malformed payload references;
- timeout, uncertain send, and recovery behavior that does not imply exactly-once execution.
Use the public TypeScript package exports and Python models and validators as executable boundaries. Do not copy one language's private source shape into another implementation and assume it is the wire contract. Focused cross-language fixtures should cover accepted messages and deliberately malformed variants, not only a happy-path JSON sample.
Compatibility discipline
Adding an optional field can still affect validators, stored history, traces, and older clients. Changing a discriminator, required field, enum, identity rule, or meaning of existing evidence requires a new explicitly supported protocol contract. During rollout, configure each server with the exact versions it actually implements and test mixed client populations before expanding the accepted set.