cortexkit_role_classifier/lib.rs
1//! Wire contract of the `classifier/v1` role.
2//!
3//! A classifier module takes a batch of items and a set of questions, calls
4//! one hosted classifier model for each item, and returns the provider's
5//! answers untouched. It claims the role by listing [`PROVIDES`] in its
6//! manifest's `capabilities.provides` and answers every op in
7//! [`REQUIRED_OPS`].
8//!
9//! `CONTRACT.md`, next to this crate's `Cargo.toml`, is the role document:
10//! it marks every rule pinned, and says where each provider shape comes
11//! from. The types here are the wire shapes it describes:
12//!
13//! - [`describe`]: the `role.describe` answer;
14//! - [`question`]: the providers' shared question shape, used both in a
15//! `classify.run` request and in the provider request it is forwarded in;
16//! - [`request`]: the `classify.run` request and its validators;
17//! - [`reply`]: the `classify.run` reply and the provider's answer objects;
18//! - [`provider`]: the provider-side request and response;
19//! - [`identity`]: the batch body identity that decides replay versus
20//! `batch_id_reuse`;
21//! - [`errors`]: admission refusal codes, per-item error codes and classes;
22//! - `vectors` (with the `test-vectors` feature): the role's vector files,
23//! compiled in, so a module's tests can use the same bytes.
24//!
25//! The batch rules this role shares with the other model-batch roles (the
26//! error vocabulary, batch identity hashing, the image shape, the status
27//! mapping) are `cortexkit-model-batch`'s; the modules above re-export them
28//! at their `classifier/v1` paths.
29//!
30//! Maps whose key order is part of what a provider documents (questions,
31//! choice options, probabilities) are [`IndexMap`]s, so a decoded and
32//! re-encoded object keeps its order. Every enumeration a consumer decodes
33//! (question type, error class) decodes open: an unknown value is kept as a
34//! string rather than refused. Decoding is not validating: the request
35//! validators still refuse an unknown question type, which a runner can
36//! neither check nor map.
37
38#![forbid(unsafe_code)]
39
40pub mod describe;
41pub mod errors;
42pub mod identity;
43pub mod provider;
44pub mod question;
45pub mod reply;
46pub mod request;
47#[cfg(any(test, feature = "test-vectors"))]
48pub mod vectors;
49
50pub use indexmap::IndexMap;
51
52/// The role name.
53pub const ROLE: &str = "classifier";
54
55/// The only major this crate defines.
56pub const VERSION: &str = "v1";
57
58/// The capability identifier a classifier module lists in its manifest's
59/// `capabilities.provides`, and the `role` member of its `role.describe`
60/// answer.
61pub const PROVIDES: &str = "classifier/v1";
62
63/// Names of the ops a classifier module serves.
64pub mod ops {
65 /// The module's limits and every model it serves, resolved from its
66 /// catalog and routing pins. Required.
67 pub const ROLE_DESCRIBE: &str = "role.describe";
68 /// Classify a batch of items against a set of questions. Required.
69 pub const CLASSIFY_RUN: &str = "classify.run";
70}
71
72/// Ops every `classifier/v1` module serves.
73pub const REQUIRED_OPS: &[&str] = &[ops::ROLE_DESCRIBE, ops::CLASSIFY_RUN];
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn provides_is_role_slash_version() {
81 assert_eq!(PROVIDES, format!("{ROLE}/{VERSION}"));
82 }
83
84 #[test]
85 fn provides_is_a_valid_capability_identifier() {
86 assert!(subc_protocol::manifest::is_valid_capability_identifier(
87 PROVIDES
88 ));
89 }
90
91 #[test]
92 fn required_ops_are_the_role_ops() {
93 assert_eq!(REQUIRED_OPS, &["role.describe", "classify.run"]);
94 }
95}