/ tests / engine.test.ts
engine.test.ts
  1  /**
  2   * Mythogen AME - Test Suite
  3   */
  4  
  5  import { describe, it, expect, beforeEach } from 'vitest';
  6  import { AffinityMapper } from '../src/engine/AffinityMapper.js';
  7  import { TrustDetector, TRUST_INDICATOR_TYPES } from '../src/engine/TrustDetector.js';
  8  import { 
  9    TransparencyEngine, 
 10    TimeLockManager, 
 11    SacredClown, 
 12    MembraneController,
 13    VCrystalSystem 
 14  } from '../src/anticapture/index.js';
 15  import type { LivingSeedPattern, Community, TrustIndicator } from '../src/models/types.js';
 16  
 17  // ============================================
 18  // AffinityMapper Tests
 19  // ============================================
 20  
 21  describe('AffinityMapper', () => {
 22    const mapper = new AffinityMapper();
 23    
 24    it('should get LJ Map with values', () => {
 25      const ljMap = mapper.getLJMap();
 26      expect(ljMap.length).toBeGreaterThan(0);
 27    });
 28    
 29    it('should filter values by cycle', () => {
 30      const selfWorthValues = mapper.findValues('self-worth');
 31      expect(selfWorthValues.length).toBeGreaterThan(0);
 32      selfWorthValues.forEach(v => {
 33        expect(v.cycle).toBe('self-worth');
 34      });
 35    });
 36    
 37    it('should filter values by column', () => {
 38      const column3Values = mapper.findValues(undefined, 3);
 39      expect(column3Values.length).toBeGreaterThan(0);
 40      column3Values.forEach(v => {
 41        expect(v.column).toBe(3);
 42      });
 43    });
 44    
 45    it('should calculate resonance between two seeds', () => {
 46      const seedA: LivingSeedPattern = {
 47        id: 'seed-a',
 48        needs: [],
 49        beliefs: [],
 50        principles: [],
 51        values: [{
 52          id: 'v1',
 53          name: 'generosity',
 54          description: 'Giving without expectation',
 55          requiresOthers: true,
 56          practicedLevel: 0.8,
 57          developmentColumn: 5,
 58          developmentCycle: 'self-expression',
 59          createdAt: new Date(),
 60        }],
 61        plantedAt: new Date(),
 62        lastUpdatedAt: new Date(),
 63        maturationLevel: 1,
 64        valuesEmbedding: [],
 65        visibility: 'private',
 66        createdAt: new Date(),
 67        updatedAt: new Date(),
 68      };
 69      
 70      const seedB: LivingSeedPattern = {
 71        ...seedA,
 72        id: 'seed-b',
 73        values: [{
 74          ...seedA.values[0],
 75          id: 'v2',
 76        }],
 77      };
 78      
 79      const resonance = mapper.calculateResonance(seedA, seedB);
 80      expect(resonance).toBe(1.0); // Exact match
 81    });
 82    
 83    it('should return low resonance for different values', () => {
 84      const seedA: LivingSeedPattern = {
 85        id: 'seed-a',
 86        needs: [],
 87        beliefs: [],
 88        principles: [],
 89        values: [{
 90          id: 'v1',
 91          name: 'survival',
 92          description: 'Basic needs',
 93          requiresOthers: true,
 94          practicedLevel: 0.8,
 95          developmentColumn: 1,
 96          developmentCycle: 'self-worth',
 97          createdAt: new Date(),
 98        }],
 99        plantedAt: new Date(),
100        lastUpdatedAt: new Date(),
101        maturationLevel: 1,
102        valuesEmbedding: [],
103        visibility: 'private',
104        createdAt: new Date(),
105        updatedAt: new Date(),
106      };
107      
108      const seedB: LivingSeedPattern = {
109        ...seedA,
110        id: 'seed-b',
111        values: [{
112          id: 'v2',
113          name: 'presence',
114          description: 'Pure awareness',
115          requiresOthers: true,
116          practicedLevel: 0.8,
117          developmentColumn: 9,
118          developmentCycle: 'selfless-expression',
119          createdAt: new Date(),
120        }],
121      };
122      
123      const resonance = mapper.calculateResonance(seedA, seedB);
124      expect(resonance).toBeLessThan(1.0);
125    });
126    
127    it('should identify desert island testable values', () => {
128      expect(mapper.isDesertIslandTestable({ name: 'generosity' })).toBe(true);
129      expect(mapper.isDesertIslandTestable({ name: 'justice' })).toBe(true);
130      expect(mapper.isDesertIslandTestable({ name: 'something-else' })).toBe(false);
131    });
132  });
133  
134  // ============================================
135  // TrustDetector Tests
136  // ============================================
137  
138  describe('TrustDetector', () => {
139    const detector = new TrustDetector();
140    
141    const createMockCommunity = (indicators: Partial<TrustIndicator>[]): Community => ({
142      id: 'community-1',
143      name: 'Test Community',
144      description: 'A test community',
145      memberIds: ['member-1', 'member-2', 'member-3'],
146      seedPattern: {
147        sharedMyth: 'Test myth',
148        foundingPrinciples: [],
149        emergentValues: [],
150        growthGeometry: 'fractal',
151      },
152      fotScore: {
153        overall: 0,
154        indicators: indicators.map((i, idx) => ({
155          type: TRUST_INDICATOR_TYPES.MUTUAL_SUPPORT,
156          currentValue: 0.5,
157          historicalValues: [0.5],
158          sampleSize: 1,
159          lastMeasuredAt: new Date(),
160          trend: 'stable',
161          ...i,
162        })),
163        membraneHealth: 0.5,
164        isPlasmaState: false,
165        hologramCoherence: 0,
166        lastCalculatedAt: new Date(),
167      },
168      createdAt: new Date(),
169      phase: 'forming',
170      sacredClownActive: false,
171      transparencyScore: 1,
172    });
173    
174    it('should return zero FOT for empty community', () => {
175      const community = createMockCommunity([]);
176      const fot = detector.calculateFOT(community);
177      expect(fot.overall).toBe(0);
178      expect(fot.isPlasmaState).toBe(false);
179    });
180    
181    it('should apply hologram principle (minimum, not average)', () => {
182      const community = createMockCommunity([
183        { type: 'mutual-support', currentValue: 0.9 },
184        { type: 'response-velocity', currentValue: 0.5 }, // Lowest
185        { type: 'conflict-engagement', currentValue: 0.8 },
186        { type: 'benefit-distribution', currentValue: 0.7 },
187        { type: 'psychological-safety', currentValue: 0.9 },
188      ]);
189      
190      const fot = detector.calculateFOT(community);
191      expect(fot.overall).toBe(0.5); // Minimum, not average
192      expect(fot.hologramCoherence).toBe(0);
193      expect(fot.isPlasmaState).toBe(false); // Below 0.7
194    });
195    
196    it('should detect plasma state when all indicators above 0.7', () => {
197      const community = createMockCommunity([
198        { type: 'mutual-support', currentValue: 0.8 },
199        { type: 'response-velocity', currentValue: 0.9 },
200        { type: 'conflict-engagement', currentValue: 0.85 },
201        { type: 'benefit-distribution', currentValue: 0.75 },
202        { type: 'psychological-safety', currentValue: 0.9 },
203      ]);
204      
205      const fot = detector.calculateFOT(community);
206      expect(fot.overall).toBe(0.75);
207      expect(fot.isPlasmaState).toBe(true);
208      expect(fot.hologramCoherence).toBe(0.75);
209    });
210    
211    it('should analyze mutual support events', () => {
212      const result = detector.analyzeEvent({
213        type: 'support',
214        data: { spontaneous: true, frequency: 8 },
215      });
216      
217      expect(result.type).toBe('mutual-support');
218      expect(result.currentValue).toBeGreaterThan(0.5);
219    });
220    
221    it('should analyze response velocity events', () => {
222      const result = detector.analyzeEvent({
223        type: 'response',
224        data: { avgResponseTimeMs: 1800000 }, // 30 minutes
225      });
226      
227      expect(result.type).toBe('response-velocity');
228      expect(result.currentValue).toBe(1.0); // Within 60 minutes = 1.0
229    });
230    
231    it('should analyze conflict engagement events', () => {
232      const result = detector.analyzeEvent({
233        type: 'conflict',
234        data: { deepenedRelationship: true, resolutionQuality: 0.8 },
235      });
236      
237      expect(result.type).toBe('conflict-engagement');
238      expect(result.currentValue).toBeGreaterThan(0.5);
239    });
240    
241    it('should determine community phase based on FOT', () => {
242      const oldDate = new Date(Date.now() - 60 * 24 * 60 * 60 * 1000); // 60 days ago
243      
244      expect(detector.determinePhase({ overall: 0.1 } as any, oldDate.getTime())).toBe('forming');
245      expect(detector.determinePhase({ overall: 0.3 } as any, oldDate.getTime())).toBe('storming');
246      expect(detector.determinePhase({ overall: 0.5 } as any, oldDate.getTime())).toBe('norming');
247      expect(detector.determinePhase({ overall: 0.7 } as any, oldDate.getTime())).toBe('performing');
248      expect(detector.determinePhase({ overall: 0.9 } as any, oldDate.getTime())).toBe('mature');
249    });
250  });
251  
252  // ============================================
253  // Anti-Capture Tests
254  // ============================================
255  
256  describe('TransparencyEngine', () => {
257    const engine = new TransparencyEngine();
258    
259    it('should generate Y Cards', () => {
260      const card = engine.generateYCard({
261        algorithm: 'test-algo',
262        purpose: 'Testing transparency',
263        dataUsed: ['name', 'email'],
264        result: 'Profile created',
265        recipientId: 'user-123',
266      });
267      
268      expect(card.id).toBeDefined();
269      expect(card.algorithm).toBe('test-algo');
270      expect(card.dataUsed).toEqual(['name', 'email']);
271      expect(card.generatedAt).toBeDefined();
272    });
273    
274    it('should format Y Cards for display', () => {
275      const card = {
276        id: 'card-1',
277        algorithm: 'test-algo',
278        purpose: 'Testing',
279        dataUsed: ['field-1'],
280        result: 'Done',
281        generatedAt: new Date(),
282        expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
283      };
284      
285      const formatted = engine.formatYCard(card);
286      expect(formatted).toContain('Y CARD');
287      expect(formatted).toContain('test-algo');
288      expect(formatted).toContain('Testing');
289    });
290  });
291  
292  describe('TimeLockManager', () => {
293    const manager = new TimeLockManager();
294    
295    it('should create time locks', () => {
296      const lock = manager.createTimeLock('seed-123');
297      
298      expect(lock.seedId).toBe('seed-123');
299      expect(lock.isMature).toBe(false);
300      expect(lock.maturesAt.getTime()).toBeGreaterThan(Date.now());
301    });
302    
303    it('should report immature status correctly', () => {
304      const lock = manager.createTimeLock('seed-123');
305      
306      expect(manager.isMature(lock)).toBe(false);
307      expect(manager.getMaturationProgress(lock)).toBeLessThan(1);
308    });
309    
310    it('should not allow manipulation before maturation', () => {
311      const lock = manager.createTimeLock('seed-123');
312      
313      expect(manager.canManipulate(lock)).toBe(false); // Returns false if NOT mature
314    });
315  });
316  
317  describe('SacredClown', () => {
318    const clown = new SacredClown();
319    
320    it('should trigger disruptions', () => {
321      const disruption = clown.triggerDisruption('community-1');
322      
323      expect(disruption.type).toBeDefined();
324      expect(disruption.message).toBeDefined();
325      expect(disruption.purpose).toBeDefined();
326    });
327    
328    it('should track disruption history', () => {
329      clown.triggerDisruption('community-2');
330      const history = clown.getDisruptions('community-2');
331      
332      expect(history.length).toBe(1);
333    });
334  });
335  
336  describe('MembraneController', () => {
337    const controller = new MembraneController();
338    
339    it('should create membrane state', () => {
340      const membrane = controller.createMembrane('community-1');
341      
342      expect(membrane.communityId).toBe('community-1');
343      expect(membrane.permeabilityLevel).toBe(0.5);
344      expect(membrane.blockedEntities).toEqual([]);
345    });
346    
347    it('should update membrane based on health', () => {
348      const membrane = controller.createMembrane('community-1');
349      const updated = controller.updateMembrane(membrane, 0.9, []);
350      
351      expect(updated.permeabilityLevel).toBeGreaterThan(0.5);
352    });
353    
354    it('should block entities', () => {
355      const membrane = controller.createMembrane('community-1');
356      const blocked = controller.blockEntity(membrane, 'bad-actor');
357      
358      expect(blocked.blockedEntities).toContain('bad-actor');
359      expect(controller.canPass(blocked, 'bad-actor')).toBe(false);
360    });
361    
362    it('should allow trusted entities', () => {
363      const membrane = controller.createMembrane('community-1');
364      const allowed = controller.allowEntity(membrane, 'trusted-member');
365      
366      expect(allowed.allowedEntities).toContain('trusted-member');
367      expect(controller.canPass(allowed, 'trusted-member')).toBe(true);
368    });
369  });
370  
371  describe('VCrystalSystem', () => {
372    const system = new VCrystalSystem();
373    
374    it('should detect V-Dynamics from trigger words', () => {
375      const dynamic = system.detectVDynamic('community-1', 'This is their fault!');
376      
377      expect(dynamic).not.toBeNull();
378      expect(dynamic?.dominantPosition).toBe('victor');
379    });
380    
381    it('should detect vengeance patterns', () => {
382      const dynamic = system.detectVDynamic('community-1', 'They deserve payback!');
383      
384      expect(dynamic?.dominantPosition).toBe('vengeful');
385      expect(system.isAutoimmuneFlare(dynamic!)).toBe(true);
386    });
387    
388    it('should resolve V-Dynamics through states', () => {
389      const dynamic = system.detectVDynamic('community-1', 'I feel hurt');
390      
391      if (dynamic) {
392        const healing = system.resolveVDynamic(dynamic);
393        expect(healing.resolutionState).toBe('healing');
394        
395        const resolved = system.resolveVDynamic(healing);
396        expect(resolved.resolutionState).toBe('resolved');
397      }
398    });
399    
400    it('should identify vulnerability as circuit breaker', () => {
401      const dynamic = system.detectVDynamic('community-1', 'I feel vulnerable and exposed');
402      
403      expect(dynamic?.dominantPosition).toBe('vulnerable');
404      expect(system.canBreakCycle(dynamic!)).toBe(true);
405    });
406    
407    it('should return null for non-triggering events', () => {
408      const dynamic = system.detectVDynamic('community-1', 'Hello everyone!');
409      
410      expect(dynamic).toBeNull();
411    });
412  });