Skip to main content

lean_ctx/core/
causal_attribution.rs

1//! Causal outcome attribution (OSS stub).
2//!
3//! Enterprise tracks which context chunks contributed to successful outcomes.
4//! OSS: no-op recording, empty chunk queries.
5
6use serde::{Deserialize, Serialize};
7use std::path::PathBuf;
8
9/// A record of a context chunk delivered to the LLM.
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ContextChunkRecord {
12    pub content_hash: String,
13    pub source: String,
14    pub token_cost: usize,
15    pub turn_provided: u64,
16}
17
18impl ContextChunkRecord {
19    pub fn new(
20        content: &str,
21        source: impl Into<String>,
22        token_cost: usize,
23        turn_provided: u64,
24    ) -> Self {
25        use std::hash::{Hash, Hasher};
26        let mut hasher = std::collections::hash_map::DefaultHasher::new();
27        content.hash(&mut hasher);
28        Self {
29            content_hash: format!("{:016x}", hasher.finish()),
30            source: source.into(),
31            token_cost,
32            turn_provided,
33        }
34    }
35}
36
37/// Outcome classification for attribution.
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub enum Outcome {
40    Success,
41    Failure,
42}
43
44/// Signal emitted when a value gate outcome is recorded.
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct OutcomeSignal {
47    pub session_id: String,
48    pub outcome: Outcome,
49    pub evidence: String,
50}
51
52/// Records a context chunk for later attribution (OSS: no-op).
53pub fn record_chunk(_session_id: &str, _chunk: ContextChunkRecord) -> Result<(), String> {
54    Ok(())
55}
56
57/// Returns chunks recorded for the session (OSS: empty).
58pub fn chunks_for_session(_session_id: &str) -> Vec<ContextChunkRecord> {
59    Vec::new()
60}
61
62/// Records a value gate outcome (OSS: no-op).
63pub fn record_outcome(_task_id: &str, _signal: OutcomeSignal) -> Result<(), String> {
64    Ok(())
65}
66
67/// Suggests context removals based on attribution data (OSS: empty).
68pub fn suggest_removals() -> Vec<String> {
69    Vec::new()
70}
71
72/// Records proxy context for attribution (OSS: no-op).
73pub fn record_proxy_context<R>(
74    _session_id: &str,
75    _request: &R,
76    _turn_provided: u64,
77) -> Result<(), String> {
78    Ok(())
79}
80
81/// Storage path resolver.
82pub struct CausalAttributor;
83
84impl CausalAttributor {
85    pub fn default_path() -> Result<PathBuf, String> {
86        let dir = dirs::data_local_dir()
87            .unwrap_or_else(|| PathBuf::from("/tmp"))
88            .join("lean-ctx");
89        Ok(dir.join("causal_attribution.jsonl"))
90    }
91}