liminal_server/agents/error.rs
1//! Named failures that never retain request words or credentials.
2
3/// The words an agent act takes on an exchange with no registry (ACCESS-013 R3).
4pub const NO_REGISTRY: &str =
5 "no agent registry; write [agents] (or [auth.lys.agents] on a Lys exchange)";
6
7/// The words an anonymous open seat's agent act takes (ACCESS-013 R2).
8pub const ANONYMOUS_SEAT: &str = "an anonymous seat has no station; write [open] name";
9
10/// Why an agent operation did nothing, or why its durable outcome is unknown.
11#[derive(Debug, thiserror::Error)]
12pub enum AgentError {
13 /// A deliberate act is still a draft in Lys.
14 #[error("{action} is deliberate: held by draft {draft}")]
15 Held {
16 /// The requested action.
17 action: String,
18 /// The retained draft id.
19 draft: String,
20 },
21 /// A boundary value is malformed; only the member is named.
22 #[error("agent_invalid: {0}")]
23 Invalid(&'static str),
24 /// A name has no retained record.
25 #[error("unknown_agent: {0}")]
26 Unknown(String),
27 /// A subscription names a station no one has placed (ACCESS-013 R3): the
28 /// words say who places one for another name.
29 #[error(
30 "unknown_agent: {0}; a station for another name is placed by a person \
31 (POST /admin/agents/create) or an approved draft"
32 )]
33 NoStation(String),
34 /// A retained name cannot be reused, including after retirement.
35 #[error("agent_name_taken: {0}")]
36 NameTaken(String),
37 /// An identity claim does not match the verified pass.
38 #[error("pass holder {holder} is not agent {agent}")]
39 Identity {
40 /// The verified holder, or unverified.
41 holder: String,
42 /// The claimed agent.
43 agent: String,
44 },
45 /// Another live connection holds this agent's seat. It is never taken
46 /// over or shared: the seat is released when that connection closes, or
47 /// when its peer stops answering the kernel's keepalive.
48 #[error(
49 "agent {agent} is already present on connection {connection}, held since unix ms \
50 {since_ms}; the seat frees when that connection closes or its peer stops answering \
51 keepalive (80 s), so give this client a seat of its own"
52 )]
53 Present {
54 /// The agent's name.
55 agent: String,
56 /// The incumbent connection.
57 connection: u64,
58 /// Epoch milliseconds the incumbent was admitted.
59 since_ms: u64,
60 },
61 /// A configured count or byte bound is reached.
62 #[error("auth.lys.agents.{bound}: limit {limit}, count {count}")]
63 Bound {
64 /// The configuration member.
65 bound: &'static str,
66 /// The configured limit.
67 limit: usize,
68 /// The measured population or byte count.
69 count: usize,
70 },
71 /// The state machine does not admit this event.
72 #[error("agent_transition_refused: {0}")]
73 Transition(&'static str),
74 /// A draft id is already bound to different immutable words.
75 #[error("agent_draft_digest_mismatch")]
76 DraftMismatch,
77 /// Only the server writes presence and state.
78 #[error("agent_subject_server_owned: {0}")]
79 ServerOwned(String),
80 /// A lock or store failed; request bodies are never included.
81 #[error("agent_registry_unavailable: {0}")]
82 Store(String),
83 /// A write may have committed; reopen before making another decision.
84 #[error("agent_registry_outcome_unknown: reopen the store before admission")]
85 Uncertain,
86 /// The library refused delivery, with no body retained in the error.
87 #[error("agent_delivery_failed: {0}")]
88 Delivery(&'static str),
89}