import { describe, test } from 'node:test'; import assert from 'node:assert/strict'; import { Arbiter } from '../../src/core/Arbiter.js'; describe('Cache invalidation paths', () => { test('relation lookup cache clears on removal', () => { const arbiter = new Arbiter(); arbiter.addNode('user', 'user'); arbiter.addNode('doc', 'document'); arbiter.addRelation('user', 'can_read', 'doc', 1.0); const srcId = arbiter.nodeIdByKey.get('user'); const dstId = arbiter.nodeIdByKey.get('doc'); const cacheKey = arbiter.relationManager._makeDirectCacheKey(srcId, 'can_read', dstId); const relation = arbiter.relationManager.getDirectRelation(srcId, 'can_read', dstId); assert.ok(relation); // RF-08: cache state moved entirely to RelationCaches. assert.ok(arbiter.relationManager._caches.relationLookupCache.has(cacheKey)); arbiter.removeRelation('user', 'can_read', 'doc'); assert.ok(!arbiter.relationManager._caches.relationLookupCache.has(cacheKey)); }); test('value cache clears on relation modification', () => { const arbiter = new Arbiter(); arbiter.addNode('user', 'user'); arbiter.addNode('account', 'account'); arbiter.addRelation('user', 'has_balance', 'account', 1.0, { value: 10 }); const srcId = arbiter.nodeIdByKey.get('user'); const dstId = arbiter.nodeIdByKey.get('account'); const cacheKey = arbiter.relationManager._makeValueCacheKey(srcId, 'has_balance', dstId); const valueRelation = arbiter.relationManager.getValueRelation(srcId, 'has_balance', dstId); assert.ok(valueRelation); assert.ok(arbiter.relationManager._caches.valueLookupCache.has(cacheKey)); arbiter.relationManager._modifyRelation('user', 'has_balance', 'account', { value: 20 }); assert.ok(!arbiter.relationManager._caches.valueLookupCache.has(cacheKey)); }); test('direct check cache clears on relation removal', () => { const arbiter = new Arbiter(); arbiter.addNode('user', 'user'); arbiter.addNode('doc', 'document'); arbiter.addRelation('user', 'can_read', 'doc', 1.0); arbiter.setRelationConfig('can_read', { type: 'direct' }); const result = arbiter.check('user', 'can_read', 'doc'); assert.strictEqual(result.possibility, 1.0); const srcId = arbiter.keyManager.getStringId('user'); const dstId = arbiter.keyManager.getStringId('doc'); const cacheKey = arbiter.keyManager.createCompositeKey(srcId, 'can_read', dstId); assert.ok(arbiter.directCheckCache.has(cacheKey)); arbiter.removeRelation('user', 'can_read', 'doc'); assert.ok(!arbiter.directCheckCache.has(cacheKey)); }); test('value cache invalidation schedules stale recompute', () => { const arbiter = new Arbiter(); arbiter.addNode('user', 'user'); arbiter.addNode('account', 'account'); arbiter.addRelation('user', 'has_balance', 'account', 1.0, { value: 10 }); const srcId = arbiter.nodeIdByKey.get('user'); const dstId = arbiter.nodeIdByKey.get('account'); const valueRelation = arbiter.relationManager.getValueRelation(srcId, 'has_balance', dstId); assert.ok(valueRelation); arbiter.relationManager._modifyRelation('user', 'has_balance', 'account', { value: 20 }); assert.strictEqual(arbiter.valueManager.staleValueItemsIndex.size, 0); }); });