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 });