/** * relation-cache-extraction.test.js — verifies RF-08 deletion test closure. * * Before this refactor, RelationManager aliased 7 cache fields from * RelationCaches (this._relationLookupCache, this._valueLookupCache, etc.). * Removing RelationCaches.js from disk without removing the aliases * would have left broken references. This test confirms: * - The aliases no longer exist on RelationManager * - All cache state lives under RelationManager._caches * - Functional behavior is unchanged: relations still work, caches still * populate and serve lookups */ import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { Arbiter } from '../../src/index.js'; describe('RF-08: RelationManager cache extraction', () => { it('does not alias cache fields (deletion test)', () => { const arbiter = new Arbiter(); const rm = arbiter.relationManager; // The seven aliased fields that used to live on RelationManager // are gone. Each must be undefined. assert.equal(rm._maxCacheSize, undefined); assert.equal(rm._relationLookupCache, undefined); assert.equal(rm._valueLookupCache, undefined); assert.equal(rm._relationLookupCacheKeys, undefined); assert.equal(rm._valueLookupCacheKeys, undefined); assert.equal(rm._valueRelationsBySrcCache, undefined); assert.equal(rm._valueRelationsByDstCache, undefined); assert.equal(rm._valueRelationsByNameCache, undefined); // The only cache surface is now _caches (the RelationCaches instance). assert.ok(rm._caches); assert.ok(rm._caches.relationLookupCache); assert.ok(rm._caches.valueLookupCache); assert.ok(rm._caches.valueRelationsBySrcCache); assert.ok(rm._caches.valueRelationsByDstCache); assert.ok(rm._caches.valueRelationsByNameCache); }); it('functional cache behavior is preserved', () => { 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'); // First call populates cache const r1 = arbiter.relationManager.getDirectRelation(srcId, 'can_read', dstId); assert.ok(r1); const cacheKey = arbiter.relationManager._makeDirectCacheKey(srcId, 'can_read', dstId); assert.ok(arbiter.relationManager._caches.relationLookupCache.has(cacheKey)); // Second call hits cache const r2 = arbiter.relationManager.getDirectRelation(srcId, 'can_read', dstId); assert.equal(r1, r2); // Removal invalidates arbiter.removeRelation('user', 'can_read', 'doc'); assert.equal(arbiter.relationManager._caches.relationLookupCache.has(cacheKey), false); }); it('value relation caches still work end-to-end', () => { const arbiter = new Arbiter(); arbiter.addNode('user', 'user'); arbiter.addNode('account', 'account'); arbiter.addRelation('user', 'has_balance', 'account', 1.0, { value: 100 }); const srcId = arbiter.nodeIdByKey.get('user'); const dstId = arbiter.nodeIdByKey.get('account'); // Populate const v1 = arbiter.relationManager.getValueRelation(srcId, 'has_balance', dstId); assert.ok(v1); assert.equal(v1.pointValue, 100); const cacheKey = arbiter.relationManager._makeValueCacheKey(srcId, 'has_balance', dstId); assert.ok(arbiter.relationManager._caches.valueLookupCache.has(cacheKey)); // Update — should invalidate arbiter.relationManager._modifyRelation('user', 'has_balance', 'account', { value: 200 }); assert.equal(arbiter.relationManager._caches.valueLookupCache.has(cacheKey), false); // Re-fetch reflects new value const v2 = arbiter.relationManager.getValueRelation(srcId, 'has_balance', dstId); assert.equal(v2.pointValue, 200); }); it('cache stats reference _caches.size() correctly', () => { const arbiter = new Arbiter(); arbiter.addNode('a', 'x'); arbiter.addNode('b', 'x'); arbiter.addRelation('a', 'rel', 'b', 1.0); const srcId = arbiter.nodeIdByKey.get('a'); const dstId = arbiter.nodeIdByKey.get('b'); arbiter.relationManager.getDirectRelation(srcId, 'rel', dstId); const stats = arbiter.relationManager.getCacheStats(); assert.ok(typeof stats.relationCacheSize === 'number'); assert.ok(typeof stats.valueCacheSize === 'number'); assert.ok(stats.relationCacheSize >= 1); }); });