use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Provenance {
Pack,
Remote,
Distilled,
Derived,
Local,
}
impl Provenance {
pub fn as_str(self) -> &'static str {
match self {
Provenance::Pack => "pack",
Provenance::Remote => "remote",
Provenance::Distilled => "distilled",
Provenance::Derived => "derived",
Provenance::Local => "local",
}
}
pub fn from_snapshot(snapshot_json: &str) -> Self {
let Ok(value) = serde_json::from_str::<serde_json::Value>(snapshot_json) else {
return Provenance::Local;
};
let source = value
.get("source")
.and_then(serde_json::Value::as_str)
.unwrap_or("");
match source {
"pack" => Provenance::Pack,
"remote" | "sync" | "org" => Provenance::Remote,
"distiller" | "distilled" | "reflection" => Provenance::Distilled,
"staple" | "merge" | "consolidation" => Provenance::Derived,
_ => Provenance::Local,
}
}
}
pub fn trust_multiplier(provenance: Provenance, _associated: bool) -> f32 {
match provenance {
Provenance::Local | Provenance::Derived => 1.0,
Provenance::Distilled => 0.95,
Provenance::Remote => 0.90,
Provenance::Pack => 0.85,
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProvenanceGroup {
pub provenance: String,
pub total: usize,
pub associated: usize,
pub unvetted: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WriteBurst {
pub minute: String,
pub writes: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditReport {
pub groups: Vec<ProvenanceGroup>,
pub bursts: Vec<WriteBurst>,
pub total: usize,
}
pub const BURST_THRESHOLD: usize = 20;
pub fn audit(conn: &rusqlite::Connection) -> kimetsu_core::KimetsuResult<AuditReport> {
use std::collections::BTreeMap;
let mut stmt = conn.prepare(
"SELECT provenance_snapshot_json, last_useful_at, created_at
FROM memories
WHERE invalidated_at IS NULL AND superseded_by IS NULL",
)?;
let rows = stmt
.query_map([], |row| {
Ok((
row.get::<_, Option<String>>(0)?,
row.get::<_, Option<String>>(1)?,
row.get::<_, String>(2)?,
))
})?
.collect::<Result<Vec<_>, _>>()?;
let mut by_provenance: BTreeMap<Provenance, (usize, usize)> = BTreeMap::new();
let mut by_minute: BTreeMap<String, usize> = BTreeMap::new();
for (snapshot, last_useful_at, created_at) in &rows {
let provenance = Provenance::from_snapshot(snapshot.as_deref().unwrap_or("{}"));
let entry = by_provenance.entry(provenance).or_insert((0, 0));
entry.0 += 1;
if last_useful_at.is_some() {
entry.1 += 1;
}
let minute: String = created_at.chars().take(16).collect();
*by_minute.entry(minute).or_insert(0) += 1;
}
let groups = by_provenance
.into_iter()
.map(|(provenance, (total, corroborated))| ProvenanceGroup {
provenance: provenance.as_str().to_string(),
total,
associated: corroborated,
unvetted: if provenance >= Provenance::Derived {
0 } else {
total
},
})
.collect();
let mut bursts: Vec<WriteBurst> = by_minute
.into_iter()
.filter(|(_, writes)| *writes >= BURST_THRESHOLD)
.map(|(minute, writes)| WriteBurst { minute, writes })
.collect();
bursts.sort_by_key(|b| std::cmp::Reverse(b.writes));
Ok(AuditReport {
groups,
bursts,
total: rows.len(),
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_enum_ordering_is_the_trust_ordering() {
assert!(Provenance::Pack < Provenance::Remote);
assert!(Provenance::Remote < Provenance::Distilled);
assert!(Provenance::Distilled < Provenance::Derived);
assert!(Provenance::Derived < Provenance::Local);
let m = |p| trust_multiplier(p, false);
assert!(m(Provenance::Pack) < m(Provenance::Remote));
assert!(m(Provenance::Remote) < m(Provenance::Distilled));
assert!(m(Provenance::Distilled) <= m(Provenance::Derived));
assert_eq!(m(Provenance::Local), 1.0);
}
#[test]
fn unknown_provenance_reads_as_local() {
assert_eq!(Provenance::from_snapshot("{}"), Provenance::Local);
assert_eq!(Provenance::from_snapshot("not json"), Provenance::Local);
assert_eq!(
Provenance::from_snapshot(r#"{"source":"manual_cli"}"#),
Provenance::Local
);
assert_eq!(
Provenance::from_snapshot(r#"{"source":"something-from-the-future"}"#),
Provenance::Local
);
}
#[test]
fn known_sources_classify() {
for (json, expected) in [
(r#"{"source":"pack"}"#, Provenance::Pack),
(r#"{"source":"sync"}"#, Provenance::Remote),
(r#"{"source":"org"}"#, Provenance::Remote),
(r#"{"source":"distiller"}"#, Provenance::Distilled),
(r#"{"source":"staple"}"#, Provenance::Derived),
] {
assert_eq!(Provenance::from_snapshot(json), expected, "for {json}");
}
}
#[test]
fn hardening_citation_retains_origin_penalty() {
for provenance in [Provenance::Pack, Provenance::Remote, Provenance::Distilled] {
assert_eq!(
trust_multiplier(provenance, true),
trust_multiplier(provenance, false)
);
assert!(trust_multiplier(provenance, true) < 1.0);
}
}
#[test]
fn trust_never_exceeds_one() {
for provenance in [
Provenance::Pack,
Provenance::Remote,
Provenance::Distilled,
Provenance::Derived,
Provenance::Local,
] {
for corroborated in [false, true] {
let m = trust_multiplier(provenance, corroborated);
assert!(
m > 0.0 && m <= 1.0,
"{provenance:?} corroborated={corroborated} gave {m}"
);
}
}
}
fn audit_conn() -> rusqlite::Connection {
let conn = rusqlite::Connection::open_in_memory().expect("open");
crate::schema::initialize(&conn).expect("schema");
conn
}
fn insert(conn: &rusqlite::Connection, id: &str, source: &str, corroborated: bool, at: &str) {
conn.execute(
"INSERT INTO memories
(memory_id, scope, kind, text, normalized_text, confidence,
provenance_snapshot_json, created_at, last_useful_at)
VALUES (?1, 'project', 'fact', ?1, ?1, 0.9, ?2, ?3, ?4)",
rusqlite::params![
id,
format!(r#"{{"source":"{source}"}}"#),
at,
corroborated.then(|| at.to_string()),
],
)
.expect("insert");
}
#[test]
fn audit_counts_the_unvetted_external_population() {
let conn = audit_conn();
insert(
&conn,
"local-1",
"manual_cli",
false,
"2026-01-01T00:00:00Z",
);
insert(&conn, "pack-1", "pack", false, "2026-01-01T00:00:00Z");
insert(&conn, "pack-2", "pack", true, "2026-01-01T00:00:00Z");
insert(
&conn,
"distilled-1",
"distiller",
false,
"2026-01-01T00:00:00Z",
);
let report = audit(&conn).expect("audit");
assert_eq!(report.total, 4);
let group = |name: &str| {
report
.groups
.iter()
.find(|g| g.provenance == name)
.unwrap_or_else(|| panic!("missing group {name}"))
.clone()
};
assert_eq!(group("local").unvetted, 0, "nothing external to vet");
assert_eq!(group("pack").total, 2);
assert_eq!(group("pack").associated, 1);
assert_eq!(group("pack").unvetted, 2, "association is not verification");
assert_eq!(group("distilled").unvetted, 1);
}
#[test]
fn audit_flags_a_write_burst_and_ignores_ordinary_writing() {
let conn = audit_conn();
for i in 0..10 {
insert(
&conn,
&format!("slow-{i}"),
"manual_cli",
false,
&format!("2026-01-01T{:02}:00:00Z", i),
);
}
assert!(
audit(&conn).expect("audit").bursts.is_empty(),
"ordinary writing is not a burst"
);
for i in 0..BURST_THRESHOLD {
insert(
&conn,
&format!("burst-{i}"),
"pack",
false,
"2026-02-02T03:04:00Z",
);
}
let bursts = audit(&conn).expect("audit").bursts;
assert_eq!(bursts.len(), 1, "got: {bursts:?}");
assert_eq!(bursts[0].minute, "2026-02-02T03:04");
assert_eq!(bursts[0].writes, BURST_THRESHOLD);
}
#[test]
fn audit_of_an_empty_brain_is_empty_not_an_error() {
let report = audit(&audit_conn()).expect("audit");
assert_eq!(report.total, 0);
assert!(report.groups.is_empty());
assert!(report.bursts.is_empty());
}
}