Files
proffesor-for-testing__agen…/tests/integration/learning/learning-improvement-proof.test.ts
Profa b91627f282 fix(quality): implement GOAP Issue #149 code quality remediation
Phase 1: Test Determinism
- Create SeededRandom utility with Mulberry32 PRNG (src/utils/SeededRandom.ts)
- Migrate 258+ Math.random() calls to SeededRandom across 65+ test files
- Add timer test utilities (tests/helpers/timerTestUtils.ts)
- Add jest.useFakeTimers() pattern to 13 test files

Phase 2: Type Safety (63.5% reduction)
- Reduce `any` types from ~1,800 to 656
- Add 50+ new interfaces across agents, core, mcp, cli modules
- Fix all TypeScript errors (0 errors, build passes)
- Replace Record<string, any> with Record<string, unknown>
- Add proper type guards for hook methods (PostTaskData, TaskErrorData)

Key improvements:
- agents/: 105 → 0 any types (100% reduction)
- mcp/: 226 → 102 any types (55% reduction)
- cli/: 277 → 168 any types (39% reduction)
- core/: 199 → 175 any types (12% reduction)

Closes #149

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 17:08:12 +00:00

312 lines
10 KiB
TypeScript

/**
* Learning Improvement Proof Test
*
* MISSION: Prove that the Nightly-Learner system produces REAL learning improvements
*
* This test validates the complete learning pipeline:
* 1. Experiences are captured from agent executions
* 2. Sleep cycles process experiences into patterns
* 3. Dream engine generates insights
* 4. Agents can use learned patterns in future executions
*
* This is NOT a mock test - it uses real database operations and validates
* actual data flow through the system.
*/
import path from 'path';
import fs from 'fs/promises';
import Database from 'better-sqlite3';
import { ExperienceCapture, AgentExecutionEvent } from '../../../src/learning/capture/ExperienceCapture';
import { SleepCycle, CycleSummary } from '../../../src/learning/scheduler/SleepCycle';
import { DreamEngine } from '../../../src/learning/dream/DreamEngine';
import { BaselineCollector } from '../../../src/learning/baselines/BaselineCollector';
import { QEAgentType } from '../../../src/types';
import { createSeededRandom } from '../../../src/utils/SeededRandom';
describe('Learning Improvement Proof', () => {
const testDir = path.join(process.cwd(), '.test-data', 'learning-improvement');
const testDbPath = path.join(testDir, 'test-learning.db');
let db: Database.Database;
let experienceCapture: ExperienceCapture;
beforeAll(async () => {
// Create test directory
await fs.mkdir(testDir, { recursive: true });
// Clean up existing test database
try {
await fs.unlink(testDbPath);
} catch {
// Ignore if doesn't exist
}
});
afterAll(async () => {
// Cleanup
try {
if (experienceCapture) {
await experienceCapture.stop();
}
ExperienceCapture.resetInstance();
await fs.rm(testDir, { recursive: true, force: true });
} catch {
// Ignore cleanup errors
}
});
describe('Phase 1: Experience Capture Integration', () => {
it('should capture agent execution experiences to database', async () => {
// Initialize ExperienceCapture
experienceCapture = new ExperienceCapture({
dbPath: testDbPath,
bufferSize: 5,
flushInterval: 1000,
});
await experienceCapture.start();
// Simulate 10 agent executions
const rng = createSeededRandom(18500);
const executions: AgentExecutionEvent[] = [];
for (let i = 0; i < 10; i++) {
executions.push({
agentId: `test-agent-${i % 3}`,
agentType: i % 2 === 0 ? 'test-generator' : 'coverage-analyzer',
taskId: `task-${i}`,
taskType: i % 2 === 0 ? 'unit-test-generation' : 'coverage-analysis',
input: { file: `src/module${i}.ts` },
output: {
testsGenerated: Math.floor(rng.random() * 10) + 1,
coverage: rng.random() * 30 + 70,
},
duration: Math.floor(rng.random() * 2000) + 500,
success: rng.random() > 0.1, // 90% success rate
timestamp: new Date(),
});
}
// Capture all executions
for (const execution of executions) {
await experienceCapture.captureExecution(execution);
}
// Force flush
await experienceCapture.flush();
// Verify data is in database
const stats = experienceCapture.getStats();
expect(stats.totalCaptured).toBe(10);
expect(stats.totalFlushed).toBeGreaterThan(0);
// Query database directly to verify persistence
db = new Database(testDbPath);
const count = db.prepare('SELECT COUNT(*) as count FROM agent_experiences').get() as { count: number };
expect(count.count).toBeGreaterThanOrEqual(10);
db.close();
});
it('should track capture statistics by agent type', async () => {
const stats = experienceCapture.getStats();
// Should have captures for both agent types
expect(Object.keys(stats.byAgentType).length).toBeGreaterThanOrEqual(2);
expect(stats.byAgentType['test-generator']).toBeGreaterThan(0);
expect(stats.byAgentType['coverage-analyzer']).toBeGreaterThan(0);
});
});
describe('Phase 2: Sleep Cycle Processing', () => {
it('should process captured experiences through sleep cycle', async () => {
// Create sleep cycle with test configuration
const sleepCycle = new SleepCycle({
budget: {
maxPatternsPerCycle: 20,
maxAgentsPerCycle: 3,
maxDurationMs: 30000, // 30 seconds max for test
},
phaseDurations: {
N1_CAPTURE: 1000, // 1 second
N2_PROCESS: 2000, // 2 seconds
N3_CONSOLIDATE: 1000, // 1 second
REM_DREAM: 2000, // 2 seconds
},
dbPath: testDbPath,
});
// Listen for phase events
const phasesCompleted: string[] = [];
sleepCycle.on('phase:start', (phase) => {
phasesCompleted.push(phase);
});
// Execute the sleep cycle
const summary: CycleSummary = await sleepCycle.execute();
// Verify cycle completed
expect(summary.aborted).toBe(false);
expect(summary.phasesCompleted.length).toBeGreaterThan(0);
expect(summary.errors.length).toBe(0);
// Verify patterns were discovered or processed
expect(summary.patternsDiscovered).toBeGreaterThanOrEqual(0);
});
});
describe('Phase 3: Dream Engine Insight Generation', () => {
it('should generate insights from patterns', async () => {
const dreamEngine = new DreamEngine({
dbPath: testDbPath,
cycleDuration: 5000, // 5 seconds for test
targetInsights: 3,
autoLoadPatterns: true,
debug: false,
});
await dreamEngine.initialize();
// Add some test concepts if none exist
const state = dreamEngine.getState();
if (state.cyclesCompleted === 0) {
// Manually add test concepts
const graph = (dreamEngine as any).graph;
if (graph) {
graph.addConcept({
id: 'test-pattern-1',
type: 'pattern',
content: 'Unit test pattern for async functions',
activationLevel: 0.8,
metadata: { framework: 'jest', category: 'async' },
});
graph.addConcept({
id: 'test-pattern-2',
type: 'pattern',
content: 'Coverage optimization for edge cases',
activationLevel: 0.7,
metadata: { framework: 'jest', category: 'coverage' },
});
}
}
// Run dream cycle
const result = await dreamEngine.dream();
// Verify results
expect(result.status).toBe('completed');
expect(result.duration).toBeGreaterThan(0);
expect(result.conceptsProcessed).toBeGreaterThanOrEqual(0);
dreamEngine.close();
});
});
describe('Phase 4: Baseline Comparison', () => {
let baselineCollector: BaselineCollector;
beforeAll(async () => {
baselineCollector = new BaselineCollector({ dbPath: testDbPath });
await baselineCollector.initialize();
});
afterAll(() => {
baselineCollector.close();
});
it('should collect baselines for comparison', async () => {
// Collect baseline for test-generator
const baseline = await baselineCollector.collectBaseline(
'proof-test-agent',
QEAgentType.TEST_GENERATOR,
'unit-test-generation'
);
expect(baseline).toBeDefined();
expect(baseline.metrics.successRate).toBeGreaterThan(0);
expect(baseline.metrics.avgCompletionTime).toBeGreaterThan(0);
});
it('should calculate improvement targets from baselines', async () => {
const baseline = await baselineCollector.getBaseline(
QEAgentType.TEST_GENERATOR,
'unit-test-generation'
);
if (baseline) {
const target = baselineCollector.getImprovementTarget(baseline);
expect(target.targets.targetSuccessRate).toBeGreaterThan(baseline.metrics.successRate);
expect(target.targets.targetCompletionTime).toBeLessThan(baseline.metrics.avgCompletionTime);
expect(target.minImprovementThreshold).toBe(0.1); // 10% min
expect(target.aspirationalThreshold).toBe(0.2); // 20% aspirational
}
});
});
describe('End-to-End: Learning Pipeline Validation', () => {
it('should prove experiences flow through the entire pipeline', async () => {
// This test validates the complete data flow
// 1. Check experiences exist
db = new Database(testDbPath);
const experienceCount = db.prepare(
'SELECT COUNT(*) as count FROM agent_experiences'
).get() as { count: number };
expect(experienceCount.count).toBeGreaterThan(0);
// 2. Check patterns table exists (created by synthesis)
const tableInfo = db.prepare(
"SELECT name FROM sqlite_master WHERE type='table' AND name='synthesized_patterns'"
).get();
// 3. Check dream insights table
const insightsInfo = db.prepare(
"SELECT name FROM sqlite_master WHERE type='table' AND name='dream_insights'"
).get();
// 4. Check baselines table
const baselinesCount = db.prepare(
'SELECT COUNT(*) as count FROM learning_baselines'
).get() as { count: number };
db.close();
// Summary: Print what exists
console.log('\n📊 Learning Pipeline Validation Summary:');
console.log(` Experiences captured: ${experienceCount.count}`);
console.log(` Patterns table exists: ${!!tableInfo}`);
console.log(` Insights table exists: ${!!insightsInfo}`);
console.log(` Baselines collected: ${baselinesCount.count}`);
// The key assertion: experiences must exist for learning to happen
expect(experienceCount.count).toBeGreaterThan(0);
});
it('should demonstrate learning readiness', async () => {
// This test proves the system is ready to learn
// 1. ExperienceCapture is running
expect(experienceCapture).toBeDefined();
expect(experienceCapture.getStats().totalCaptured).toBeGreaterThan(0);
// 2. Database tables are created
db = new Database(testDbPath);
const tables = db.prepare(`
SELECT name FROM sqlite_master
WHERE type='table'
AND name IN ('agent_experiences', 'learning_baselines', 'concept_nodes', 'dream_insights')
`).all() as { name: string }[];
db.close();
// Should have core tables
const tableNames = tables.map(t => t.name);
expect(tableNames).toContain('agent_experiences');
expect(tableNames).toContain('learning_baselines');
console.log('\n✅ Learning System is READY for continuous improvement');
console.log(' Tables created:', tableNames.join(', '));
});
});
});