/** * C1 regression: Knowledge Store schema alignment. * Bug: DebugKnowledgeStore and LearnedMemoryStore used .air/shared/ paths, * had non-canonical column names, and were missing PRAGMAs. * Fix: moved to .air/local/, renamed columns, added WAL/synchronous/foreign_keys PRAGMAs. */ import { describe, it, expect } from 'bun:test' import { readFileSync } from 'fs' import { join } from 'path' describe('C1: Knowledge Store schema alignment', () => { const debug_src = readFileSync( join(import.meta.dir, '..', '..', 'src', 'knowledge', 'DebugKnowledgeStore.ts'), 'utf-8' ) const memory_src = readFileSync( join(import.meta.dir, '..', '..', 'src', 'knowledge', 'LearnedMemoryStore.ts'), 'utf-8' ) it('DebugKnowledgeStore DB path uses .air/local/ not .air/shared/', () => { expect(debug_src).toContain("'.air', 'local', 'debug-records.db'") expect(debug_src).not.toContain("'.air', 'shared', 'debug-records.db'") }) it('LearnedMemoryStore DB path uses .air/local/ not .air/shared/', () => { expect(memory_src).toContain("'.air', 'local', 'learned-memory.db'") expect(memory_src).not.toContain("'.air', 'shared', 'learned-memory.db'") }) it('DebugRecord has failure_signature not signature', () => { const iface_match = debug_src.match(/export interface DebugRecord\s*\{([\s\S]*?)\}/) expect(iface_match).not.toBeNull() const iface_body = iface_match![1] expect(iface_body).toContain('failure_signature') // Should not have bare 'signature' field (failure_signature contains 'signature' as substring, so check for the exact field pattern) expect(iface_body).not.toMatch(/^\s*signature\s*:/m) }) it('DebugRecord has summary and fix_ref fields', () => { const iface_match = debug_src.match(/export interface DebugRecord\s*\{([\s\S]*?)\}/) expect(iface_match).not.toBeNull() const iface_body = iface_match![1] expect(iface_body).toContain('summary') expect(iface_body).toContain('fix_ref') }) it('DebugRecord does not have error_kind or session_id', () => { const iface_match = debug_src.match(/export interface DebugRecord\s*\{([\s\S]*?)\}/) expect(iface_match).not.toBeNull() const iface_body = iface_match![1] expect(iface_body).not.toContain('error_kind') expect(iface_body).not.toContain('session_id') }) it('DebugKnowledgeStore applies WAL PRAGMA', () => { expect(debug_src).toContain('PRAGMA journal_mode = WAL') }) it('LearnedMemoryStore table is learned_memories (plural)', () => { expect(memory_src).toContain('learned_memories') // Ensure we don't have the singular form used as table name expect(memory_src).not.toMatch(/FROM learned_memory\b/) expect(memory_src).not.toMatch(/INTO learned_memory\b/) expect(memory_src).not.toMatch(/UPDATE learned_memory\b/) expect(memory_src).not.toMatch(/TABLE.*learned_memory\b/) }) it('MemoryEntry.memory_type has 4 spec values', () => { const iface_match = memory_src.match(/export interface MemoryEntry\s*\{([\s\S]*?)\}/) expect(iface_match).not.toBeNull() const iface_body = iface_match![1] expect(iface_body).toContain("'project_rule'") expect(iface_body).toContain("'toolchain_rule'") expect(iface_body).toContain("'skill_update'") expect(iface_body).toContain("'debug_experience'") expect(iface_body).toContain('memory_type') }) it('MemoryEntry.status has 4 spec values: candidate, promoted, archived, rejected', () => { const iface_match = memory_src.match(/export interface MemoryEntry\s*\{([\s\S]*?)\}/) expect(iface_match).not.toBeNull() const iface_body = iface_match![1] expect(iface_body).toContain("'candidate'") expect(iface_body).toContain("'promoted'") expect(iface_body).toContain("'archived'") expect(iface_body).toContain("'rejected'") }) it('MemoryEntry.status default is candidate not draft', () => { // Check that the CREATE TABLE DDL uses 'candidate' as default expect(memory_src).toContain("DEFAULT 'candidate'") expect(memory_src).not.toContain("DEFAULT 'draft'") }) it('MemoryEntry uses source_entity_type + source_entity_id', () => { const iface_match = memory_src.match(/export interface MemoryEntry\s*\{([\s\S]*?)\}/) expect(iface_match).not.toBeNull() const iface_body = iface_match![1] expect(iface_body).toContain('source_entity_type') expect(iface_body).toContain('source_entity_id') expect(iface_body).not.toContain('source_task_ids') }) })