fix(precedents): חילוץ מספר-תיק קנוני מהציטוט — לא ציטוט-מלא כמזהה (#137)
בהעלאה דרך "פסיקה-חסרה" (ענף ועדת-ערר), כשטופס case_number ריק המסלול נפל-לאחור לציטוט המלא (committee_case_number = case_number.strip() or citation), כך שמחרוזת- תצוגה עם שמות-צדדים הושתלה בשדה-המזהה — הפרת INV-ID2/INV-ID1 (X1). נצפה על precedent 1bf0bae0 (ערר 85074-04-25 רפאל לוי/חולון): case_number=85074/0425, case_name=ציטוט שלם. תיקון (G1 — נרמול-במקור, G2 — שימוש-חוזר בפרסר הקנוני): - court_citation.case_number_from_citation(citation) — מחזיר את אסימון-המספר המנורמל בלבד (classify; '' כשאין מספר). חולץ נכון 85074-04-25 גם מתוך "ערר (ת\"א 85074-04-25) ...". reuse של הפרסר היחיד, בלי regex מקביל. - web/app.py (ענף ועדת-ערר): fallback דרך case_number_from_citation; אם אין מספר — HTTPException 400 "נא להזין מספר-תיק ידנית" במקום השתלת ציטוט-מלא. - db._canonical_case_number: מוקשח לחלץ את אסימון-המספר (זורק זנב שמות-צדדים), כך ששדה-המזהה לעולם לא נשמר מזוהם — גם בקריאה ישירה (committee + active cases). מספר נקי חוזר ללא שינוי; חודש לא מומצא (X1 §1). - תיקון-נתון: scripts/fix_137_committee_case_number.py (בוצע) — 1bf0bae0: case_number→85074-04-25, case_name→צדדים, token ב-citation_formatted. אומת היחיד עם canon(num)≠num ב-internal_committee. אידמפוטנטי. מחוץ-לתחום (תועד כ-follow-up): מסלול external (precedent_library) משתמש בציטוט- מלא כמזהה-מורשת — זהו פריט-המיגרציה X1 §5 (138 רשומות external/cited_only), לא הבאג הזה. prefill ב-UI של /missing-precedents — דורש שער Claude Design. בדיקות: test_court_citation (case_number_from_citation: party-strip/forms/empty), test_canonical_case_number (harden). כל 339 בדיקות mcp עוברות. guards נקיים. Invariants: G1 (נרמול-במקור), INV-ID1/ID2 (מזהה מנורמל, אין ציטוט-מלא כמזהה), G2 (פרסר יחיד), G12 (leak-guard נקי). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
17
web/app.py
17
web/app.py
@@ -7081,6 +7081,7 @@ async def bulletin_upload(file: UploadFile = File(...)):
|
||||
|
||||
|
||||
from legal_mcp.services import internal_decisions as int_decisions_service # noqa: E402
|
||||
from legal_mcp.services import court_citation # noqa: E402
|
||||
|
||||
|
||||
@app.post("/api/internal-decisions/upload")
|
||||
@@ -7917,8 +7918,20 @@ async def missing_precedent_upload(
|
||||
or int_decisions_service._district_from_court(citation)
|
||||
or PLACEHOLDER_PENDING_EXTRACTION
|
||||
)
|
||||
# case_number for the committee decision (not the cited-in case)
|
||||
committee_case_number = case_number.strip() or citation
|
||||
# case_number for the committee decision (not the cited-in case).
|
||||
# When the form leaves it blank, derive the canonical number from
|
||||
# the citation — NEVER fall back to the raw citation string, which
|
||||
# planted the full display text (party names) into the identifier
|
||||
# field (#137, INV-ID2). If no number can be parsed, demand one.
|
||||
committee_case_number = (
|
||||
case_number.strip()
|
||||
or court_citation.case_number_from_citation(citation)
|
||||
)
|
||||
if not committee_case_number:
|
||||
raise HTTPException(
|
||||
400,
|
||||
"לא ניתן לחלץ מספר-תיק מהציטוט — נא להזין מספר-תיק ידנית.",
|
||||
)
|
||||
result = await int_decisions_service.ingest_internal_decision(
|
||||
case_number=committee_case_number,
|
||||
case_name=(case_name.strip() or mp.get("case_name") or "").strip(),
|
||||
|
||||
Reference in New Issue
Block a user