fix(evidence): filter active data in every search
This commit is contained in:
@@ -250,6 +250,75 @@ def test_active_searcher_without_active_fails_closed_for_evidence(tmp_path):
|
||||
assert wrapped.search([1.0], kinds=["memory"]) == ["legacy"]
|
||||
|
||||
|
||||
def test_active_searcher_splits_default_and_mixed_kinds_before_global_limit(tmp_path):
|
||||
from types import SimpleNamespace
|
||||
from tht.search.evidence import ActiveEvidenceSearcher
|
||||
|
||||
store = CorpusStore(tmp_path / "corpus")
|
||||
generation = store.stage(CorpusManifest(), {}, generation="gen:" + "a" * 32)
|
||||
store.publish(generation)
|
||||
calls = []
|
||||
|
||||
class Delegate:
|
||||
def search(self, embedding, top_n=10, kinds=None, metadata_filter=None):
|
||||
calls.append((kinds, metadata_filter))
|
||||
if kinds == ["evidence"]:
|
||||
return [SimpleNamespace(id="active", similarity=0.8)]
|
||||
return [SimpleNamespace(id="memory", similarity=0.9)]
|
||||
|
||||
searcher = ActiveEvidenceSearcher(store, Delegate())
|
||||
hits = searcher.search([1.0], top_n=1, kinds=["evidence", "memory"])
|
||||
assert [hit.id for hit in hits] == ["memory"]
|
||||
assert calls[0] == (["memory"], None)
|
||||
# Empty manifest means no Evidence query, but the split remains explicit and safe.
|
||||
assert all(call[0] != ["evidence"] for call in calls)
|
||||
calls.clear()
|
||||
searcher.search([1.0], top_n=1)
|
||||
assert calls[0][0] == ["memory", "schema_column", "schema_table", "solved_question"]
|
||||
assert all(call[0] is not None for call in calls)
|
||||
|
||||
|
||||
def test_active_evidence_query_holds_lock_against_publish(tmp_path):
|
||||
import threading
|
||||
from types import SimpleNamespace
|
||||
from tht.search.evidence import ActiveEvidenceSearcher
|
||||
|
||||
first_pipeline = pipeline(tmp_path, Source([(item("one", "a"), "old")]), vectors=Vectors())
|
||||
first_pipeline.run()
|
||||
store = first_pipeline.store
|
||||
entered = threading.Event()
|
||||
release = threading.Event()
|
||||
published = threading.Event()
|
||||
|
||||
class Delegate:
|
||||
def search(self, embedding, top_n=10, kinds=None, metadata_filter=None):
|
||||
entered.set()
|
||||
assert release.wait(5)
|
||||
return [SimpleNamespace(id="active", similarity=1.0)]
|
||||
|
||||
search = threading.Thread(
|
||||
target=lambda: ActiveEvidenceSearcher(store, Delegate()).search(
|
||||
[1.0], kinds=["evidence"]
|
||||
)
|
||||
)
|
||||
search.start()
|
||||
assert entered.wait(5)
|
||||
next_generation = store.stage(CorpusManifest(), {})
|
||||
|
||||
def publish():
|
||||
with store.writer_lock():
|
||||
store.publish(next_generation)
|
||||
published.set()
|
||||
|
||||
publisher = threading.Thread(target=publish)
|
||||
publisher.start()
|
||||
assert not published.wait(0.1)
|
||||
release.set()
|
||||
search.join(5)
|
||||
publisher.join(5)
|
||||
assert published.is_set()
|
||||
|
||||
|
||||
def test_unchanged_documents_skip_acquire_normalize_chunk_and_embed(tmp_path):
|
||||
one = item("one", "a")
|
||||
first_source = Source([(one, "hello")])
|
||||
|
||||
Reference in New Issue
Block a user