diff --git a/src/mind/mod.rs b/src/mind/mod.rs index 11d45b1..474e2c2 100644 --- a/src/mind/mod.rs +++ b/src/mind/mod.rs @@ -103,9 +103,13 @@ fn collect_memory_scores(ctx: &ContextState) -> std::collections::BTreeMap, path: &std::path::Path) { - if let Ok(json) = serde_json::to_string_pretty(scores) { - let _ = std::fs::write(path, json); - dbglog!("[scoring] saved {} scores to {}", scores.len(), path.display()); + match serde_json::to_string_pretty(scores) { + Ok(json) => match std::fs::write(path, &json) { + Ok(()) => dbglog!("[scoring] saved {} scores to {} ({} bytes)", + scores.len(), path.display(), json.len()), + Err(e) => dbglog!("[scoring] save FAILED ({}): {}", path.display(), e), + }, + Err(e) => dbglog!("[scoring] serialize FAILED: {}", e), } } @@ -506,6 +510,17 @@ impl Mind { // Load persistent subconscious state let state_path = self.config.session_dir.join("subconscious-state.json"); self.subconscious.lock().await.set_state_path(state_path); + + // Kick off an incremental scoring pass on startup so memories due + // for re-scoring get evaluated without requiring a user message. + { + let mut s = self.shared.lock().unwrap(); + if !s.scoring_in_flight { + s.scoring_in_flight = true; + drop(s); + self.start_memory_scoring(); + } + } } pub fn turn_watch(&self) -> tokio::sync::watch::Receiver { @@ -619,14 +634,40 @@ impl Mind { let mut ctx = agent.context.lock().await; // Find memory by key in identity or conversation let found = find_memory_by_key(&ctx, &key); - if let Some((section, i)) = found { - ctx.set_score(section, i, Some(score)); + match found { + Some((section, i)) => { + ctx.set_score(section, i, Some(score)); + let nodes: &[crate::agent::context::AstNode] = match section { + Section::Identity => ctx.identity(), + Section::Conversation => ctx.conversation(), + _ => &[], + }; + let read_back = match nodes.get(i) { + Some(crate::agent::context::AstNode::Leaf(l)) => match l.body() { + crate::agent::context::NodeBody::Memory { score, .. } => format!("{:?}", score), + _ => "not-memory".to_string(), + }, + _ => "out-of-bounds".to_string(), + }; + dbglog!("[scoring] persisted {} → {:.3} ({:?}[{}]) read_back={}", + key, score, section, i, read_back); + } + None => { + dbglog!( + "[scoring] DROP {}: find_memory_by_key None (id={}, cv={})", + key, ctx.identity().len(), ctx.conversation().len() + ); + } } let snapshot = collect_memory_scores(&ctx); + let in_snapshot = snapshot.contains_key(&key); + dbglog!("[scoring] snapshot size={} contains({})={}", + snapshot.len(), key, in_snapshot); drop(ctx); agent.state.lock().await.changed.notify_one(); snapshot }; + dbglog!("[scoring] about to save {} entries", scores_snapshot.len()); save_memory_scores(&scores_snapshot, &path); } },