102 lines
42 KiB
Plaintext
102 lines
42 KiB
Plaintext
[2026-05-14T18:18:21.152Z] RESULT
|
|
============================================================
|
|
{
|
|
"success": true,
|
|
"output": "## Test Coverage Analysis\n\n### Finding: Zero Test Coverage (0%)\n\nThis project has **no source code and no tests**. It's a pure runtime/configuration installation of the claude-flow agent orchestration framework containing only:\n\n- `package.json` — dependency manifest\n- `claude-flow.config.json` — runtime configuration\n- `data/memory/schema.sql` — SQLite schema for RuFlo V3\n- Binary databases (`ruvector.db`, `memory.db`)\n\nThere is nothing to \"cover\" in the traditional sense. However, the system has **significant integration surface area** that is completely untested. Here's a full gap analysis with skeletons.\n\n---\n\n## Gap Analysis & Test Skeletons\n\n### 1. Configuration Validation (Critical — no coverage)\n\nThe config is loaded at runtime but never validated for correctness.\n\n**Gaps:**\n- No schema validation for `claude-flow.config.json`\n- Invalid `vectorDimension` values could trigger bug #1947 (dimension mismatch)\n- `maxConcurrent`/`maxAgents` mismatches (config has 8 in both places — coincidence, not enforced)\n\n```javascript\n// tests/config.test.js\nimport { describe, it, expect } from 'vitest';\nimport config from '../claude-flow.config.json';\n\ndescribe('claude-flow.config.json', () => {\n it('has required top-level keys', () => {\n expect(config).toHaveProperty('version');\n expect(config).toHaveProperty('agents');\n expect(config).toHaveProperty('swarm');\n expect(config).toHaveProperty('memory');\n expect(config).toHaveProperty('mcp');\n });\n\n it('vectorDimension matches HNSW default index (bug #1947)', () => {\n // HNSW rejects inserts whose dim does not match schema default (384)\n expect(config.memory.vectorDimension).toBe(384);\n });\n\n it('maxConcurrent does not exceed swarm maxAgents', () => {\n expect(config.agents.maxConcurrent).toBeLessThanOrEqual(config.swarm.maxAgents);\n });\n\n it('memory persistPath is a relative path', () => {\n expect(config.memory.persistPath).toMatch(/^\\.\\//);\n });\n\n it('mcp transport is stdio or http', () => {\n expect(['stdio', 'http']).toContain(config.mcp.transportType);\n });\n\n it('swarm topology is a known value', () => {\n const valid = ['hierarchical', 'mesh', 'ring', 'star'];\n expect(valid).toContain(config.swarm.topology);\n });\n});\n```\n\n---\n\n### 2. Database Schema Integrity (Critical — no coverage)\n\nThe schema has known constraints and a documented bug (#1947). Nothing verifies the live DB matches the schema.\n\n**Gaps:**\n- No test that the live `memory.db` was initialized from the correct schema version\n- No test that the `vector_indexes` default row has `dimensions = 384` (bug #1947 would break all vector ops)\n- No test for CHECK constraints on `type`, `status`, `pattern_type` columns\n- No test for the `UNIQUE(namespace, key)` constraint on `memory_entries`\n\n```javascript\n// tests/schema.test.js\nimport Database from 'better-sqlite3';\nimport path from 'path';\n\nconst DB_PATH = path.resolve('./data/memory/memory.db');\n\ndescribe('RuFlo V3 schema integrity', () => {\n let db;\n\n beforeAll(() => { db = new Database(DB_PATH, { readonly: true }); });\n afterAll(() => { db.close(); });\n\n it('schema version is 3.0.0', () => {\n const row = db.prepare(\"SELECT value FROM metadata WHERE key = 'schema_version'\").get();\n expect(row.value).toBe('3.0.0');\n });\n\n it('default HNSW vector index has dimension 384 (bug #1947 guard)', () => {\n const row = db.prepare(\"SELECT dimensions FROM vector_indexes WHERE name = 'default'\").get();\n expect(row).toBeDefined();\n expect(row.dimensions).toBe(384);\n });\n\n it('patterns index has dimension 384', () => {\n const row = db.prepare(\"SELECT dimensions FROM vector_indexes WHERE name = 'patterns'\").get();\n expect(row.dimensions).toBe(384);\n });\n\n it('all required tables exist', () => {\n const tables = db.prepare(\n \"SELECT name FROM sqlite_master WHERE type='table'\"\n ).all().map(r => r.name);\n const required = [\n 'memory_entries', 'patterns', 'pattern_history',\n 'trajectories', 'trajectory_steps', 'migration_state',\n 'sessions', 'vector_indexes', 'metadata'\n ];\n for (const t of required) expect(tables).toContain(t);\n });\n\n it('WAL mode is enabled', () => {\n const row = db.prepare('PRAGMA journal_mode').get();\n expect(row.journal_mode).toBe('wal');\n });\n\n it('foreign keys are enforced', () => {\n const row = db.prepare('PRAGMA foreign_keys').get();\n expect(row.foreign_keys).toBe(1);\n });\n});\n```\n\n---\n\n### 3. Memory CRUD Operations (High — no coverage)\n\nThe `memory_store`/`memory_search` MCP tools are the core interface, but no smoke tests exist.\n\n**Gaps:**\n- No store → retrieve round-trip test\n- No namespace isolation test\n- No expiry/TTL behavior test\n- No `UNIQUE(namespace, key)` upsert behavior test\n- No `status` filtering test (active vs archived vs deleted)\n\n```javascript\n// tests/memory-crud.test.js\nimport Database from 'better-sqlite3';\nimport { randomUUID } from 'crypto';\n\nconst DB_PATH = './data/memory/memory.db';\n\ndescribe('memory_entries CRUD', () => {\n let db;\n\n beforeAll(() => { db = new Database(DB_PATH); });\n afterAll(() => { db.close(); });\n\n it('inserts and retrieves a memory entry', () => {\n const id = randomUUID();\n db.prepare(`\n INSERT INTO memory_entries (id, key, namespace, content)\n VALUES (?, ?, ?, ?)\n `).run(id, 'test-key', 'test-ns', 'hello world');\n\n const row = db.prepare('SELECT * FROM memory_entries WHERE id = ?').get(id);\n expect(row.content).toBe('hello world');\n expect(row.status).toBe('active');\n });\n\n it('enforces UNIQUE(namespace, key)', () => {\n const ns = `ns-${randomUUID()}`;\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(randomUUID(), 'dup-key', ns, 'first');\n\n expect(() =>\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(randomUUID(), 'dup-key', ns, 'second')\n ).toThrow(/UNIQUE constraint failed/);\n });\n\n it('rejects invalid type values', () => {\n expect(() =>\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content, type) VALUES (?, ?, ?, ?, ?)'\n ).run(randomUUID(), 'k', 'ns', 'c', 'invalid-type')\n ).toThrow(/CHECK constraint failed/);\n });\n\n it('soft-delete via status = deleted', () => {\n const id = randomUUID();\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(id, `del-${id}`, 'del-ns', 'to be deleted');\n\n db.prepare(\"UPDATE memory_entries SET status = 'deleted' WHERE id = ?\").run(id);\n const row = db.prepare(\"SELECT * FROM memory_entries WHERE id = ? AND status = 'active'\").get(id);\n expect(row).toBeUndefined();\n });\n\n it('isolates namespaces', () => {\n const ns1 = `ns1-${randomUUID()}`;\n const ns2 = `ns2-${randomUUID()}`;\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(randomUUID(), 'shared-key', ns1, 'ns1-value');\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(randomUUID(), 'shared-key', ns2, 'ns2-value');\n\n const r1 = db.prepare('SELECT content FROM memory_entries WHERE namespace = ? AND key = ?').get(ns1, 'shared-key');\n const r2 = db.prepare('SELECT content FROM memory_entries WHERE namespace = ? AND key = ?').get(ns2, 'shared-key');\n expect(r1.content).toBe('ns1-value');\n expect(r2.content).toBe('ns2-value');\n });\n});\n```\n\n---\n\n### 4. Pattern Learning & Confidence Decay (High — no coverage)\n\nThe patterns table has a confidence scoring system with decay — none of it is tested.\n\n**Gaps:**\n- No test that confidence stays in [0.0, 1.0]\n- No test for `success_count`/`failure_count` incrementing correctly\n- No test that `pattern_history` records are created on changes\n- No test for the `parent_id` self-referential FK (versioning)\n- No test for `experimental` → `active` promotion logic\n\n```javascript\n// tests/pattern-learning.test.js\ndescribe('pattern confidence scoring', () => {\n it('new patterns default to 0.5 confidence', () => {\n const id = randomUUID();\n db.prepare(`\n INSERT INTO patterns (id, name, pattern_type, condition, action)\n VALUES (?, ?, ?, ?, ?)\n `).run(id, 'test-pattern', 'task-routing', 'foo.*', 'route to coder');\n\n const row = db.prepare('SELECT confidence FROM patterns WHERE id = ?').get(id);\n expect(row.confidence).toBe(0.5);\n });\n\n it('rejects invalid pattern_type', () => {\n expect(() =>\n db.prepare(`\n INSERT INTO patterns (id, name, pattern_type, condition, action)\n VALUES (?, ?, ?, ?, ?)\n `).run(randomUUID(), 'x', 'invalid-type', '.', '.')\n ).toThrow(/CHECK constraint failed/);\n });\n\n it('pattern_history records on update', () => {\n const id = randomUUID();\n db.prepare(`\n INSERT INTO patterns (id, name, pattern_type, condition, action)\n VALUES (?, ?, ?, ?, ?)\n `).run(id, 'track-me', 'learning', '.*', 'store');\n\n db.prepare(`\n INSERT INTO pattern_history (pattern_id, version, confidence, change_type)\n VALUES (?, ?, ?, ?)\n `).run(id, 1, 0.5, 'created');\n\n const rows = db.prepare('SELECT * FROM pattern_history WHERE pattern_id = ?').all(id);\n expect(rows).toHaveLength(1);\n expect(rows[0].change_type).toBe('created');\n });\n\n it('parent_id FK references patterns table', () => {\n expect(() =>\n db.prepare(`\n INSERT INTO patterns (id, name, pattern_type, condition, action, parent_id)\n VALUES (?, ?, ?, ?, ?, ?)\n `).run(randomUUID(), 'child', 'learning', '.', '.', 'nonexistent-id')\n ).toThrow(/FOREIGN KEY constraint failed/);\n });\n});\n```\n\n---\n\n### 5. MCP Server Connectivity (Medium — no coverage)\n\nThe MCP server is configured for `localhost:3000` but startup and tool availability are never verified.\n\n**Gaps:**\n- No smoke test that the MCP server starts\n- No test that claude-flow tools respond to health checks\n- No test for stdio transport handshake\n\n```javascript\n// tests/mcp-smoke.test.js\nimport { execSync, spawn } from 'child_process';\n\ndescribe('MCP server', () => {\n it('claude-flow CLI is available', () => {\n const result = execSync('npx @claude-flow/cli@latest --version', { encoding: 'utf8' });\n expect(result.trim()).toMatch(/\\d+\\.\\d+/);\n });\n\n it('system health check passes', () => {\n const result = execSync('npx @claude-flow/cli@latest doctor', {\n encoding: 'utf8',\n timeout: 15_000\n });\n expect(result).toMatch(/health|ok|pass/i);\n });\n\n it('memory backend is reachable', () => {\n const result = execSync(\n 'npx @claude-flow/cli@latest memory stats',\n { encoding: 'utf8', timeout: 10_000 }\n );\n expect(result).not.toMatch(/error|fail/i);\n });\n});\n```\n\n---\n\n### 6. Session Lifecycle (Medium — no coverage)\n\nSessions are the persistence layer for agent context across runs. Nothing tests their lifecycle.\n\n**Gaps:**\n- No test for session creation with required `state` JSON\n- No test for session expiry (`expires_at` in the past)\n- No test for `paused` → `active` status transition\n- No test that `tasks_completed` increments correctly\n\n```javascript\n// tests/session-lifecycle.test.js\ndescribe('sessions table', () => {\n it('creates a session with valid JSON state', () => {\n const id = randomUUID();\n const state = JSON.stringify({ agentId: 'coder-1', task: 'write tests' });\n db.prepare(\n 'INSERT INTO sessions (id, state) VALUES (?, ?)'\n ).run(id, state);\n\n const row = db.prepare('SELECT * FROM sessions WHERE id = ?').get(id);\n expect(JSON.parse(row.state).agentId).toBe('coder-1');\n expect(row.status).toBe('active');\n });\n\n it('rejects invalid status values', () => {\n expect(() =>\n db.prepare(\n 'INSERT INTO sessions (id, state, status) VALUES (?, ?, ?)'\n ).run(randomUUID(), '{}', 'running') // 'running' not in CHECK list\n ).toThrow(/CHECK constraint failed/);\n });\n\n it('expired sessions have expires_at in the past', () => {\n const id = randomUUID();\n const pastMs = Date.now() - 1000;\n db.prepare(\n 'INSERT INTO sessions (id, state, expires_at) VALUES (?, ?, ?)'\n ).run(id, '{}', pastMs);\n\n const now = Date.now();\n const expired = db.prepare(\n 'SELECT * FROM sessions WHERE expires_at < ? AND id = ?'\n ).get(now, id);\n expect(expired).toBeDefined();\n });\n});\n```\n\n---\n\n### 7. Migration State Tracking (Medium — no coverage)\n\nThe migration system supports resume-on-failure but has no tests.\n\n**Gaps:**\n- No test for idempotent migration (re-running a completed migration)\n- No test that `in_progress` → `completed` transition updates `processed_items`\n- No test that `rolled_back` status halts further processing\n- No test for `errors` JSON array accumulation\n\n```javascript\n// tests/migration-state.test.js\ndescribe('migration_state', () => {\n it('tracks progress through a migration', () => {\n const id = randomUUID();\n db.prepare(`\n INSERT INTO migration_state (id, migration_type, total_items, status)\n VALUES (?, ?, ?, ?)\n `).run(id, 'v2-to-v3', 100, 'in_progress');\n\n db.prepare(`\n UPDATE migration_state\n SET processed_items = 50, current_batch = 5\n WHERE id = ?\n `).run(id);\n\n const row = db.prepare('SELECT * FROM migration_state WHERE id = ?').get(id);\n expect(row.processed_items).toBe(50);\n expect(row.current_batch).toBe(5);\n expect(row.total_items).toBe(100);\n });\n\n it('stores errors as JSON array', () => {\n const id = randomUUID();\n const errors = JSON.stringify([{ item: 'abc', reason: 'parse error' }]);\n db.prepare(`\n INSERT INTO migration_state (id, migration_type, errors, status)\n VALUES (?, ?, ?, ?)\n `).run(id, 'pattern', errors, 'failed');\n\n const row = db.prepare('SELECT errors FROM migration_state WHERE id = ?').get(id);\n const parsed = JSON.parse(row.errors);\n expect(parsed[0].reason).toBe('parse error');\n });\n});\n```\n\n---\n\n## Summary of Gaps\n\n| Area | Priority | Gap Count | Effort |\n|------|----------|-----------|--------|\n| Config validation | Critical | 6 | Low |\n| Schema integrity + bug #1947 guard | Critical | 8 | Low |\n| Memory CRUD | High | 5 | Medium |\n| Pattern learning | High | 5 | Medium |\n| MCP server smoke tests | Medium | 3 | Low |\n| Session lifecycle | Medium | 4 | Low |\n| Migration tracking | Medium | 3 | Low |\n\n**Recommended first step:** Add `vitest` or `jest` + `better-sqlite3` to `devDependencies` and wire up a `test` script in `package.json`. The schema integrity tests and config validation tests can be running in under an hour and would catch bug #1947 on every fresh install.\n",
|
|
"parsedOutput": {
|
|
"sections": [
|
|
{
|
|
"title": "Test Coverage Analysis",
|
|
"content": "\n",
|
|
"level": 2
|
|
},
|
|
{
|
|
"title": "Finding: Zero Test Coverage (0%)",
|
|
"content": "\nThis project has **no source code and no tests**. It's a pure runtime/configuration installation of the claude-flow agent orchestration framework containing only:\n\n- `package.json` — dependency manifest\n- `claude-flow.config.json` — runtime configuration\n- `data/memory/schema.sql` — SQLite schema for RuFlo V3\n- Binary databases (`ruvector.db`, `memory.db`)\n\nThere is nothing to \"cover\" in the traditional sense. However, the system has **significant integration surface area** that is completely untested. Here's a full gap analysis with skeletons.\n\n---\n\n",
|
|
"level": 3
|
|
},
|
|
{
|
|
"title": "Gap Analysis & Test Skeletons",
|
|
"content": "\n",
|
|
"level": 2
|
|
},
|
|
{
|
|
"title": "1. Configuration Validation (Critical — no coverage)",
|
|
"content": "\nThe config is loaded at runtime but never validated for correctness.\n\n**Gaps:**\n- No schema validation for `claude-flow.config.json`\n- Invalid `vectorDimension` values could trigger bug #1947 (dimension mismatch)\n- `maxConcurrent`/`maxAgents` mismatches (config has 8 in both places — coincidence, not enforced)\n\n```javascript\n// tests/config.test.js\nimport { describe, it, expect } from 'vitest';\nimport config from '../claude-flow.config.json';\n\ndescribe('claude-flow.config.json', () => {\n it('has required top-level keys', () => {\n expect(config).toHaveProperty('version');\n expect(config).toHaveProperty('agents');\n expect(config).toHaveProperty('swarm');\n expect(config).toHaveProperty('memory');\n expect(config).toHaveProperty('mcp');\n });\n\n it('vectorDimension matches HNSW default index (bug #1947)', () => {\n // HNSW rejects inserts whose dim does not match schema default (384)\n expect(config.memory.vectorDimension).toBe(384);\n });\n\n it('maxConcurrent does not exceed swarm maxAgents', () => {\n expect(config.agents.maxConcurrent).toBeLessThanOrEqual(config.swarm.maxAgents);\n });\n\n it('memory persistPath is a relative path', () => {\n expect(config.memory.persistPath).toMatch(/^\\.\\//);\n });\n\n it('mcp transport is stdio or http', () => {\n expect(['stdio', 'http']).toContain(config.mcp.transportType);\n });\n\n it('swarm topology is a known value', () => {\n const valid = ['hierarchical', 'mesh', 'ring', 'star'];\n expect(valid).toContain(config.swarm.topology);\n });\n});\n```\n\n---\n\n",
|
|
"level": 3
|
|
},
|
|
{
|
|
"title": "2. Database Schema Integrity (Critical — no coverage)",
|
|
"content": "\nThe schema has known constraints and a documented bug (#1947). Nothing verifies the live DB matches the schema.\n\n**Gaps:**\n- No test that the live `memory.db` was initialized from the correct schema version\n- No test that the `vector_indexes` default row has `dimensions = 384` (bug #1947 would break all vector ops)\n- No test for CHECK constraints on `type`, `status`, `pattern_type` columns\n- No test for the `UNIQUE(namespace, key)` constraint on `memory_entries`\n\n```javascript\n// tests/schema.test.js\nimport Database from 'better-sqlite3';\nimport path from 'path';\n\nconst DB_PATH = path.resolve('./data/memory/memory.db');\n\ndescribe('RuFlo V3 schema integrity', () => {\n let db;\n\n beforeAll(() => { db = new Database(DB_PATH, { readonly: true }); });\n afterAll(() => { db.close(); });\n\n it('schema version is 3.0.0', () => {\n const row = db.prepare(\"SELECT value FROM metadata WHERE key = 'schema_version'\").get();\n expect(row.value).toBe('3.0.0');\n });\n\n it('default HNSW vector index has dimension 384 (bug #1947 guard)', () => {\n const row = db.prepare(\"SELECT dimensions FROM vector_indexes WHERE name = 'default'\").get();\n expect(row).toBeDefined();\n expect(row.dimensions).toBe(384);\n });\n\n it('patterns index has dimension 384', () => {\n const row = db.prepare(\"SELECT dimensions FROM vector_indexes WHERE name = 'patterns'\").get();\n expect(row.dimensions).toBe(384);\n });\n\n it('all required tables exist', () => {\n const tables = db.prepare(\n \"SELECT name FROM sqlite_master WHERE type='table'\"\n ).all().map(r => r.name);\n const required = [\n 'memory_entries', 'patterns', 'pattern_history',\n 'trajectories', 'trajectory_steps', 'migration_state',\n 'sessions', 'vector_indexes', 'metadata'\n ];\n for (const t of required) expect(tables).toContain(t);\n });\n\n it('WAL mode is enabled', () => {\n const row = db.prepare('PRAGMA journal_mode').get();\n expect(row.journal_mode).toBe('wal');\n });\n\n it('foreign keys are enforced', () => {\n const row = db.prepare('PRAGMA foreign_keys').get();\n expect(row.foreign_keys).toBe(1);\n });\n});\n```\n\n---\n\n",
|
|
"level": 3
|
|
},
|
|
{
|
|
"title": "3. Memory CRUD Operations (High — no coverage)",
|
|
"content": "\nThe `memory_store`/`memory_search` MCP tools are the core interface, but no smoke tests exist.\n\n**Gaps:**\n- No store → retrieve round-trip test\n- No namespace isolation test\n- No expiry/TTL behavior test\n- No `UNIQUE(namespace, key)` upsert behavior test\n- No `status` filtering test (active vs archived vs deleted)\n\n```javascript\n// tests/memory-crud.test.js\nimport Database from 'better-sqlite3';\nimport { randomUUID } from 'crypto';\n\nconst DB_PATH = './data/memory/memory.db';\n\ndescribe('memory_entries CRUD', () => {\n let db;\n\n beforeAll(() => { db = new Database(DB_PATH); });\n afterAll(() => { db.close(); });\n\n it('inserts and retrieves a memory entry', () => {\n const id = randomUUID();\n db.prepare(`\n INSERT INTO memory_entries (id, key, namespace, content)\n VALUES (?, ?, ?, ?)\n `).run(id, 'test-key', 'test-ns', 'hello world');\n\n const row = db.prepare('SELECT * FROM memory_entries WHERE id = ?').get(id);\n expect(row.content).toBe('hello world');\n expect(row.status).toBe('active');\n });\n\n it('enforces UNIQUE(namespace, key)', () => {\n const ns = `ns-${randomUUID()}`;\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(randomUUID(), 'dup-key', ns, 'first');\n\n expect(() =>\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(randomUUID(), 'dup-key', ns, 'second')\n ).toThrow(/UNIQUE constraint failed/);\n });\n\n it('rejects invalid type values', () => {\n expect(() =>\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content, type) VALUES (?, ?, ?, ?, ?)'\n ).run(randomUUID(), 'k', 'ns', 'c', 'invalid-type')\n ).toThrow(/CHECK constraint failed/);\n });\n\n it('soft-delete via status = deleted', () => {\n const id = randomUUID();\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(id, `del-${id}`, 'del-ns', 'to be deleted');\n\n db.prepare(\"UPDATE memory_entries SET status = 'deleted' WHERE id = ?\").run(id);\n const row = db.prepare(\"SELECT * FROM memory_entries WHERE id = ? AND status = 'active'\").get(id);\n expect(row).toBeUndefined();\n });\n\n it('isolates namespaces', () => {\n const ns1 = `ns1-${randomUUID()}`;\n const ns2 = `ns2-${randomUUID()}`;\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(randomUUID(), 'shared-key', ns1, 'ns1-value');\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(randomUUID(), 'shared-key', ns2, 'ns2-value');\n\n const r1 = db.prepare('SELECT content FROM memory_entries WHERE namespace = ? AND key = ?').get(ns1, 'shared-key');\n const r2 = db.prepare('SELECT content FROM memory_entries WHERE namespace = ? AND key = ?').get(ns2, 'shared-key');\n expect(r1.content).toBe('ns1-value');\n expect(r2.content).toBe('ns2-value');\n });\n});\n```\n\n---\n\n",
|
|
"level": 3
|
|
},
|
|
{
|
|
"title": "4. Pattern Learning & Confidence Decay (High — no coverage)",
|
|
"content": "\nThe patterns table has a confidence scoring system with decay — none of it is tested.\n\n**Gaps:**\n- No test that confidence stays in [0.0, 1.0]\n- No test for `success_count`/`failure_count` incrementing correctly\n- No test that `pattern_history` records are created on changes\n- No test for the `parent_id` self-referential FK (versioning)\n- No test for `experimental` → `active` promotion logic\n\n```javascript\n// tests/pattern-learning.test.js\ndescribe('pattern confidence scoring', () => {\n it('new patterns default to 0.5 confidence', () => {\n const id = randomUUID();\n db.prepare(`\n INSERT INTO patterns (id, name, pattern_type, condition, action)\n VALUES (?, ?, ?, ?, ?)\n `).run(id, 'test-pattern', 'task-routing', 'foo.*', 'route to coder');\n\n const row = db.prepare('SELECT confidence FROM patterns WHERE id = ?').get(id);\n expect(row.confidence).toBe(0.5);\n });\n\n it('rejects invalid pattern_type', () => {\n expect(() =>\n db.prepare(`\n INSERT INTO patterns (id, name, pattern_type, condition, action)\n VALUES (?, ?, ?, ?, ?)\n `).run(randomUUID(), 'x', 'invalid-type', '.', '.')\n ).toThrow(/CHECK constraint failed/);\n });\n\n it('pattern_history records on update', () => {\n const id = randomUUID();\n db.prepare(`\n INSERT INTO patterns (id, name, pattern_type, condition, action)\n VALUES (?, ?, ?, ?, ?)\n `).run(id, 'track-me', 'learning', '.*', 'store');\n\n db.prepare(`\n INSERT INTO pattern_history (pattern_id, version, confidence, change_type)\n VALUES (?, ?, ?, ?)\n `).run(id, 1, 0.5, 'created');\n\n const rows = db.prepare('SELECT * FROM pattern_history WHERE pattern_id = ?').all(id);\n expect(rows).toHaveLength(1);\n expect(rows[0].change_type).toBe('created');\n });\n\n it('parent_id FK references patterns table', () => {\n expect(() =>\n db.prepare(`\n INSERT INTO patterns (id, name, pattern_type, condition, action, parent_id)\n VALUES (?, ?, ?, ?, ?, ?)\n `).run(randomUUID(), 'child', 'learning', '.', '.', 'nonexistent-id')\n ).toThrow(/FOREIGN KEY constraint failed/);\n });\n});\n```\n\n---\n\n",
|
|
"level": 3
|
|
},
|
|
{
|
|
"title": "5. MCP Server Connectivity (Medium — no coverage)",
|
|
"content": "\nThe MCP server is configured for `localhost:3000` but startup and tool availability are never verified.\n\n**Gaps:**\n- No smoke test that the MCP server starts\n- No test that claude-flow tools respond to health checks\n- No test for stdio transport handshake\n\n```javascript\n// tests/mcp-smoke.test.js\nimport { execSync, spawn } from 'child_process';\n\ndescribe('MCP server', () => {\n it('claude-flow CLI is available', () => {\n const result = execSync('npx @claude-flow/cli@latest --version', { encoding: 'utf8' });\n expect(result.trim()).toMatch(/\\d+\\.\\d+/);\n });\n\n it('system health check passes', () => {\n const result = execSync('npx @claude-flow/cli@latest doctor', {\n encoding: 'utf8',\n timeout: 15_000\n });\n expect(result).toMatch(/health|ok|pass/i);\n });\n\n it('memory backend is reachable', () => {\n const result = execSync(\n 'npx @claude-flow/cli@latest memory stats',\n { encoding: 'utf8', timeout: 10_000 }\n );\n expect(result).not.toMatch(/error|fail/i);\n });\n});\n```\n\n---\n\n",
|
|
"level": 3
|
|
},
|
|
{
|
|
"title": "6. Session Lifecycle (Medium — no coverage)",
|
|
"content": "\nSessions are the persistence layer for agent context across runs. Nothing tests their lifecycle.\n\n**Gaps:**\n- No test for session creation with required `state` JSON\n- No test for session expiry (`expires_at` in the past)\n- No test for `paused` → `active` status transition\n- No test that `tasks_completed` increments correctly\n\n```javascript\n// tests/session-lifecycle.test.js\ndescribe('sessions table', () => {\n it('creates a session with valid JSON state', () => {\n const id = randomUUID();\n const state = JSON.stringify({ agentId: 'coder-1', task: 'write tests' });\n db.prepare(\n 'INSERT INTO sessions (id, state) VALUES (?, ?)'\n ).run(id, state);\n\n const row = db.prepare('SELECT * FROM sessions WHERE id = ?').get(id);\n expect(JSON.parse(row.state).agentId).toBe('coder-1');\n expect(row.status).toBe('active');\n });\n\n it('rejects invalid status values', () => {\n expect(() =>\n db.prepare(\n 'INSERT INTO sessions (id, state, status) VALUES (?, ?, ?)'\n ).run(randomUUID(), '{}', 'running') // 'running' not in CHECK list\n ).toThrow(/CHECK constraint failed/);\n });\n\n it('expired sessions have expires_at in the past', () => {\n const id = randomUUID();\n const pastMs = Date.now() - 1000;\n db.prepare(\n 'INSERT INTO sessions (id, state, expires_at) VALUES (?, ?, ?)'\n ).run(id, '{}', pastMs);\n\n const now = Date.now();\n const expired = db.prepare(\n 'SELECT * FROM sessions WHERE expires_at < ? AND id = ?'\n ).get(now, id);\n expect(expired).toBeDefined();\n });\n});\n```\n\n---\n\n",
|
|
"level": 3
|
|
},
|
|
{
|
|
"title": "7. Migration State Tracking (Medium — no coverage)",
|
|
"content": "\nThe migration system supports resume-on-failure but has no tests.\n\n**Gaps:**\n- No test for idempotent migration (re-running a completed migration)\n- No test that `in_progress` → `completed` transition updates `processed_items`\n- No test that `rolled_back` status halts further processing\n- No test for `errors` JSON array accumulation\n\n```javascript\n// tests/migration-state.test.js\ndescribe('migration_state', () => {\n it('tracks progress through a migration', () => {\n const id = randomUUID();\n db.prepare(`\n INSERT INTO migration_state (id, migration_type, total_items, status)\n VALUES (?, ?, ?, ?)\n `).run(id, 'v2-to-v3', 100, 'in_progress');\n\n db.prepare(`\n UPDATE migration_state\n SET processed_items = 50, current_batch = 5\n WHERE id = ?\n `).run(id);\n\n const row = db.prepare('SELECT * FROM migration_state WHERE id = ?').get(id);\n expect(row.processed_items).toBe(50);\n expect(row.current_batch).toBe(5);\n expect(row.total_items).toBe(100);\n });\n\n it('stores errors as JSON array', () => {\n const id = randomUUID();\n const errors = JSON.stringify([{ item: 'abc', reason: 'parse error' }]);\n db.prepare(`\n INSERT INTO migration_state (id, migration_type, errors, status)\n VALUES (?, ?, ?, ?)\n `).run(id, 'pattern', errors, 'failed');\n\n const row = db.prepare('SELECT errors FROM migration_state WHERE id = ?').get(id);\n const parsed = JSON.parse(row.errors);\n expect(parsed[0].reason).toBe('parse error');\n });\n});\n```\n\n---\n\n",
|
|
"level": 3
|
|
},
|
|
{
|
|
"title": "Summary of Gaps",
|
|
"content": "| Area | Priority | Gap Count | Effort |\n|------|----------|-----------|--------|\n| Config validation | Critical | 6 | Low |\n| Schema integrity + bug #1947 guard | Critical | 8 | Low |\n| Memory CRUD | High | 5 | Medium |\n| Pattern learning | High | 5 | Medium |\n| MCP server smoke tests | Medium | 3 | Low |\n| Session lifecycle | Medium | 4 | Low |\n| Migration tracking | Medium | 3 | Low |\n\n**Recommended first step:** Add `vitest` or `jest` + `better-sqlite3` to `devDependencies` and wire up a `test` script in `package.json`. The schema integrity tests and config validation tests can be running in under an hour and would catch bug #1947 on every fresh install.",
|
|
"level": 2
|
|
}
|
|
],
|
|
"codeBlocks": [
|
|
{
|
|
"language": "javascript",
|
|
"code": "// tests/config.test.js\nimport { describe, it, expect } from 'vitest';\nimport config from '../claude-flow.config.json';\n\ndescribe('claude-flow.config.json', () => {\n it('has required top-level keys', () => {\n expect(config).toHaveProperty('version');\n expect(config).toHaveProperty('agents');\n expect(config).toHaveProperty('swarm');\n expect(config).toHaveProperty('memory');\n expect(config).toHaveProperty('mcp');\n });\n\n it('vectorDimension matches HNSW default index (bug #1947)', () => {\n // HNSW rejects inserts whose dim does not match schema default (384)\n expect(config.memory.vectorDimension).toBe(384);\n });\n\n it('maxConcurrent does not exceed swarm maxAgents', () => {\n expect(config.agents.maxConcurrent).toBeLessThanOrEqual(config.swarm.maxAgents);\n });\n\n it('memory persistPath is a relative path', () => {\n expect(config.memory.persistPath).toMatch(/^\\.\\//);\n });\n\n it('mcp transport is stdio or http', () => {\n expect(['stdio', 'http']).toContain(config.mcp.transportType);\n });\n\n it('swarm topology is a known value', () => {\n const valid = ['hierarchical', 'mesh', 'ring', 'star'];\n expect(valid).toContain(config.swarm.topology);\n });\n});"
|
|
},
|
|
{
|
|
"language": "javascript",
|
|
"code": "// tests/schema.test.js\nimport Database from 'better-sqlite3';\nimport path from 'path';\n\nconst DB_PATH = path.resolve('./data/memory/memory.db');\n\ndescribe('RuFlo V3 schema integrity', () => {\n let db;\n\n beforeAll(() => { db = new Database(DB_PATH, { readonly: true }); });\n afterAll(() => { db.close(); });\n\n it('schema version is 3.0.0', () => {\n const row = db.prepare(\"SELECT value FROM metadata WHERE key = 'schema_version'\").get();\n expect(row.value).toBe('3.0.0');\n });\n\n it('default HNSW vector index has dimension 384 (bug #1947 guard)', () => {\n const row = db.prepare(\"SELECT dimensions FROM vector_indexes WHERE name = 'default'\").get();\n expect(row).toBeDefined();\n expect(row.dimensions).toBe(384);\n });\n\n it('patterns index has dimension 384', () => {\n const row = db.prepare(\"SELECT dimensions FROM vector_indexes WHERE name = 'patterns'\").get();\n expect(row.dimensions).toBe(384);\n });\n\n it('all required tables exist', () => {\n const tables = db.prepare(\n \"SELECT name FROM sqlite_master WHERE type='table'\"\n ).all().map(r => r.name);\n const required = [\n 'memory_entries', 'patterns', 'pattern_history',\n 'trajectories', 'trajectory_steps', 'migration_state',\n 'sessions', 'vector_indexes', 'metadata'\n ];\n for (const t of required) expect(tables).toContain(t);\n });\n\n it('WAL mode is enabled', () => {\n const row = db.prepare('PRAGMA journal_mode').get();\n expect(row.journal_mode).toBe('wal');\n });\n\n it('foreign keys are enforced', () => {\n const row = db.prepare('PRAGMA foreign_keys').get();\n expect(row.foreign_keys).toBe(1);\n });\n});"
|
|
},
|
|
{
|
|
"language": "javascript",
|
|
"code": "// tests/memory-crud.test.js\nimport Database from 'better-sqlite3';\nimport { randomUUID } from 'crypto';\n\nconst DB_PATH = './data/memory/memory.db';\n\ndescribe('memory_entries CRUD', () => {\n let db;\n\n beforeAll(() => { db = new Database(DB_PATH); });\n afterAll(() => { db.close(); });\n\n it('inserts and retrieves a memory entry', () => {\n const id = randomUUID();\n db.prepare(`\n INSERT INTO memory_entries (id, key, namespace, content)\n VALUES (?, ?, ?, ?)\n `).run(id, 'test-key', 'test-ns', 'hello world');\n\n const row = db.prepare('SELECT * FROM memory_entries WHERE id = ?').get(id);\n expect(row.content).toBe('hello world');\n expect(row.status).toBe('active');\n });\n\n it('enforces UNIQUE(namespace, key)', () => {\n const ns = `ns-${randomUUID()}`;\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(randomUUID(), 'dup-key', ns, 'first');\n\n expect(() =>\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(randomUUID(), 'dup-key', ns, 'second')\n ).toThrow(/UNIQUE constraint failed/);\n });\n\n it('rejects invalid type values', () => {\n expect(() =>\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content, type) VALUES (?, ?, ?, ?, ?)'\n ).run(randomUUID(), 'k', 'ns', 'c', 'invalid-type')\n ).toThrow(/CHECK constraint failed/);\n });\n\n it('soft-delete via status = deleted', () => {\n const id = randomUUID();\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(id, `del-${id}`, 'del-ns', 'to be deleted');\n\n db.prepare(\"UPDATE memory_entries SET status = 'deleted' WHERE id = ?\").run(id);\n const row = db.prepare(\"SELECT * FROM memory_entries WHERE id = ? AND status = 'active'\").get(id);\n expect(row).toBeUndefined();\n });\n\n it('isolates namespaces', () => {\n const ns1 = `ns1-${randomUUID()}`;\n const ns2 = `ns2-${randomUUID()}`;\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(randomUUID(), 'shared-key', ns1, 'ns1-value');\n db.prepare(\n 'INSERT INTO memory_entries (id, key, namespace, content) VALUES (?, ?, ?, ?)'\n ).run(randomUUID(), 'shared-key', ns2, 'ns2-value');\n\n const r1 = db.prepare('SELECT content FROM memory_entries WHERE namespace = ? AND key = ?').get(ns1, 'shared-key');\n const r2 = db.prepare('SELECT content FROM memory_entries WHERE namespace = ? AND key = ?').get(ns2, 'shared-key');\n expect(r1.content).toBe('ns1-value');\n expect(r2.content).toBe('ns2-value');\n });\n});"
|
|
},
|
|
{
|
|
"language": "javascript",
|
|
"code": "// tests/pattern-learning.test.js\ndescribe('pattern confidence scoring', () => {\n it('new patterns default to 0.5 confidence', () => {\n const id = randomUUID();\n db.prepare(`\n INSERT INTO patterns (id, name, pattern_type, condition, action)\n VALUES (?, ?, ?, ?, ?)\n `).run(id, 'test-pattern', 'task-routing', 'foo.*', 'route to coder');\n\n const row = db.prepare('SELECT confidence FROM patterns WHERE id = ?').get(id);\n expect(row.confidence).toBe(0.5);\n });\n\n it('rejects invalid pattern_type', () => {\n expect(() =>\n db.prepare(`\n INSERT INTO patterns (id, name, pattern_type, condition, action)\n VALUES (?, ?, ?, ?, ?)\n `).run(randomUUID(), 'x', 'invalid-type', '.', '.')\n ).toThrow(/CHECK constraint failed/);\n });\n\n it('pattern_history records on update', () => {\n const id = randomUUID();\n db.prepare(`\n INSERT INTO patterns (id, name, pattern_type, condition, action)\n VALUES (?, ?, ?, ?, ?)\n `).run(id, 'track-me', 'learning', '.*', 'store');\n\n db.prepare(`\n INSERT INTO pattern_history (pattern_id, version, confidence, change_type)\n VALUES (?, ?, ?, ?)\n `).run(id, 1, 0.5, 'created');\n\n const rows = db.prepare('SELECT * FROM pattern_history WHERE pattern_id = ?').all(id);\n expect(rows).toHaveLength(1);\n expect(rows[0].change_type).toBe('created');\n });\n\n it('parent_id FK references patterns table', () => {\n expect(() =>\n db.prepare(`\n INSERT INTO patterns (id, name, pattern_type, condition, action, parent_id)\n VALUES (?, ?, ?, ?, ?, ?)\n `).run(randomUUID(), 'child', 'learning', '.', '.', 'nonexistent-id')\n ).toThrow(/FOREIGN KEY constraint failed/);\n });\n});"
|
|
},
|
|
{
|
|
"language": "javascript",
|
|
"code": "// tests/mcp-smoke.test.js\nimport { execSync, spawn } from 'child_process';\n\ndescribe('MCP server', () => {\n it('claude-flow CLI is available', () => {\n const result = execSync('npx @claude-flow/cli@latest --version', { encoding: 'utf8' });\n expect(result.trim()).toMatch(/\\d+\\.\\d+/);\n });\n\n it('system health check passes', () => {\n const result = execSync('npx @claude-flow/cli@latest doctor', {\n encoding: 'utf8',\n timeout: 15_000\n });\n expect(result).toMatch(/health|ok|pass/i);\n });\n\n it('memory backend is reachable', () => {\n const result = execSync(\n 'npx @claude-flow/cli@latest memory stats',\n { encoding: 'utf8', timeout: 10_000 }\n );\n expect(result).not.toMatch(/error|fail/i);\n });\n});"
|
|
},
|
|
{
|
|
"language": "javascript",
|
|
"code": "// tests/session-lifecycle.test.js\ndescribe('sessions table', () => {\n it('creates a session with valid JSON state', () => {\n const id = randomUUID();\n const state = JSON.stringify({ agentId: 'coder-1', task: 'write tests' });\n db.prepare(\n 'INSERT INTO sessions (id, state) VALUES (?, ?)'\n ).run(id, state);\n\n const row = db.prepare('SELECT * FROM sessions WHERE id = ?').get(id);\n expect(JSON.parse(row.state).agentId).toBe('coder-1');\n expect(row.status).toBe('active');\n });\n\n it('rejects invalid status values', () => {\n expect(() =>\n db.prepare(\n 'INSERT INTO sessions (id, state, status) VALUES (?, ?, ?)'\n ).run(randomUUID(), '{}', 'running') // 'running' not in CHECK list\n ).toThrow(/CHECK constraint failed/);\n });\n\n it('expired sessions have expires_at in the past', () => {\n const id = randomUUID();\n const pastMs = Date.now() - 1000;\n db.prepare(\n 'INSERT INTO sessions (id, state, expires_at) VALUES (?, ?, ?)'\n ).run(id, '{}', pastMs);\n\n const now = Date.now();\n const expired = db.prepare(\n 'SELECT * FROM sessions WHERE expires_at < ? AND id = ?'\n ).get(now, id);\n expect(expired).toBeDefined();\n });\n});"
|
|
},
|
|
{
|
|
"language": "javascript",
|
|
"code": "// tests/migration-state.test.js\ndescribe('migration_state', () => {\n it('tracks progress through a migration', () => {\n const id = randomUUID();\n db.prepare(`\n INSERT INTO migration_state (id, migration_type, total_items, status)\n VALUES (?, ?, ?, ?)\n `).run(id, 'v2-to-v3', 100, 'in_progress');\n\n db.prepare(`\n UPDATE migration_state\n SET processed_items = 50, current_batch = 5\n WHERE id = ?\n `).run(id);\n\n const row = db.prepare('SELECT * FROM migration_state WHERE id = ?').get(id);\n expect(row.processed_items).toBe(50);\n expect(row.current_batch).toBe(5);\n expect(row.total_items).toBe(100);\n });\n\n it('stores errors as JSON array', () => {\n const id = randomUUID();\n const errors = JSON.stringify([{ item: 'abc', reason: 'parse error' }]);\n db.prepare(`\n INSERT INTO migration_state (id, migration_type, errors, status)\n VALUES (?, ?, ?, ?)\n `).run(id, 'pattern', errors, 'failed');\n\n const row = db.prepare('SELECT errors FROM migration_state WHERE id = ?').get(id);\n const parsed = JSON.parse(row.errors);\n expect(parsed[0].reason).toBe('parse error');\n });\n});"
|
|
}
|
|
]
|
|
},
|
|
"durationMs": 161706,
|
|
"model": "sonnet",
|
|
"sandboxMode": "permissive",
|
|
"workerType": "testgaps",
|
|
"timestamp": "2026-05-14T18:18:21.139Z",
|
|
"executionId": "testgaps_1778782539433_bx0bw1"
|
|
}
|