Initial curated RAGcore source from c16667f0c9397e2bfc8dd0255b114fba23c8d05e
This commit is contained in:
commit
7ca726caf2
659 files changed
+98171
No files matched your search
@@ -0,0 +1,96 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from types import SimpleNamespace
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
from qdrant_client.http import models
|
||||
|
||||
from ragcore.application.models.selection import EmbeddingCutoverRejected
|
||||
from ragcore.domain.control import DataPolicy
|
||||
from ragcore.domain.models import EmbeddingProfile, EmbeddingProvider, EmbeddingSelection
|
||||
from ragcore.infrastructure.qdrant.selection_verifier import QdrantEmbeddingSelectionVerifier
|
||||
|
||||
|
||||
def _profile() -> EmbeddingProfile:
|
||||
return EmbeddingProfile(
|
||||
id=uuid4(),
|
||||
profile="selected-index",
|
||||
version="v2",
|
||||
provider=EmbeddingProvider.MODELFORGE,
|
||||
model_identifier="rag.embedding@1",
|
||||
model_digest="b" * 64,
|
||||
dimensions=3,
|
||||
context_limit=4096,
|
||||
tokenizer="capability-managed",
|
||||
data_policy=DataPolicy.LOCAL_ONLY,
|
||||
embedding_space_id=uuid4(),
|
||||
)
|
||||
|
||||
|
||||
class FakeQdrant:
|
||||
def __init__(self, *, dimension: int, payloads: list[dict[str, object]]) -> None:
|
||||
self.dimension = dimension
|
||||
self.payloads = payloads
|
||||
self.collections: list[str] = []
|
||||
|
||||
async def get_collection(self, collection_name: str) -> SimpleNamespace:
|
||||
self.collections.append(collection_name)
|
||||
return SimpleNamespace(
|
||||
config=SimpleNamespace(
|
||||
params=SimpleNamespace(
|
||||
vectors={
|
||||
"dense": models.VectorParams(
|
||||
size=self.dimension, distance=models.Distance.COSINE
|
||||
)
|
||||
},
|
||||
sparse_vectors={"sparse": models.SparseVectorParams()},
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
async def scroll(self, **_kwargs: object) -> tuple[list[SimpleNamespace], None]:
|
||||
return [SimpleNamespace(payload=value) for value in self.payloads], None
|
||||
|
||||
|
||||
def _payload(profile: EmbeddingProfile) -> dict[str, object]:
|
||||
return {
|
||||
"embedding_model_digest": profile.model_digest,
|
||||
"chunk_profile_version": profile.version,
|
||||
"embedding_space_id": str(profile.embedding_space_id),
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_collection_verifier_rejects_a_stale_vector_dimension() -> None:
|
||||
profile = _profile()
|
||||
selection = EmbeddingSelection.from_profile(profile, experiment_route_key="lab-route-next")
|
||||
client = FakeQdrant(dimension=2, payloads=[_payload(profile)])
|
||||
|
||||
with pytest.raises(EmbeddingCutoverRejected, match="vector shape"):
|
||||
await QdrantEmbeddingSelectionVerifier(client).verify(selection, profile) # type: ignore[arg-type]
|
||||
|
||||
assert client.collections == ["rag_dense_selected-index_v2"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_collection_verifier_rejects_stale_profile_identity_pins() -> None:
|
||||
profile = _profile()
|
||||
selection = EmbeddingSelection.from_profile(profile, experiment_route_key="lab-route-next")
|
||||
stale = {**_payload(profile), "embedding_space_id": str(uuid4())}
|
||||
client = FakeQdrant(dimension=3, payloads=[stale])
|
||||
|
||||
with pytest.raises(EmbeddingCutoverRejected, match="embedding-space pin"):
|
||||
await QdrantEmbeddingSelectionVerifier(client).verify(selection, profile) # type: ignore[arg-type]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_collection_verifier_counts_only_the_exact_pinned_collection() -> None:
|
||||
profile = _profile()
|
||||
selection = EmbeddingSelection.from_profile(profile)
|
||||
client = FakeQdrant(dimension=3, payloads=[_payload(profile), _payload(profile)])
|
||||
|
||||
result = await QdrantEmbeddingSelectionVerifier(client).verify(selection, profile) # type: ignore[arg-type]
|
||||
|
||||
assert client.collections == ["rag_dense_selected-index_v2"]
|
||||
assert result.verified_point_count == 2
|
||||
@@ -0,0 +1,91 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from types import SimpleNamespace
|
||||
from uuid import uuid4
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
from qdrant_client.http import models
|
||||
from qdrant_client.http.exceptions import UnexpectedResponse
|
||||
|
||||
from ragcore.application.indexes.models import IndexBuildError
|
||||
from ragcore.infrastructure.qdrant.adapter import CollectionProfileMismatchError
|
||||
from ragcore.infrastructure.qdrant.models import CollectionKind, CollectionProfile
|
||||
from ragcore.infrastructure.qdrant.rebuild import QdrantRebuildStore
|
||||
|
||||
|
||||
class MissingQdrantCollection:
|
||||
def __init__(self) -> None:
|
||||
self.reads = 0
|
||||
self.creates = 0
|
||||
|
||||
async def get_collection(self, _name: str) -> object:
|
||||
self.reads += 1
|
||||
raise UnexpectedResponse(404, "Not Found", b"missing", httpx.Headers())
|
||||
|
||||
async def create_collection(self, **_kwargs: object) -> None:
|
||||
self.creates += 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_selected_collection_verification_fails_without_recreating_missing_collection() -> (
|
||||
None
|
||||
):
|
||||
client = MissingQdrantCollection()
|
||||
profile = CollectionProfile(
|
||||
kind=CollectionKind.DENSE,
|
||||
profile="selected-profile",
|
||||
version="v2",
|
||||
dimensions=4,
|
||||
model_digest="a" * 64,
|
||||
embedding_space_id=uuid4(),
|
||||
)
|
||||
|
||||
with pytest.raises(CollectionProfileMismatchError, match="refusing to recreate"):
|
||||
await QdrantRebuildStore(client).verify_existing_selection(profile) # type: ignore[arg-type]
|
||||
|
||||
assert client.reads == 1
|
||||
assert client.creates == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_selected_collection_verification_checks_every_existing_point_pin() -> None:
|
||||
space_id = uuid4()
|
||||
|
||||
class StalePinnedCollection:
|
||||
async def get_collection(self, _name: str) -> object:
|
||||
return SimpleNamespace(
|
||||
config=SimpleNamespace(
|
||||
params=SimpleNamespace(
|
||||
vectors={
|
||||
"dense": models.VectorParams(size=4, distance=models.Distance.COSINE)
|
||||
},
|
||||
sparse_vectors={"sparse": models.SparseVectorParams()},
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
async def scroll(self, **_kwargs: object) -> tuple[list[SimpleNamespace], None]:
|
||||
return [
|
||||
SimpleNamespace(
|
||||
payload={
|
||||
"embedding_model_digest": "b" * 64,
|
||||
"chunk_profile_version": "v2",
|
||||
"embedding_space_id": str(space_id),
|
||||
}
|
||||
)
|
||||
], None
|
||||
|
||||
profile = CollectionProfile(
|
||||
kind=CollectionKind.DENSE,
|
||||
profile="selected-profile",
|
||||
version="v2",
|
||||
dimensions=4,
|
||||
model_digest="a" * 64,
|
||||
embedding_space_id=space_id,
|
||||
)
|
||||
|
||||
with pytest.raises(IndexBuildError, match="incompatible identity pins"):
|
||||
await QdrantRebuildStore(StalePinnedCollection()).verify_existing_selection( # type: ignore[arg-type]
|
||||
profile
|
||||
)
|
||||
Reference in new issue
Block a user