sochdb_memory/
provenance.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
5pub struct TrustScore {
6 pub value: f32,
7 pub source_count: u32,
8 pub recency_factor: f32,
9 pub contradiction_penalty: f32,
10}
11
12#[derive(Debug, Clone)]
13pub struct TrustScoreConfig {
14 pub source_weight: f32,
15 pub recency_weight: f32,
16 pub contradiction_weight: f32,
17 pub half_life_secs: f64,
18}
19
20impl Default for TrustScoreConfig {
21 fn default() -> Self {
22 Self {
23 source_weight: 0.4,
24 recency_weight: 0.4,
25 contradiction_weight: 0.2,
26 half_life_secs: 86_400.0 * 30.0,
27 }
28 }
29}
30
31impl TrustScore {
32 pub fn compute(
33 cfg: &TrustScoreConfig,
34 source_count: u32,
35 t_created: u64,
36 contradiction_count: u32,
37 ) -> Self {
38 let now = std::time::SystemTime::now()
39 .duration_since(std::time::UNIX_EPOCH)
40 .map(|d| d.as_secs())
41 .unwrap_or(0);
42 let age_secs = now.saturating_sub(t_created / 1_000_000) as f64;
43 let recency = (-age_secs / cfg.half_life_secs).exp() as f32;
44 let source_factor = (source_count as f32).ln_1p().min(3.0) / 3.0;
45 let contradiction_penalty = (contradiction_count as f32 * 0.25).min(1.0);
46 let value = (cfg.source_weight * source_factor + cfg.recency_weight * recency
47 - cfg.contradiction_weight * contradiction_penalty)
48 .clamp(0.0, 1.0);
49 Self {
50 value,
51 source_count,
52 recency_factor: recency,
53 contradiction_penalty,
54 }
55 }
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct ProvenanceBundle {
60 pub episode_id: u64,
61 pub t_valid_from: u64,
62 pub t_valid_to: u64,
63 pub trust: TrustScore,
64}