test: cover qdrant delete-kinds scoping
This commit is contained in:
@@ -112,3 +112,33 @@ Notes:
|
|||||||
|
|
||||||
- Legacy HTTP/vector-rest deployments do not gain a new destructive RPC surface from this fix; they keep their previous behavior and continue to fail closed for unsupported cleanup.
|
- Legacy HTTP/vector-rest deployments do not gain a new destructive RPC surface from this fix; they keep their previous behavior and continue to fail closed for unsupported cleanup.
|
||||||
- The broader suite still emits the same pre-existing deprecation and serializer warnings already noted above; this round did not introduce new warnings.
|
- The broader suite still emits the same pre-existing deprecation and serializer warnings already noted above; this round did not introduce new warnings.
|
||||||
|
|
||||||
|
## Fix round 3 (2026-08-08)
|
||||||
|
|
||||||
|
Scope:
|
||||||
|
|
||||||
|
- Added an adapter-level Qdrant regression for mixed semantic kinds within one workspace plus a second workspace memory point.
|
||||||
|
- Verified that `delete_kinds("memory", ["memory"])` emits the real adapter filter with both `workspace_id=demo` and `record_kind=memory`.
|
||||||
|
- Verified that non-memory semantic kinds in the same workspace and memory from another workspace survive the delete.
|
||||||
|
|
||||||
|
RED evidence:
|
||||||
|
|
||||||
|
- Re-review identified a test gap rather than a confirmed runtime bug:
|
||||||
|
- existing coverage asserted only the CLI mock call shape for qdrant memory clear
|
||||||
|
- there was no adapter-level regression proving the real Qdrant delete filter and resulting fake-Qdrant state across mixed semantic kinds/workspaces
|
||||||
|
- Added regression:
|
||||||
|
- `tests/test_qdrant_vector_store.py::test_delete_kinds_is_workspace_scoped_and_preserves_other_semantic_kinds`
|
||||||
|
|
||||||
|
GREEN evidence:
|
||||||
|
|
||||||
|
- Requested focused suite:
|
||||||
|
- `cd harness && .venv/bin/pytest tests/test_qdrant_vector_store.py tests/test_qdrant_cli_commands.py tests/test_semantic_kind_isolation.py -q`
|
||||||
|
- Result: `18 passed`
|
||||||
|
- Ruff on changed files:
|
||||||
|
- `cd harness && .venv/bin/ruff check tests/test_qdrant_vector_store.py`
|
||||||
|
- Result: clean
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- This round required no production change; the new adapter regression passed against the existing Qdrant implementation.
|
||||||
|
- The focused suite still emits the same pre-existing `testcontainers.postgres` deprecation warning from `tests/conftest.py`; no new warnings were introduced.
|
||||||
|
|||||||
@@ -307,6 +307,51 @@ def test_existing_hashes_health_and_exact_generation_inventory_and_delete():
|
|||||||
assert health.dimension_compatible is True
|
assert health.dimension_compatible is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete_kinds_is_workspace_scoped_and_preserves_other_semantic_kinds():
|
||||||
|
fake = FakeQdrantHttp()
|
||||||
|
store = _store(fake)
|
||||||
|
|
||||||
|
store.upsert("memory", [_write_record("memory:1", "memory")])
|
||||||
|
store.upsert("memory", [_write_record("solved:1", "solved_question")])
|
||||||
|
store.upsert("schema_records", [_write_record("schema_table:patients", "schema_table")])
|
||||||
|
|
||||||
|
other_workspace_memory = next(
|
||||||
|
point for point in fake.points.values() if point["payload"]["record_key"] == "memory:1"
|
||||||
|
).copy()
|
||||||
|
other_workspace_memory["id"] = point_id("other", "memory", "memory:other")
|
||||||
|
other_workspace_memory["payload"] = {
|
||||||
|
**other_workspace_memory["payload"],
|
||||||
|
"workspace_id": "other",
|
||||||
|
"record_key": "memory:other",
|
||||||
|
"title": "title:memory:other",
|
||||||
|
"content": "content:memory:other",
|
||||||
|
"ref": "ref:memory:other",
|
||||||
|
}
|
||||||
|
fake.points[other_workspace_memory["id"]] = other_workspace_memory
|
||||||
|
|
||||||
|
assert store.delete_kinds("memory", ["memory"]) == 1
|
||||||
|
|
||||||
|
delete_call = next(
|
||||||
|
call
|
||||||
|
for call in fake.calls
|
||||||
|
if call[0] == "POST" and call[1].endswith("/points/delete?wait=true")
|
||||||
|
)
|
||||||
|
assert delete_call[2]["filter"] == {
|
||||||
|
"must": [
|
||||||
|
{"key": "workspace_id", "match": {"value": "demo"}},
|
||||||
|
{"key": "record_kind", "match": {"any": ["memory"]}},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
assert {
|
||||||
|
point["payload"]["record_key"]: point["payload"]["record_kind"]
|
||||||
|
for point in fake.points.values()
|
||||||
|
} == {
|
||||||
|
"solved:1": "solved_question",
|
||||||
|
"schema_table:patients": "schema_table",
|
||||||
|
"memory:other": "memory",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_sanitizes_timeout_and_malformed_responses():
|
def test_sanitizes_timeout_and_malformed_responses():
|
||||||
fake = FakeQdrantHttp()
|
fake = FakeQdrantHttp()
|
||||||
store = _store(fake)
|
store = _store(fake)
|
||||||
|
|||||||
Reference in New Issue
Block a user