Skip to content

fix(memory): SYNAPSE seeds=0 immediately after entity extraction (FTS5+WAL visibility) #2166

@bug-ops

Description

@bug-ops

Summary

SYNAPSE spreading activation returns result_count=0 immediately after entity extraction in the previous session. Entities are visible via direct SELECT but FTS5 fuzzy queries (MATCH 'word*') return empty.

Reproduction

Session 1: Send a message that triggers entity extraction:

Charlie works at MegaCorp and uses Golang for all backend services.

Graph extraction completes — entities Charlie, MegaCorp, Golang are extracted and stored.

Session 2 (immediately after): Send a causal/relational query:

Tell me about Charlie.

Expected:

spreading activation: seeds=1 "Tell me about Charlie."
spreading activation: graph recall complete result_count=N

Actual:

spreading activation: starting graph recall query_len=22 limit=10
spreading activation: graph recall complete result_count=0

No seeds=N debug line appears — find_seed_entities returns empty before the activation loop.

Root Cause

find_seed_entities in crates/zeph-memory/src/graph/retrieval.rs calls store.find_entities_fuzzy(word, ...) which queries FTS5 with MATCH 'word*'.

SQLite WAL mode buffers writes in the WAL file. FTS5 shadow tables (entities_fts) are updated transactionally, but FTS5 full-text indexes may not be visible to new connections (or re-opened connections) until a WAL checkpoint occurs. Direct SELECT * FROM graph_entities returns rows immediately; FTS5 MATCH queries on the same data return empty.

Once a WAL checkpoint runs (either automatically at 1000 pages or manually via PRAGMA wal_checkpoint), FTS5 queries start working correctly in subsequent sessions.

Code Path

graph_recall_activated()
  └── find_seed_entities(store, query, limit)
        └── store.find_entities_fuzzy(word, limit*2)
              └── FTS5: SELECT ... FROM entities_fts WHERE entities_fts MATCH 'charlie*'
                  → returns 0 rows (WAL not checkpointed)
  → returns empty Vec → early return at line ~220, no seeds logged

Expected Fix

Options (in preference order):

  1. Issue a PRAGMA wal_checkpoint(PASSIVE) after FTS5 inserts (in GraphStore::add_entity or after batch extraction completes)
  2. Use PRAGMA wal_checkpoint(RESTART) at graph store open if FTS5 virtual tables are present
  3. Add a fallback LIKE query (name LIKE 'charlie%') when FTS5 returns 0 results, to bypass the FTS5 visibility issue
  4. Configure PRAGMA journal_mode=DELETE for the graph store connection (trades performance for immediate FTS5 visibility)

Option 1 is least invasive — a passive checkpoint after batch entity insertion ensures subsequent FTS5 queries see the new data without blocking writers.

Impact

  • Severity: High — SYNAPSE is silently disabled for all queries in fresh sessions after entity extraction. The feature appears to work (no error, no warning) but returns no graph context.
  • Causal queries ("Why did X...", "How does X relate to Y") are most affected — these rely heavily on graph recall.
  • Queries in the same session as extraction may work (same connection, WAL visible), but cross-session queries fail.

Verified

Confirmed with debug logging (RUST_LOG=zeph_memory=debug) in CI-101:

  • Direct SELECT id, name FROM graph_entities → rows present
  • FTS5 SELECT name FROM entities_fts WHERE entities_fts MATCH 'charlie*' → 0 rows (same connection, different transaction)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmemoryzeph-memory crate (SQLite)

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions