返回 CodeWhale
exact_fleet_workflow.rs
根目录 / crates / workflow / tests / exact_fleet_workflow.rs
1 //! End-to-end vertical for an exact named Fleet at the crate boundary:
2 //! parse → attach a reusable Reasoning Router → freeze routes → router decision
3 //! → reasoning resolution → immutable Workflow snapshot.
4 //!
5 //! No live provider calls: the router's response is a fixture string.
6
7 use codewhale_workflow::{
8 CapturedReasoningRouter, CredentialReadiness, EffectiveReasoning, EffectiveReasoningSource,
9 EndpointIdentity, FleetDocument, FleetSearchRoot, FleetSnapshot, NamedFleetError,
10 PreflightedRoute, ProviderEffectiveReasoning, QualifiedFleetId, REASONING_ROUTER_DIR,
11 REASONING_ROUTER_SERVICE_KIND, ReasoningCapability, ReasoningRouterError,
12 ReasoningRouterProfile, ReasoningTier, RequestedReasoning, RouterAvailability,
13 RouterCallReasoning, RouterIdentity, bounded_routing_payload, parse_router_decision,
14 resolve_exact_member_reasoning, router_call_plan, router_system_prompt, router_user_message,
15 };
16
17 const GLM_FLEET: &str = r#"
18 name = "glm-pair"
19 description = "GLM workers with a shared GPT-5.6 Luna reasoning router"
20 schema = "exact"
21 schema_revision = 1
22 reasoning_router = "luna-low"
23
24 [[members]]
25 id = "implementer"
26 role = "builder"
27 provider = "zai"
28 model = "glm-5"
29 reasoning = "auto"
30 permissions = "read_write"
31
32 [[members]]
33 id = "auditor"
34 role = "reviewer"
35 provider = "zai"
36 model = "glm-5"
37 reasoning = "high"
38 permissions = "read_only"
39 "#;
40
41 /// The user's example: GPT-5.6 Luna, called at `low`.
42 const LUNA: &str = r#"
43 name = "luna-low"
44 schema = "reasoning_router"
45 schema_revision = 1
46 provider = "openai"
47 model = "gpt-5.6-luna"
48 call_reasoning = "low"
49 "#;
50
51 fn fleet_id(name: &str) -> QualifiedFleetId {
52 QualifiedFleetId {
53 name: name.to_string(),
54 origin: "workspace".to_string(),
55 }
56 }
57
58 fn luna() -> CapturedReasoningRouter {
59 let profile = ReasoningRouterProfile::parse(LUNA).expect("router profile");
60 CapturedReasoningRouter::from_profile(&profile, "workspace")
61 }
62
63 fn route(member: &str, provider: &str, model: &str) -> PreflightedRoute {
64 PreflightedRoute {
65 member_id: member.to_string(),
66 provider_id: provider.to_string(),
67 provider_config_id: None,
68 provider_kind: provider.to_string(),
69 declared_model: model.to_string(),
70 wire_model: model.to_string(),
71 endpoint: EndpointIdentity::from_base_url("https://api.example.test/v1"),
72 credential: CredentialReadiness::Configured,
73 capability: ReasoningCapability::tiered(),
74 }
75 }
76
77 /// A workspace holding one Fleet and one Router profile, plus its search roots.
78 fn workspace_with(fleet: &str, router: Option<&str>) -> (tempfile::TempDir, Vec<FleetSearchRoot>) {
79 let tmp = tempfile::tempdir().expect("tmp");
80 std::fs::create_dir_all(tmp.path().join("fleets")).expect("fleets dir");
81 std::fs::write(tmp.path().join("fleets/glm-pair.toml"), fleet).expect("fleet");
82 if let Some(router) = router {
83 std::fs::create_dir_all(tmp.path().join(REASONING_ROUTER_DIR)).expect("routers dir");
84 std::fs::write(
85 tmp.path().join(REASONING_ROUTER_DIR).join("luna-low.toml"),
86 router,
87 )
88 .expect("router");
89 }
90 let roots = vec![FleetSearchRoot::new("workspace", tmp.path())];
91 (tmp, roots)
92 }
93
94 #[test]
95 fn a_fleet_and_its_referenced_router_resolve_reasoning_without_moving_the_route() {
96 let (_tmp, roots) = workspace_with(GLM_FLEET, Some(LUNA));
97 let (document, id) = FleetDocument::load_by_name("glm-pair", &roots).expect("fleet loads");
98 let exact = document.exact().expect("exact");
99
100 // The Router is a *reference* to a separately saved service.
101 assert_eq!(exact.reasoning_router.as_deref(), Some("luna-low"));
102 assert!(exact.legacy_inline_router().is_none());
103
104 let (profile, router_id) =
105 ReasoningRouterProfile::load_by_name("luna-low", &roots).expect("router loads");
106 assert_eq!(router_id.qualified(), "workspace/luna-low");
107 let captured = CapturedReasoningRouter::from_profile(&profile, router_id.origin);
108
109 let snapshot = FleetSnapshot::capture(id, &document, "2026-07-26T00:00:00Z", Some(captured))
110 .expect("capture");
111
112 // Routes are frozen from the snapshot, before any reasoning resolution.
113 let member = snapshot.member("implementer").expect("member");
114 let frozen = member.route.clone();
115 assert_eq!(frozen.provider, "zai");
116 assert_eq!(frozen.model, "glm-5");
117
118 // The Router is a non-dispatchable service with no authority.
119 let router = snapshot.router().expect("router service");
120 assert_eq!(router.service_kind, REASONING_ROUTER_SERVICE_KIND);
121 assert_eq!(router.route.model, "gpt-5.6-luna");
122 assert_eq!(router.requested_call_reasoning, RouterCallReasoning::Low);
123 assert!(!router.dispatchable);
124 assert!(!router.permissions.tools);
125
126 let decision = parse_router_decision(
127 r#"```json
128 {"reasoning":"max"}
129 ```"#,
130 )
131 .expect("router decision parses");
132
133 let identity = RouterIdentity::from_captured(
134 router,
135 Some(&route("router", "openai", "gpt-5.6-luna")),
136 Some(
137 router_call_plan(
138 router.requested_call_reasoning,
139 &ReasoningCapability::tiered(),
140 )
141 .disclosure,
142 ),
143 );
144
145 let resolved = resolve_exact_member_reasoning(
146 &member.id,
147 &frozen,
148 member.requested_reasoning,
149 &ReasoningCapability::tiered(),
150 &RouterAvailability::Ready,
151 Some(&decision),
152 Some(&identity),
153 )
154 .expect("ready router resolves auto");
155
156 assert_eq!(resolved.requested(), RequestedReasoning::Auto);
157 assert_eq!(
158 resolved.effective(),
159 EffectiveReasoning::Tier(ReasoningTier::Max)
160 );
161 assert_eq!(resolved.source(), EffectiveReasoningSource::FleetRouter);
162
163 // The router's own call ran at the configured `low`, and says so.
164 let call = resolved
165 .router()
166 .expect("router identity")
167 .call
168 .as_ref()
169 .expect("call disclosure");
170 assert_eq!(call.requested, "low");
171 assert_eq!(call.effective, "low");
172
173 // The worker's provider/model did not move.
174 assert_eq!(snapshot.member("implementer").unwrap().route, frozen);
175 }
176
177 /// One saved Router profile, referenced by two different Fleets.
178 #[test]
179 fn one_router_profile_serves_two_fleets() {
180 let tmp = tempfile::tempdir().expect("tmp");
181 std::fs::create_dir_all(tmp.path().join("fleets")).expect("fleets dir");
182 std::fs::create_dir_all(tmp.path().join(REASONING_ROUTER_DIR)).expect("routers dir");
183 std::fs::write(
184 tmp.path().join(REASONING_ROUTER_DIR).join("luna-low.toml"),
185 LUNA,
186 )
187 .expect("router");
188 std::fs::write(tmp.path().join("fleets/glm-pair.toml"), GLM_FLEET).expect("first");
189 std::fs::write(
190 tmp.path().join("fleets/glm-solo.toml"),
191 GLM_FLEET.replace("name = \"glm-pair\"", "name = \"glm-solo\""),
192 )
193 .expect("second");
194 let roots = vec![FleetSearchRoot::new("workspace", tmp.path())];
195
196 let mut snapshots = Vec::new();
197 for name in ["glm-pair", "glm-solo"] {
198 let (document, id) = FleetDocument::load_by_name(name, &roots).expect("fleet loads");
199 let reference = document
200 .exact()
201 .expect("exact")
202 .reasoning_router
203 .clone()
204 .expect("router reference");
205 let (profile, router_id) =
206 ReasoningRouterProfile::load_by_name(&reference, &roots).expect("router loads");
207 snapshots.push(
208 FleetSnapshot::capture(
209 id,
210 &document,
211 "2026-07-26T00:00:00Z",
212 Some(CapturedReasoningRouter::from_profile(
213 &profile,
214 router_id.origin,
215 )),
216 )
217 .expect("capture"),
218 );
219 }
220
221 assert_eq!(
222 snapshots[0].router(),
223 snapshots[1].router(),
224 "both fleets attach the identical captured router service"
225 );
226 assert_ne!(snapshots[0].fleet(), snapshots[1].fleet());
227 assert_eq!(
228 snapshots[0].router().expect("router").qualified(),
229 "workspace/luna-low"
230 );
231 }
232
233 /// A bare Router name defined in two origins is ambiguous; a qualified origin
234 /// resolves it. Shadowing would silently change which provider sees every
235 /// routing summary.
236 #[test]
237 fn a_router_defined_in_two_origins_is_ambiguous_until_qualified() {
238 let tmp = tempfile::tempdir().expect("tmp");
239 let home = tmp.path().join("home");
240 let workspace = tmp.path().join("workspace");
241 for root in [&home, &workspace] {
242 std::fs::create_dir_all(root.join(REASONING_ROUTER_DIR)).expect("routers dir");
243 }
244 std::fs::write(
245 home.join(REASONING_ROUTER_DIR).join("luna-low.toml"),
246 LUNA.replace("gpt-5.6-luna", "gpt-5.6-luna-mini"),
247 )
248 .expect("home");
249 std::fs::write(
250 workspace.join(REASONING_ROUTER_DIR).join("luna-low.toml"),
251 LUNA,
252 )
253 .expect("workspace");
254
255 let roots = vec![
256 FleetSearchRoot::new("codewhale_home", &home),
257 FleetSearchRoot::new("workspace", &workspace),
258 ];
259
260 let err = ReasoningRouterProfile::load_by_name("luna-low", &roots)
261 .expect_err("a bare name must not be resolved by shadowing");
262 assert!(
263 matches!(err, ReasoningRouterError::AmbiguousRouter { .. }),
264 "{err:?}"
265 );
266
267 assert_eq!(
268 ReasoningRouterProfile::load_by_name("workspace/luna-low", &roots)
269 .expect("qualified")
270 .0
271 .model,
272 "gpt-5.6-luna"
273 );
274 assert_eq!(
275 ReasoningRouterProfile::load_by_name("codewhale_home/luna-low", &roots)
276 .expect("qualified")
277 .0
278 .model,
279 "gpt-5.6-luna-mini"
280 );
281 }
282
283 /// A Router may only run at `off` or `low`. `medium`/`high`/`max` are rejected,
284 /// not silently clamped — the operator must see that their setting was refused.
285 #[test]
286 fn an_expensive_router_call_tier_is_rejected_rather_than_clamped() {
287 for value in ["medium", "high", "max"] {
288 let text = LUNA.replace("\"low\"", &format!("\"{value}\""));
289 let err = ReasoningRouterProfile::parse(&text).expect_err("expensive tier");
290 assert!(
291 matches!(err, ReasoningRouterError::CallReasoningTooExpensive { .. }),
292 "value={value} err={err:?}"
293 );
294 }
295
296 // And `low` is honored end to end, never forced to `off` behind the label.
297 let profile = ReasoningRouterProfile::parse(LUNA).expect("parse");
298 let plan = router_call_plan(profile.call_reasoning, &ReasoningCapability::tiered());
299 assert_eq!(plan.tier, ReasoningTier::Low);
300 assert_eq!(plan.disclosure.effective, "low");
301 assert_eq!(plan.disclosure.provider_effective, "low");
302 }
303
304 /// A manual tier consults no Router at all.
305 #[test]
306 fn a_non_auto_member_never_consults_the_router() {
307 let document = FleetDocument::parse(GLM_FLEET).expect("parse");
308 let exact = document.exact().expect("exact");
309 let auditor = exact.member("auditor").expect("auditor");
310
311 let resolved = resolve_exact_member_reasoning(
312 &auditor.id,
313 &auditor.frozen_route(),
314 auditor.reasoning,
315 &ReasoningCapability::tiered(),
316 // Deliberately absent — an explicit tier must not need a router.
317 &RouterAvailability::Absent,
318 None,
319 None,
320 )
321 .expect("explicit tier resolves");
322
323 assert_eq!(
324 resolved.effective(),
325 EffectiveReasoning::Tier(ReasoningTier::High)
326 );
327 assert_eq!(resolved.source(), EffectiveReasoningSource::MemberExplicit);
328 assert!(resolved.router().is_none(), "no router was involved");
329 }
330
331 #[test]
332 fn an_auto_member_in_a_router_less_fleet_fails_before_work_starts() {
333 let router_less = GLM_FLEET.replace("reasoning_router = \"luna-low\"\n", "");
334 let document = FleetDocument::parse(&router_less).expect("parse");
335 let exact = document.exact().expect("exact");
336 assert!(exact.router_ref().is_none());
337
338 let member = exact.member("implementer").expect("member");
339 let err = resolve_exact_member_reasoning(
340 &member.id,
341 &member.frozen_route(),
342 member.reasoning,
343 &ReasoningCapability::tiered(),
344 &RouterAvailability::Absent,
345 None,
346 None,
347 )
348 .expect_err("auto without a router must fail closed");
349
350 let message = err.to_string();
351 assert!(message.contains("implementer"), "{message}");
352 assert!(message.contains("reasoning_router"), "{message}");
353 }
354
355 /// A Fleet that references a Router profile which is not installed cannot be
356 /// resolved — decided locally, with no provider contacted.
357 #[test]
358 fn a_missing_router_profile_is_a_local_load_failure() {
359 let (_tmp, roots) = workspace_with(GLM_FLEET, None);
360 let (document, _id) = FleetDocument::load_by_name("glm-pair", &roots).expect("fleet loads");
361 let reference = document
362 .exact()
363 .expect("exact")
364 .reasoning_router
365 .clone()
366 .expect("reference");
367
368 assert!(matches!(
369 ReasoningRouterProfile::load_by_name(&reference, &roots).expect_err("missing"),
370 ReasoningRouterError::NotFound { .. }
371 ));
372 }
373
374 #[test]
375 fn legacy_permissions_do_not_enter_the_member_snapshot() {
376 let document = FleetDocument::parse(GLM_FLEET).expect("parse");
377 let snapshot = FleetSnapshot::capture(
378 fleet_id("glm-pair"),
379 &document,
380 "2026-07-26T00:00:00Z",
381 Some(luna()),
382 )
383 .expect("capture");
384
385 let implementer = snapshot.member("implementer").expect("member");
386 let encoded = serde_json::to_value(implementer).expect("serialize member snapshot");
387 assert!(
388 encoded.get("permissions").is_none(),
389 "Fleet identity/snapshot must not own Runtime authority: {encoded}"
390 );
391 }
392
393 /// The bounded routing summary is transmitted exactly once, and the receipt's
394 /// count and hash describe exactly those bytes.
395 #[test]
396 fn the_routing_summary_is_transmitted_once_and_disclosed_without_content() {
397 let payload = bounded_routing_payload("refactor the parser in /Users/hunter/app");
398 let disclosure = payload.disclosure().clone();
399 let input = codewhale_workflow::RouterCallInput {
400 fleet: "workspace/glm-pair".to_string(),
401 member_id: "implementer".to_string(),
402 frozen: codewhale_workflow::FrozenRoute {
403 provider: "zai".to_string(),
404 model: "glm-5".to_string(),
405 },
406 payload,
407 };
408
409 let system = router_system_prompt(&input);
410 let user = router_user_message(&input);
411
412 assert!(!system.contains("refactor the parser"), "{system}");
413 assert!(!user.contains("/Users/"), "paths are redacted: {user}");
414 // The disclosed count and hash describe exactly the bytes that were sent —
415 // and the summary appears exactly once across the whole request.
416 assert_eq!(disclosure.transmitted_bytes, user.len());
417 assert_eq!(disclosure.transmitted_chars, user.chars().count());
418 assert_eq!(
419 format!("{system}\n{user}").matches(user.as_str()).count(),
420 1,
421 "the bounded summary must be transmitted once, not duplicated"
422 );
423 assert!(disclosure.redacted);
424 assert!(disclosure.redactions.contains(&"absolute_path".to_string()));
425 }
426
427 /// Legacy role-map fleets keep loading through the same store.
428 #[test]
429 fn legacy_fleet_files_still_load_through_the_same_store() {
430 let root = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
431 .join("..")
432 .join("..");
433 let (document, id) =
434 FleetDocument::load_by_name("stopship", &[FleetSearchRoot::new("workspace", root)])
435 .expect("workspace legacy fleet loads");
436
437 assert!(document.is_legacy());
438 assert_eq!(document.schema_kind(), "legacy");
439 assert_eq!(id.qualified(), "workspace/stopship");
440 let legacy = document.legacy().expect("legacy body");
441 legacy.validate_stopship_roles().expect("required roles");
442 // The stopship fixture binds release_lead to the canonical advisor role
443 // (role-only world: no saved manager member to bind).
444 assert_eq!(legacy.resolve("release_lead").unwrap(), "advisor");
445 }
446
447 /// A personal `~/.codewhale` Fleet must not silently shadow — or be shadowed
448 /// by — a project Fleet of the same name.
449 #[test]
450 fn an_exact_fleet_defined_in_two_origins_is_ambiguous_until_qualified() {
451 let tmp = tempfile::tempdir().expect("tmp");
452 let home = tmp.path().join("home");
453 let workspace = tmp.path().join("workspace");
454 for root in [&home, &workspace] {
455 std::fs::create_dir_all(root.join("fleets")).expect("fleets dir");
456 }
457 std::fs::write(
458 home.join("fleets/glm-pair.toml"),
459 GLM_FLEET.replace("model = \"glm-5\"", "model = \"glm-4\""),
460 )
461 .expect("home fleet");
462 std::fs::write(workspace.join("fleets/glm-pair.toml"), GLM_FLEET).expect("workspace fleet");
463
464 let roots = vec![
465 FleetSearchRoot::new("codewhale_home", &home),
466 FleetSearchRoot::new("workspace", &workspace),
467 ];
468
469 let err = FleetDocument::load_by_name("glm-pair", &roots)
470 .expect_err("an exact fleet must not be resolved by shadowing");
471 assert!(
472 matches!(err, NamedFleetError::AmbiguousFleet { .. }),
473 "{err:?}"
474 );
475
476 let (document, id) =
477 FleetDocument::load_by_name("workspace/glm-pair", &roots).expect("qualified load");
478 assert_eq!(id.qualified(), "workspace/glm-pair");
479 assert_eq!(
480 document
481 .exact()
482 .expect("exact")
483 .member("implementer")
484 .expect("member")
485 .model,
486 "glm-5"
487 );
488
489 let (home_document, home_id) =
490 FleetDocument::load_by_name("codewhale_home/glm-pair", &roots).expect("qualified load");
491 assert_eq!(home_id.qualified(), "codewhale_home/glm-pair");
492 assert_eq!(
493 home_document
494 .exact()
495 .expect("exact")
496 .member("implementer")
497 .expect("member")
498 .model,
499 "glm-4"
500 );
501 }
502
503 /// Legacy role maps keep their historic first-hit-wins behavior: a role map
504 /// resolves through the same profile store from either origin.
505 #[test]
506 fn legacy_fleets_in_two_origins_keep_first_hit_wins() {
507 let tmp = tempfile::tempdir().expect("tmp");
508 let home = tmp.path().join("home");
509 let workspace = tmp.path().join("workspace");
510 for root in [&home, &workspace] {
511 std::fs::create_dir_all(root.join("fleets")).expect("fleets dir");
512 }
513 std::fs::write(
514 home.join("fleets/pair.toml"),
515 "name = \"pair\"\n\n[roles]\nscout = \"home-scout\"\n",
516 )
517 .expect("home fleet");
518 std::fs::write(
519 workspace.join("fleets/pair.toml"),
520 "name = \"pair\"\n\n[roles]\nscout = \"workspace-scout\"\n",
521 )
522 .expect("workspace fleet");
523
524 let (document, id) = FleetDocument::load_by_name(
525 "pair",
526 &[
527 FleetSearchRoot::new("codewhale_home", &home),
528 FleetSearchRoot::new("workspace", &workspace),
529 ],
530 )
531 .expect("legacy collisions stay resolvable");
532
533 assert!(document.is_legacy());
534 assert_eq!(id.origin, "codewhale_home");
535 assert_eq!(
536 document.legacy().expect("legacy").resolve("scout").unwrap(),
537 "home-scout"
538 );
539 }
540
541 /// A broken file in a *shadowed* origin must not fail a legacy load that has
542 /// always worked.
543 #[test]
544 fn a_malformed_shadowed_sibling_does_not_regress_legacy_first_hit() {
545 let tmp = tempfile::tempdir().expect("tmp");
546 let home = tmp.path().join("home");
547 let workspace = tmp.path().join("workspace");
548 for root in [&home, &workspace] {
549 std::fs::create_dir_all(root.join("fleets")).expect("fleets dir");
550 }
551 std::fs::write(
552 home.join("fleets/pair.toml"),
553 "name = \"pair\"\n\n[roles]\nscout = \"home-scout\"\n",
554 )
555 .expect("home fleet");
556 std::fs::write(
557 workspace.join("fleets/pair.toml"),
558 "name = \"pair\"\n[roles\nscout = = = \"\"\"broken\n",
559 )
560 .expect("workspace fleet");
561
562 let (document, id) = FleetDocument::load_by_name(
563 "pair",
564 &[
565 FleetSearchRoot::new("codewhale_home", &home),
566 FleetSearchRoot::new("workspace", &workspace),
567 ],
568 )
569 .expect("a broken shadowed sibling must not break first-hit-wins");
570
571 assert_eq!(id.origin, "codewhale_home");
572 assert_eq!(
573 document.legacy().expect("legacy").resolve("scout").unwrap(),
574 "home-scout"
575 );
576 }
577
578 /// Roster invariants hold at the crate boundary, not just inside the parser.
579 #[test]
580 fn duplicate_roles_and_reserved_router_identities_are_rejected_at_load() {
581 let duplicate_role = GLM_FLEET.replace("role = \"reviewer\"", "role = \"builder\"");
582 assert!(
583 FleetDocument::parse(&duplicate_role).is_err(),
584 "two members must not share the role `builder`"
585 );
586
587 let worker_router = GLM_FLEET.replace("role = \"reviewer\"", "role = \"router\"");
588 assert!(
589 FleetDocument::parse(&worker_router).is_err(),
590 "a worker must not claim the reserved role `router`"
591 );
592 }
593
594 /// The legacy inline Router form still parses and normalizes into the same
595 /// captured service — one runtime representation, whichever way it was written.
596 #[test]
597 fn a_legacy_inline_router_still_works_and_normalizes() {
598 let inline = format!(
599 "{}\n[[members]]\nid = \"router\"\nkind = \"router\"\nprovider = \"zai\"\nmodel = \
600 \"glm-5-turbo\"\n",
601 GLM_FLEET.replace("reasoning_router = \"luna-low\"\n", "")
602 );
603 let document = FleetDocument::parse(&inline).expect("legacy inline parses");
604 let exact = document.exact().expect("exact");
605 let captured = codewhale_workflow::captured_legacy_inline_router(exact).expect("inline router");
606
607 assert!(captured.legacy_inline);
608 assert_eq!(captured.service_kind, REASONING_ROUTER_SERVICE_KIND);
609 assert_eq!(captured.route.model, "glm-5-turbo");
610 assert_eq!(captured.requested_call_reasoning, RouterCallReasoning::Off);
611 assert!(!captured.is_dispatchable());
612
613 let snapshot = FleetSnapshot::capture(
614 fleet_id("glm-pair"),
615 &document,
616 "2026-07-26T00:00:00Z",
617 Some(captured),
618 )
619 .expect("capture");
620 assert!(snapshot.member("router").is_none());
621 assert_eq!(snapshot.members().len(), 2);
622 }
623
624 /// The provider-effective control is reported separately from the selector
625 /// tier: a Z.AI GLM route expresses only thinking on/off, so `high` and `max`
626 /// must not be presented as two distinct provider-effective tiers.
627 #[test]
628 fn glm_receipts_do_not_invent_distinct_high_and_max_provider_tiers() {
629 let document = FleetDocument::parse(GLM_FLEET).expect("parse");
630 let exact = document.exact().expect("exact");
631 let auditor = exact.member("auditor").expect("auditor");
632 let glm = ReasoningCapability::enabled_disabled();
633
634 let high = resolve_exact_member_reasoning(
635 &auditor.id,
636 &auditor.frozen_route(),
637 RequestedReasoning::High,
638 &glm,
639 &RouterAvailability::Absent,
640 None,
641 None,
642 )
643 .expect("resolve");
644 let max = resolve_exact_member_reasoning(
645 &auditor.id,
646 &auditor.frozen_route(),
647 RequestedReasoning::Max,
648 &glm,
649 &RouterAvailability::Absent,
650 None,
651 None,
652 )
653 .expect("resolve");
654
655 assert_eq!(
656 high.provider_effective(),
657 ProviderEffectiveReasoning::Enabled
658 );
659 assert_eq!(
660 max.provider_effective(),
661 ProviderEffectiveReasoning::Enabled
662 );
663 assert_ne!(high.effective(), max.effective());
664 }
665
665 lines RUST