/ tests / feature-validation.ts
feature-validation.ts
 1  import { captureGuardianCheckpoint, prepareGuardianRecovery } from '../src/lib/server/agents/guardian'
 2  import { applyMMR } from '../src/lib/server/mmr'
 3  import { execSync } from 'child_process'
 4  import fs from 'fs'
 5  import path from 'path'
 6  import os from 'os'
 7  
 8  // Mock types for MMR test
 9  interface MemoryEntry {
10    id: string
11    title: string
12    content: string
13    category: string
14    createdAt: number
15    updatedAt: number
16    [key: string]: unknown
17  }
18  
19  async function runTests() {
20    console.log('🚀 Starting SwarmClaw Advanced Feature Validation...\n')
21  
22    // --- 1. Test MMR Diversity ---
23    console.log('--- Testing MMR (Maximal Marginal Relevance) ---')
24    
25    // Use distinct embeddings
26    const queryEmbedding = [1, 0, 0] 
27    const now = Date.now()
28    const candidates = [
29      {
30        entry: { id: '1', title: 'Python Loop', content: 'How to write a for loop in python', category: 'note', createdAt: now, updatedAt: now } as MemoryEntry,
31        salience: 0.9,
32        embedding: [1, 0.1, 0] // High relevance
33      },
34      {
35        entry: { id: '2', title: 'Python For', content: 'Writing for loops in python language', category: 'note', createdAt: now, updatedAt: now } as MemoryEntry,
36        salience: 0.89,
37        embedding: [1, 0.11, 0] // High relevance, but almost identical to #1
38      },
39      {
40        entry: { id: '3', title: 'React Hooks', content: 'Using useEffect and useState in React', category: 'note', createdAt: now, updatedAt: now } as MemoryEntry,
41        salience: 0.7,
42        embedding: [0, 1, 0] // Lower relevance, but very diverse
43      },
44    ]
45  
46    console.log('Running MMR with lambda=0.2 (High Diversity)...')
47    const diverseResults = applyMMR(queryEmbedding, candidates, 2, 0.2)
48    console.log('Selected IDs:', diverseResults.map(r => r.id))
49    
50    // With lambda=0.2, ID '3' should definitely be picked over '2'
51    if (diverseResults.some(r => r.id === '3')) {
52      console.log('✅ MMR Diversity Test Passed!')
53    } else {
54      console.log('❌ MMR Diversity Test Failed: Diversity still not prioritized.')
55    }
56  
57    // --- 2. Test Guardian Recovery Prep ---
58    console.log('\n--- Testing Guardian Recovery Preparation ---')
59    const testRepoDir = path.join(os.tmpdir(), `swarmclaw-test-repo-${Date.now()}`)
60    fs.mkdirSync(testRepoDir)
61    
62    try {
63      execSync('git init', { cwd: testRepoDir })
64      execSync('git config user.email "test@example.com"', { cwd: testRepoDir })
65      execSync('git config user.name "Test User"', { cwd: testRepoDir })
66      fs.writeFileSync(path.join(testRepoDir, 'config.json'), '{"status": "ok"}')
67      execSync('git add . && git commit -m "Initial commit"', { cwd: testRepoDir })
68      
69      const checkpoint = captureGuardianCheckpoint(testRepoDir, 'feature-validation')
70      if (!checkpoint.ok) {
71        console.log('❌ Guardian Checkpoint Test Failed: unable to capture checkpoint.')
72        return
73      }
74  
75      // Corrupt the file
76      fs.writeFileSync(path.join(testRepoDir, 'config.json'), '{"status": "CORRUPTED"}')
77      console.log('Simulating workspace corruption...')
78  
79      const recovery = prepareGuardianRecovery({
80        cwd: testRepoDir,
81        reason: 'Feature validation corruption test',
82        requester: 'feature-validation',
83      })
84  
85      if (recovery.ok && recovery.approval?.id && recovery.checkpoint?.approvalId === recovery.approval.id) {
86        console.log('✅ Guardian Recovery Prep Test Passed! (Checkpoint + approval created)')
87      } else {
88        console.log('❌ Guardian Recovery Prep Test Failed!')
89      }
90    } catch (err) {
91      console.error('Guardian test error:', err)
92    } finally {
93      try { fs.rmSync(testRepoDir, { recursive: true, force: true }) } catch {}
94    }
95  
96    console.log('\n--- Validation Complete ---')
97  }
98  
99  runTests().catch(console.error)