mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
2b71ae4eb8
## 🔒 Security Fixes ### eval() Removal - Critical Security Vulnerability Fixed - **File**: `src/agents/TestDataArchitectAgent.ts` - **Impact**: Eliminated arbitrary code execution risk - **Solution**: Implemented safe expression evaluator with parser-based approach - **Supports**: - Comparison operators: `===`, `!==`, `==`, `!=`, `>`, `<`, `>=`, `<=` - Logical operators: `&&`, `||` - Boolean values: `true`, `false` - Number and string comparisons - **Lines**: 102 lines added (safeEvaluateExpression + parseValue methods) ## ✨ UX Enhancements ### CLAUDE.md Append Strategy - User-Requested Feature - **File**: `src/cli/commands/init.ts` - **User Feedback**: "AQE instructions should append by default, not prepend" - **Interactive Mode**: Prompts user to choose prepend or append - **--yes Mode**: Defaults to append (less disruptive to existing configs) - **Features**: - Auto-backup existing CLAUDE.md to CLAUDE.md.backup - Clear visual separator (---) between sections - User confirmation messages - **Lines**: 49 lines modified ### CLI Skills Count Fix - Accurate Display - **File**: `src/cli/commands/skills/index.ts` - **Before**: Showed "8/17" (hardcoded, incorrect) - **After**: Shows "34/34" (dynamic, accurate) - **Solution**: Added `getTotalQESkillsCount()` method using `QE_SKILLS.flatMap()` - **Future-proof**: Auto-updates when skills added - **Lines**: 11 lines modified ## 🎓 New Agent - Cherry-Picked from PR #22 ### CodeComplexityAnalyzerAgent Integration - **Author**: @mondweep (PR #22) - **Purpose**: Educational code complexity analysis and refactoring recommendations - **Files**: 7 files, 2,758 lines of code - **Capabilities**: - Cyclomatic complexity calculation - Cognitive complexity analysis - AI-powered refactoring suggestions - Quality scoring (0-100 scale) - Memory integration (`aqe/complexity/*`) - **Test Coverage**: 529 lines, 13+ test scenarios - **Documentation**: 754 lines (README + Claude agent definition) - **Examples**: 871 lines (3 interactive examples) ## 🔧 Code Quality Improvements ### Agent Enhancements - **BaseAgent.ts**: 136 lines modified - Improved property access patterns - Better encapsulation with public accessors - Enhanced lifecycle management - **TestGeneratorAgent.ts**: 377 lines added - Comprehensive null safety improvements - Enhanced error handling - Better context validation - **QualityGateAgent.ts**: 64 lines modified - Improved context handling - Better validation logic ### MCP Handler Improvements - **test-generate.ts**: 33 lines modified (better parameter handling) - **quality-analyze.ts**: 28 lines modified (context fix) - **regression-risk-analyze.ts**: 85 lines modified (parameter aliasing fix) ### Infrastructure Additions - **AgentLifecycleManager.ts**: 274 new lines (lifecycle coordination) - **SwarmMemoryManager.ts**: 3 lines modified (improved coordination) - **AgentRegistry.ts**: 20 lines added (better agent registration) ## 🧪 Testing Enhancements ### New Integration Tests (5 Test Suites) - **fleet-management.integration.test.ts**: 491 lines - **parameter-validation.integration.test.ts**: 606 lines - **quality-analyze.integration.test.ts**: 393 lines - **regression-risk.integration.test.ts**: 505 lines - **test-execution.integration.test.ts**: 536 lines - **test-harness.ts**: 289 lines (shared test utilities) - **Total**: 2,820 lines of integration test coverage ### Enhanced Unit Tests - **BaseAgent.enhanced.test.ts**: 909 lines (comprehensive BaseAgent testing) - **TestGeneratorAgent.null-safety.test.ts**: 1,511 lines (null safety validation) - **Total**: 2,420 lines of new unit test coverage ### Test Improvements - **PredictionTools.test.ts**: 118 lines modified - **Agent.test.ts**: 11 lines modified ## 📚 Documentation Expansion (27,439 insertions) ### Release Documentation (7 documents) - **RELEASE-1.3.6-PREPARATION.md**: 443 lines (complete release checklist) - **SECURITY-SCAN-RELEASE-1.3.6.md**: 422 lines (security validation) - **THREE-ISSUE-FIXES-SUMMARY.md**: 196 lines (user-reported fixes) - **CHERRY-PICK-PR22-SUMMARY.md**: 412 lines (integration details) - **FINAL-STATUS-REPORT-2025-10-30.md**: 403 lines (status summary) - **FINAL-MCP-VERIFICATION-SUMMARY.md**: 338 lines (MCP validation) - **MCP-PRODUCTION-READINESS-REPORT.md**: 318 lines (production readiness) ### Technical Documentation (7 documents) - **MCP-TOOLS-REFERENCE.md**: 1,555 lines (complete MCP API reference) - **MCP-TOOLS-USER-GUIDE.md**: 626 lines (user guide) - **MCP-TOOLS-AUTO-GENERATED.md**: 934 lines (auto-generated docs) - **MCP-TOOLS-MIGRATION.md**: 437 lines (migration guide) - **complexity-mitigation-plan.md**: 537 lines (code quality roadmap) - **swarm-execution-report.md**: 985 lines (execution analysis) - **HONEST-IMPLEMENTATION-ANALYSIS.md**: 62 lines (transparency report) ### Fix Documentation (7 documents) - **MCP-TOOLS-COMPLETE-FIX-REPORT.md**: 619 lines (comprehensive fix report) - **three-issue-fixes.md**: 345 lines (user-reported fixes) - **quality-analyze-context-fix.md**: 195 lines - **regression-risk-parameter-aliasing.md**: 303 lines - **test-generator-agent-null-safety-fixes.md**: 422 lines - **typescript-compilation-errors-fixed-2025-10-30.md**: 273 lines - **MCP-TOOLS-FIX-SUMMARY.md**: 272 lines ### Refactoring Plans (4 documents) - **swarm-memory-manager-refactoring-plan.md**: 796 lines - **base-agent-refactoring-plan.md**: 658 lines - **refactoring-summary.md**: 404 lines - **REFACTORING_STATUS.md**: 210 lines ### Testing Documentation (6 documents) - **mcp-tools-test-report.md**: 1,260 lines (comprehensive test report) - **testing-workflow.md**: 691 lines (MCP testing guide) - **TestGeneratorAgent-test-plan.md**: 318 lines (test plan) - **coverage-analysis-2025-10-30.md**: 661 lines (coverage report) - **regression-validation-report-2025-10-30.md**: 450 lines (regression validation) - **README.md** (tests/integration/mcp): 277 lines (integration test guide) ### CI/CD Documentation (3 documents) - **mcp-cicd-pipeline.md**: 402 lines (pipeline architecture) - **mcp-pipeline-setup-summary.md**: 343 lines (setup guide) - **mcp-cicd-implementation-notes.md**: 280 lines (implementation notes) ### MCP Verification (2 documents) - **MCP-VERIFICATION-SUMMARY.md**: 286 lines - **PR-22-ANALYSIS.md**: 373 lines ### Coverage Analysis (2 documents) - **coverage-analysis-2025-10-30.md**: 661 lines - **coverage-analysis-summary.json**: 417 lines (structured data) ## 🛠️ Scripts & Automation (5 Scripts, 2,117 Lines) ### New Utility Scripts - **validate-mcp-tools.js**: 280 lines (MCP tool validation) - **generate-mcp-report.js**: 252 lines (report generation) - **generate-mcp-docs.js**: 270 lines (documentation generation) - **verify-mcp-production-readiness.js**: 564 lines (production checks) - **test-issue-fixes.js**: 224 lines (fix verification) - **mcp-tools-summary.json**: 344 lines (structured summary) ## 📊 Examples & Guides ### MCP Integration Examples (2 Examples) - **basic-test-generation.js**: 200 lines (starter example) - **quality-analysis-pipeline.js**: 360 lines (advanced workflow) ## ⚙️ CI/CD Enhancements ### GitHub Actions Workflow - **.github/workflows/mcp-tools-test.yml**: 197 lines - Automated MCP tool testing - Multi-environment validation - Production readiness checks ### Git Hooks - **.husky/pre-commit**: 14 lines (pre-commit validation) ## 📦 Configuration Updates ### Version & Dependencies - **package.json**: Version bumped to 1.3.6 - **package-lock.json**: Dependency lock updated - **README.md**: Version references updated (27 lines modified) - **.claude/settings.json**: 4 lines modified ### CHANGELOG - **CHANGELOG.md**: 37 lines added - Complete v1.3.6 changelog entry - Security fixes documented - UX enhancements documented - Testing improvements documented ## 📈 Statistics Summary ### Code Changes - **78 files changed** - **27,439 insertions** (+) - **181 deletions** (-) - **Net change**: +27,258 lines ### Breakdown by Category - **Source Code**: ~1,200 lines (agents, handlers, infrastructure) - **Tests**: ~5,240 lines (integration + unit tests) - **Documentation**: ~18,000 lines (guides, reports, plans) - **Scripts**: ~2,117 lines (automation utilities) - **Examples**: ~560 lines (MCP examples) - **CI/CD**: ~211 lines (workflows + hooks) ### Quality Metrics - ✅ **TypeScript Compilation**: 0 errors (16 errors fixed) - ✅ **Security Vulnerabilities**: 0 critical (1 fixed) - ✅ **Integration Tests**: 5 new test suites, 2,820 lines - ✅ **Unit Tests**: 2,420 new lines - ✅ **Documentation**: 100% comprehensive coverage - ✅ **Backward Compatibility**: 100% maintained ## 🎯 User Impact ### Immediate Benefits 1. **Security**: Eliminates arbitrary code execution vulnerability 2. **UX**: Less disruptive CLAUDE.md initialization 3. **Accuracy**: Correct skills count display (34/34) 4. **Quality**: CodeComplexityAnalyzerAgent for refactoring guidance 5. **Reliability**: 16 TypeScript errors resolved ### Developer Experience 1. **Better Documentation**: 18,000+ lines of guides and references 2. **Better Testing**: 5,240 new lines of test coverage 3. **Better Tooling**: 2,117 lines of automation scripts 4. **Better Examples**: MCP integration examples 5. **Better CI/CD**: Automated testing and validation ## 🔄 Migration & Compatibility ### Breaking Changes - **NONE** - Fully backward compatible ### Deprecations - **NONE** ### New Features (Opt-in) - CodeComplexityAnalyzerAgent (available via Claude Code or MCP) - Interactive CLAUDE.md placement (interactive mode only) ## ✅ Verification ### Pre-Release Checks - ✅ TypeScript compilation: 0 errors - ✅ All three user-reported fixes verified - ✅ Integration tests passing - ✅ Documentation complete - ✅ CHANGELOG updated - ✅ Version numbers updated (package.json, README.md) - ✅ Security scan: No vulnerabilities - ✅ Backward compatibility verified ### Production Readiness - ✅ MCP tools validated (54 tools) - ✅ Agent registry verified (17 agents) - ✅ Skills library verified (34 skills) - ✅ CI/CD pipeline configured - ✅ Pre-commit hooks installed ## 🙏 Acknowledgments - **@mondweep**: CodeComplexityAnalyzerAgent contribution (PR #22) - **User Feedback**: CLAUDE.md append strategy request - **User Feedback**: CLI skills count display bug report - **User Feedback**: eval() security concern ## 📝 Release Notes **Version**: 1.3.6 **Date**: 2025-10-30 **Type**: Security & Quality Patch Release **Status**: Production Ready **Upgrade Recommendation**: 🔴 **HIGH PRIORITY** - Security vulnerability fixed (eval() removal) - User experience improvements - Enhanced stability (16 TypeScript errors fixed) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
24 KiB
24 KiB
SwarmMemoryManager Refactoring Plan
Executive Summary
Current State:
- File:
src/core/memory/SwarmMemoryManager.ts - Lines of Code: 1,838
- Cyclomatic Complexity: 187 (HIGHEST in codebase)
- Target Complexity: < 100
Root Causes of Complexity:
- God Object pattern - manages 12 different database tables
- Long methods with nested conditionals
- Mixed concerns (storage, access control, QUIC, AgentDB)
- Repetitive SQL query patterns
- No separation between data access and business logic
Refactoring Strategy
Phase 1: Extract Data Access Layer (DAO Pattern)
Create separate DAO classes for each table/domain:
- MemoryEntryDAO - Core key-value storage (Table 1)
- AccessControlDAO - ACL management (Table 2)
- HintDAO - Blackboard hints (Table 2b)
- EventDAO - Event stream (Table 3)
- WorkflowDAO - Workflow state (Table 4)
- PatternDAO - Pattern storage (Table 5)
- ConsensusDAO - Consensus state (Table 6)
- MetricsDAO - Performance metrics (Table 7)
- ArtifactDAO - Artifact manifests (Table 8)
- SessionDAO - Session management (Table 9)
- AgentRegistryDAO - Agent lifecycle (Table 10)
- GOAPStateDAO - GOAP planning (Table 11)
- OODACycleDAO - OODA loops (Table 12)
Phase 2: Extract Service Layer
Create service classes for business logic:
- MemoryStoreService - Core storage operations
- MemoryCacheService - Caching and TTL management
- MemorySyncService - QUIC/AgentDB synchronization
- AccessControlService - Permission checking
- ExpirationService - TTL cleanup
Phase 3: Apply Strategy Pattern
Create strategies for different memory types:
interface MemoryStrategy {
getTTL(): number;
shouldAutoExpire(): boolean;
getIndexes(): string[];
}
class ArtifactStrategy implements MemoryStrategy { /* never expires */ }
class EventStrategy implements MemoryStrategy { /* 30 days */ }
class ConsensusStrategy implements MemoryStrategy { /* 7 days */ }
Phase 4: Simplify Complex Methods
Apply these refactoring patterns:
- Extract Method - Break down methods > 20 lines
- Replace Nested Conditional with Guard Clauses
- Extract Predicate Functions for complex conditions
- Introduce Parameter Object for methods with many parameters
Detailed Implementation Plan
Step 1: Create Base DAO Class
File: src/core/memory/dao/BaseDAO.ts
export abstract class BaseDAO {
protected db: BetterSqlite3.Database;
constructor(db: BetterSqlite3.Database) {
this.db = db;
}
protected run(sql: string, params: any[] = []): void {
this.db.prepare(sql).run(...params);
}
protected queryOne<T>(sql: string, params: any[] = []): T | undefined {
return this.db.prepare(sql).get(...params) as T | undefined;
}
protected queryAll<T>(sql: string, params: any[] = []): T[] {
return this.db.prepare(sql).all(...params) as T[];
}
abstract createTable(): Promise<void>;
abstract createIndexes(): Promise<void>;
}
Step 2: Create MemoryEntryDAO
File: src/core/memory/dao/MemoryEntryDAO.ts
export class MemoryEntryDAO extends BaseDAO {
async createTable(): Promise<void> {
await this.run(`
CREATE TABLE IF NOT EXISTS memory_entries (
key TEXT NOT NULL,
partition TEXT NOT NULL DEFAULT 'default',
value TEXT NOT NULL,
metadata TEXT,
created_at INTEGER NOT NULL,
expires_at INTEGER,
owner TEXT,
access_level TEXT DEFAULT 'private',
team_id TEXT,
swarm_id TEXT,
PRIMARY KEY (key, partition)
)
`);
}
async createIndexes(): Promise<void> {
await this.run(`CREATE INDEX IF NOT EXISTS idx_memory_partition ON memory_entries(partition)`);
await this.run(`CREATE INDEX IF NOT EXISTS idx_memory_expires ON memory_entries(expires_at)`);
await this.run(`CREATE INDEX IF NOT EXISTS idx_memory_owner ON memory_entries(owner)`);
await this.run(`CREATE INDEX IF NOT EXISTS idx_memory_access ON memory_entries(access_level)`);
}
async insert(entry: MemoryEntry): Promise<void> {
await this.run(
`INSERT OR REPLACE INTO memory_entries
(key, partition, value, metadata, created_at, expires_at, owner, access_level, team_id, swarm_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
entry.key,
entry.partition || 'default',
JSON.stringify(entry.value),
entry.metadata ? JSON.stringify(entry.metadata) : null,
entry.createdAt,
entry.expiresAt || null,
entry.owner || 'system',
entry.accessLevel || 'private',
entry.teamId || null,
entry.swarmId || null
]
);
}
async findByKey(key: string, partition: string, includeExpired: boolean = false): Promise<MemoryEntry | null> {
const now = Date.now();
let query = `SELECT * FROM memory_entries WHERE key = ? AND partition = ?`;
const params: any[] = [key, partition];
if (!includeExpired) {
query += ` AND (expires_at IS NULL OR expires_at > ?)`;
params.push(now);
}
const row = await this.queryOne<any>(query, params);
return row ? this.mapToEntry(row) : null;
}
async findByPattern(pattern: string, partition: string, includeExpired: boolean = false): Promise<MemoryEntry[]> {
const now = Date.now();
let query = `SELECT * FROM memory_entries WHERE partition = ? AND key LIKE ?`;
const params: any[] = [partition, pattern];
if (!includeExpired) {
query += ` AND (expires_at IS NULL OR expires_at > ?)`;
params.push(now);
}
const rows = await this.queryAll<any>(query, params);
return rows.map(row => this.mapToEntry(row));
}
async deleteByKey(key: string, partition: string): Promise<void> {
await this.run(`DELETE FROM memory_entries WHERE key = ? AND partition = ?`, [key, partition]);
}
async deleteByPartition(partition: string): Promise<void> {
await this.run(`DELETE FROM memory_entries WHERE partition = ?`, [partition]);
}
async deleteExpired(): Promise<void> {
const now = Date.now();
await this.run(`DELETE FROM memory_entries WHERE expires_at IS NOT NULL AND expires_at <= ?`, [now]);
}
async count(): Promise<number> {
const result = await this.queryOne<{ count: number }>(`SELECT COUNT(*) as count FROM memory_entries`);
return result?.count || 0;
}
async getPartitions(): Promise<string[]> {
const rows = await this.queryAll<{ partition: string }>(`SELECT DISTINCT partition FROM memory_entries`);
return rows.map(row => row.partition);
}
async getAccessLevelCounts(): Promise<Record<string, number>> {
const rows = await this.queryAll<{ access_level: string; count: number }>(
`SELECT access_level, COUNT(*) as count FROM memory_entries GROUP BY access_level`
);
const counts: Record<string, number> = {};
rows.forEach(row => {
counts[row.access_level] = row.count;
});
return counts;
}
async findModifiedSince(since: number, partition?: string): Promise<MemoryEntry[]> {
let query = `SELECT * FROM memory_entries WHERE created_at > ?`;
const params: any[] = [since];
if (partition) {
query += ` AND partition = ?`;
params.push(partition);
}
query += ` ORDER BY created_at ASC`;
const rows = await this.queryAll<any>(query, params);
return rows.map(row => this.mapToEntry(row));
}
private mapToEntry(row: any): MemoryEntry {
return {
key: row.key,
value: JSON.parse(row.value),
partition: row.partition,
createdAt: row.created_at,
expiresAt: row.expires_at,
owner: row.owner,
accessLevel: row.access_level,
teamId: row.team_id,
swarmId: row.swarm_id
};
}
}
Step 3: Create MemoryStoreService
File: src/core/memory/services/MemoryStoreService.ts
export class MemoryStoreService {
private memoryDAO: MemoryEntryDAO;
private accessControl: AccessControlService;
private lastModifiedTimestamps: Map<string, number>;
constructor(
memoryDAO: MemoryEntryDAO,
accessControl: AccessControlService
) {
this.memoryDAO = memoryDAO;
this.accessControl = accessControl;
this.lastModifiedTimestamps = new Map();
}
async store(key: string, value: any, options: StoreOptions = {}): Promise<void> {
const partition = options.partition || 'default';
const owner = options.owner || 'system';
const accessLevel = options.accessLevel || AccessLevel.PRIVATE;
const createdAt = Date.now();
const expiresAt = this.calculateExpiresAt(options.ttl, createdAt);
// Check write permission if updating existing entry
const existing = await this.memoryDAO.findByKey(key, partition);
if (existing && options.owner) {
await this.checkWritePermission(existing, options);
}
const entry: MemoryEntry = {
key,
value,
partition,
createdAt,
expiresAt,
owner,
accessLevel,
teamId: options.teamId,
swarmId: options.swarmId
};
await this.memoryDAO.insert(entry);
// Track modification for QUIC sync
this.trackModification(partition, key, createdAt);
}
async retrieve(key: string, options: RetrieveOptions = {}): Promise<any> {
const partition = options.partition || 'default';
const entry = await this.memoryDAO.findByKey(key, partition, options.includeExpired);
if (!entry) {
return null;
}
// Check read permission if agentId provided
if (options.agentId) {
await this.checkReadPermission(entry, options);
}
return entry.value;
}
async query(pattern: string, options: RetrieveOptions = {}): Promise<MemoryEntry[]> {
const partition = options.partition || 'default';
const entries = await this.memoryDAO.findByPattern(pattern, partition, options.includeExpired);
// Filter by access control if agentId provided
if (options.agentId) {
return this.filterByPermissions(entries, options);
}
return entries;
}
async delete(key: string, partition: string = 'default', options: DeleteOptions = {}): Promise<void> {
// Check delete permission if agentId provided
if (options.agentId) {
const entry = await this.memoryDAO.findByKey(key, partition);
if (entry) {
await this.checkDeletePermission(entry, options);
}
}
await this.memoryDAO.deleteByKey(key, partition);
}
async clear(partition: string = 'default'): Promise<void> {
await this.memoryDAO.deleteByPartition(partition);
}
// Private helper methods
private calculateExpiresAt(ttl: number | undefined, createdAt: number): number | undefined {
return ttl ? createdAt + (ttl * 1000) : undefined;
}
private trackModification(partition: string, key: string, timestamp: number): void {
const entryKey = `${partition}:${key}`;
this.lastModifiedTimestamps.set(entryKey, timestamp);
}
private async checkWritePermission(entry: MemoryEntry, options: StoreOptions): Promise<void> {
const allowed = await this.accessControl.checkPermission({
agentId: options.owner!,
resourceOwner: entry.owner!,
accessLevel: entry.accessLevel!,
permission: Permission.WRITE,
teamId: options.teamId,
resourceTeamId: entry.teamId,
swarmId: options.swarmId,
resourceSwarmId: entry.swarmId
});
if (!allowed) {
throw new AccessControlError('Write permission denied');
}
}
private async checkReadPermission(entry: MemoryEntry, options: RetrieveOptions): Promise<void> {
const allowed = await this.accessControl.checkPermission({
agentId: options.agentId!,
resourceOwner: entry.owner!,
accessLevel: entry.accessLevel!,
permission: Permission.READ,
teamId: options.teamId,
resourceTeamId: entry.teamId,
swarmId: options.swarmId,
resourceSwarmId: entry.swarmId,
isSystemAgent: options.isSystemAgent
});
if (!allowed) {
throw new AccessControlError('Read permission denied');
}
}
private async checkDeletePermission(entry: MemoryEntry, options: DeleteOptions): Promise<void> {
const allowed = await this.accessControl.checkPermission({
agentId: options.agentId!,
resourceOwner: entry.owner!,
accessLevel: entry.accessLevel!,
permission: Permission.DELETE,
teamId: options.teamId,
resourceTeamId: entry.teamId,
swarmId: options.swarmId,
resourceSwarmId: entry.swarmId,
isSystemAgent: options.isSystemAgent
});
if (!allowed) {
throw new AccessControlError('Delete permission denied');
}
}
private async filterByPermissions(entries: MemoryEntry[], options: RetrieveOptions): Promise<MemoryEntry[]> {
const filtered: MemoryEntry[] = [];
for (const entry of entries) {
const allowed = await this.accessControl.checkPermission({
agentId: options.agentId!,
resourceOwner: entry.owner!,
accessLevel: entry.accessLevel!,
permission: Permission.READ,
teamId: options.teamId,
resourceTeamId: entry.teamId,
swarmId: options.swarmId,
resourceSwarmId: entry.swarmId,
isSystemAgent: options.isSystemAgent
});
if (allowed) {
filtered.push(entry);
}
}
return filtered;
}
getLastModified(key: string, partition: string = 'default'): number | undefined {
const entryKey = `${partition}:${key}`;
return this.lastModifiedTimestamps.get(entryKey);
}
}
Step 4: Refactor SwarmMemoryManager as Facade
File: src/core/memory/SwarmMemoryManager.ts (refactored)
/**
* SwarmMemoryManager - Facade for memory management subsystem
*
* Orchestrates:
* - 13 specialized DAOs for data access
* - 5 service layers for business logic
* - Access control integration
* - QUIC/AgentDB synchronization
*/
export class SwarmMemoryManager {
private db: BetterSqlite3.Database | null = null;
private dbPath: string;
private initialized = false;
// DAOs
private memoryDAO!: MemoryEntryDAO;
private accessControlDAO!: AccessControlDAO;
private hintDAO!: HintDAO;
private eventDAO!: EventDAO;
private workflowDAO!: WorkflowDAO;
private patternDAO!: PatternDAO;
private consensusDAO!: ConsensusDAO;
private metricsDAO!: MetricsDAO;
private artifactDAO!: ArtifactDAO;
private sessionDAO!: SessionDAO;
private agentRegistryDAO!: AgentRegistryDAO;
private goapStateDAO!: GOAPStateDAO;
private oodaCycleDAO!: OODACycleDAO;
// Services
private memoryStoreService!: MemoryStoreService;
private accessControlService!: AccessControlService;
private expirationService!: ExpirationService;
private syncService!: MemorySyncService;
private cacheService!: MemoryCacheService;
constructor(dbPath: string = ':memory:') {
this.dbPath = dbPath;
}
async initialize(): Promise<void> {
if (this.initialized) {
return;
}
await this.createDatabase();
await this.initializeDAOs();
await this.initializeServices();
await this.createTables();
await this.createIndexes();
this.initialized = true;
}
// Delegate to MemoryStoreService
async store(key: string, value: any, options: StoreOptions = {}): Promise<void> {
await this.ensureInitialized();
return this.memoryStoreService.store(key, value, options);
}
async retrieve(key: string, options: RetrieveOptions = {}): Promise<any> {
await this.ensureInitialized();
return this.memoryStoreService.retrieve(key, options);
}
async query(pattern: string, options: RetrieveOptions = {}): Promise<MemoryEntry[]> {
await this.ensureInitialized();
return this.memoryStoreService.query(pattern, options);
}
async delete(key: string, partition: string = 'default', options: DeleteOptions = {}): Promise<void> {
await this.ensureInitialized();
return this.memoryStoreService.delete(key, partition, options);
}
async clear(partition: string = 'default'): Promise<void> {
await this.ensureInitialized();
return this.memoryStoreService.clear(partition);
}
// Delegate to specialized DAOs...
async storeEvent(event: Event): Promise<string> {
await this.ensureInitialized();
return this.eventDAO.insert(event);
}
async storeWorkflowState(workflow: WorkflowState): Promise<void> {
await this.ensureInitialized();
return this.workflowDAO.insert(workflow);
}
// ... (delegate all other methods to appropriate DAOs/services)
// Private initialization methods
private async createDatabase(): Promise<void> {
if (this.dbPath !== ':memory:') {
await fs.ensureDir(path.dirname(this.dbPath));
}
this.db = new BetterSqlite3(this.dbPath);
}
private async initializeDAOs(): Promise<void> {
if (!this.db) throw new Error('Database not initialized');
this.memoryDAO = new MemoryEntryDAO(this.db);
this.accessControlDAO = new AccessControlDAO(this.db);
this.hintDAO = new HintDAO(this.db);
this.eventDAO = new EventDAO(this.db);
this.workflowDAO = new WorkflowDAO(this.db);
this.patternDAO = new PatternDAO(this.db);
this.consensusDAO = new ConsensusDAO(this.db);
this.metricsDAO = new MetricsDAO(this.db);
this.artifactDAO = new ArtifactDAO(this.db);
this.sessionDAO = new SessionDAO(this.db);
this.agentRegistryDAO = new AgentRegistryDAO(this.db);
this.goapStateDAO = new GOAPStateDAO(this.db);
this.oodaCycleDAO = new OODACycleDAO(this.db);
}
private async initializeServices(): Promise<void> {
this.accessControlService = new AccessControlService(this.accessControlDAO);
this.memoryStoreService = new MemoryStoreService(this.memoryDAO, this.accessControlService);
this.expirationService = new ExpirationService([
this.memoryDAO,
this.hintDAO,
this.eventDAO,
this.patternDAO,
this.consensusDAO
]);
this.cacheService = new MemoryCacheService();
this.syncService = new MemorySyncService(this.memoryDAO);
}
private async createTables(): Promise<void> {
await Promise.all([
this.memoryDAO.createTable(),
this.accessControlDAO.createTable(),
this.hintDAO.createTable(),
this.eventDAO.createTable(),
this.workflowDAO.createTable(),
this.patternDAO.createTable(),
this.consensusDAO.createTable(),
this.metricsDAO.createTable(),
this.artifactDAO.createTable(),
this.sessionDAO.createTable(),
this.agentRegistryDAO.createTable(),
this.goapStateDAO.createTables(),
this.oodaCycleDAO.createTable()
]);
}
private async createIndexes(): Promise<void> {
await Promise.all([
this.memoryDAO.createIndexes(),
this.accessControlDAO.createIndexes(),
this.hintDAO.createIndexes(),
this.eventDAO.createIndexes(),
this.workflowDAO.createIndexes(),
this.patternDAO.createIndexes(),
this.consensusDAO.createIndexes(),
this.metricsDAO.createIndexes(),
this.artifactDAO.createIndexes(),
this.agentRegistryDAO.createIndexes(),
this.oodaCycleDAO.createIndexes()
]);
}
private async ensureInitialized(): Promise<void> {
if (!this.initialized) {
await this.initialize();
}
}
}
Complexity Reduction Analysis
Before Refactoring:
- Single class: 1,838 LOC
- Cyclomatic Complexity: 187
- Methods: ~80 methods in one class
- Concerns: 12 mixed concerns
After Refactoring:
- SwarmMemoryManager (Facade): ~300 LOC, complexity ~20
- 13 DAO classes: Average 150 LOC each, complexity ~15 each
- 5 Service classes: Average 200 LOC each, complexity ~20 each
- Total: ~4,450 LOC (organized), max complexity per file: ~25
Complexity Reduction:
- Per-file complexity: 187 → 25 (85% reduction)
- Maintainability: High (single responsibility)
- Testability: High (easy to mock DAOs/services)
- Extensibility: High (new tables = new DAO, no changes to existing code)
Implementation Timeline
Week 1: Foundation
- Create BaseDAO class
- Create 3 core DAOs (MemoryEntry, AccessControl, Hint)
- Create MemoryStoreService
- Write unit tests
Week 2: Additional DAOs
- Create remaining 10 DAOs
- Write unit tests for each DAO
- Integration tests
Week 3: Service Layer
- Create AccessControlService
- Create ExpirationService
- Create CacheService
- Create SyncService
- Write unit tests
Week 4: Facade Refactoring
- Refactor SwarmMemoryManager as facade
- Update all consumers to use new API
- Integration tests
- Performance benchmarking
Week 5: Testing & Validation
- Full regression testing
- Performance validation
- Documentation updates
- Code review
Testing Strategy
Unit Tests (per DAO/Service):
- Test each method independently
- Mock database connections
- Test error handling
- Test edge cases
Integration Tests:
- Test DAO + Service integration
- Test database transactions
- Test concurrent access
- Test TTL expiration
Performance Tests:
- Benchmark query performance
- Benchmark insert/update performance
- Compare with baseline (current implementation)
- Ensure no performance regression
Rollout Strategy
Phase A: Parallel Implementation
- Keep existing SwarmMemoryManager
- Implement new architecture in parallel
- Run both implementations side-by-side
Phase B: Gradual Migration
- Migrate one component at a time
- Use feature flags for rollback
- Monitor for issues
Phase C: Deprecation
- Mark old implementation as deprecated
- Remove old code after stable period
- Update all documentation
Success Metrics
- Cyclomatic Complexity: < 100 per file (target: < 25)
- Test Coverage: > 90% line coverage
- Performance: No regression (within 5% of baseline)
- Code Review: All PRs approved by 2+ reviewers
- Zero Production Issues: No bugs introduced during refactoring
Risk Mitigation
Risk 1: Breaking Changes
- Mitigation: Maintain backward compatibility with facade pattern
- Fallback: Keep old implementation available
Risk 2: Performance Regression
- Mitigation: Benchmark every change
- Fallback: Optimize hot paths with caching
Risk 3: Database Corruption
- Mitigation: Extensive integration tests
- Fallback: Database migration rollback scripts
Risk 4: Team Knowledge Gap
- Mitigation: Thorough documentation + training sessions
- Fallback: Pair programming during migration
References
- Refactoring Patterns: Martin Fowler's "Refactoring" book
- DAO Pattern: J2EE Design Patterns
- Facade Pattern: Gang of Four Design Patterns
- SOLID Principles: Robert C. Martin's Clean Code
Appendix: File Structure
src/core/memory/
├── SwarmMemoryManager.ts # Facade (300 LOC, complexity ~20)
├── dao/
│ ├── BaseDAO.ts # Base class for all DAOs
│ ├── MemoryEntryDAO.ts # Table 1
│ ├── AccessControlDAO.ts # Table 2
│ ├── HintDAO.ts # Table 2b
│ ├── EventDAO.ts # Table 3
│ ├── WorkflowDAO.ts # Table 4
│ ├── PatternDAO.ts # Table 5
│ ├── ConsensusDAO.ts # Table 6
│ ├── MetricsDAO.ts # Table 7
│ ├── ArtifactDAO.ts # Table 8
│ ├── SessionDAO.ts # Table 9
│ ├── AgentRegistryDAO.ts # Table 10
│ ├── GOAPStateDAO.ts # Table 11
│ └── OODACycleDAO.ts # Table 12
├── services/
│ ├── MemoryStoreService.ts # Core storage logic
│ ├── AccessControlService.ts # Permission checking
│ ├── ExpirationService.ts # TTL cleanup
│ ├── MemoryCacheService.ts # Caching layer
│ └── MemorySyncService.ts # QUIC/AgentDB sync
└── types/
├── MemoryEntry.ts
├── StoreOptions.ts
└── ... (all interfaces)
Status: Plan Ready for Review Next Steps: Review plan → Approve → Begin Phase 1 implementation