From 0b50a624b8efd34924f689af81bd4d21e9c9cb2e Mon Sep 17 00:00:00 2001 From: dave Date: Wed, 13 May 2026 08:12:42 +0000 Subject: [PATCH] obs(session_store): log every record/lookup/remove for warm-resume diagnostics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Helps explain WHY each spawn goes warm vs cold. The existing `spawn mode=warm|cold` log only shows the outcome at the spawn point — to count where warmth is being lost, we need to see: - when a session_id is recorded (and for which key), - what every lookup returns (key + Some/None), - when remove_sessions_for_story prunes (which is currently the only explicit cold-induction path beyond "first ever spawn"). After this lands a grep of "session_store" in the logs gives the full warm-resume health picture: which (story,agent,model) triples have a recorded session, which lookups are hitting it, and which prunes are costing us a warm respawn. Co-Authored-By: Claude Opus 4.7 (1M context) --- server/src/agents/session_store.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/server/src/agents/session_store.rs b/server/src/agents/session_store.rs index 717e556f..f5abef1b 100644 --- a/server/src/agents/session_store.rs +++ b/server/src/agents/session_store.rs @@ -12,6 +12,8 @@ use std::collections::HashMap; use std::path::Path; +use crate::slog; + /// Composite key for the session store: `{story_id}:{agent_name}:{model}`. fn session_key(story_id: &str, agent_name: &str, model: &str) -> String { format!("{story_id}:{agent_name}:{model}") @@ -55,8 +57,9 @@ pub fn record_session( ) { let key = session_key(story_id, agent_name, model); let mut data = read_store(project_root); - data.insert(key, session_id.to_string()); + data.insert(key.clone(), session_id.to_string()); write_store(project_root, &data); + slog!("[agents] session_store record key={key} session={session_id}"); } /// Look up the last session_id for a (story_id, agent_name, model) triple. @@ -70,7 +73,12 @@ pub fn lookup_session( model: &str, ) -> Option { let key = session_key(story_id, agent_name, model); - read_store(project_root).get(&key).cloned() + let result = read_store(project_root).get(&key).cloned(); + match &result { + Some(sid) => slog!("[agents] session_store lookup key={key} => found session={sid}"), + None => slog!("[agents] session_store lookup key={key} => no record"), + } + result } /// Remove all session entries for a story. @@ -84,8 +92,12 @@ pub fn remove_sessions_for_story(project_root: &Path, story_id: &str) { let prefix = format!("{story_id}:"); let before = data.len(); data.retain(|k, _| !k.starts_with(&prefix)); - if data.len() < before { + let removed = before - data.len(); + if removed > 0 { write_store(project_root, &data); + slog!("[agents] session_store removed {removed} key(s) for story={story_id}"); + } else { + slog!("[agents] session_store remove for story={story_id}: no entries matched"); } }