Skip to main content

synapse_core/
audit.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use std::sync::RwLock;
5
6/// Record of an inference operation
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct InferenceRecord {
9    pub timestamp: DateTime<Utc>,
10    pub namespace: String,
11    pub strategy: String,
12    pub input_triples: usize,
13    pub inferred_triples: usize,
14    pub duplicates_skipped: usize,
15    pub sample_inferences: Vec<(String, String, String)>,
16}
17
18/// Audit trail for tracking inference operations
19pub struct InferenceAudit {
20    /// Namespace -> inference records
21    records: RwLock<HashMap<String, Vec<InferenceRecord>>>,
22    /// Maximum records per namespace
23    max_records: usize,
24}
25
26impl Default for InferenceAudit {
27    fn default() -> Self {
28        Self::new()
29    }
30}
31
32impl InferenceAudit {
33    pub fn new() -> Self {
34        Self {
35            records: RwLock::new(HashMap::new()),
36            max_records: 100,
37        }
38    }
39
40    /// Log an inference operation
41    pub fn log(&self, namespace: &str, strategy: &str, input: usize, inferred: usize, skipped: usize, samples: Vec<(String, String, String)>) {
42        let record = InferenceRecord {
43            timestamp: Utc::now(),
44            namespace: namespace.to_string(),
45            strategy: strategy.to_string(),
46            input_triples: input,
47            inferred_triples: inferred,
48            duplicates_skipped: skipped,
49            sample_inferences: samples.into_iter().take(10).collect(),
50        };
51
52        let mut records = self.records.write().unwrap();
53        let ns_records = records.entry(namespace.to_string()).or_insert_with(Vec::new);
54        
55        ns_records.push(record);
56        
57        // Trim to max records
58        if ns_records.len() > self.max_records {
59            ns_records.remove(0);
60        }
61    }
62
63    /// Get inference history for a namespace
64    pub fn get_history(&self, namespace: &str) -> Vec<InferenceRecord> {
65        let records = self.records.read().unwrap();
66        records.get(namespace).cloned().unwrap_or_default()
67    }
68
69    /// Get last inference for a namespace
70    pub fn get_last(&self, namespace: &str) -> Option<InferenceRecord> {
71        let records = self.records.read().unwrap();
72        records.get(namespace).and_then(|r| r.last().cloned())
73    }
74
75    /// Export all records as JSON
76    pub fn export_json(&self) -> String {
77        let records = self.records.read().unwrap();
78        serde_json::to_string_pretty(&*records).unwrap_or_default()
79    }
80}