feat(provider): validate scope_filter against the v0.5 4-axis lattice
bifrost 0.7.0 (wire v0.5) makes agent_self canonical: the scope lattice is
now {end_user, group, tenant, agent_self}. Our store was MORE permissive than
bifrost's reference (no _validate_scope_filter), which silently 0-zeroed the
#295 cold recall instead of a loud 400. Now matched: search rejects an
out-of-lattice axis with InvalidFilter (-> memory.invalid_filter 400), agent_self
admitted. Purely additive — everything that validated before still validates.
Closes the parity gap our own foot-gun flag opened (bifrost-dev shipped the
lattice add #10 off it). Pin bumped bifrost>=0.6.1 -> >=0.7.0. Contract
search PRE-003 + lattice_axes test; 2 new store tests; full suite 429 green.
This commit is contained in:
@@ -10,7 +10,12 @@ from __future__ import annotations
|
||||
import types
|
||||
|
||||
import pytest
|
||||
from bifrost.memory import IdempotencyConflict, InvalidArguments, RevisionMismatch
|
||||
from bifrost.memory import (
|
||||
IdempotencyConflict,
|
||||
InvalidArguments,
|
||||
InvalidFilter,
|
||||
RevisionMismatch,
|
||||
)
|
||||
|
||||
from ratatoskr.provider.memory_store import (
|
||||
build_memory_provider_app,
|
||||
@@ -221,6 +226,28 @@ async def test_search_non_dict_scope_filter_rejected():
|
||||
await store.search(_vec(1.0), top_k=5, scope_filter="u1")
|
||||
|
||||
|
||||
async def test_search_out_of_lattice_scope_axis_rejected():
|
||||
# v0.5 scope lattice = {end_user, group, tenant, agent_self}; an axis outside
|
||||
# it is InvalidFilter (-> memory.invalid_filter 400), matching bifrost's reference.
|
||||
store = open_memory_store(":memory:", embedding_dim=EMBEDDING_DIM)
|
||||
with pytest.raises(InvalidFilter):
|
||||
await store.search(_vec(1.0), top_k=5, scope_filter={"bogus_axis": "x"})
|
||||
|
||||
|
||||
async def test_search_agent_self_axis_accepted():
|
||||
# agent_self became canonical at wire v0.5 (#10) — admitted, not rejected.
|
||||
store = open_memory_store(":memory:", embedding_dim=EMBEDDING_DIM)
|
||||
await store.upsert_many(
|
||||
[_chunk("a1", scope={"agent_self": "ratatoskr:smoke"})],
|
||||
idempotency_key="k1",
|
||||
ctx=_ctx(),
|
||||
)
|
||||
results = await store.search(
|
||||
_vec(1.0), top_k=5, scope_filter={"agent_self": "ratatoskr:smoke"}
|
||||
)
|
||||
assert [r["chunk_id"] for r in results] == ["a1"]
|
||||
|
||||
|
||||
async def test_search_top_k_zero_returns_empty():
|
||||
# POST-001: at most top_k — zero means zero
|
||||
store = open_memory_store(":memory:", embedding_dim=EMBEDDING_DIM)
|
||||
|
||||
Reference in New Issue
Block a user