provenance: convert from enum to freeform string

The Provenance enum couldn't represent agents defined outside the
source code. Replace it with a Text field in the capnp schema so any
agent can write its own provenance label (e.g. "extractor:write",
"rename:tombstone") without a code change.

Schema: rename old enum fields to provenanceOld, add new Text
provenance fields. Old enum kept for reading legacy records.
Migration: from_capnp_migrate() falls back to old enum when the
new text field is empty.

Also adds `poc-memory tail` command for viewing recent store writes.

Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-03-11 01:19:52 -04:00
parent de204e3075
commit d76b14dfcd
14 changed files with 160 additions and 67 deletions

View file

@ -217,7 +217,7 @@ impl DepthDb {
pub fn save(&self, store: &mut Store) {
if let Ok(json) = serde_json::to_string(&self.depths) {
store.upsert_provenance(DEPTH_DB_KEY, &json,
store::Provenance::AgentKnowledgeObservation).ok();
"observation:write").ok();
}
}
@ -295,12 +295,11 @@ pub fn apply_action(
timestamp: &str,
depth: i32,
) -> bool {
let provenance = agent_provenance(agent);
match &action.kind {
ActionKind::WriteNode { key, content, .. } => {
let stamped = stamp_content(content, agent, timestamp, depth);
store.upsert_provenance(key, &stamped, provenance).is_ok()
let prov = format!("{}:write", agent);
store.upsert_provenance(key, &stamped, &prov).is_ok()
}
ActionKind::Link { source, target } => {
if has_edge(store, source, target) {
@ -320,15 +319,17 @@ pub fn apply_action(
0.3,
source, target,
);
rel.provenance = provenance;
rel.provenance = format!("{}:link", agent);
store.add_relation(rel).is_ok()
}
ActionKind::Refine { key, content } => {
let stamped = stamp_content(content, agent, timestamp, depth);
store.upsert_provenance(key, &stamped, provenance).is_ok()
let prov = format!("{}:refine", agent);
store.upsert_provenance(key, &stamped, &prov).is_ok()
}
ActionKind::Demote { key } => {
if let Some(node) = store.nodes.get_mut(key) {
node.provenance = format!("{}:demote", agent);
node.weight = (node.weight * 0.5).max(0.05);
true
} else {
@ -338,13 +339,13 @@ pub fn apply_action(
}
}
fn agent_provenance(agent: &str) -> store::Provenance {
fn agent_provenance(agent: &str) -> String {
match agent {
"observation" => store::Provenance::AgentKnowledgeObservation,
"extractor" | "pattern" => store::Provenance::AgentKnowledgePattern,
"connector" => store::Provenance::AgentKnowledgeConnector,
"challenger" => store::Provenance::AgentKnowledgeChallenger,
_ => store::Provenance::Agent,
"observation" => "agent:knowledge-observation".to_string(),
"extractor" | "pattern" => "agent:knowledge-pattern".to_string(),
"connector" => "agent:knowledge-connector".to_string(),
"challenger" => "agent:knowledge-challenger".to_string(),
_ => format!("agent:{}", agent),
}
}
@ -587,7 +588,7 @@ pub fn run_one_agent(
let ts = store::compact_timestamp();
let report_key = format!("_{}-{}-{}", llm_tag, agent_name, ts);
let provenance = agent_provenance(agent_name);
store.upsert_provenance(&report_key, &output, provenance).ok();
store.upsert_provenance(&report_key, &output, &provenance).ok();
let actions = parse_all_actions(&output);
let no_ops = count_no_ops(&output);
@ -824,7 +825,7 @@ pub fn run_knowledge_loop(config: &KnowledgeLoopConfig) -> Result<Vec<CycleResul
if let Ok(json) = serde_json::to_string_pretty(&history) {
store = Store::load()?;
store.upsert_provenance(&key, &json,
store::Provenance::AgentKnowledgeObservation).ok();
"observation:write").ok();
depth_db.save(&mut store);
store.save()?;
}