lean_ctx/core/context_kernel/
coverage_class.rs1#[derive(
5 Debug, Clone, Copy, PartialEq, Eq, Hash, Default, serde::Serialize, serde::Deserialize,
6)]
7pub enum CoverageClass {
8 FullInline,
10 #[default]
12 ContextControlled,
13 ObserveOnly,
15 Unmanaged,
17}
18
19#[derive(Debug, Clone, Copy)]
21pub struct CoverageCapabilities {
22 pub can_compress: bool,
24 pub can_route: bool,
26 pub can_cache: bool,
28 pub can_measure_output: bool,
30}
31
32pub fn detect_coverage(has_proxy: bool, has_mcp: bool, has_hooks: bool) -> CoverageClass {
34 if has_proxy {
35 CoverageClass::FullInline
36 } else if has_mcp {
37 CoverageClass::ContextControlled
38 } else if has_hooks {
39 CoverageClass::ObserveOnly
40 } else {
41 CoverageClass::Unmanaged
42 }
43}
44
45pub fn coverage_label(class: CoverageClass) -> &'static str {
47 match class {
48 CoverageClass::FullInline => "full_inline",
49 CoverageClass::ContextControlled => "context_controlled",
50 CoverageClass::ObserveOnly => "observe_only",
51 CoverageClass::Unmanaged => "unmanaged",
52 }
53}
54
55pub fn is_addressable(class: CoverageClass) -> bool {
57 matches!(
58 class,
59 CoverageClass::FullInline | CoverageClass::ContextControlled
60 )
61}
62
63pub fn capabilities(class: CoverageClass) -> CoverageCapabilities {
65 match class {
66 CoverageClass::FullInline => CoverageCapabilities {
67 can_compress: true,
68 can_route: true,
69 can_cache: true,
70 can_measure_output: true,
71 },
72 CoverageClass::ContextControlled => CoverageCapabilities {
73 can_compress: true,
74 can_route: false,
75 can_cache: true,
76 can_measure_output: false,
77 },
78 CoverageClass::ObserveOnly | CoverageClass::Unmanaged => CoverageCapabilities {
79 can_compress: false,
80 can_route: false,
81 can_cache: false,
82 can_measure_output: false,
83 },
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::{CoverageClass, capabilities, detect_coverage, is_addressable};
90
91 #[test]
92 fn detect_proxy_is_full_inline() {
93 assert_eq!(
94 detect_coverage(true, false, false),
95 CoverageClass::FullInline
96 );
97 }
98
99 #[test]
100 fn detect_mcp_only_is_context_controlled() {
101 assert_eq!(
102 detect_coverage(false, true, false),
103 CoverageClass::ContextControlled
104 );
105 }
106
107 #[test]
108 fn detect_hooks_only_is_observe_only() {
109 assert_eq!(
110 detect_coverage(false, false, true),
111 CoverageClass::ObserveOnly
112 );
113 }
114
115 #[test]
116 fn detect_nothing_is_unmanaged() {
117 assert_eq!(
118 detect_coverage(false, false, false),
119 CoverageClass::Unmanaged
120 );
121 }
122
123 #[test]
124 fn full_inline_is_addressable() {
125 assert!(is_addressable(CoverageClass::FullInline));
126 }
127
128 #[test]
129 fn unmanaged_not_addressable() {
130 assert!(!is_addressable(CoverageClass::Unmanaged));
131 }
132
133 #[test]
134 fn capabilities_full_inline_all_true() {
135 let capabilities = capabilities(CoverageClass::FullInline);
136
137 assert!(capabilities.can_compress);
138 assert!(capabilities.can_route);
139 assert!(capabilities.can_cache);
140 assert!(capabilities.can_measure_output);
141 }
142
143 #[test]
144 fn serde_roundtrip() {
145 let class = CoverageClass::ObserveOnly;
146 let serialized = serde_json::to_string(&class).unwrap();
147 let deserialized = serde_json::from_str(&serialized).unwrap();
148
149 assert_eq!(class, deserialized);
150 }
151}