singularity-forge/docs/dev/MEMORY-SYSTEM-ARCHITECTURE.md
2026-05-07 03:33:14 +02:00

539 lines
19 KiB
Markdown

# SF Memory System Architecture
## Overview
Singularity-forge includes a **complete autonomous memory system** built on SQLite (Node 24 native) with no external dependencies. The memory system enables SF to:
- **Learn** from unit execution patterns and outcomes
- **Recall** similar past situations for context-aware decisions
- **Adapt** dispatch ranking based on historical patterns
- **Detect** recurring issues and gotchas
- **Preserve** architectural knowledge and conventions
## Core Modules
### 1. **memory-store.js** (Core CRUD Layer)
**Location:** `src/resources/extensions/sf/memory-store.js`
**Purpose:** Foundational CRUD operations and ranking engine for all memory operations.
**Key Functions:**
- `createMemory(category, content, confidence = 0.8)` — Create a new memory entry
- `getRelevantMemoriesRanked(embedding, category, limit = 5)` — Query by similarity and category
- `updateMemoryConfidence(memoryId, confidence)` — Adjust confidence scores
- `deleteMemory(memoryId)` — Remove outdated memories
- `getMemoriesByRelation(fromId, relationName)` — Follow relationship graphs
- `isDbAvailable()` — Check database connectivity
**Categories Supported:**
- `gotcha` — Known issues, workarounds, edge cases
- `convention` — Coding standards, naming patterns, architectural rules
- `architecture` — Design decisions, module responsibilities
- `pattern` — Recurring execution patterns (unit types, dependencies)
- `environment` — Configuration, setup, environment-specific behaviors
- `preference` — User preferences, optimization decisions
**Storage Schema:**
```sql
memories (
id TEXT PRIMARY KEY,
category TEXT,
content TEXT,
confidence REAL,
created_at TEXT,
updated_at TEXT,
hit_count INTEGER
)
```
---
### 2. **memory-embeddings.js** (Vector Operations)
**Location:** `src/resources/extensions/sf/memory-embeddings.js`
**Purpose:** Convert content to embeddings and perform similarity operations (cosine distance).
**Key Functions:**
- `computeEmbedding(content)` — Generate deterministic embedding
- `storeEmbedding(memoryId, embedding, model = "default")` — Persist embedding as BLOB
- `getEmbedding(memoryId)` — Retrieve stored embedding
- `cosineSimilarity(embedding1, embedding2)` — Compute similarity score (0-1)
**Vector Format:**
- Embeddings stored as Float32Array → serialized BLOB in SQLite
- Default: 128-dimensional vectors
- Deterministic: same content always produces same embedding
**Storage Schema:**
```sql
memory_embeddings (
memory_id TEXT PRIMARY KEY,
model TEXT,
dimensions INTEGER,
vector BLOB,
updated_at TEXT
)
```
---
### 3. **memory-relations.js** (Graph Layer)
**Location:** `src/resources/extensions/sf/memory-relations.js`
**Purpose:** Create and query relationship graphs between memories.
**Key Functions:**
- `createRelation(fromId, toId, relationName, confidence = 0.8)` — Link two memories
- `getRelatedMemories(fromId, relationName)` — Follow outgoing edges
- `getReverseRelations(toId, relationName)` — Follow incoming edges
- `computePathWeight(fromId, toId, relationName)` — Path strength
**Relationship Types:**
- `"caused_by"` — Unit failure → root cause
- `"similar_to"` — Pattern similarity
- `"workaround_for"` — Known fix for issue
- `"depends_on"` — Architectural dependency
**Storage Schema:**
```sql
memory_relations (
from_id TEXT,
to_id TEXT,
relation_name TEXT,
confidence REAL,
created_at TEXT,
PRIMARY KEY (from_id, to_id, relation_name)
)
```
---
### 4. **memory-ingest.js** (Input Layer)
**Location:** `src/resources/extensions/sf/memory-ingest.js`
**Purpose:** Ingest external knowledge (files, URLs, documentation) into memory.
**Key Functions:**
- `ingestFile(filePath, category, options)` — Load from local file
- `ingestUrl(url, category, options)` — Fetch and parse URL content
- `ingestMarkdown(content, category)` — Parse markdown headers as memory entries
- `ingestCodeSnippet(code, language, category)` — Extract and learn from code
**Use Cases:**
- Load README.md as architectural conventions
- Import docs/ as foundational knowledge
- Parse error logs as gotchas
- Extract code patterns from examples
---
### 5. **memory-extractor.js** (Auto-Learning)
**Location:** `src/resources/extensions/sf/memory-extractor.js`
**Purpose:** Automatically extract and learn patterns from unit execution.
**Key Functions:**
- `extractPatternFromUnit(unit, status, result)` — Learn from unit completion
- `extractFailureGotcha(unit, error)` — Record and categorize failures
- `extractConventionFromCode(filePath, codeContent)` — Detect patterns
- `deduplicateMemory(memoryId, similarMemories)` — Merge similar learnings
**Learning Strategy:**
- Success: high confidence (0.9) — strong signal
- Failure: medium confidence (0.5) — more variable
- Conventions: learned from code reviews
- Architectures: extracted from design docs
---
### 6. **memory-embeddings-llm-gateway.js** (Semantic Reranking)
**Location:** `src/resources/extensions/sf/memory-embeddings-llm-gateway.js`
**Purpose:** Optional LLM-powered semantic reranking of retrieved memories.
**Key Functions:**
- `rerankedByLLM(memories, query, topK = 3)` — Use LLM to rerank results
- `isLLMAvailable()` — Check if LLM provider configured
- `cacheRerankResult(query, topK, result)` — Cache LLM rankings
**Workflow:**
1. Vector similarity returns candidates (cosine-based)
2. LLM gateway reranks semantically
3. Top results returned with adjusted scores
4. Cache results for subsequent identical queries
**Fallback:** If LLM unavailable, returns original vector-ranked results
---
### 7. **memory-relations.js** (Graph Operations)
**Location:** `src/resources/extensions/sf/memory-relations.js`
**Purpose:** Create and traverse memory relationship graphs.
**Key Functions:**
- `linkMemories(fromId, toId, relationName, confidence)` — Create edges
- `findRelationPath(fromId, toId, maxDepth)` — Path finding (similar to BFS)
- `computeGraphConfidence(fromId, toId)` — Multi-hop confidence decay
**Graph Traversal:**
- Relation strength decays with path depth
- Can find indirect causes of failures
- Enables multi-hop pattern matching
---
### 8. **memory-sleeper.js** (Decay & Supersession)
**Location:** `src/resources/extensions/sf/memory-sleeper.js`
**Purpose:** Age memories and mark superseded entries.
**Key Functions:**
- `markSuperseded(oldMemoryId, newMemoryId)` — Chain updates
- `decayOldMemories(olderThanDays = 30)` — Reduce confidence of old entries
- `archiveMemory(memoryId)` — Mark as historical
- `reactivateMemory(memoryId)` — Re-promote archived memory
**Strategy:**
- Memories age over time (confidence decay)
- New learnings override old ones via supersession
- Archive doesn't delete; keeps full history
- Old memories still searchable with lower weight
---
### 9. **memory-backfill.js** (Historical Data)
**Location:** `src/resources/extensions/sf/memory-backfill.js`
**Purpose:** Bulk-load historical data from past runs into memory.
**Key Functions:**
- `backfillFromRunLogs(logPath)` — Import execution history
- `backfillFromGitHistory(repoPath)` — Learn from git commits
- `backfillFromTestResults(testPath)` — Ingest test data
- `computeBackfillConfidence(dataSource)` — Adjust confidence by source quality
**Use Cases:**
- Initial knowledge load from project history
- Recover from database reset
- Merge memories from multiple SF instances
---
### 10. **memory-source-store.js** (Source Tracking)
**Location:** `src/resources/extensions/sf/memory-source-store.js`
**Purpose:** Track origins of memories for traceability and debugging.
**Key Functions:**
- `trackMemorySource(memoryId, sourceUri, sourceType)` — Record where memory came from
- `getMemorySources(memoryId)` — Audit trail of memory
- `validateSourceFreshness(sourceUri)` — Check if source updated
- `revalidateMemory(memoryId)` — Re-fetch from source if changed
**Source Types:**
- `"unit-outcome"` — Learned from unit execution
- `"documentation"` — From docs/
- `"user-input"` — Manually added
- `"llm-extracted"` — From LLM analysis
- `"git-history"` — From commits
**Storage Schema:**
```sql
memory_sources (
memory_id TEXT,
source_uri TEXT,
source_type TEXT,
created_at TEXT,
last_validated_at TEXT
)
```
---
### 11. **commands-memory.js** (CLI Interface)
**Location:** `src/resources/extensions/sf/commands-memory.js`
**Purpose:** Command-line interface to memory system.
**Commands:**
- `/sf memory list [category]` — List all memories (optionally filtered)
- `/sf memory search <query>` — Find memories by content
- `/sf memory note <content>` — Manually add memory
- `/sf memory status` — Memory database statistics
- `/sf memory decay [--older-than-days N]` — Age memories
- `/sf memory export <path.json>` — Export all memories to JSON
- `/sf memory import <path.json>` — Import memories from JSON
---
### 12. **memory-tools.js** (Tool Exports)
**Location:** `src/resources/extensions/sf/tools/memory-tools.js`
**Purpose:** Export memory functions as SF tools for agent use.
**Exported Tools:**
- `recall-memory` — Query by context
- `create-memory` — Store new learning
- `link-memories` — Create relationships
- `search-memories` — Full-text search
- `get-memory-stats` — Analytics
---
## Databases
### **sf-db.js** (SQLite Backend)
**Location:** `src/resources/extensions/sf/sf-db.js`
**Purpose:** Core SQLite database abstraction (Node 24 native, no external deps).
**Tables:**
- `memories` — Memory entries
- `memory_embeddings` — Vector data
- `memory_relations` — Relationship graph
- `memory_sources` — Source tracking
- Plus other SF tables (uok, env, etc.)
**Key Advantage:** Node 24.15+ has native SQLite support (`node:sqlite`)
---
## Integration Points
### 1. **UOK Kernel Integration** (Unit Recording)
**File:** `src/resources/extensions/sf/uok/unit-runtime.js`
Function added: `recordUnitOutcomeInMemory(unit, status, result)`
```typescript
recordUnitOutcomeInMemory(unit, "completed", {
success: true,
executionTimeMs: 2341
})
// Stores pattern: "unit-type:code-review success confidence:0.9"
```
---
### 2. **Dispatch Ranking** (Decision Enhancement)
**File:** `src/resources/extensions/sf/auto-dispatch.js`
Function added: `enhanceUnitRankingWithMemory(units, baseScores)`
```typescript
const enhanced = await enhanceUnitRankingWithMemory(candidates, {
'unit-1': 0.75,
'unit-2': 0.60
})
// Boosts scores based on learned patterns
// Boost = baseScore + (topMemoryConfidence * 0.15)
```
---
### 3. **Gate Context** (Failure Diagnostics)
**File:** `src/resources/extensions/sf/uok/gate-runner.js`
Function added: `enrichGateResultWithMemory(gateResult, gateId)`
```typescript
const enriched = await enrichGateResultWithMemory(
{ outcome: 'fail', reason: 'timeout' },
'deployment-gate'
)
// Adds memoryContext: { hasHistoricalPattern: true, ... }
// Pure diagnostic, never changes gate logic
```
---
## Usage Examples
### Example 1: Record Unit Completion
```typescript
import { recordUnitOutcomeInMemory } from './uok/unit-runtime.js';
// After unit executes
recordUnitOutcomeInMemory(unit, 'completed', {
success: true,
duration: 2341
});
// Fire-and-forget: stores pattern in memory
```
### Example 2: Get Dispatch Context
```typescript
import { enhanceUnitRankingWithMemory } from './auto-dispatch.js';
const candidates = [
{ id: 'unit-a', type: 'research', readiness: 0.8 },
{ id: 'unit-b', type: 'research', readiness: 0.6 },
];
const enhanced = await enhanceUnitRankingWithMemory(candidates, {
'unit-a': 0.8,
'unit-b': 0.6
});
// Returns ranked with memory boost
// { id: 'unit-a', score: 0.92 } (boosted by 0.12)
// { id: 'unit-b', score: 0.60 } (no pattern match)
```
### Example 3: Search for Gotchas
```typescript
import { getRelevantMemoriesRanked } from './memory-store.js';
const gotchas = await getRelevantMemoriesRanked(
unitEmbedding,
'gotcha',
3 // top 3
);
// Returns similar past issues
// [
// { id: 'm1', confidence: 0.95, content: 'Network timeout during...' },
// { id: 'm2', confidence: 0.87, content: 'Database lock contention...' },
// ...
// ]
```
---
## Architecture Diagram
```
┌─────────────────────────────────────────────────────────────┐
│ SF Dispatch Loop │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ For each unit candidate: │ │
│ │ 1. Base score (readiness, priority, etc.) │ │
│ │ 2. enhanceUnitRankingWithMemory() │ │
│ │ ├─→ query memory for similar patterns │ │
│ │ └─→ boost matching candidates │ │
│ │ 3. Apply dispatch rules │ │
│ │ 4. Return selected unit │ │
│ └────────────────────────────────────────────────────┘ │
│ ↓ │
│ Execute Selected Unit │
│ ↓ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ recordUnitOutcomeInMemory() │ │
│ │ ├─→ Extract pattern from result │ │
│ │ ├─→ Compute confidence (0.9 for success) │ │
│ │ └─→ Store in memory (fire-and-forget) │ │
│ └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Memory System │
│ │
│ ┌─────────────────┐ ┌──────────────────┐ │
│ │ memory-store.js │ │memory-embeddings.│ ← Cosine sim │
│ │ (CRUD layer) │ │ (vectors) │ │
│ └─────────────────┘ └──────────────────┘ │
│ ↓ ↓ │
│ ┌─────────────────────────────────────┐ │
│ │ memory-relations.js (Graph) │ │
│ │ memory-sleeper.js (Decay) │ │
│ │ memory-source-store.js (Tracking) │ │
│ └─────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────┐ │
│ │ SQLite (sf-db.js) │ │
│ │ Node 24 native sqlite │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
---
## Graceful Degradation
All memory operations follow the **fire-and-forget pattern**:
1. **Memory unavailable** → dispatch continues without boost
2. **DB error** → operation fails silently, decision unaffected
3. **LLM reranking fails** → fall back to vector similarity
4. **Embedding computation fails** → use default embedding
**Result:** Memory is always optional; never blocks dispatch or UOK execution.
---
## Performance Characteristics
| Operation | Latency | Notes |
|-----------|---------|-------|
| `createMemory()` | <5ms | Async write, fire-and-forget |
| `getRelevantMemoriesRanked()` | 10-50ms | Depends on DB size and vector dim |
| `cosineSimilarity()` | <1ms | 128D vectors, hardware-accelerated |
| `computeEmbedding()` | 5-20ms | Deterministic hash-based |
| Dispatch boost overhead | <10ms | Per dispatch cycle |
---
## Data Retention & Growth
**Memory Lifecycle:**
1. Created with confidence score (0.0-1.0)
2. Hit count incremented on each use
3. Confidence may decay over time (sleeper)
4. Marked superseded or archived
5. Historical records preserved (never deleted)
**Growth Management:**
- Embeddings indexed by memory_id (fast lookup)
- Relations indexed by from_id, to_id (graph traversal)
- Decay/supersession prevent stale data
- Archive doesn't grow real table (historical only)
---
## Security & Privacy
- **Memory is local** All data stored in SF's SQLite (no external services except optional LLM)
- **Source tracking** Full audit trail of where memories came from
- **No sensitive data** Memory system stores patterns and architecture, not credentials
- **Encapsulated** Memory functions exported only to SF extensions
---
## Future Enhancements
1. **Distributed memory** Share learnings across SF instances
2. **Memory compression** Archive old embeddings to reduce DB size
3. **Active learning** Automatically query for improvements
4. **Temporal indexing** Query memories by creation date
5. **Semantic clustering** Group similar memories automatically
6. **Telemetry** Track which memories most influence dispatch
---
## Architecture Decision: SF Tools, Not MCP
**Memory is NOT exposed as MCP server.**
- **SF is an MCP *client* only** SF consumes MCP tools from external services
- **Memory is internal SF infrastructure** uses SQLite (Node 24 native)
- **Memory exported as SF tools** LLM agents within SF call memory functions
- **No external exposure** Memory system is not a service; it's SF's autonomous learning mechanism
This keeps memory **private to SF** and prevents:
- External memory pollution
- Uncontrolled confidence scoring
- Inconsistent learning patterns
- Loss of autonomy (memory decisions stay internal)
---
## See Also
- **ADR-0075:** UOK Gate Architecture
- **ADR-0000:** Purpose-to-Software Compiler
- `docs/dev/UOK-SELF-EVOLUTION.md` How SF learns
- `src/resources/extensions/sf/uok/unit-runtime.js` Unit recording
- `src/resources/extensions/sf/auto-dispatch.js` Dispatch ranking
- `src/resources/extensions/sf/tools/memory-tools.js` SF tool executors