kcode_k1_daemon_lib_testkit/
lib.rs1#![forbid(unsafe_code)]
2
3const REQUIRED_LINES: &[&str] = &[
4 "kcode-k1-access = \"0.6.2\"",
5 "kcode-k1-access-audio-classifier = \"0.1.0\"",
6 "kcode-k1-access-full-audio = \"0.10.0\"",
7 "kcode-k1-access-launch-nodes = \"0.2.2\"",
8 "kcode-k1-access-persons = \"0.3.0\"",
9 "kcode-k1-access-profiles = \"0.6.2\"",
10 "kcode-k1-audio-classification = \"0.6.0\"",
11 "kcode-k1-audio-classifier = \"0.1.1\"",
12 "kcode-k1-authority-filters = \"0.2.0\"",
13 "kcode-k1-chat-service = \"0.11.0\"",
14 "kcode-k1-codex-adapter = \"0.5.3\"",
15 "kcode-k1-codex-websearch = \"0.2.0\"",
16 "kcode-k1-daemon-code-services = \"0.1.8\"",
17 "kcode-k1-daemon-http-boundary = \"0.1.1\"",
18 "kcode-k1-daemon-provider-config = \"0.2.0\"",
19 "kcode-k1-daemon-startup-error = \"0.1.1\"",
20 "kcode-k1-daemon-web-startup = \"0.1.1\"",
21 "kcode-k1-full-audio = \"0.4.0\"",
22 "kcode-k1-http-access-context = \"0.2.0\"",
23 "kcode-k1-http-access-profile-presentation = \"0.1.0\"",
24 "kcode-k1-http-audio = \"0.4.0\"",
25 "kcode-k1-http-chat = \"0.7.2\"",
26 "kcode-k1-http-kmap = \"0.1.0\"",
27 "kcode-k1-http-launch-nodes = \"0.3.0\"",
28 "kcode-k1-http-people = \"0.9.0\"",
29 "kcode-k1-http-persons = \"0.3.0\"",
30 "kcode-k1-ktool-set-launch-node = \"0.1.1\"",
31 "kcode-k1-ktool-social = \"0.1.1\"",
32 "kcode-k1-launch-nodes = \"0.4.0\"",
33 "kcode-k1-objects = \"0.2.2\"",
34 "kcode-k1-peering = \"0.3.1\"",
35 "kcode-k1-txn-ordering = \"0.5.1\"",
36 "kcode-speaker-v3-analysis = \"0.3.5\"",
37];
38
39const OBSOLETE_LINES: &[&str] = &[
40 "kcode-k1-access = \"0.6.1\"",
41 "kcode-k1-access-full-audio = \"0.9.1\"",
42 "kcode-k1-access-full-audio = \"0.9.4\"",
43 "kcode-k1-access-launch-nodes = \"0.2.0\"",
44 "kcode-k1-audio-classification = \"0.5.9\"",
45 "kcode-k1-audio-classification = \"0.5.10\"",
46 "kcode-k1-chat-service = \"0.3.0\"",
47 "kcode-k1-chat-service = \"0.6.0\"",
48 "kcode-k1-chat-service = \"0.7.0\"",
49 "kcode-k1-chat-service = \"0.8.0\"",
50 "kcode-k1-chat-service = \"0.9.0\"",
51 "kcode-k1-chat-service = \"0.10.0\"",
52 "kcode-k1-chat-service = \"0.10.1\"",
53 "kcode-k1-chat-service = \"0.10.2\"",
54 "kcode-k1-chat-service = \"0.10.3\"",
55 "kcode-k1-chat-service = \"0.10.4\"",
56 "kcode-k1-chat-service = \"0.10.5\"",
57 "kcode-k1-chat-service = \"0.10.6\"",
58 "kcode-k1-chat-service = \"0.10.7\"",
59 "kcode-k1-chat-service = \"0.10.8\"",
60 "kcode-k1-chat-service = \"0.10.9\"",
61 "kcode-k1-codex-adapter = \"0.5.0\"",
62 "kcode-k1-codex-adapter = \"0.5.1\"",
63 "kcode-k1-codex-websearch = \"0.1.0\"",
64 "kcode-k1-daemon-code-services = \"0.1.0\"",
65 "kcode-k1-daemon-code-services = \"0.1.1\"",
66 "kcode-k1-daemon-code-services = \"0.1.2\"",
67 "kcode-k1-daemon-code-services = \"0.1.3\"",
68 "kcode-k1-daemon-code-services = \"0.1.4\"",
69 "kcode-k1-daemon-code-services = \"0.1.5\"",
70 "kcode-k1-daemon-code-services = \"0.1.6\"",
71 "kcode-k1-daemon-code-services = \"0.1.7\"",
72 "kcode-k1-daemon-http-boundary = \"0.1.0\"",
73 "kcode-k1-daemon-provider-config = \"0.1.4\"",
74 "kcode-k1-daemon-provider-config = \"0.1.5\"",
75 "kcode-k1-daemon-provider-config = \"0.1.6\"",
76 "kcode-k1-daemon-startup-error = \"0.1.0\"",
77 "kcode-k1-daemon-web-startup = \"0.1.0\"",
78 "kcode-k1-full-audio = \"0.3.7\"",
79 "kcode-k1-http-audio = \"0.3.0\"",
80 "kcode-k1-http-audio = \"0.3.1\"",
81 "kcode-k1-http-chat = \"0.2.0\"",
82 "kcode-k1-http-chat = \"0.5.0\"",
83 "kcode-k1-http-chat = \"0.6.0\"",
84 "kcode-k1-http-chat = \"0.6.1\"",
85 "kcode-k1-http-chat = \"0.7.0\"",
86 "kcode-k1-http-chat = \"0.7.1\"",
87 "kcode-k1-http-launch-nodes = \"0.2.0\"",
88 "kcode-k1-ktool-set-launch-node = \"0.1.0\"",
89 "kcode-k1-ktool-social = \"0.1.0\"",
90 "kcode-k1-launch-nodes = \"0.3.0\"",
91 "kcode-k1-objects = \"0.2.1\"",
92 "kcode-k1-peering = \"0.3.0\"",
93 "kcode-k1-web-code-ktool-service = \"0.1.1\"",
94 "kcode-k1-web-http = \"0.1.0\"",
95];
96
97const REQUIRED_SOURCE: &[&str] = &[
98 "AudioClassification::open(",
99 ".shutdown()",
100 "kcode_k1_http_audio::authenticated_routes",
101 "SocialKtools::new(",
102 "SetLaunchNodeKtool::new(",
103 "let web = open(",
104 "web.router()",
105 "web.projection()",
106 "CodeServices::open(",
107 ".into_parts()",
108 "K1ChatService::open_with_social_and_set_launch_node_and_rust_code_and_web_code(",
109 "with_cause(\"daemon files\")",
110 "with_cause(\"Code services\")",
111 "redacted_stage(\"Vault\")",
112 "redacted_stage(\"Gemini API key\")",
113 "redacted_stage(\"Gemini client\")",
114];
115
116const PROHIBITED_SOURCE: &[&str] = &[
117 "audio-classification-v2",
118 "http_audio_artifacts",
119 "retry_fragment",
120 "artifact_route",
121 "open_router(",
122 "RustCodeKtoolService::new(",
123 "K1WebCodeKtoolService::new(",
124 "let chat = K1ChatService::open(",
125 "K1ChatService::open_with_social(",
126 "K1ChatService::open_with_social_and_set_launch_node(",
127 ".map_err(stage(",
128 "StartupError::Stage(",
129];
130
131pub fn verify_manifest(manifest: &str) {
132 for required in REQUIRED_LINES {
133 assert!(
134 manifest.lines().any(|line| line == *required),
135 "missing required manifest line: {required}"
136 );
137 }
138 for obsolete in OBSOLETE_LINES {
139 assert!(
140 !manifest.lines().any(|line| line == *obsolete),
141 "obsolete manifest line: {obsolete}"
142 );
143 }
144 assert!(
145 !manifest.lines().any(|line| line
146 .trim_start()
147 .starts_with("kcode-k1-http-audio-artifacts")),
148 "artifact manifest selection"
149 );
150 assert!(
151 !manifest.lines().any(|line| line.contains(" = \"=")),
152 "manifest contains an exact internal pin"
153 );
154}
155
156pub fn verify_source(source: &str) {
157 for required in REQUIRED_SOURCE {
158 assert!(
159 source.contains(required),
160 "missing required source evidence: {required}"
161 );
162 }
163 for prohibited in PROHIBITED_SOURCE {
164 assert!(
165 !source.contains(prohibited),
166 "prohibited source token: {prohibited}"
167 );
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174
175 fn good_manifest() -> String {
176 REQUIRED_LINES.join("\n")
177 }
178 fn good_source() -> &'static str {
179 "AudioClassification::open(\nservice.shutdown()\nkcode_k1_http_audio::authenticated_routes\nSocialKtools::new(\nSetLaunchNodeKtool::new(\nlet web = open(\nweb.router()\nweb.projection()\nCodeServices::open(\ncode_services.into_parts()\nK1ChatService::open_with_social_and_set_launch_node_and_rust_code_and_web_code(\nwith_cause(\"daemon files\")\nwith_cause(\"Code services\")\nredacted_stage(\"Vault\")\nredacted_stage(\"Gemini API key\")\nredacted_stage(\"Gemini client\")"
180 }
181
182 #[test]
183 fn accepts_current_inputs() {
184 verify_manifest(&good_manifest());
185 verify_source(good_source());
186 }
187
188 #[test]
189 fn rejects_missing_current_selections() {
190 for line in [
191 "kcode-k1-chat-service = \"0.11.0\"",
192 "kcode-k1-daemon-provider-config = \"0.2.0\"",
193 "kcode-k1-daemon-code-services = \"0.1.8\"",
194 "kcode-k1-daemon-startup-error = \"0.1.1\"",
195 "kcode-k1-daemon-web-startup = \"0.1.1\"",
196 "kcode-k1-objects = \"0.2.2\"",
197 ] {
198 assert!(
199 std::panic::catch_unwind(|| verify_manifest(&good_manifest().replace(line, "")))
200 .is_err()
201 );
202 }
203 }
204
205 #[test]
206 fn rejects_missing_or_prohibited_source_evidence() {
207 for evidence in REQUIRED_SOURCE {
208 assert!(
209 std::panic::catch_unwind(|| verify_source(&good_source().replace(evidence, "")))
210 .is_err()
211 );
212 }
213 for token in PROHIBITED_SOURCE {
214 assert!(
215 std::panic::catch_unwind(|| verify_source(&format!("{} {token}", good_source())))
216 .is_err()
217 );
218 }
219 }
220
221 #[test]
222 fn rejects_old_selections_artifact_package_and_exact_pins() {
223 for line in [
224 "kcode-k1-chat-service = \"0.10.9\"",
225 "kcode-k1-daemon-provider-config = \"0.1.6\"",
226 "kcode-k1-http-chat = \"0.7.1\"",
227 ] {
228 assert!(
229 std::panic::catch_unwind(|| verify_manifest(&format!(
230 "{}\n{line}",
231 good_manifest()
232 )))
233 .is_err()
234 );
235 }
236 assert!(
237 std::panic::catch_unwind(|| verify_manifest(&format!(
238 "{}\nkcode-k1-http-audio-artifacts = \"0.4.0\"",
239 good_manifest()
240 )))
241 .is_err()
242 );
243 assert!(
244 std::panic::catch_unwind(|| verify_manifest(&format!(
245 "{}\nkcode-k1-peering = \"=0.3.1\"",
246 good_manifest()
247 )))
248 .is_err()
249 );
250 }
251
252 #[test]
253 fn full_chat_constructor_does_not_match_former_names() {
254 let current =
255 "K1ChatService::open_with_social_and_set_launch_node_and_rust_code_and_web_code(";
256 assert!(!current.contains("K1ChatService::open_with_social("));
257 assert!(!current.contains("K1ChatService::open_with_social_and_set_launch_node("));
258 }
259}