"""Semantic / vector retrieval abstraction (stub + in-memory mock). A real implementation will talk to a vector DB / embedding store and return "semantically similar" artifacts. For bootstrap we keep the Protocol open and provide a deterministic mock. """ from __future__ import annotations from dataclasses import dataclass, field from typing import Protocol, Optional, Sequence from uuid import UUID @dataclass class SemanticHit: artifact_id: UUID score: float snippet: str = "" metadata: dict = field(default_factory=dict) class SemanticStore(Protocol): """Future vector / embedding store interface.""" async def search( self, tenant_id: UUID, query: str, *, project_id: Optional[UUID] = None, top_k: int = 10, filters: Optional[dict] = None, ) -> Sequence[SemanticHit]: ... async def index_artifact( self, tenant_id: UUID, artifact_id: UUID, text: str, metadata: Optional[dict] = None, ) -> None: ... class InMemorySemanticStoreMock(SemanticStore): """Deterministic, no-op mock. Useful for unit tests and for getting the Context Engine scaffolding up before a real vector DB is deployed. Always returns an empty hit list so callers gracefully degrade to structural context only. """ async def search( self, tenant_id: UUID, query: str, *, project_id: Optional[UUID] = None, top_k: int = 10, filters: Optional[dict] = None, ) -> Sequence[SemanticHit]: return tuple() async def index_artifact( self, tenant_id: UUID, artifact_id: UUID, text: str, metadata: Optional[dict] = None, ) -> None: # pragma: no cover - mock side effect return None