1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! The `/admin/v1` protocol and service boundary: how durable state is changed,
//! by whom, and under what guarantees.
//!
//! A stateful deployment has two entirely separate surfaces (ADR 0027). `/v1`
//! serves inference from an immutable snapshot and never queries the control
//! plane. `/admin/v1` — this module — is the only way desired state changes, and
//! every request on it reads or writes the control plane. The separation is the
//! availability argument: a control-plane outage stalls administration and
//! convergence while replicas keep serving.
//!
//! One path under the prefix is deliberately not this surface:
//! `GET /admin/v1/status` is the replica diagnostic, registered on the inference
//! router and authenticated with a gateway credential carrying
//! [`Capability::Status`](crate::principals::Capability::Status). It reads
//! this process's cached component states and never the control plane, which is
//! why it answers in both modes and why an inference credential is the right one
//! for it. It borrows only this module's method contract: a wrong method on it
//! answers [`AdminError::MethodNotAllowed`] rather than an empty-bodied 405.
//! Deployments that put a network boundary on the prefix have to route it with
//! the inference listener; see `docs/operations/admin-api.md`.
//!
//! | Module | Owns |
//! | --- | --- |
//! | [`error`] | the typed envelope and its closed vocabulary of stable codes |
//! | [`auth`] | administrative identity: OIDC humans, attributed breakglass, and the disjointness from inference credentials |
//! | [`protocol`] | the mutation preconditions: idempotency key, expected revision, dry run, audit summary |
//! | [`diff`] | the redacted semantic diff between two complete desired states |
//! | [`reads`] | bounded read projections: state, history, audit, convergence |
//! | [`catalogue`] | the tenant-scoped management catalogue: what a tenant has enabled, and why a model is not routable |
//! | [`resources`] | the typed request documents, and the edits they become |
//! | [`mod@secrets`] | the credential lifecycle: material in, references out, never the reverse |
//! | [`service`] | the one path a mutation takes: mode, authority, read, validate, diff, publish |
//! | [`handlers`] | the routes themselves: parse, plan, delegate |
//! | [`mod@router`] | the route table, its authentication layer, and its precondition layer |
//! | [`runtime`] | the authorities a running gateway builds, and the surface `serve` mounts |
//! | [`cli`] | `axond admin`: an HTTP client for these routes, with no second way in |
//!
//! # The five properties this slice exists to make structural
//!
//! **Stateless mode answers without a backend.** [`AdminService::stateless`]
//! holds no [`ControlPlaneStore`], so every operation is
//! [`AdminError::StatefulModeRequired`] and there is nothing to touch — not a
//! connection, not a query, not a health check.
//!
//! **Inference credentials carry no administrative authority.** There is no
//! conversion from an inference principal to an [`AdminIdentity`], the two
//! routers layer different authentication, and a presented `axt1.` token or
//! `x-api-key` is refused with [`AdminAuthError::InferenceCredential`] rather
//! than being looked up.
//!
//! **A mutation cannot skip its preconditions.** The idempotency key and the
//! expected revision are parsed by the router's layer for any mutating route and
//! required by the service, and the expected revision is checked against the head
//! before any state is hydrated.
//!
//! **A dry run has no durable effect.** It stops after validating the complete
//! candidate and computing the diff, and never calls `publish_revision`.
//!
//! **Secrets are absent by type.** Resource bodies are never rendered: a diff and
//! a state read describe a body by form, checksum, and — for a blob — digest and
//! size. Backend text stays in [`AdminError::operator_detail`], which is logged
//! and never serialized. Credentials live in a `SecretString` inside
//! [`AdminCredential`], which has no [`Debug`] rendering of its material, and no
//! error variant can hold presented material.
//!
//! # One way in
//!
//! A handler holds no store. It parses a document, resolves the scope it
//! changes, and hands an edit to [`service::AdminService`], which is the only
//! code that publishes. `axond admin` speaks the same routes over HTTP rather
//! than reaching into the domain, so the CLI cannot acquire an authority or skip
//! a precondition the API enforces.
//!
//! [`AdminCredential`]: auth::AdminCredential
//! [`AdminAuthError::InferenceCredential`]: auth::AdminAuthError::InferenceCredential
//! [`AdminIdentity`]: auth::AdminIdentity
//! [`AdminError::StatefulModeRequired`]: error::AdminError::StatefulModeRequired
//! [`AdminError::operator_detail`]: error::AdminError::operator_detail
//! [`AdminService::stateless`]: service::AdminService::stateless
//! [`ControlPlaneStore`]: crate::backends::control_plane::ControlPlaneStore
//! [`Debug`]: std::fmt::Debug
pub
// The administrative facade. `allow(unused_imports)` for the same reason
// `desired_state` needs it: this is a binary crate, and a re-export that no
// handler names *yet* is still part of the contract #143 builds against.
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;