Ships the dispatch-lock work from issue #103 — the 420s-class hard timeouts that silently dropped remember_note / hydrate writes.
Fixed
Dispatch-lock contention now fails fast instead of hanging. Concurrent tool calls (the primary's stdio handler and proxied daemon calls from other agent profiles) all serialize on one shared single-writer RLock. That wait used to be unbounded, so a slow or runaway operation — a hydration stuck on a dead embedding backend, a wedged primary — made every other caller queue until the MCP host's own tool-call timeout, up to 600s in the field.
make_local_dispatcher now acquires the lock with a 30s bound and raises an explicit, retryable error instead:
memory server busy: 'index_paths' holds the dispatch lock (waited 30s); retry this call later
Nothing was written when this fires, so retrying cannot duplicate.
__version__ source fallback was stale at 0.24.1 since the 0.26.0 release. It only applies to un-installed source checkouts — the live value comes from importlib.metadata — but it now tracks the real version again.
Added
TQMEMORY_DISPATCH_LOCK_TIMEOUT tunes the bound without waiting for a release:
export TQMEMORY_DISPATCH_LOCK_TIMEOUT=90 # seconds; default 30
export TQMEMORY_DISPATCH_LOCK_TIMEOUT=0 # <= 0: unbounded wait (pre-0.27.0 behaviour)The escape hatch matters for deployments whose legitimate long operations — a large index_paths run over a big repo, a cold embedding backend — would rather queue than get a busy error. Unparseable values log a warning and fall back to the default rather than disabling dispatch. Keep the bound under the proxy's own RPC_TIMEOUT_SECONDS (120s) so the explicit error wins over an opaque RPC timeout.
The busy error names the blocking tool, in the message and in a [tqmemory] stderr line. A caller only ever sees its own tool name, so the holder is the part that makes a field stall diagnosable.
Not fixed
A runaway operation still holds the lock until it finishes; nothing kills it. The structural fix — not holding a global lock across long operations — is separate work.
Upgrade
uv tool install --force "git+https://github.com/Lexus2016/turbo_quant_memory@v0.27.0"The on-disk tool upgrades immediately, but a running MCP server keeps the old version in memory — health reports the previous version until the MCP client reconnects.
Thanks to @Da-Mikey for PR #3, which landed the bounded acquire.
Full changelog: v0.26.0...v0.27.0