use std::sync::Mutex;
use sha2::{Digest, Sha256};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CacheKey(pub String);
impl CacheKey {
#[must_use]
pub fn from_prefix(prefix: &str) -> Self {
let mut hasher = Sha256::new();
hasher.update(prefix.as_bytes());
let digest = hasher.finalize();
Self(format!("{digest:x}"))
}
#[must_use]
pub fn as_hex(&self) -> &str {
&self.0
}
}
pub const EXPLICIT_TRUST_INSTRUCTION: &str = "\
Do NOT re-run discovery. The following pre-computed helper output is \
authoritative; trust it.";
#[must_use]
pub fn build_shared_prefix(pipeline_variant: &str, system_prompt: &str) -> String {
format!(
"[SYSTEM] You are an ingest assistant for the v0.7.0 multi-step ingest \
substrate (variant={pipeline_variant}). {system_prompt}\n\
[TRUST INSTRUCTION] {EXPLICIT_TRUST_INSTRUCTION}\n"
)
}
#[derive(Debug, Default)]
pub struct PromptCacheTelemetry {
keys: Mutex<Vec<CacheKey>>,
}
impl PromptCacheTelemetry {
#[must_use]
pub fn new() -> Self {
Self {
keys: Mutex::new(Vec::new()),
}
}
pub fn record(&self, key: CacheKey) {
if let Ok(mut g) = self.keys.lock() {
g.push(key);
}
}
#[must_use]
pub fn snapshot(&self) -> Vec<CacheKey> {
self.keys.lock().map(|g| g.clone()).unwrap_or_default()
}
#[must_use]
pub fn all_keys_match(&self) -> bool {
let snap = self.snapshot();
match snap.split_first() {
None => true,
Some((first, rest)) => rest.iter().all(|k| k == first),
}
}
#[must_use]
pub fn len(&self) -> usize {
self.snapshot().len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cache_key_is_deterministic_for_same_prefix() {
let a = CacheKey::from_prefix("hello world");
let b = CacheKey::from_prefix("hello world");
assert_eq!(a, b);
assert_eq!(a.as_hex().len(), 64);
}
#[test]
fn cache_key_differs_for_different_prefixes() {
let a = CacheKey::from_prefix("hello");
let b = CacheKey::from_prefix("world");
assert_ne!(a, b);
}
#[test]
fn shared_prefix_includes_trust_instruction_verbatim() {
let prefix = build_shared_prefix("two_phase", "Summarise.");
assert!(
prefix.contains(EXPLICIT_TRUST_INSTRUCTION),
"prefix must carry the explicit-trust instruction"
);
assert!(prefix.contains("variant=two_phase"));
}
#[test]
fn shared_prefix_differs_per_variant() {
let a = build_shared_prefix("two_phase", "Same.");
let b = build_shared_prefix("four_step", "Same.");
assert_ne!(a, b);
assert_ne!(CacheKey::from_prefix(&a), CacheKey::from_prefix(&b));
}
#[test]
fn telemetry_all_keys_match_holds_for_empty_and_single() {
let t = PromptCacheTelemetry::new();
assert!(t.all_keys_match(), "empty telemetry trivially matches");
t.record(CacheKey::from_prefix("a"));
assert!(t.all_keys_match(), "single record trivially matches");
}
#[test]
fn telemetry_detects_drift_across_records() {
let t = PromptCacheTelemetry::new();
t.record(CacheKey::from_prefix("a"));
t.record(CacheKey::from_prefix("b"));
assert!(!t.all_keys_match(), "differing keys should fail the check");
assert_eq!(t.len(), 2);
}
#[test]
fn telemetry_matches_when_every_record_is_identical() {
let t = PromptCacheTelemetry::new();
let key = CacheKey::from_prefix("shared");
t.record(key.clone());
t.record(key.clone());
t.record(key);
assert!(t.all_keys_match());
assert_eq!(t.len(), 3);
}
}