feat: Vestige v1.9.1 AUTONOMIC — self-regulating memory with graph visualization

Retention Target System: auto-GC low-retention memories during consolidation
(VESTIGE_RETENTION_TARGET env var, default 0.8). Auto-Promote: memories
accessed 3+ times in 24h get frequency-dependent potentiation. Waking SWR
Tagging: promoted memories get preferential 70/30 dream replay. Improved
Consolidation Scheduler: triggers on 6h staleness or 2h active use.

New tools: memory_health (retention dashboard with distribution buckets,
trend tracking, recommendations) and memory_graph (subgraph export with
Fruchterman-Reingold force-directed layout, up to 200 nodes).

Dream connections now persist to database via save_connection(), enabling
memory_graph traversal. Schema Migration V8 adds waking_tag, utility_score,
times_retrieved/useful columns and retention_snapshots table. 21 MCP tools.

v1.9.1 fixes: ConnectionRecord export, UTF-8 safe truncation, link_type
normalization, utility_score clamping, only-new-connections persistence,
70/30 split capacity fill, nonexistent center_id error handling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sam Valladares 2026-02-21 02:02:06 -06:00
parent c29023dd80
commit 5b90a73055
62 changed files with 2922 additions and 931 deletions

View file

@ -85,7 +85,7 @@ struct CodebaseArgs {
/// Execute the unified codebase tool
pub async fn execute(
storage: &Arc<Mutex<Storage>>,
storage: &Arc<Storage>,
cognitive: &Arc<Mutex<CognitiveEngine>>,
args: Option<Value>,
) -> Result<Value, String> {
@ -107,7 +107,7 @@ pub async fn execute(
/// Remember a code pattern
async fn execute_remember_pattern(
storage: &Arc<Mutex<Storage>>,
storage: &Arc<Storage>,
cognitive: &Arc<Mutex<CognitiveEngine>>,
args: &CodebaseArgs,
) -> Result<Value, String> {
@ -153,10 +153,8 @@ async fn execute_remember_pattern(
valid_until: None,
};
let mut storage = storage.lock().await;
let node = storage.ingest(input).map_err(|e| e.to_string())?;
let node_id = node.id.clone();
drop(storage);
// ====================================================================
// COGNITIVE: Cross-project pattern recording
@ -186,7 +184,7 @@ async fn execute_remember_pattern(
/// Remember an architectural decision
async fn execute_remember_decision(
storage: &Arc<Mutex<Storage>>,
storage: &Arc<Storage>,
cognitive: &Arc<Mutex<CognitiveEngine>>,
args: &CodebaseArgs,
) -> Result<Value, String> {
@ -250,10 +248,8 @@ async fn execute_remember_decision(
valid_until: None,
};
let mut storage = storage.lock().await;
let node = storage.ingest(input).map_err(|e| e.to_string())?;
let node_id = node.id.clone();
drop(storage);
// ====================================================================
// COGNITIVE: Cross-project decision recording
@ -282,12 +278,11 @@ async fn execute_remember_decision(
/// Get codebase context (patterns and decisions)
async fn execute_get_context(
storage: &Arc<Mutex<Storage>>,
storage: &Arc<Storage>,
cognitive: &Arc<Mutex<CognitiveEngine>>,
args: &CodebaseArgs,
) -> Result<Value, String> {
let limit = args.limit.unwrap_or(10).clamp(1, 50);
let storage = storage.lock().await;
// Build tag filter for codebase
let tag_filter = args
@ -304,7 +299,6 @@ async fn execute_get_context(
let decisions = storage
.get_nodes_by_type_and_tag("decision", tag_filter.as_deref(), limit)
.unwrap_or_default();
drop(storage);
let formatted_patterns: Vec<Value> = patterns
.iter()
@ -403,10 +397,10 @@ mod tests {
Arc::new(Mutex::new(CognitiveEngine::new()))
}
async fn test_storage() -> (Arc<Mutex<Storage>>, tempfile::TempDir) {
async fn test_storage() -> (Arc<Storage>, tempfile::TempDir) {
let dir = tempfile::TempDir::new().unwrap();
let storage = Storage::new(Some(dir.path().join("test.db"))).unwrap();
(Arc::new(Mutex::new(storage)), dir)
(Arc::new(storage), dir)
}
#[tokio::test]