fix(retrieval): סף מכויל-קוסינוס סינן פלט RRF — דף אימות-הפסיקה הציג אפס תקדימים
`hybrid_search._merge_sem_lex` דורס את `score` בערך RRF (~0.008–0.02) ברגע
שה-leg הלקסיקלי מחזיר שורות. `score` הוא אות-דירוג לגיטימי, אבל הוא מפסיק
להיות קוסינוס — ואילו `case_citation_verification._SUGGEST_FLOOR = 0.45`
כויל לקוסינוס. התוצאה: **כל שאילתה במונחים משפטיים נפוצים סוננה עד
האחרונה**, והדף הציג "אין תקדים תומך" לכל טיעון בכל תיק.
אותה פונקציה החזירה שתי סקאלות, תלוי בשאילתה:
"המונח חזית הבניין יפורש..." leg לקסיקלי ריק → 0.63–0.71 (קוסינוס)
"סמכות ועדה מקומית לפי 62א" leg לקסיקלי מלא → 0.016 (RRF)
מה שונה
- **עוגן קוסינוס במקור (G1):** `db.search_precedent_library_semantic` מסמן
`relevance` לצד `score`. **לא** בפונקציה הלקסיקלית — שם `ts_rank_cd`,
ולסמן אותו כ-relevance היה חוזר על אותה טעות בדיוק.
- **הפיוז'ן משמר:** `_merge_sem_lex` מעביר את הקוסינוס הלאה. שורה
לקסיקלית-בלבד מקבלת `relevance = None` — "לא נמדד" אינו "נמדד כלא-רלוונטי".
- **הצרכן קורא `relevance`:** `_passes_floor()` במקום השוואה ל-`score`.
שורות לקסיקליות-בלבד **נשמרות במודע** — הן הגיעו לצמרת בדירוג BM25 בתוך
top-k זעיר, וסינונן היה מחביא בדיוק את התאמות-הביטוי ומספרי-התיק שהיו"ר
מחפש בשם.
הדירוג לא השתנה: RRF ממשיך לקבוע סדר. רק הסינון עבר לסקאלה יציבה.
אימות מול הקורפוס החי:
8124-09-24: 0 → **32 מתוך 32** טיעונים עם תקדים תומך (21.5 שנ', שלם)
1069-04-26: 0 → **29 מתוך 69** (24.1 שנ', חלקי — תקציב הזמן)
שורה סמנטית: score=0.0082 · relevance=0.7297
היומונים לא נפגעו ולא נגעתי בהם: `case_digest_radar` עובר דרך
`search_digests_semantic` — סמנטי טהור, בלי RRF, ולכן `min_score=0.45` שלו
מכויל נכון.
invariants: G1 (עוגן במקור, לא תיקון-סף בקריאה) · G2 (הגדרה אחת ל-relevance
לכל הצרכנים) · INV-AH (היעדר-מדידה אינו היעדר-רלוונטיות)
טסטים: 6 חדשים (tests/test_relevance_scale.py) — אחד מהם מוכיח את הבאג
ואת התיקון באותה שורה. 531 עוברים.
This commit is contained in:
@@ -48,6 +48,25 @@ _SUGGEST_FLOOR = 0.45
|
||||
#: deadlocks. Bounding the fan-out both fixes the failure and speeds it up.
|
||||
_MAX_CONCURRENT_LOOKUPS = 8
|
||||
|
||||
def _passes_floor(hit: dict) -> bool:
|
||||
"""Is this hit similar enough to the argument to suggest to the chair?
|
||||
|
||||
Reads ``relevance`` (always a cosine similarity), NOT ``score`` — ``score``
|
||||
becomes a rank-fusion value (~0.008-0.02) as soon as the lexical leg returns
|
||||
rows, and comparing that against a cosine-calibrated floor rejected every
|
||||
hit. That is why this tab showed no supporting precedent for any argument.
|
||||
|
||||
``relevance is None`` means the row came from the lexical leg only, so no
|
||||
cosine was ever computed. It is KEPT: it earned its place by BM25 rank
|
||||
inside an already-tiny top-k, and dropping it would silently hide exact
|
||||
phrase/docket matches — the very hits a chair searches for by name.
|
||||
"""
|
||||
rel = hit.get("relevance")
|
||||
if rel is None:
|
||||
return True
|
||||
return float(rel) >= _SUGGEST_FLOOR
|
||||
|
||||
|
||||
#: Wall-clock ceiling for the whole retrieval phase. The proxy gives up at 30s;
|
||||
#: cutting ourselves off earlier lets us return the suggestions that DID land
|
||||
#: instead of a 500 that shows the chair nothing. Partial results are labelled
|
||||
@@ -103,7 +122,7 @@ async def build_view(case_number: str) -> dict:
|
||||
logger.warning("citation_verification search failed (%s): %s", title[:30], e)
|
||||
# Resolve the authority breakdown for the hit set in one batched query.
|
||||
clids = [UUID(str(h["case_law_id"])) for h in hits
|
||||
if h.get("case_law_id") and float(h.get("score", 0) or 0) >= _SUGGEST_FLOOR]
|
||||
if h.get("case_law_id") and _passes_floor(h)]
|
||||
authority = await db.citation_authority(clids) if clids else {}
|
||||
return hits, authority
|
||||
|
||||
@@ -157,7 +176,7 @@ async def build_view(case_number: str) -> dict:
|
||||
clid = str(h.get("case_law_id") or "")
|
||||
if not clid or clid in seen:
|
||||
continue
|
||||
if float(h.get("score", 0) or 0) < _SUGGEST_FLOOR:
|
||||
if not _passes_floor(h):
|
||||
continue
|
||||
seen.add(clid)
|
||||
att = attached_by_arg.get(aid, {}).get(clid)
|
||||
|
||||
Reference in New Issue
Block a user