feat(search): retrieval telemetry — log every semantic retrieval
CI & Build / Python lint (push) Successful in 2s
CI & Build / integration (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 44s
CI & Build / Build & push image (push) Successful in 58s

Add retrieval_logs (migration 0068) + services/retrieval_telemetry with a
fire-and-forget record_retrieval(), wired into the MCP search tool
(source=mcp_search) and the REST search route (source=rest_search). Captures
query, effective params, and the per-result score distribution so KB-injection
thresholds can be tuned from data rather than guessed.

Scribe: project 2, milestone 93, task 1032.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xz4j1H7pjYSjKsEpgcNH5E
This commit is contained in:
2026-06-22 20:10:15 -04:00
parent 513019786e
commit 807f478cac
7 changed files with 384 additions and 2 deletions
+15 -1
View File
@@ -1,7 +1,14 @@
import time
from quart import Blueprint, jsonify, request
from scribe.auth import login_required, get_current_user_id
from scribe.services.embeddings import semantic_search_notes
from scribe.services.retrieval_telemetry import record_retrieval
# This route searches with a looser floor than the MCP tool default — it powers
# an interactive feed where loosely-related hits still have value.
_REST_SEARCH_THRESHOLD = 0.3
search_bp = Blueprint("search", __name__, url_prefix="/api/search")
@@ -27,8 +34,15 @@ async def search_route():
limit = min(request.args.get("limit", 10, type=int), 50)
is_task = _content_type_to_is_task(content_type)
t0 = time.perf_counter()
results = await semantic_search_notes(
uid, q, limit=limit, is_task=is_task, threshold=0.3
uid, q, limit=limit, is_task=is_task, threshold=_REST_SEARCH_THRESHOLD
)
record_retrieval(
user_id=uid, source="rest_search", query=q,
threshold=_REST_SEARCH_THRESHOLD, limit=limit,
project_id=None, is_task=is_task, results=results,
duration_ms=(time.perf_counter() - t0) * 1000.0,
)
return jsonify({
"results": [