Skip to content

fix: address 6 open issues (#64, #150-#154) and bump to v3.3.0 - #157

Merged
acidkill merged 7 commits into
mainfrom
fix/issues-64-150-154
Aug 3, 2026
Merged

fix: address 6 open issues (#64, #150-#154) and bump to v3.3.0#157
acidkill merged 7 commits into
mainfrom
fix/issues-64-150-154

Conversation

@acidkill

@acidkill acidkill commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Summary

Addresses all 6 open issues, verified independently against current main before any fix (several claims in the original reports needed re-checking against code that had moved since they were filed).

Breaking change

smem_drift MCP tool is removed (#151). It never returned a trustworthy result on the SurrealDB backend — every call path swallowed its own failure and reported a hardcoded "clean". TagNormalizer.detect_drift (already backing smem doctor's tag-drift warnings) covers the same practical need without needing storage.

Test plan

  • ruff check / ruff format --check — clean
  • mypy src/ — clean (2 pre-existing, unrelated missing-stub errors)
  • check_dead_modules.py --strict — clean
  • Full unit suite: 6806 passed, coverage 70.1% (gate 65%)
  • New CI integration job verified manually end-to-end against a throwaway SurrealDB container (39/39 integration tests, 292/292 gated unit tests, then full suite 6849 passed in ~2m12s)
  • Regression tests added for every fix (both-direction acronym pinning, shouted-text guard, hub.py brain-leak, _query_values, tool-stats days filter, brain-files path omission)
  • No test brains left behind (smem brain list → only default)

check_dead_modules computed reachability from every import it found, but
never checked that the imported module actually exists — five benchmark
and script files kept importing the SQLite backend removed in 3.0.0, and
the guard reported "No unreachable modules." while all five would fail to
run. It now resolves every root's imports against the tree and reports
the ones that don't.

stress_at_scale.py measured only the removed backend and is deleted; the
other four (rehearsal_coverage_overhead, benchmark_mem0_vs_nm,
benchmark_cognee_vs_nm, e2e_gemini_recall) now require a live
SURREALDB_URL instead of silently falling back to SQLite.
…write (#151)

smem_drift always reported "clean" on the only shipped backend: its two
inputs (tag co-occurrence, session summaries) raised on SurrealDB, were
caught, and turned into empty results indistinguishable from a real
analysis that found nothing. Those two things were never implemented on
SurrealDB and never had been -- even before the SQLite backend's removal,
temporal/activation drift detection had no working data source. The
merge action never merged tags either; it only flipped a status field.

Removed entirely: engine/drift_detection.py, mcp/drift_handler.py, the
smem_drift MCP tool and its schema, the DETECT_DRIFT consolidation
strategy, and the tag-cooccurrence write in the encode hot path.
TagNormalizer.detect_drift needs no storage and already backs smem
doctor's tag-drift warnings -- it remains and covers the same need.

A second, unrelated swallowed failure in the same review: ReflexPipeline
periodically tried to persist a session summary via a storage method that
was removed with the same backend and never existed on SurrealDB. That
write path is removed too; session tracking itself (record_query,
get_top_topics) is untouched.

BREAKING: the smem_drift MCP tool is gone. Docs/tool count regenerated
(57 tools, was 58).
…ain (#152)

hub_status and hub_devices take brain_id from the URL path and called
storage.set_brain(brain_id) on the process-wide shared storage instance
to answer their own lookup. Background maintenance loops (consolidation,
decay) read storage.brain_id off that same shared instance on every
tick, so a read-only GET for one brain could redirect the next scheduled
pass onto a brain the operator never switched to.

Both endpoints now read through storage_for_scope, a scoped-storage
helper moved to server/dependencies.py from reasoning_training.py (the
same pattern already protected its read endpoints with) -- it reuses the
shared instance when it is already bound to the requested brain, or opens
an isolated one otherwise, without ever mutating the shared instance's
brain as a side effect of a read.
Every existing job either mocked the database or skipped whenever
SURREALDB_URL was unset, so the only production backend never ran in
CI -- the exact gap that let a query returning plausible garbage
(#143's SELECT VALUE bug) reach main undetected by its own new test,
which had been skipping since the day it was added.

The job starts the official image via a plain `docker run` step: GitHub
Actions' `services:` only accepts `options:` (docker-create flags), never
a container command, and the image's ENTRYPOINT has no default CMD --
`services:` cannot pass the `start ...` arguments SurrealDB requires.
Waits on `/surreal isready`, then runs pytest sequentially (no -n auto:
parallel workers sharing one connection produce transaction-conflict
errors that are about contention, not correctness). Verified end-to-end
against a throwaway container matching this recipe: full suite passes in
~2m12s with zero flakiness.
- Dashboard tool-stats: get_tool_stats took no `days` argument, so
  switching the 7/30/90-day range filter changed the daily chart but not
  the summary above it -- three ranges rendered a byte-identical summary.
  Now respects the same window as the daily series.
- get_tool_stats / get_tool_stats_by_period existed only on the SurrealDB
  mixin, reachable through `# type: ignore[attr-defined]` with no
  declaration on NeuralStorage and no in-memory implementation --
  AttributeError on any other backend. Declared on the interface with an
  inert default and a real in-memory implementation.
- store.py's shared query helper is typed to return row dicts, which
  understates what a `SELECT VALUE` query actually returns: the selected
  field for one row can itself be an array, indistinguishable by shape
  alone from several scalar rows -- the mechanism behind #143's fixed
  bug. The one live SELECT VALUE call site (get_connected_neuron_ids) now
  goes through a separate, honestly-typed _query_values instead.
- /health's schema_version moved from the 2.x SQLite constant (40) to the
  active backend's own version (9 on SurrealDB) with no line in the
  migration guide explaining it -- monitoring that parses the field could
  read it as a regression. Documented in Troubleshooting; the same table
  edit also drops a "drift clusters" carried-state row #151 made stale.
- The Settings brain-files panel built and returned a path for every
  brain regardless of whether a file existed there -- a SurrealDB-only
  brain has none, so the panel showed a plausible path to nothing.
  size_bytes was already correctly 0; path is now omitted too when the
  file does not exist.
- Renamed ensure_aiosqlite_or_exit_cli to ensure_sqlite_or_exit_cli: it
  has only ever checked the stdlib sqlite3 module, never aiosqlite, and
  the name misled anyone reading the CLI startup path. Internal-only.
)

A contributor's audit rejected the obvious fix -- removing ma/na/co/sa
from STOP_WORDS_PL -- because N/A and S.A. don't actually collide:
punctuation fragments them below the minimum word length before the
stop-word check ever runs, so removing the words would trade real
Polish function-word noise for a niche acronym gain. Only the bare
uppercase forms (MA, NA, CO, SA) collide.

A token that is ALL-CAPS in the source now survives even when its
lowercased form is a stop word, but only when the token was uppercase in
the original text (str.isupper(), which already rejects a
sentence-initial "Ma"/"Na") -- every other token is tokenized and
filtered exactly as before. Gated by how much of the whole text is
uppercase: fully-capitalized text (a shouted note, a heading) has no
acronym to rescue, only every word incidentally capitalized, and must
not have its stop-word filtering disabled wholesale.
MINOR: mostly bug fixes plus one narrow, disclosed breaking removal
(the never-functional smem_drift tool, #151) -- same class of change
v3.2.0 shipped as MINOR rather than MAJOR.
@acidkill
acidkill merged commit 20dbe5f into main Aug 3, 2026
8 checks passed
@acidkill
acidkill deleted the fix/issues-64-150-154 branch August 3, 2026 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant