fix: add hnsw:space=cosine to drawer collection creation#304
fix: add hnsw:space=cosine to drawer collection creation#304dr-robert-li wants to merge 2 commits intoMemPalace:developfrom
Conversation
searcher.py computes similarity = 1 - distance, which only yields a meaningful score in the [0, 1] range when the underlying distance metric is cosine. ChromaDB defaults to L2 when no metadata is supplied, producing negative similarity scores for every search result regardless of relevance.
Adds metadata={'hnsw:space': 'cosine'} to both create_collection call sites (miner.py and convo_miner.py) plus regression tests in test_miner.py and test_convo_miner.py that assert the cosine metric on newly-created collections.
Note: existing collections are unaffected because the metric is set at creation time. Users with a palace already mined will need to wipe and re-mine to benefit from the fix.
Closes MemPalace#218
PR Review: fix: add hnsw:space=cosine to drawer collection creationExecutive Summary
Affected Areas: Business Impact: Search results currently show negative similarity scores for all users, making relevance ranking unreliable. This fix corrects it for new palaces. Flow Changes: Ratings
PR Health
High Priority Issues🐛 #1: Missed
|
mcp_server._get_collection(create=True) and cli.cmd_repair bypassed the original MemPalace#218 fix — an MCP-first palace or a post-repair palace silently reverted to L2 distance, reintroducing negative similarity scores. Extract DRAWER_HNSW_METADATA into config so all four drawer-collection call sites (miner, convo_miner, mcp_server, cli) share one source of truth. Drops the three duplicated 3-line comments down to a single module-level comment. Closes review on MemPalace#218.
|
Addresses review feedback in 05af34b.
New regression tests: |
- pyproject.toml: widen chromadb to <2.0 for Python 3.14 compat (MemPalace#302) - config.py + miner/convo_miner/mcp_server: add hnsw:space=cosine so similarity = 1 - distance stays in [0,1] instead of negative L2 (MemPalace#304) - searcher.py + layers.py: guard against ChromaDB 1.x empty-outer query results (IndexError on fresh collections) (MemPalace#305) - mcp_server.py: redirect stdout→stderr at import to protect JSON-RPC wire from chromadb/posthog chatter (MemPalace#306) - mcp_server.py: replace 10k-limited col.get with paginating _iter_all_metadatas helper; stop swallowing errors silently (MemPalace#307) - mcp_server.py: drop undocumented wait_for_previous arg injected by Gemini MCP clients (MemPalace#322) - searcher.py + hybrid_searcher.py + mcp_server.py: add min_similarity threshold filter so callers get a clean "no results" signal (MemPalace#350) - entity_detector.py: add CODE_KEYWORDS blocklist (~80 terms) to stop Rust types / React / framework names being detected as entities (MemPalace#349) Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
|
Hey — I've taken a look and ran it through CLI. Thanks for the fix on the cosine distance bug! There are three open PRs addressing #218 (#262, #304, #240). Going with #262 because of its test coverage and its explicit issue linkage. Closing this one as superseded — the bug is still getting fixed, just via the other PR. Really appreciate the contribution. 💜 |
|
Reopening — this was closed too quickly and your work deserves proper review. Standing by for merge once we clear the current security baseline. Thank you for the contribution. |
|
Hey @dr-robert-li — I owe you an apology. A few of your PRs got closed too fast without the review they deserved. You put in more work than almost any other contributor this week and that shouldn't have been brushed aside. We've reopened your PRs and they'll get proper review once the security baseline lands. Thanks for sticking with us. |
web3guru888
left a comment
There was a problem hiding this comment.
Strong +1 — we already use hnsw:space=cosine in our integration and can confirm it's essential. Without it, similarity = 1 - distance produces meaningless negative scores with L2, which silently degrades search quality.
The approach is thorough:
DRAWER_HNSW_METADATAas a shared constant inconfig.pyis clean — single source of truth acrossminer.py,convo_miner.py,mcp_server.py, andcli.py(repair command).- The repair command fix is important — without it,
mempalace repairwould silently revert a cosine collection back to L2. get_or_create_collectioninmcp_server.pywill apply the metadata to new collections but note: this won't change the metric on existing collections. ChromaDB setshnsw:spaceat creation time and it's immutable after that. The PR description mentions this, which is good.
From our experience:
- We pin
chromadb >=0.6.0,<0.7.0and have been using cosine space across 710+ KG entities and 208 discoveries. Search relevance went from unreliable to 100% after this change. - One thing to consider: should there be a startup warning if an existing collection was created with L2? Something like checking
col.metadata.get("hnsw:space") != "cosine"and logging a "runmempalace repairto fix search scoring" message. This would help users discover they need to re-mine.
Test coverage is excellent — 5 new tests covering all creation paths plus the repair regression. Well done.
🔭 Reviewed as part of the MemPalace-AGI integration project — autonomous research with perfect memory. Community interaction updates are posted regularly on the dashboard.
What does this PR do?
Adds
metadata={'hnsw:space': 'cosine'}to bothcreate_collectioncall sites (mempalace/miner.pyandmempalace/convo_miner.py).searcher.pycomputessimilarity = 1 - distance, which only yields a meaningful score in[0, 1]when the underlying distance metric is cosine. ChromaDB defaults to L2 when no metadata is supplied, producing negative similarity scores for every search result.Fixes #218.
How to test
Existing collections are unaffected (the metric is set at creation time). Users with a palace already mined will need to wipe and re-mine to benefit.
Checklist
python -m pytest tests/ -v) — 119 passed, 0 failedruff check .)