Description
Found while migrating our production install onto 3.0.3 — so this comes with the caveat that
#141 was clearly the right call and we are not asking you to undo any of it. This is just the
tail it left behind.
Six storage methods that #141 removed with the SQLite backend still have live callers in
src/. Every one of those call sites is wrapped in try: ... except Exception: and annotated
# type: ignore[attr-defined], so on the only backend that ships today — SurrealDB — the
AttributeError is swallowed and the caller reports success.
Two user-visible consequences:
smem drift / smem_drift(action="detect") always answers
"No semantic drift detected. Tag usage is consistent." That answer is indistinguishable
from a real, successful analysis. The feature cannot produce any other result on SurrealDB,
because both of its inputs raise before they are read.
- Session summaries are never persisted.
ReflexPipeline calls save_session_summary on
every session.needs_persist(); it raises, is caught, and logged at debug.
The methods with no definition anywhere in src/:
record_tag_cooccurrence, get_tag_cooccurrence, get_tag_fiber_counts, save_drift_cluster,
get_drift_clusters, resolve_drift_cluster, save_session_summary.
To Reproduce
- Install on a SurrealDB backend (the default since v2.0.0) with some tagged memories.
- Run
smem drift detect, or call the MCP tool smem_drift(action="detect").
- Observe
status: "clean" with the message above — regardless of the tag data present.
- Confirm the cause without a database:
git grep -c "def get_tag_cooccurrence" v3.0.3 -- src/ # 0 definitions
git grep -n "get_tag_cooccurrence" v3.0.3 -- src/ # live callers
git grep -n "save_session_summary" v3.0.3 -- src/ # 1 caller, 0 definitions
storage = await get_shared_storage() # SurrealDBStorage
hasattr(storage, "get_tag_cooccurrence") # False
Expected Behavior
A capability that cannot run should say so. Either the drift family is restored behind the
NeuralStorage interface — exactly the pattern #139 used for pinning and #145 for watch
state — or the command and the MCP tool are removed. A third option, which is the current
state, is the worst of the three: an answer that looks like an analysis.
Actual Behavior
run_drift_detection degrades to empty inputs through three separate swallows, and the handler
turns the empty result into a success message.
# src/surreal_memory/engine/drift_detection.py:415-443
try:
cooccurrences = await storage.get_tag_cooccurrence( # type: ignore[attr-defined]
min_count=MIN_COOCCURRENCE_COUNT,
)
except Exception:
cooccurrences = [] # (1) AttributeError -> "no data"
try:
tag_fiber_counts = await storage.get_tag_fiber_counts() # type: ignore[attr-defined]
except Exception:
tag_fiber_counts = {} # (2) AttributeError -> "no data"
reports = detect_clusters(cooccurrences, tag_fiber_counts) # [] from empty inputs
for report in reports: # never entered
try:
await storage.save_drift_cluster(...) # type: ignore[attr-defined]
except Exception:
pass # (3)
# src/surreal_memory/mcp/drift_handler.py:63-69
if not clusters and not temporal:
return {
"status": "clean",
"message": "No semantic drift detected. Tag usage is consistent.",
}
# src/surreal_memory/engine/retrieval.py:831-845
if session.needs_persist():
try:
summary = session.to_summary_dict()
await self._storage.save_session_summary( # type: ignore[attr-defined]
...
)
except Exception:
logger.debug(...) # summaries silently never written
Two of the nine call sites are honest about it — engine/uncertainty_report.py:112,228 probe
with getattr(storage, "get_drift_clusters", None), and the docstring on line 227 already says
"SQLite-only; [] on backends without get_drift_clusters". So part of the codebase knows the
methods are gone; the drift command does not.
Error Message
There is none, and that is the bug. Every failure is caught. With logging turned up, the only
trace is the logger.debug line in retrieval.py.
Environment
- OS: Linux (x86-64)
- Python version: 3.12.13
- Surreal-Memory version: 3.0.3 (
ac20df41, origin/main at the time of writing)
- Installation method: source,
pip install -e ".[dev,server,surrealdb]"
- Backend: SurrealDB 3.2.0
Additional Context
The call sites are annotated # type: ignore[attr-defined], which is why mypy src/ --ignore-missing-imports stays green over methods that no longer exist — the annotation was
correct while the SQLite backend existed and became a silencer when it went away. If the
family is restored on the interface, those type: ignore comments should go with it; ruff's
RUF100 will then point at any that are left.
Related: #141 (backend removal), #139 (the pinning family moved onto the interface),
#145 (the watch family moved onto the interface).
Description
Found while migrating our production install onto 3.0.3 — so this comes with the caveat that
#141was clearly the right call and we are not asking you to undo any of it. This is just thetail it left behind.
Six storage methods that
#141removed with the SQLite backend still have live callers insrc/. Every one of those call sites is wrapped intry: ... except Exception:and annotated# type: ignore[attr-defined], so on the only backend that ships today — SurrealDB — theAttributeErroris swallowed and the caller reports success.Two user-visible consequences:
smem drift/smem_drift(action="detect")always answers"No semantic drift detected. Tag usage is consistent."That answer is indistinguishablefrom a real, successful analysis. The feature cannot produce any other result on SurrealDB,
because both of its inputs raise before they are read.
ReflexPipelinecallssave_session_summaryonevery
session.needs_persist(); it raises, is caught, and logged atdebug.The methods with no definition anywhere in
src/:record_tag_cooccurrence,get_tag_cooccurrence,get_tag_fiber_counts,save_drift_cluster,get_drift_clusters,resolve_drift_cluster,save_session_summary.To Reproduce
smem drift detect, or call the MCP toolsmem_drift(action="detect").status: "clean"with the message above — regardless of the tag data present.Expected Behavior
A capability that cannot run should say so. Either the drift family is restored behind the
NeuralStorageinterface — exactly the pattern#139used for pinning and#145for watchstate — or the command and the MCP tool are removed. A third option, which is the current
state, is the worst of the three: an answer that looks like an analysis.
Actual Behavior
run_drift_detectiondegrades to empty inputs through three separate swallows, and the handlerturns the empty result into a success message.
Two of the nine call sites are honest about it —
engine/uncertainty_report.py:112,228probewith
getattr(storage, "get_drift_clusters", None), and the docstring on line 227 already says"SQLite-only; [] on backends without get_drift_clusters". So part of the codebase knows the
methods are gone; the drift command does not.
Error Message
There is none, and that is the bug. Every failure is caught. With logging turned up, the only
trace is the
logger.debugline inretrieval.py.Environment
ac20df41,origin/mainat the time of writing)pip install -e ".[dev,server,surrealdb]"Additional Context
The call sites are annotated
# type: ignore[attr-defined], which is whymypy src/ --ignore-missing-importsstays green over methods that no longer exist — the annotation wascorrect while the SQLite backend existed and became a silencer when it went away. If the
family is restored on the interface, those
type: ignorecomments should go with it; ruff'sRUF100will then point at any that are left.Related:
#141(backend removal),#139(the pinning family moved onto the interface),#145(the watch family moved onto the interface).