fix(evidence): bind corpus to workspace identity

This commit is contained in:
2026-07-12 05:57:23 +02:00
parent 78ff360882
commit db35ddb041
6 changed files with 109 additions and 10 deletions
+60
View File
@@ -329,6 +329,66 @@ def test_pipeline_result_dump_does_not_deepcopy_frozen_metadata():
assert payload["manifest"]["metadata"] == {"nested": {"value": ["safe"]}}
def test_reused_corpus_root_rejects_workspace_rename_before_any_mutation(tmp_path):
vectors = Vectors()
first = pipeline(tmp_path, Source([(item("one", "a"), "stable")]), vectors=vectors)
first.run_as_job(
workspace_id="workspace-a", workspace_root=tmp_path,
config_fingerprint="sha256:" + "1" * 64,
input_fingerprint="sha256:" + "2" * 64,
)
active = first.store.active_generation()
records = list(vectors.records)
renamed_source = Source([(item("one", "a"), "stable")])
renamed = pipeline(tmp_path, renamed_source, vectors=vectors)
with pytest.raises(PipelineError, match="different workspace"):
renamed.run_as_job(
workspace_id="workspace-b", workspace_root=tmp_path,
config_fingerprint="sha256:" + "1" * 64,
input_fingerprint="sha256:" + "2" * 64,
)
assert renamed_source.acquire_calls == []
assert renamed.store.active_generation() == active
assert vectors.records == records
def test_gc_rejects_workspace_mismatch_without_deleting(tmp_path):
vectors = Vectors()
owner = pipeline(tmp_path, Source([(item("one", "a"), "stable")]), vectors=vectors)
owner.run_as_job(
workspace_id="workspace-a", workspace_root=tmp_path,
config_fingerprint="sha256:" + "1" * 64,
input_fingerprint="sha256:" + "2" * 64,
)
generations = owner.store.list_generations()
wrong = pipeline(tmp_path, Source([]), vectors=vectors)
wrong.workspace_id = "workspace-b"
with pytest.raises(PipelineError, match="different workspace"):
wrong.gc(workspace_root=tmp_path)
assert wrong.store.list_generations() == generations
def test_active_search_rejects_workspace_mismatch_before_delegate(tmp_path):
from tht.search.evidence import ActiveEvidenceSearcher, CorpusWorkspaceMismatchError
vectors = Vectors()
owner = pipeline(tmp_path, Source([(item("one", "a"), "stable")]), vectors=vectors)
owner.run_as_job(
workspace_id="workspace-a", workspace_root=tmp_path,
config_fingerprint="sha256:" + "1" * 64,
input_fingerprint="sha256:" + "2" * 64,
)
class Delegate:
def search(self, *args, **kwargs):
raise AssertionError("workspace mismatch reached vector delegate")
with pytest.raises(CorpusWorkspaceMismatchError, match="different workspace"):
ActiveEvidenceSearcher(
owner.store, Delegate(), expected_workspace_id="workspace-b",
).search([1.0], kinds=["evidence"])
def test_unchanged_documents_skip_acquire_normalize_chunk_and_embed(tmp_path):
one = item("one", "a")
first_source = Source([(one, "hello")])