journal: remove all stringly-typed key patterns, use NodeType

- journal_new: key is slugified title (agent names things properly)
- journal_tail: sort by created_at (immutable), not timestamp (mutable)
- journal_update: find latest by created_at
- {{latest_journal}}: query by NodeType::EpisodicSession, not "journal" key
- poc-memory journal write: requires a name argument
- Removed all journal#j-{timestamp}-{slug} patterns from:
  - prompts.rs (rename candidates)
  - graph.rs (date extraction, organize skip list)
  - cursor.rs (date extraction)
  - store/mod.rs (doc comment)
- graph.rs organize: filter by NodeType::Semantic instead of key prefix
- cursor.rs: use created_at for date extraction instead of key parsing

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
ProofOfConcept 2026-03-26 19:11:17 -04:00
parent 85fa54cba9
commit eac59b423e
9 changed files with 63 additions and 67 deletions

View file

@ -552,22 +552,16 @@ fn resolve(
Some(Resolved { text, keys: vec![] })
}
// latest_journal — the most recent journal entry for the journal agent
// latest_journal — the most recent EpisodicSession entry
"latest_journal" => {
let text = store.nodes.get("journal")
.map(|n| {
// Get the last entry (last ## section)
let content = &n.content;
content.rfind("\n## ")
.map(|pos| content[pos..].to_string())
.unwrap_or_else(|| {
// Take the last 2000 chars if no ## found
let start = content.len().saturating_sub(2000);
content[start..].to_string()
})
})
.unwrap_or_else(|| "(no previous journal entry)".to_string());
Some(Resolved { text, keys: vec!["journal".to_string()] })
let latest = store.nodes.values()
.filter(|n| n.node_type == crate::store::NodeType::EpisodicSession)
.max_by_key(|n| n.created_at);
let (text, keys) = match latest {
Some(n) => (n.content.clone(), vec![n.key.clone()]),
None => ("(no previous journal entry)".to_string(), vec![]),
};
Some(Resolved { text, keys })
}
_ => None,

View file

@ -243,10 +243,10 @@ pub fn format_pairs_section(
pub fn format_rename_candidates(store: &Store, count: usize) -> (Vec<String>, String) {
let mut candidates: Vec<(&str, &crate::store::Node)> = store.nodes.iter()
.filter(|(key, _)| {
.filter(|(key, node)| {
if key.starts_with("_facts-") { return true; }
if key.len() < 60 { return false; }
if key.starts_with("journal#j-") { return true; }
if node.node_type == crate::store::NodeType::EpisodicSession { return true; }
if key.starts_with("_mined-transcripts#f-") { return true; }
false
})
@ -271,9 +271,9 @@ pub fn format_rename_candidates(store: &Store, count: usize) -> (Vec<String>, St
let mut out = String::new();
out.push_str(&format!("## Nodes to rename ({} of {} candidates)\n\n",
candidates.len(),
store.nodes.keys().filter(|k| k.starts_with("_facts-") ||
store.nodes.iter().filter(|(k, n)| k.starts_with("_facts-") ||
(k.len() >= 60 &&
(k.starts_with("journal#j-") || k.starts_with("_mined-transcripts#f-")))).count()));
(n.node_type == crate::store::NodeType::EpisodicSession || k.starts_with("_mined-transcripts#f-")))).count()));
for (key, node) in &candidates {
out.push_str(&format!("### {}\n", key));