Summary
On @claude-flow/cli 3.41.2, a connected Ruflo MCP can successfully retrieve and search memory through its AgentDB bridge while memory_stats fails before reaching that bridge.
The current main source still calls ensureInitialized(), then checkMemoryInitialization(), then listEntries({ limit: 100000 }) in the memory_stats handler:
https://github.com/ruvnet/ruflo/blob/main/v3/@claude-flow/cli/src/mcp-tools/memory-tools.ts
checkMemoryInitialization() imports sql.js, reads the main database file, and opens a whole-image snapshot. Such a snapshot cannot include live SQLite WAL frames. Our downstream raw-WAL safety guard correctly refuses this path; removing that guard is not a fix. Without the guard the same upstream design can inspect an incomplete main-file view.
Observed evidence
- Actual running implementation: @claude-flow/cli 3.41.2, not a branding wrapper's version.
- The same conversation's exact memory_retrieve returned the expected value and tags via the bridge; memory_search returned real records.
- memory_stats returned initialized:false with the raw whole-image/WAL refusal.
- This is not evidence of a broken native binding, lost records, or corrupt storage.
Related but distinct: #3249 covers the raw initialization probe's encrypted-input/cleanup leak; #2735 covers raw whole-image/WAL safety; closed #2120 concerned legacy NULL status filtering.
Proposed narrow fix
Make memory_stats query the same ControllerRegistry-owned AgentDB database handle used by live MCP CRUD. Do not create another driver, read a main-file snapshot, checkpoint, unlink sidecars, migrate, or close a borrowed handle. Aggregate active/legacy-NULL rows by namespace in one statement rather than listing 100,000 contents. Preserve arbitrary namespace names safely. Return explicit unavailable/error state with null counts on failure; do not infer HNSW readiness or version from defaults.
This also removes the existing 100,000-entry truncation of namespace/embedding counts and avoids treating failed listEntries results as a healthy empty store.
Acceptance tests / retirement evidence
- Healthy bridge plus a throwing raw initialization probe still produces accurate stats without calling the probe.
- Reuse exactly the registry's handle; no competing connection, raw file read, DDL, migration, checkpoint, or close.
- Include active and legacy NULL rows; exclude deleted rows.
- Correct complete counts beyond 100,000 entries and for arbitrary namespaces including proto and constructor.
- Empty is distinct from unavailable; registry/query failures are explicit and never fake zero.
- One consistent aggregate result; embedding counts are storage presence, not proof of semantic/HNSW readiness.
- Existing WAL guard remains unchanged.
A narrowly anchored downstream patch and behavioral tests will be linked here when verified.
Summary
On @claude-flow/cli 3.41.2, a connected Ruflo MCP can successfully retrieve and search memory through its AgentDB bridge while memory_stats fails before reaching that bridge.
The current main source still calls ensureInitialized(), then checkMemoryInitialization(), then listEntries({ limit: 100000 }) in the memory_stats handler:
https://github.com/ruvnet/ruflo/blob/main/v3/@claude-flow/cli/src/mcp-tools/memory-tools.ts
checkMemoryInitialization() imports sql.js, reads the main database file, and opens a whole-image snapshot. Such a snapshot cannot include live SQLite WAL frames. Our downstream raw-WAL safety guard correctly refuses this path; removing that guard is not a fix. Without the guard the same upstream design can inspect an incomplete main-file view.
Observed evidence
Related but distinct: #3249 covers the raw initialization probe's encrypted-input/cleanup leak; #2735 covers raw whole-image/WAL safety; closed #2120 concerned legacy NULL status filtering.
Proposed narrow fix
Make memory_stats query the same ControllerRegistry-owned AgentDB database handle used by live MCP CRUD. Do not create another driver, read a main-file snapshot, checkpoint, unlink sidecars, migrate, or close a borrowed handle. Aggregate active/legacy-NULL rows by namespace in one statement rather than listing 100,000 contents. Preserve arbitrary namespace names safely. Return explicit unavailable/error state with null counts on failure; do not infer HNSW readiness or version from defaults.
This also removes the existing 100,000-entry truncation of namespace/embedding counts and avoids treating failed listEntries results as a healthy empty store.
Acceptance tests / retirement evidence
A narrowly anchored downstream patch and behavioral tests will be linked here when verified.