fix(vector_store): make VectorManager methods work on persistent backends (#855) - #914
Conversation
|
ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing |
PR Summary by QodoFix VectorManager health/stats on persistent vector stores via VectorStore.count()
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Code Review by Qodo
1.
|
|
@yunaremaia can you fix the qodo reviews, before we review it. |
Address Qodo review findings on semantica-agi#914: - Persistent backend with no wrapped store no longer silently returns 0 (which masked a missing initialization as an empty, healthy store); it now raises NotImplementedError like get_vector()/get_metadata(). - A mis-shaped adapter exposing a non-callable 'count' attribute now surfaces a clean NotImplementedError instead of a TypeError, via a getattr + callable() capability check. Adds regression tests for both cases.
|
Fixed both Qodo findings in cd972c9:
Regression tests added for both cases (12/12 passing in the persistent-backend suite). Ready for review. |
Thanks @yunaremaia will review it. |
Address Qodo review findings on semantica-agi#914: - Persistent backend with no wrapped store no longer silently returns 0 (which masked a missing initialization as an empty, healthy store); it now raises NotImplementedError like get_vector()/get_metadata(). - A mis-shaped adapter exposing a non-callable 'count' attribute now surfaces a clean NotImplementedError instead of a TypeError, via a getattr + callable() capability check. Adds regression tests for both cases.
cd972c9 to
a5ba75f
Compare
|
Rebased onto the latest main (was behind) — no conflicts, the 12 persistent-backend tests still pass. Ready for your review whenever convenient. |
Address Qodo review findings on semantica-agi#914: - Persistent backend with no wrapped store no longer silently returns 0 (which masked a missing initialization as an empty, healthy store); it now raises NotImplementedError like get_vector()/get_metadata(). - A mis-shaped adapter exposing a non-callable 'count' attribute now surfaces a clean NotImplementedError instead of a TypeError, via a getattr + callable() capability check. Adds regression tests for both cases.
dc3f967 to
082da9a
Compare
Address Qodo review findings on semantica-agi#914: - Persistent backend with no wrapped store no longer silently returns 0 (which masked a missing initialization as an empty, healthy store); it now raises NotImplementedError like get_vector()/get_metadata(). - A mis-shaped adapter exposing a non-callable 'count' attribute now surfaces a clean NotImplementedError instead of a TypeError, via a getattr + callable() capability check. Adds regression tests for both cases.
|
Thanks for assigning #914 to me — I'll take it to merge. Current state: rebased onto latest |
Address Qodo review findings on semantica-agi#914: - Persistent backend with no wrapped store no longer silently returns 0 (which masked a missing initialization as an empty, healthy store); it now raises NotImplementedError like get_vector()/get_metadata(). - A mis-shaped adapter exposing a non-callable 'count' attribute now surfaces a clean NotImplementedError instead of a TypeError, via a getattr + callable() capability check. Adds regression tests for both cases.
082da9a to
2886e8d
Compare
…ends (semantica-agi#855) maintain_store() and collect_statistics() reached into VectorStore internals (.vectors/.metadata), which only exist for the inmemory backend — any persistent backend (FAISS, Qdrant, Pinecone, Milvus, ...) crashed with AttributeError. Add a public backend-agnostic VectorStore.count() accessor following the get_vector()/get_metadata() precedent (semantica-agi#843) and the NotImplementedError-on-unsupported-capability precedent of _filter_by_metadata() (semantica-agi#848): inmemory counts its dict, persistent backends delegate to count() when available, and raise NotImplementedError otherwise. VectorManager methods now go through count(); maintain_store() keeps the exact inmemory semantics (separate vector/metadata dict counts) and reports a 1:1 count for persistent backends, where metadata is stored alongside each vector. Tests: 10 hermetic unit tests covering inmemory, delegation and the NotImplementedError path. Core vector_store suite: 40 passed.
Address Qodo review findings on semantica-agi#914: - Persistent backend with no wrapped store no longer silently returns 0 (which masked a missing initialization as an empty, healthy store); it now raises NotImplementedError like get_vector()/get_metadata(). - A mis-shaped adapter exposing a non-callable 'count' attribute now surfaces a clean NotImplementedError instead of a TypeError, via a getattr + callable() capability check. Adds regression tests for both cases.
2886e8d to
3838a4c
Compare
semantica-agi#914) - FAISSStore.count(): returns len(index.vector_ids); 0 when no index exists yet - SQLiteVecStore.count(): delegates to get_stats()[vector_count] (SELECT COUNT(*)) - PgVectorStore.count(): delegates to get_stats()[vector_count] (SELECT COUNT(*)) - VectorStore.count(): fix misleading NotImplementedError message; now describes how to add count() support to a backend adapter rather than claiming only the inmemory backend can ever support counting - VectorManager.maintain_store(): split inmemory and persistent paths: * inmemory: independently reads len(vectors) and len(metadata) and compares them as an integrity check (original semantics preserved) * persistent: calls store.count(); returns metadata_count=None because metadata is co-located with vectors in the backend and cannot be counted independently; never manufactures metadata_count=vector_count as a vacuous tautology (semantica-agi#914 Qodo review) - Tests: rewrite test_vector_manager_persistent.py with 31 tests covering dispatch logic, inmemory divergence detection, persistent metadata_count=None invariant, FAISSStore/PgVectorStore via mocks, and SQLiteVecStore via real in-memory SQLite (skipped when sqlite-vec absent)
Sameer6305
left a comment
There was a problem hiding this comment.
Thanks @yunaremaia for the solid work on this fix and for addressing the persistent-backend compatibility issue.
I reviewed the implementation against the existing VectorStore/VectorManager abstractions, backend behavior, edge cases, and the added tests.
During review, I found that the initial count() abstraction still left the shipped persistent backends without an actual count implementation, and maintain_store() was treating metadata_count == vector_count as a guaranteed invariant for persistent stores. So corrected this by:
- Adding
count()implementations for FAISS, SQLiteVec, and PgVector where reliable counts are available. - Keeping
NotImplementedErrorfor backends where a reliable count cannot currently be guaranteed. - Updating
maintain_store()so persistent backends reportmetadata_count=Nonerather than manufacturing a 1:1 metadata invariant. - Improving the unsupported-count error message.
- Expanding the regression tests to cover the new backend behavior and persistent/in-memory semantics.
These fixes are included in commit df02fa88 (fix(vector_store): implement count() on FAISS/SQLite/PgVector backends (#914)).
The focused validation passed (25/25 targeted tests; SQLite-specific tests are skipped when sqlite-vec is unavailable), and the working tree/diff checks are clean.
@KaifAhmad1 From my side, this is approved and ready for your final review/verdict before merge.
…emantica-agi#914, closes semantica-agi#855) Records the VectorStore.count() accessor, the FAISS/SQLite/PgVector implementations added during review, and the maintain_store() metadata_count fix (no longer fabricates equality for persistent backends).
KaifAhmad1
left a comment
There was a problem hiding this comment.
Approving — thanks both.
@yunaremaia, nice fix for #855: the backend-agnostic VectorStore.count() is the right shape (following the get_vector()/get_metadata() precedent from #843), and you were quick to close out both Qodo findings.
@Sameer6305, good catch that the initial version didn't actually ship a count() on any real backend, and that maintain_store() was manufacturing a vacuous metadata_count == vector_count for persistent stores — the metadata_count: None fix is the honest answer there.
Independently reviewed the diff against the actual FAISSStore/PgVectorStore/SQLiteVecStore internals (not just the description) — confirmed FAISS really has no delete path so len(index.vector_ids) is safe, confirmed FAISS's count() correctly avoids the get_stats() "no_index" dict (which lacks a vector_count key, unlike Pg/SQLite's), and checked there are no other callers in the repo that depend on metadata_count being a non-None int. Added a changelog entry (859690c) documenting the fix. No blockers — ready to merge.
|
Thank you @KaifAhmad1! The backend-agnostic count() shape was the goal — glad it matches the repo's precedent. Standing by for the CI to finish. |
Closes #855
Problem
VectorManager.maintain_store()andVectorManager.collect_statistics()reached intoVectorStoreinternals (store.vectors/store.metadata), which are only initialized for theinmemorybackend. Any persistent backend (FAISS, Qdrant, Pinecone, Milvus, ...) never sets them, so both methods crashed immediately withAttributeError— they were unusable outside the inmemory backend.Fix
VectorStore.count()accessor (backend-agnostic), following theget_vector()/get_metadata()precedent from AttributeError in VectorStore.get_vector() and get_metadata() when using persistent backends #843 and theNotImplementedError-on-unsupported-capability precedent from AttributeError: 'VectorStore' object has no attribute 'vectors' in build_decision_context() and explain_decision() #848's_filter_by_metadata()fix:inmemory→ counts its local dictcount()→ delegatesNotImplementedErrorwith a clear message (so callers can tell "no vectors" from "counting not supported")VectorManager.maintain_store()andcollect_statistics()now go throughstore.count()instead of poking internals.maintain_store()keeps the exact inmemory semantics (separate vector/metadata dict counts, so a desync still reportshealthy: false) and reports a 1:1metadata_countfor persistent backends, where metadata is stored alongside each vector.Tests
10 hermetic unit tests (no external services): inmemory count, empty store, delegation to a backend
count(),NotImplementedErrorpath, and bothVectorManagermethods against inmemory, counting and non-counting persistent-style stores — including a regression assertion that the failure mode isNotImplementedError, notAttributeError.Core vector_store suite: 40 passed. (Pre-existing environment failures in
test_kg_integration.py/test_decision_embedding_pipeline.pyare unrelated — they fail identically onmainwithout this change.)