provenance: add label() method, show provenance in history output

Move provenance_label() from query.rs private function to a pub
label() method on Provenance, eliminating duplication. History command
now shows provenance, human-readable timestamps, and content size for
each version.

Handle pre-migration nodes with bogus timestamps gracefully instead
of panicking.
This commit is contained in:
ProofOfConcept 2026-03-06 21:41:26 -05:00
parent 851fc0d417
commit d3075dc235
3 changed files with 35 additions and 24 deletions

View file

@ -1583,16 +1583,24 @@ fn cmd_history(args: &[String]) -> Result<(), String> {
} }
eprintln!("{} versions of '{}':\n", versions.len(), key); eprintln!("{} versions of '{}':\n", versions.len(), key);
for (i, node) in versions.iter().enumerate() { for node in &versions {
let preview: String = node.content.chars().take(200).collect(); let ts = if node.timestamp > 0 && node.timestamp < 4_000_000_000 {
store::format_datetime(node.timestamp)
} else {
format!("(raw:{})", node.timestamp)
};
let content_len = node.content.len();
let preview: String = node.content.chars().take(120).collect();
let preview = preview.replace('\n', "\\n"); let preview = preview.replace('\n', "\\n");
eprintln!(" v{} (w={:.3}, {}): {}", eprintln!(" v{:<3} {} {:24} w={:.3} {}b",
node.version, node.weight, node.timestamp, preview); node.version, ts, node.provenance.label(), node.weight, content_len);
eprintln!(" {}", preview);
} }
// Show latest full content // Show latest full content
if let Some(latest) = versions.last() { if let Some(latest) = versions.last() {
eprintln!("\n--- Latest content (v{}) ---", latest.version); eprintln!("\n--- Latest content (v{}, {}) ---",
latest.version, latest.provenance.label());
print!("{}", latest.content); print!("{}", latest.content);
} }

View file

@ -173,7 +173,7 @@ fn resolve_field(field: &str, key: &str, store: &Store, graph: &Graph) -> Option
"weight" => Some(Value::Num(node.weight as f64)), "weight" => Some(Value::Num(node.weight as f64)),
"category" => Some(Value::Str(node.category.label().to_string())), "category" => Some(Value::Str(node.category.label().to_string())),
"node_type" => Some(Value::Str(node_type_label(node.node_type).to_string())), "node_type" => Some(Value::Str(node_type_label(node.node_type).to_string())),
"provenance" => Some(Value::Str(provenance_label(node.provenance).to_string())), "provenance" => Some(Value::Str(node.provenance.label().to_string())),
"emotion" => Some(Value::Num(node.emotion as f64)), "emotion" => Some(Value::Num(node.emotion as f64)),
"retrievals" => Some(Value::Num(node.retrievals as f64)), "retrievals" => Some(Value::Num(node.retrievals as f64)),
"uses" => Some(Value::Num(node.uses as f64)), "uses" => Some(Value::Num(node.uses as f64)),
@ -200,24 +200,6 @@ fn node_type_label(nt: NodeType) -> &'static str {
} }
} }
fn provenance_label(p: Provenance) -> &'static str {
match p {
Provenance::Manual => "manual",
Provenance::Journal => "journal",
Provenance::Agent => "agent",
Provenance::Dream => "dream",
Provenance::Derived => "derived",
Provenance::AgentExperienceMine => "agent:experience-mine",
Provenance::AgentKnowledgeObservation => "agent:knowledge-observation",
Provenance::AgentKnowledgePattern => "agent:knowledge-pattern",
Provenance::AgentKnowledgeConnector => "agent:knowledge-connector",
Provenance::AgentKnowledgeChallenger => "agent:knowledge-challenger",
Provenance::AgentConsolidate => "agent:consolidate",
Provenance::AgentDigest => "agent:digest",
Provenance::AgentFactMine => "agent:fact-mine",
Provenance::AgentDecay => "agent:decay",
}
}
fn rel_type_label(r: RelationType) -> &'static str { fn rel_type_label(r: RelationType) -> &'static str {
match r { match r {

View file

@ -247,6 +247,27 @@ pub enum Provenance {
AgentDecay, AgentDecay,
} }
impl Provenance {
pub fn label(&self) -> &'static str {
match self {
Self::Manual => "manual",
Self::Journal => "journal",
Self::Agent => "agent",
Self::Dream => "dream",
Self::Derived => "derived",
Self::AgentExperienceMine => "agent:experience-mine",
Self::AgentKnowledgeObservation => "agent:knowledge-observation",
Self::AgentKnowledgePattern => "agent:knowledge-pattern",
Self::AgentKnowledgeConnector => "agent:knowledge-connector",
Self::AgentKnowledgeChallenger => "agent:knowledge-challenger",
Self::AgentConsolidate => "agent:consolidate",
Self::AgentDigest => "agent:digest",
Self::AgentFactMine => "agent:fact-mine",
Self::AgentDecay => "agent:decay",
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
#[archive(check_bytes)] #[archive(check_bytes)]
pub enum Category { pub enum Category {