liminal_protocol/reason_code.rs
1//! Stable refusal reason codes, and the band map that governs who mints them.
2//!
3//! A refusal that travels back to a client carries a `u16` reason code beside
4//! its human-readable message. The code is the part a program may branch on;
5//! the message is the part a person reads. More than one crate in this
6//! workspace mints such codes, and a client that hardcodes a number cannot see
7//! which crate minted it — so the numeric space is partitioned into bands, and
8//! the partition is recorded here, beside the codes it governs.
9//!
10//! # The band map
11//!
12//! | Band | Owner | Currently minted in |
13//! | --- | --- | --- |
14//! | `0x0000`–`0x00FF` | protocol layer — parse, negotiation, auth | `ProtocolError`'s associated consts in the `liminal` crate, `crates/liminal/src/protocol/error.rs:56-72` (`0x0001`–`0x0009` in use) |
15//! | `0x0100`–`0x01FF` | server layer — channel-roster refusals | this module ([`CHANNEL_NOT_REGISTERED_CODE`], [`CHANNEL_QUIESCED_CODE`]; the rest of the band is reserved for further roster refusals) |
16//! | `0xFFFF` | the server's undifferentiated error | `SERVER_ERROR_CODE` in `liminal-server`, minted privately in four modules: `src/server/connection/apply.rs:26`, `src/server/connection/pending_reply.rs:51`, `src/server/connection/delivery.rs:45`, `src/server/connection/channel_registry.rs` |
17//!
18//! The map is the fence. Two crates minting `u16` reason codes with no shared
19//! registry collide eventually, and the collision is silent: a client reads a
20//! number that means one thing to the crate that sent it and another to the
21//! crate that documented it. A new code is minted by taking the next free value
22//! inside its layer's band and recording it in the row above; a band that has
23//! no row here has no owner and may not be minted into.
24//!
25//! Channel-roster refusals sit outside the protocol band deliberately. A name
26//! that is not on the roster is an application-layer statement about server
27//! state, not a parse, negotiation, or authentication failure; filing it under
28//! the protocol band would make that band mean nothing.
29//!
30//! The codes live in this crate rather than beside the protocol-layer consts
31//! they neighbour numerically, because `liminal-protocol` is the crate a wire
32//! client actually depends on: `liminal-sdk` requires it unconditionally and
33//! takes `liminal` only as an optional dependency, so a code minted in
34//! `liminal` — or in `liminal-server` — is a code every SDK client would
35//! otherwise hardcode as a bare literal.
36//!
37//! # Not the participant tag registry
38//!
39//! [`crate::wire::ServerDiscriminant`] also occupies `0x0100..=0x0124`, and
40//! [`crate::wire::ClientDiscriminant`] also occupies `0x0001..=0x0008`. Those
41//! are a different `u16` altogether: the discriminant field selecting a
42//! participant value inside a participant frame (see [`crate::outcome`]), not a
43//! refusal's reason code. The two registries reuse numbers without colliding
44//! because they never share a field. Nothing in the band map above governs,
45//! reserves, or constrains that registry, and nothing in that registry
46//! reserves a reason code.
47
48#[cfg(test)]
49mod band_tests;
50
51/// The named channel is not on the server's roster.
52///
53/// Reserved in the server-layer band (`0x0100`–`0x01FF`). The code is reserved
54/// for the admission decision itself: a failure raised *after* a channel was
55/// admitted is not a statement about the roster and carries the
56/// undifferentiated `0xFFFF` instead.
57pub const CHANNEL_NOT_REGISTERED_CODE: u16 = 0x0101;
58
59/// The named channel is on the roster but quiesced; the reason it was quiesced
60/// travels in the refusal's message, not in this code.
61///
62/// Reserved in the server-layer band (`0x0100`–`0x01FF`). It is a distinct code
63/// rather than a reuse of [`CHANNEL_NOT_REGISTERED_CODE`] because the two say
64/// opposite things about the roster, and rather than a fallback to `0xFFFF`
65/// because a quiesced channel would then be indistinguishable from an internal
66/// fault.
67pub const CHANNEL_QUIESCED_CODE: u16 = 0x0102;