Skip to main content

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//! Maps whose key order is part of what a provider documents (questions,
26//! choice options, probabilities) are [`IndexMap`]s, so a decoded and
27//! re-encoded object keeps its order. Every enumeration a consumer decodes
28//! (question type, error class) decodes open: an unknown value is kept as a
29//! string rather than refused. Decoding is not validating: the request
30//! validators still refuse an unknown question type, which a runner can
31//! neither check nor map.
32
33#![forbid(unsafe_code)]
34
35pub mod describe;
36pub mod errors;
37pub mod identity;
38pub mod provider;
39pub mod question;
40pub mod reply;
41pub mod request;
42#[cfg(any(test, feature = "test-vectors"))]
43pub mod vectors;
44
45pub use indexmap::IndexMap;
46
47/// The role name.
48pub const ROLE: &str = "classifier";
49
50/// The only major this crate defines.
51pub const VERSION: &str = "v1";
52
53/// The capability identifier a classifier module lists in its manifest's
54/// `capabilities.provides`, and the `role` member of its `role.describe`
55/// answer.
56pub const PROVIDES: &str = "classifier/v1";
57
58/// Names of the ops a classifier module serves.
59pub mod ops {
60    /// The module's limits and every model it serves, resolved from its
61    /// catalog and routing pins. Required.
62    pub const ROLE_DESCRIBE: &str = "role.describe";
63    /// Classify a batch of items against a set of questions. Required.
64    pub const CLASSIFY_RUN: &str = "classify.run";
65}
66
67/// Ops every `classifier/v1` module serves.
68pub const REQUIRED_OPS: &[&str] = &[ops::ROLE_DESCRIBE, ops::CLASSIFY_RUN];
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn provides_is_role_slash_version() {
76        assert_eq!(PROVIDES, format!("{ROLE}/{VERSION}"));
77    }
78
79    #[test]
80    fn provides_is_a_valid_capability_identifier() {
81        assert!(subc_protocol::manifest::is_valid_capability_identifier(
82            PROVIDES
83        ));
84    }
85
86    #[test]
87    fn required_ops_are_the_role_ops() {
88        assert_eq!(REQUIRED_OPS, &["role.describe", "classify.run"]);
89    }
90}