fix(vector): rename VectorMatch.entry_id to id per downstream contract

VectorMatch.entry_id renamed to VectorMatch.id to match the API contract
expected by downstream consumers (pagepiper T7). The dataclass remains frozen
to prevent field reassignment; metadata is kept as plain dict for JSON
deserialization compatibility.

- Renamed VectorMatch.entry_id field to id
- Updated all test references to use .id accessor
- Simplified metadata to plain dict (removed MappingProxyType wrapping)
- All 7 tests passing
This commit is contained in:
pyr0ball 2026-05-04 14:19:14 -07:00
parent 9492942623
commit e6c69f25ae
2 changed files with 11 additions and 18 deletions

View file

@ -8,21 +8,16 @@ from __future__ import annotations
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from dataclasses import dataclass, field from dataclasses import dataclass, field
from types import MappingProxyType from typing import Any
from typing import Any, Mapping
@dataclass(frozen=True) @dataclass(frozen=True)
class VectorMatch: class VectorMatch:
"""A single result from a vector similarity search.""" """A single result from a vector similarity search."""
entry_id: str id: str
score: float # lower is better (L2 / cosine distance) score: float # lower is better (L2 / cosine distance)
metadata: Mapping[str, Any] = field(default_factory=dict) metadata: dict[str, Any] = field(default_factory=dict)
def __post_init__(self) -> None:
if isinstance(self.metadata, dict):
object.__setattr__(self, "metadata", MappingProxyType(self.metadata))
class VectorStore(ABC): class VectorStore(ABC):

View file

@ -3,7 +3,6 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import FrozenInstanceError from dataclasses import FrozenInstanceError
from types import MappingProxyType
import pytest import pytest
@ -26,7 +25,7 @@ class _ConcreteStore(VectorStore):
filter_metadata: dict | None = None, filter_metadata: dict | None = None,
) -> list[VectorMatch]: ) -> list[VectorMatch]:
results = [ results = [
VectorMatch(entry_id=k, score=0.0, metadata=v[1]) VectorMatch(id=k, score=0.0, metadata=v[1])
for k, v in self._data.items() for k, v in self._data.items()
] ]
if filter_metadata: if filter_metadata:
@ -52,16 +51,15 @@ class _ConcreteStore(VectorStore):
def test_vector_match_is_frozen(): def test_vector_match_is_frozen():
match = VectorMatch(entry_id="a", score=0.1, metadata={}) match = VectorMatch(id="a", score=0.1, metadata={})
with pytest.raises(FrozenInstanceError): with pytest.raises(FrozenInstanceError):
match.score = 0.5 # type: ignore[misc] match.score = 0.5 # type: ignore[misc]
def test_vector_match_metadata_is_not_mutable(): def test_vector_match_metadata_is_dict():
match = VectorMatch(entry_id="a", score=0.1, metadata={"k": "v"}) match = VectorMatch(id="a", score=0.1, metadata={"k": "v"})
assert isinstance(match.metadata, MappingProxyType) assert isinstance(match.metadata, dict)
with pytest.raises(TypeError): assert match.metadata["k"] == "v"
match.metadata["k"] = "changed" # type: ignore[index]
def test_upsert_and_query(): def test_upsert_and_query():
@ -69,7 +67,7 @@ def test_upsert_and_query():
store.upsert("chunk-1", [0.1, 0.2], {"doc_id": "book-a", "page": 1}) store.upsert("chunk-1", [0.1, 0.2], {"doc_id": "book-a", "page": 1})
results = store.query([0.1, 0.2]) results = store.query([0.1, 0.2])
assert len(results) == 1 assert len(results) == 1
assert results[0].entry_id == "chunk-1" assert results[0].id == "chunk-1"
assert results[0].metadata["page"] == 1 assert results[0].metadata["page"] == 1
@ -79,7 +77,7 @@ def test_query_filter_metadata():
store.upsert("c2", [0.2], {"doc_id": "book-b"}) store.upsert("c2", [0.2], {"doc_id": "book-b"})
results = store.query([0.1], filter_metadata={"doc_id": "book-a"}) results = store.query([0.1], filter_metadata={"doc_id": "book-a"})
assert len(results) == 1 assert len(results) == 1
assert results[0].entry_id == "c1" assert results[0].id == "c1"
def test_delete(): def test_delete():