/** * @module tests/unit/storage/registered-blob-contract * @description Declared derived-index blob FAMILIES are * undeletable through the storage layer — an in-process GC/sweeper cannot remove * a load-bearing index file (the lost-main.dkann class). Covers declare → * protected-delete-throws; unregister → delete-ok; transient passthrough; * namespace prefix protects children; removeRawPrefix refuses a protected * intersection; persistence across reopen; missing-on-open detection. */ import { describe, it, expect, beforeEach, afterEach } from 'vitest' import * as fs from 'node:fs' import * as os from 'node:os' import * as path from 'node:path' import { MemoryStorage } from '../../../src/storage/adapters/memoryStorage.js' import { FileSystemStorage } from '../../../src/storage/adapters/fileSystemStorage.js' import { ProtectedArtifactError } from '../../../src/index.js' describe('registered-blob family contract', () => { let storage: any beforeEach(async () => { storage = new MemoryStorage() await storage.init() }) const seedVectorFamily = async () => { await storage.saveBinaryBlob('_system/vector-index/main.dkann', Buffer.from([1])) await storage.saveBinaryBlob('_system/vector-index/main.slotmap', Buffer.from([2])) await storage.saveBinaryBlob('_system/vector-index/main.slotrev', Buffer.from([3])) await storage.registerDerivedFamily({ name: 'vector-base', members: [ '_system/vector-index/main.dkann', '_system/vector-index/main.slotmap', '_system/vector-index/main.slotrev' ] }) } it('a declared member is undeletable (throws ProtectedArtifactError)', async () => { await seedVectorFamily() await expect(storage.deleteBinaryBlob('_system/vector-index/main.dkann')).rejects.toBeInstanceOf( ProtectedArtifactError ) // The blob is still there. expect(await storage.loadBinaryBlob('_system/vector-index/main.dkann')).not.toBeNull() }) it('unregistering the family makes its members deletable again', async () => { await seedVectorFamily() await storage.unregisterDerivedFamily('vector-base') await expect(storage.deleteBinaryBlob('_system/vector-index/main.dkann')).resolves.toBeUndefined() expect(await storage.loadBinaryBlob('_system/vector-index/main.dkann')).toBeNull() }) it('an undeclared blob is still deletable (contract does not lock everything)', async () => { await seedVectorFamily() await storage.saveBinaryBlob('graph-lsm/source/sstable-1', Buffer.from([9])) await expect(storage.deleteBinaryBlob('graph-lsm/source/sstable-1')).resolves.toBeUndefined() }) it('a transient (*.tmp.*) is deletable even if it sits under a protected namespace', async () => { await storage.registerDerivedFamily({ name: 'vector-ns', members: ['_system/vector-index/'], namespace: true }) await storage.saveBinaryBlob('_system/vector-index/main.dkann.tmp.123', Buffer.from([1])) await expect( storage.deleteBinaryBlob('_system/vector-index/main.dkann.tmp.123') ).resolves.toBeUndefined() }) it('a namespace family protects a growing child key', async () => { await storage.registerDerivedFamily({ name: 'vector-segments', members: ['_system/vector-index/'], namespace: true }) await storage.saveBinaryBlob('_system/vector-index/seg-42', Buffer.from([7])) await expect(storage.deleteBinaryBlob('_system/vector-index/seg-42')).rejects.toBeInstanceOf( ProtectedArtifactError ) }) it('checkDerivedFamiliesPresent() names a member deleted outside the write path', async () => { await seedVectorFamily() // Simulate an EXTERNAL deleter (bypasses the in-process refusal): drop a // member straight from the underlying store. ;(storage as any).blobStore.delete('_system/vector-index/main.slotmap') const incomplete = await storage.checkDerivedFamiliesPresent() expect(incomplete).toHaveLength(1) expect(incomplete[0].name).toBe('vector-base') expect(incomplete[0].missing).toContain('_system/vector-index/main.slotmap') expect(incomplete[0].rebuildable).toBe(true) }) it('no families registered → deleteBinaryBlob behaves exactly as before (no enforcement)', async () => { await storage.saveBinaryBlob('some/blob', Buffer.from([1])) await expect(storage.deleteBinaryBlob('some/blob')).resolves.toBeUndefined() }) }) describe('registered-blob family protection survives a reopen (FileSystemStorage)', () => { let dir: string beforeEach(() => { dir = fs.mkdtempSync(path.join(os.tmpdir(), 'brainy-regblob-')) }) afterEach(() => fs.rmSync(dir, { recursive: true, force: true })) it('a family declared in one session protects members after reopen', async () => { const s1: any = new FileSystemStorage(dir) await s1.init() await s1.saveBinaryBlob('_system/vector-index/main.dkann', Buffer.from([1])) await s1.registerDerivedFamily({ name: 'vector-base', members: ['_system/vector-index/main.dkann'] }) // Reopen — the registry is loaded from _system/derived-artifacts.json. const s2: any = new FileSystemStorage(dir) await s2.init() expect(await s2.listDerivedFamilies()).toHaveLength(1) await expect(s2.deleteBinaryBlob('_system/vector-index/main.dkann')).rejects.toBeInstanceOf( ProtectedArtifactError ) // removeRawPrefix nuking the vector dir is also refused. await expect(s2.removeRawPrefix('_blobs/_system/vector-index')).rejects.toBeInstanceOf( ProtectedArtifactError ) }) })