test: two tests that had to move with the chunk-carrying select (#4243)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / integration (push) Successful in 47s
CI & Build / TypeScript typecheck (push) Successful in 56s
CI & Build / Python tests (push) Successful in 1m36s
CI & Build / Build & push image (push) Successful in 30s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / integration (push) Successful in 47s
CI & Build / TypeScript typecheck (push) Successful in 56s
CI & Build / Python tests (push) Successful in 1m36s
CI & Build / Build & push image (push) Successful in 30s
test_chunking::test_search_collapses_chunk_rows_to_best_chunk_per_note feeds rows straight into the real semantic_search_notes, so widening the select to carry chunk_index/chunk_text broke its 2-tuple fakes. I had claimed no unit test did this after grepping test_embeddings.py, which was the wrong file. Rows are 4-tuples now, and the test additionally asserts the winning chunk is REPORTED and not merely used for scoring — the property #4243 exists for, and this is where it belongs, beside the collapse it comes from. test_task_work_log_surface's ACL test asserted "task_logs.user_id" was absent from the compiled statement. It is present in every SELECT as a projected column; the claim was about the WHERE clause. Asserts on stmt.whereclause now, which is what was actually meant and still fails if an owner filter returns. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
This commit is contained in:
+18
-2
@@ -148,23 +148,39 @@ async def test_search_collapses_chunk_rows_to_best_chunk_per_note():
|
|||||||
from scribe.services import embeddings as emb
|
from scribe.services import embeddings as emb
|
||||||
|
|
||||||
note_a, note_b = MagicMock(id=1), MagicMock(id=2)
|
note_a, note_b = MagicMock(id=1), MagicMock(id=2)
|
||||||
rows = [(note_a, 0.10), (note_b, 0.20), (note_a, 0.25), (note_a, 0.30)]
|
# Rows are (Note, distance, chunk_index, chunk_text) — the chunk columns
|
||||||
|
# ride along so the collapse can report WHICH passage won (#4243).
|
||||||
|
rows = [
|
||||||
|
(note_a, 0.10, 3, "the passage that actually matched"),
|
||||||
|
(note_b, 0.20, 0, "b's best"),
|
||||||
|
(note_a, 0.25, 7, "a worse chunk of a"),
|
||||||
|
(note_a, 0.30, 1, "a worse chunk of a"),
|
||||||
|
]
|
||||||
result = MagicMock()
|
result = MagicMock()
|
||||||
result.all.return_value = rows
|
result.all.return_value = rows
|
||||||
session, ctx = _session_ctx()
|
session, ctx = _session_ctx()
|
||||||
session.execute = AsyncMock(return_value=result)
|
session.execute = AsyncMock(return_value=result)
|
||||||
|
|
||||||
|
report: dict = {}
|
||||||
with (
|
with (
|
||||||
patch.object(emb, "async_session", return_value=ctx),
|
patch.object(emb, "async_session", return_value=ctx),
|
||||||
patch.object(emb, "get_embedding", AsyncMock(return_value=[0.0] * 384)),
|
patch.object(emb, "get_embedding", AsyncMock(return_value=[0.0] * 384)),
|
||||||
):
|
):
|
||||||
out = await emb.semantic_search_notes(
|
out = await emb.semantic_search_notes(
|
||||||
1, "a query", limit=8, demote_superseded=False
|
1, "a query", limit=8, demote_superseded=False, report=report
|
||||||
)
|
)
|
||||||
|
|
||||||
assert [note.id for _s, note in out] == [1, 2]
|
assert [note.id for _s, note in out] == [1, 2]
|
||||||
assert out[0][0] == 1.0 - 0.10 # the BEST chunk's score, not a later one
|
assert out[0][0] == 1.0 - 0.10 # the BEST chunk's score, not a later one
|
||||||
|
|
||||||
|
# And the winning chunk is reported, not merely used for scoring. Without
|
||||||
|
# this a caller can only preview the head of the body — a span this query
|
||||||
|
# has already ranked lower than the one that won (#4243).
|
||||||
|
assert report["best_chunk"][1] == {
|
||||||
|
"index": 3, "text": "the passage that actually matched",
|
||||||
|
}
|
||||||
|
assert report["best_chunk"][2]["index"] == 0
|
||||||
|
|
||||||
|
|
||||||
# --- the write path: one row per chunk (#280 step 3) -------------------------
|
# --- the write path: one row per chunk (#280 step 3) -------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -322,9 +322,12 @@ async def test_logs_for_task_is_not_filtered_by_who_wrote_the_entry():
|
|||||||
patch("scribe.services.task_logs.async_session",
|
patch("scribe.services.task_logs.async_session",
|
||||||
MagicMock(return_value=session)):
|
MagicMock(return_value=session)):
|
||||||
await logs_for_task(7, 42)
|
await logs_for_task(7, 42)
|
||||||
stmt = str(session.execute.await_args.args[0])
|
# The WHERE clause specifically — `user_id` is a selected COLUMN of the
|
||||||
assert "task_logs.task_id" in stmt
|
# row and appears in every SELECT, so asserting against the whole compiled
|
||||||
assert "task_logs.user_id" not in stmt
|
# statement tests the projection rather than the scoping.
|
||||||
|
where = str(session.execute.await_args.args[0].whereclause)
|
||||||
|
assert "task_logs.task_id" in where
|
||||||
|
assert "task_logs.user_id" not in where
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
|||||||
Reference in New Issue
Block a user