1use super::{
2 CrpMode, HookPoint, PluginManager, ReadMode, ReadOutput, ReadTuning, SessionCache,
3 count_tokens, dedup_hook, handle_with_options_inner, kernel, protocol,
4};
5const MAX_RELAY_CONTENT_BYTES: usize = 8192;
6
7const RELAY_ELIGIBLE_MODES: &[&str] = &["map", "map:v2", "signatures", "signatures:v2"];
9
10fn relay_eligible_content(result: &ReadOutput) -> (Option<&str>, Option<&str>) {
12 let mode = result.resolved_mode.as_str();
13 if RELAY_ELIGIBLE_MODES.iter().any(|m| mode.starts_with(m))
14 && result.content.len() <= MAX_RELAY_CONTENT_BYTES
15 {
16 (Some(&result.content), Some(mode))
17 } else {
18 (None, None)
19 }
20}
21pub fn handle(cache: &mut SessionCache, path: &str, mode: &str, crp_mode: CrpMode) -> String {
23 handle_with_options(cache, path, mode, false, crp_mode, None)
24}
25
26pub fn handle_fresh(cache: &mut SessionCache, path: &str, mode: &str, crp_mode: CrpMode) -> String {
28 handle_with_options(cache, path, mode, true, crp_mode, None)
29}
30
31pub fn handle_with_task(
33 cache: &mut SessionCache,
34 path: &str,
35 mode: &str,
36 crp_mode: CrpMode,
37 task: Option<&str>,
38) -> String {
39 let mut result = handle_with_options(cache, path, mode, false, crp_mode, task);
40 kernel::enrich_with_kernel(&mut result, task);
41 result
42}
43
44pub fn handle_with_task_resolved(
46 cache: &mut SessionCache,
47 path: &str,
48 mode: &str,
49 crp_mode: CrpMode,
50 task: Option<&str>,
51) -> ReadOutput {
52 handle_with_options_resolved(
53 cache,
54 path,
55 mode,
56 false,
57 crp_mode,
58 task,
59 ReadTuning::resolve(None, &[]),
60 )
61}
62
63pub fn handle_with_task_resolved_tuned(
67 cache: &mut SessionCache,
68 path: &str,
69 mode: &str,
70 crp_mode: CrpMode,
71 task: Option<&str>,
72 aggressiveness: Option<f64>,
73 protect: &[String],
74) -> ReadOutput {
75 handle_with_options_resolved(
76 cache,
77 path,
78 mode,
79 false,
80 crp_mode,
81 task,
82 ReadTuning::resolve(aggressiveness, protect),
83 )
84}
85
86#[allow(clippy::too_many_arguments)]
89pub fn handle_with_preread(
90 cache: &mut SessionCache,
91 path: &str,
92 mode: &str,
93 fresh: bool,
94 crp_mode: CrpMode,
95 task: Option<&str>,
96 aggressiveness: Option<f64>,
97 protect: &[String],
98 preread: String,
99) -> ReadOutput {
100 handle_with_options_resolved_preread(
101 cache,
102 path,
103 mode,
104 fresh,
105 crp_mode,
106 task,
107 ReadTuning::resolve(aggressiveness, protect),
108 Some(preread),
109 )
110}
111
112pub fn handle_fresh_with_task(
114 cache: &mut SessionCache,
115 path: &str,
116 mode: &str,
117 crp_mode: CrpMode,
118 task: Option<&str>,
119) -> String {
120 handle_with_options(cache, path, mode, true, crp_mode, task)
121}
122
123pub fn handle_fresh_with_task_resolved(
125 cache: &mut SessionCache,
126 path: &str,
127 mode: &str,
128 crp_mode: CrpMode,
129 task: Option<&str>,
130) -> ReadOutput {
131 handle_with_options_resolved(
132 cache,
133 path,
134 mode,
135 true,
136 crp_mode,
137 task,
138 ReadTuning::resolve(None, &[]),
139 )
140}
141
142pub fn handle_fresh_with_task_resolved_tuned(
144 cache: &mut SessionCache,
145 path: &str,
146 mode: &str,
147 crp_mode: CrpMode,
148 task: Option<&str>,
149 aggressiveness: Option<f64>,
150 protect: &[String],
151) -> ReadOutput {
152 handle_with_options_resolved(
153 cache,
154 path,
155 mode,
156 true,
157 crp_mode,
158 task,
159 ReadTuning::resolve(aggressiveness, protect),
160 )
161}
162
163fn handle_with_options(
164 cache: &mut SessionCache,
165 path: &str,
166 mode: &str,
167 fresh: bool,
168 crp_mode: CrpMode,
169 task: Option<&str>,
170) -> String {
171 handle_with_options_resolved(
172 cache,
173 path,
174 mode,
175 fresh,
176 crp_mode,
177 task,
178 ReadTuning::resolve(None, &[]),
179 )
180 .content
181}
182
183pub(crate) fn force_fresh_env() -> bool {
186 static FORCE_FRESH: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
187 *FORCE_FRESH.get_or_init(|| {
188 std::env::var("LEAN_CTX_FORCE_FRESH").is_ok_and(|v| v == "1" || v == "true")
189 })
190}
191
192pub(crate) fn is_subagent_context() -> bool {
206 static IS_SUBAGENT: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
207 *IS_SUBAGENT.get_or_init(|| {
208 std::env::var("CURSOR_TASK_ID").is_ok_and(|v| !v.is_empty())
209 || std::env::var("CLAUDE_CODE_ENTRYPOINT")
210 .ok()
211 .as_deref()
212 .map(str::trim)
213 == Some("local-agent")
214 })
215}
216
217#[allow(clippy::fn_params_excessive_bools)]
220pub(crate) fn effective_fresh_flags(
221 fresh: bool,
222 force_fresh: bool,
223 subagent_context: bool,
224 delivery_for_subagents: bool,
225) -> (bool, bool) {
226 let effective_fresh_for_cache = fresh || force_fresh || subagent_context;
227 let effective_fresh_for_delivery =
228 fresh || force_fresh || (subagent_context && !delivery_for_subagents);
229 (effective_fresh_for_cache, effective_fresh_for_delivery)
230}
231
232pub(crate) fn effective_fresh_for_delivery(fresh: bool) -> bool {
233 let config = crate::core::config::Config::load();
234 effective_fresh_flags(
235 fresh,
236 force_fresh_env(),
237 is_subagent_context(),
238 config.ocla.delivery.delivery_for_subagents,
239 )
240 .1
241}
242
243fn handle_with_options_resolved(
244 cache: &mut SessionCache,
245 path: &str,
246 mode: &str,
247 fresh: bool,
248 crp_mode: CrpMode,
249 task: Option<&str>,
250 tuning: ReadTuning<'_>,
251) -> ReadOutput {
252 handle_with_options_resolved_preread(cache, path, mode, fresh, crp_mode, task, tuning, None)
253}
254
255fn handle_with_options_resolved_preread(
256 cache: &mut SessionCache,
257 path: &str,
258 mode: &str,
259 fresh: bool,
260 crp_mode: CrpMode,
261 task: Option<&str>,
262 tuning: ReadTuning<'_>,
263 preread: Option<String>,
264) -> ReadOutput {
265 let config = crate::core::config::Config::load();
268 let (effective_fresh_for_cache, effective_fresh_for_delivery) = effective_fresh_flags(
269 fresh,
270 force_fresh_env(),
271 is_subagent_context(),
272 config.ocla.delivery.delivery_for_subagents,
273 );
274
275 let compress_protected = mode != "raw"
276 && !mode.starts_with("lines:")
277 && crate::core::config::Config::load()
278 .proxy
279 .is_path_compress_protected(path);
280
281 let delivery_metadata = config
284 .ocla
285 .delivery_enabled()
286 .then(|| file_blake3_prefix(path))
287 .flatten();
288
289 if !effective_fresh_for_delivery
290 && !compress_protected
291 && let Some((hash, mtime)) = delivery_metadata
292 && let Some(stub) = try_cross_agent_stub(path, mode, hash, mtime)
293 {
294 return stub;
295 }
296
297 if mode == "auto" {
298 let touched: Vec<String> = cache
299 .get_all_entries()
300 .iter()
301 .map(|(p, _)| (*p).clone())
302 .collect();
303 if crate::core::relevance_gate::should_gate(path, mode, task, &touched) {
304 let meta = std::fs::metadata(path);
305 let byte_count = meta.as_ref().map_or(0, std::fs::Metadata::len);
306 let line_count = preread
307 .as_ref()
308 .map_or(0, |c| bytecount::count(c.as_bytes(), b'\n'));
309 let stub = crate::core::relevance_gate::irrelevant_stub(path, line_count, byte_count);
310 let stub_tokens = count_tokens(&stub);
311 return ReadOutput {
312 content: stub,
313 resolved_mode: "auto".into(),
314 output_tokens: stub_tokens,
315 is_cache_hit: false,
316 };
317 }
318 }
319
320 if PluginManager::has_listener("pre_read") {
321 PluginManager::fire_hook_background(HookPoint::PreRead {
322 path: path.to_string(),
323 });
324 }
325
326 if let Ok(mut bt) = crate::core::bounce_tracker::global().lock() {
327 bt.next_seq();
328 }
329 let mut result = handle_with_options_inner(
330 cache,
331 path,
332 mode,
333 effective_fresh_for_cache,
334 crp_mode,
335 task,
336 tuning,
337 preread,
338 );
339
340 if let Some(entry) = cache.get_mut(path) {
341 entry.last_mode.clone_from(&result.resolved_mode);
342 if matches!(result.resolved_mode.as_str(), "full" | "full-compact")
343 && entry.full_content_delivered
344 && result.is_cache_hit
345 && entry.bump_reread() >= crate::core::cache::full_degradation_threshold()
346 {
347 entry.full_content_delivered = false;
348 entry.reset_reread_count();
349 crate::core::auto_mode_resolver::count_source("full_delivery_degraded");
350 }
351 if !matches!(result.resolved_mode.as_str(), "full" | "full-compact") {
357 entry.full_content_delivered = false;
358 entry.reset_reread_count();
359 }
360 }
361
362 if !result.is_cache_hit
363 && let Some((hash, mtime)) = delivery_metadata
364 {
365 let line_count = cache.get(path).map_or(0, |entry| entry.line_count as u32);
366 let relay = relay_eligible_content(&result);
367 record_cross_agent_delivery(
368 path,
369 hash,
370 mtime,
371 line_count,
372 result.output_tokens,
373 relay.0,
374 relay.1,
375 );
376 }
377
378 let dedup_allowed = result
380 .resolved_mode
381 .parse::<ReadMode>()
382 .is_ok_and(|m| m.is_lossy_summary());
383 if dedup_allowed && let Some(deduped) = cache.apply_dedup(path, &result.content) {
384 let new_tokens = count_tokens(&deduped);
385 if new_tokens < result.output_tokens {
386 result.content = deduped;
387 result.output_tokens = new_tokens;
388 }
389 }
390
391 if let Some(stub) = dedup_hook::maybe_dedup(path, &result.content, mode, fresh) {
393 let stub_tokens = count_tokens(&stub);
394 if stub_tokens < result.output_tokens {
395 result.content = stub;
396 result.output_tokens = stub_tokens;
397 result.is_cache_hit = true;
398 }
399 }
400
401 crate::core::context_kernel::adaptive_hook::update_from_bounce_tracker();
403 if let Ok(mut bt) = crate::core::bounce_tracker::global().lock() {
404 let original_tokens = cache.get(path).map_or(0, |e| e.original_tokens);
405 bt.record_read(
406 path,
407 &result.resolved_mode,
408 result.output_tokens,
409 original_tokens,
410 );
411
412 let compressed = result
422 .resolved_mode
423 .parse::<ReadMode>()
424 .map_or(true, |m| m.counts_as_compressed());
425 if compressed {
426 crate::core::adaptive_thresholds::record_quality_signal(
427 path,
428 crate::core::threshold_learning::QualitySignal::CleanCompressed,
429 );
430 } else if result.resolved_mode == "full"
431 && result.output_tokens > 2000
432 && bt.bounce_rate_for_extension(path).unwrap_or(0.0) < 0.05
433 {
434 crate::core::adaptive_thresholds::record_quality_signal(
435 path,
436 crate::core::threshold_learning::QualitySignal::WastedFull,
437 );
438 }
439 }
440
441 if PluginManager::has_listener("post_compress") {
443 let original_tokens = cache.get(path).map_or(0, |e| e.original_tokens);
444 PluginManager::fire_hook_background(HookPoint::PostCompress {
445 path: path.to_string(),
446 original_tokens,
447 compressed_tokens: result.output_tokens,
448 });
449 }
450
451 {
458 let self_agent = crate::core::scent_field::scent_agent_id();
459 let scent_path = crate::core::pathutil::normalize_tool_path(path);
460 std::thread::spawn(move || {
461 crate::core::scent_field::deposit(
462 self_agent,
463 crate::core::scent_field::ScentKind::Hot,
464 &scent_path,
465 0.3,
466 );
467 });
468 }
469
470 crate::core::context_gc::maybe_gc(cache);
471
472 result
473}
474
475pub fn try_stub_hit_readonly(cache: &SessionCache, path: &str) -> Option<ReadOutput> {
486 let current_conversation = crate::core::conversation::current_conversation_id_fresh();
490 try_stub_hit_readonly_scoped(cache, path, current_conversation.as_deref())
491}
492
493pub(crate) fn try_stub_hit_readonly_scoped(
497 cache: &SessionCache,
498 path: &str,
499 current_conversation: Option<&str>,
500) -> Option<ReadOutput> {
501 let no_deg = crate::core::config::Config::load().no_degrade_effective();
502 let prof = crate::core::profiles::active_profile();
503 let force_full = no_deg
504 || (prof.read.default_mode_effective() == "full"
505 && prof.compression.crp_mode_effective() == "off");
506 let policy_allows_stub =
507 crate::server::compaction_sync::effective_cache_policy() != "safe" && !force_full;
508 if !policy_allows_stub {
509 return None;
510 }
511
512 if let Some(file_ref) = cache.get_file_ref_readonly(path) {
514 let (cached_mtime, cached_hash, line_count, delivered_conv) = {
515 let entry = cache.get(path)?;
516 (
517 entry.stored_mtime,
518 entry.hash.clone(),
519 entry.line_count,
520 entry.delivered_conversation.clone(),
521 )
522 };
523 if crate::core::cache::is_cache_entry_stale_verified(path, cached_mtime, &cached_hash)
524 || !cache.is_full_delivered(path)
525 {
526 return None;
527 }
528 if !crate::core::conversation::conversation_allows_stub(
534 current_conversation,
535 delivered_conv.as_deref(),
536 ) {
537 crate::core::cache_telemetry::record_conversation_mismatch();
538 return None;
539 }
540 let original_tokens = cache.record_cache_hit(path)?.original_tokens;
541 crate::core::telemetry::global_metrics().record_cache(true);
542 let stub = render_unchanged_stub(&file_ref, path, line_count);
543 crate::core::stats::record_reread(original_tokens.saturating_sub(stub.output_tokens));
544 return Some(stub);
545 }
546
547 let rec = crate::core::read_stub_index::lookup(path)?;
553 if crate::core::cache::is_cache_entry_stale_verified(path, rec.stored_mtime(), &rec.hash) {
554 return None;
555 }
556 if !crate::core::conversation::conversation_allows_cold_stub(
557 current_conversation,
558 rec.delivered_conversation.as_deref(),
559 ) {
560 crate::core::cache_telemetry::record_conversation_mismatch();
561 return None;
562 }
563 Some(render_unchanged_stub(&rec.file_ref, path, rec.line_count))
564}
565
566fn render_unchanged_stub(file_ref: &str, path: &str, line_count: usize) -> ReadOutput {
574 let short = protocol::shorten_path(path);
575 let out = if crate::core::protocol::meta_visible() {
576 format!(
577 "{file_ref}={short} [unchanged {line_count}L]\nUnchanged on disk. Use fresh=true to force re-read.",
578 )
579 } else {
580 format!("{file_ref}={short} [unchanged {line_count}L · fresh=true to re-read]")
581 };
582 let out = crate::core::redaction::redact_text_if_enabled(&out);
583 let sent = count_tokens(&out);
584 ReadOutput {
585 content: out,
586 resolved_mode: "full".into(),
587 output_tokens: sent,
588 is_cache_hit: true,
589 }
590}
591
592#[derive(Debug, Clone, PartialEq, Eq)]
595pub struct DeltaExplicitDecision {
596 pub mode: String,
599 pub note: Option<String>,
603}
604
605pub fn resolve_explicit_delta_mode(
627 cache: &SessionCache,
628 path: &str,
629 mode: &str,
630 explicit_mode: bool,
631 fresh: bool,
632 enabled: bool,
633) -> DeltaExplicitDecision {
634 let unchanged = DeltaExplicitDecision {
635 mode: mode.to_string(),
636 note: None,
637 };
638 if fresh
639 || !enabled
640 || !explicit_mode
641 || !(mode == "full" || mode == "full-compact" || mode.starts_with("lines:"))
642 {
643 return unchanged;
644 }
645 let Some(entry) = cache.get(path) else {
646 return unchanged;
648 };
649 let stale =
650 crate::core::cache::is_cache_entry_stale_verified(path, entry.stored_mtime, &entry.hash);
651 if stale {
652 if entry.content().is_some() {
656 return DeltaExplicitDecision {
657 mode: "diff".to_string(),
658 note: Some(format!(
659 "[delta-explicit] requested mode={mode} served as a diff: the file \
660 changed since your last read and the diff is the new information. \
661 Pass fresh=true if you need the full content re-emitted."
662 )),
663 };
664 }
665 return unchanged;
666 }
667 if mode.starts_with("lines:") && cache.is_full_delivered(path) {
671 return DeltaExplicitDecision {
672 mode: "full".to_string(),
673 note: None,
674 };
675 }
676 unchanged
677}
678
679pub(crate) fn file_blake3_prefix(path: &str) -> Option<([u8; 12], u64)> {
680 let meta = std::fs::metadata(path).ok()?;
681 let mtime = meta
682 .modified()
683 .ok()?
684 .duration_since(std::time::UNIX_EPOCH)
685 .ok()?
686 .as_secs();
687 let bytes = std::fs::read(path).ok()?;
688 let hash = blake3::hash(&bytes);
689 let full = hash.as_bytes();
690 let mut prefix = [0u8; 12];
691 prefix.copy_from_slice(&full[..12]);
692 Some((prefix, mtime))
693}
694
695pub(crate) fn try_cross_agent_stub(
696 path: &str,
697 mode: &str,
698 hash: [u8; 12],
699 mtime: u64,
700) -> Option<ReadOutput> {
701 if !crate::core::config::Config::load().ocla.delivery_enabled() {
702 return None;
703 }
704 if matches!(mode, "full" | "raw" | "diff") {
705 return None;
706 }
707 let current_agent = std::env::var("CURSOR_TASK_ID")
708 .or_else(|_| std::env::var("CLAUDECODE"))
709 .unwrap_or_else(|_| format!("local-{}", std::process::id()));
710 let current_conversation = crate::core::conversation::current_conversation_id()
711 .unwrap_or_else(|| current_agent.clone());
712 let reg = crate::core::ocla::OclaRegistry::global();
713 let record = crate::daemon_client::try_delivery_check_blocking(
714 &hash,
715 mtime,
716 path,
717 Some(¤t_agent),
718 Some(¤t_conversation),
719 )
720 .or_else(|| {
721 reg.delivery_registry.check_delivery(
722 &hash,
723 mtime,
724 path,
725 Some(¤t_agent),
726 Some(¤t_conversation),
727 )
728 })?;
729
730 let short = protocol::shorten_path(path);
731
732 if let Some(ref content) = record.relay_content {
733 let relay_mode = record.relay_mode.as_deref().unwrap_or("map");
734 let header = format!(
735 "{short} [relayed from {} · {relay_mode} · {}L]",
736 record.agent_id, record.line_count,
737 );
738 let body = format!("{header}\n{content}");
739 let tokens = count_tokens(&body);
740 reg.delivery_registry
741 .record_stub_served(&record, tokens as u64);
742 return Some(ReadOutput {
743 content: body,
744 resolved_mode: "cross-agent-relay".into(),
745 output_tokens: tokens,
746 is_cache_hit: true,
747 });
748 }
749
750 let stub = format!(
751 "{short} [cross-agent · {lines}L · read by {agent} · use fresh=true to force]",
752 lines = record.line_count,
753 agent = record.agent_id,
754 );
755 let tokens = count_tokens(&stub);
756 reg.delivery_registry
757 .record_stub_served(&record, tokens as u64);
758 Some(ReadOutput {
759 content: stub,
760 resolved_mode: "cross-agent-stub".into(),
761 output_tokens: tokens,
762 is_cache_hit: true,
763 })
764}
765
766pub(crate) fn record_cross_agent_delivery(
767 path: &str,
768 hash: [u8; 12],
769 mtime: u64,
770 line_count: u32,
771 tokens: usize,
772 relay_content: Option<&str>,
773 relay_mode: Option<&str>,
774) {
775 if !crate::core::config::Config::load().ocla.delivery_enabled() {
776 return;
777 }
778 let agent_id = std::env::var("CURSOR_TASK_ID")
779 .or_else(|_| std::env::var("CLAUDECODE"))
780 .unwrap_or_else(|_| format!("local-{}", std::process::id()));
781 let conversation_id =
782 crate::core::conversation::current_conversation_id().unwrap_or_else(|| agent_id.clone());
783 let entry = crate::core::ocla::types::DeliveryEntry {
784 blake3: hash,
785 path: path.into(),
786 line_count,
787 token_count: tokens as u64,
788 agent_id,
789 conversation_id,
790 mtime,
791 relay_content: relay_content
792 .filter(|c| c.len() <= MAX_RELAY_CONTENT_BYTES)
793 .map(str::to_string),
794 relay_mode: relay_mode.map(str::to_string),
795 };
796 crate::daemon_client::try_delivery_record_blocking(&entry);
797 let reg = crate::core::ocla::OclaRegistry::global();
798 reg.delivery_registry.record_delivery(entry);
799}
800
801#[cfg(test)]
802mod tests {
803 use super::{
804 SessionCache, effective_fresh_flags, try_cross_agent_stub, try_stub_hit_readonly_scoped,
805 };
806 use std::sync::atomic::Ordering;
807
808 #[test]
809 fn cross_agent_stub_miss_returns_none() {
810 let stub = try_cross_agent_stub("/nonexistent/file.rs", "auto", [0; 12], 0);
811 assert!(stub.is_none());
812 }
813
814 #[test]
815 fn subagent_delivery_policy_keeps_cache_fresh_but_allows_delivery_by_default() {
816 let delivery_for_subagents =
817 crate::core::config::DeliveryConfig::default().delivery_for_subagents;
818 assert!(
819 delivery_for_subagents,
820 "delivery must default to enabled for subagents"
821 );
822 let (cache_fresh, delivery_fresh) =
823 effective_fresh_flags(false, false, true, delivery_for_subagents);
824 assert!(cache_fresh, "subagent cache must remain isolated");
825 assert!(
826 !delivery_fresh,
827 "default policy must allow a cross-agent delivery lookup"
828 );
829 }
830
831 #[test]
832 fn subagent_delivery_policy_can_force_fresh_delivery() {
833 let (cache_fresh, delivery_fresh) = effective_fresh_flags(false, false, true, false);
834 assert!(cache_fresh);
835 assert!(delivery_fresh, "disabled policy must bypass delivery stubs");
836 }
837
838 #[test]
839 fn cross_agent_fallback_is_deterministic() {
840 let _lock = crate::core::data_dir::test_env_lock();
843 crate::test_env::remove_var("CURSOR_TASK_ID");
844 crate::test_env::remove_var("CLAUDECODE");
845 let id1 = std::env::var("CURSOR_TASK_ID")
846 .or_else(|_| std::env::var("CLAUDECODE"))
847 .unwrap_or_else(|_| format!("local-{}", std::process::id()));
848 let id2 = std::env::var("CURSOR_TASK_ID")
849 .or_else(|_| std::env::var("CLAUDECODE"))
850 .unwrap_or_else(|_| format!("local-{}", std::process::id()));
851 assert_eq!(id1, id2, "fallback agent ID must be deterministic");
852 assert!(!id1.contains("proc:"), "must not contain PID");
853 }
854
855 #[test]
856 fn warm_stub_hit_records_central_telemetry() {
857 let dir = tempfile::tempdir().unwrap();
858 let file = dir.path().join("telemetry-hit.rs");
859 std::fs::write(&file, "fn telemetry_hit() {}\n").unwrap();
860 let path = file.to_string_lossy();
861 let mut cache = SessionCache::new();
862 cache.store(&path, "fn telemetry_hit() {}\n");
863 cache.mark_full_delivered(&path);
864
865 let metrics = crate::core::telemetry::global_metrics();
866 let before = metrics.cache_hits.load(Ordering::Relaxed);
867 let output = try_stub_hit_readonly_scoped(&cache, &path, None);
868 let after = metrics.cache_hits.load(Ordering::Relaxed);
869
870 assert!(output.is_some(), "warm re-read must use the stub cache");
871 assert!(
872 after > before,
873 "stub cache hit must increment central telemetry"
874 );
875 }
876
877 #[test]
878 fn relay_does_not_poison_session_cache() {
879 let mut cache = SessionCache::new();
880 let path = "/tmp/test_relay_poison.rs";
881 cache.store(path, "original content");
882 assert_eq!(
883 cache
884 .get(path)
885 .map(|e| e.compressed_outputs.contains_key("cross-agent-relay")),
886 Some(false),
887 "cross-agent-relay must not exist in session cache"
888 );
889 }
890}