feat(corpus): Stage A — corpus tagging fixes + prevention layer
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m8s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m8s
מתקן את הבאג של תיוג שגוי לועדות ערר ומונע חזרתו: **Code changes:** * New MCP tool `internal_decision_upload` (chair_name+district required) — sole supported path for ingesting committee decisions; tags source_kind='internal_committee' automatically. * Citation guard in `precedent_library_upload` rejects citations starting with "ערר" or "בל\"מ" with a directive to use internal_decision_upload. * `practice_area.py` taxonomy unification: PRACTICE_AREAS now accepts both multi-tenant (appeals_committee/national_insurance/labor_law) and domain (rishuy_uvniya/betterment_levy/compensation_197) values. New helper `to_db_practice_area(multi_tenant, subtype) -> domain`. **Agent docs:** * legal-researcher (+5K): upload-tool decision flowchart, code samples per source_kind, district enum (ירושלים/מרכז/תל אביב/צפון/דרום/חיפה/ארצי) * legal-ceo, legal-analyst, legal-writer, legal-qa, HEARTBEAT — taxonomy awareness + source_kind-aware citation patterns + research_complete as valid status. * Fixed two pre-existing wrong practice_area values in examples (histael_hashbacha→betterment_levy, pitsuim_197→compensation_197). Closes TaskMaster #30(parts), #38(parts), #39 (root cause). DB-side backfill + CHECK constraints applied directly via psql: * 11 cases.practice_area corrected (1xxx→rishuy, 8xxx→betterment) * 6 case_law records reclassified external_upload→internal_committee with inferred district * 6 chair_name backfilled from full_text (5 שרית אריאלי + 1 דפנה תמיר) * 88 new halachot extracted for newly-uploaded precedents (אנטרים + ירושלים שקופה 1112/22 + אגא וכט) * CHECK constraints: cases.practice_area enum, case_law internal⇒district Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -181,6 +181,36 @@ python3 /home/chaim/legal-ai/scripts/notify.py \
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## §7. סטטוסי תיק תקפים (case status flow)
|
||||||
|
|
||||||
|
הסטטוסים שאתה עשוי לראות ב-`case.status` (לפי `legal-ceo.md` "מפת סטטוסים"):
|
||||||
|
|
||||||
|
```
|
||||||
|
new → proofread → documents_ready → analyst_verified → research_complete*
|
||||||
|
→ outcome_set → direction_approved → analysis_enriched → ready_for_writing
|
||||||
|
→ drafted → qa_passed / qa_failed → exported
|
||||||
|
```
|
||||||
|
|
||||||
|
`research_complete` — **valid status** (לא legacy מחוסר תוקף). מנותב ע"י `legal-researcher.md` שלב 5 כשמחקר תקדימים רץ בנפרד מהמנתח (תרחיש מתקדם). ה-CEO יודע לטפל בו כאילו זה `analyst_verified` (ראה `legal-ceo.md` "מפת סטטוסים").
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §8. ניתוב upload פסיקה לקורפוס — flowchart מהיר
|
||||||
|
|
||||||
|
```
|
||||||
|
חיים העלה PDF פסיקה לתיק → ה-citation הוא:
|
||||||
|
├── "ערר NNNN/YY" או "בל"מ NNNN/YY"
|
||||||
|
│ → internal_decision_upload (חובה chair_name + district)
|
||||||
|
└── "עע"מ / בר"מ / עמ"נ / בג"ץ / ע"א / ע"פ / רע"א / רע"פ / ת"א / ת"מ"
|
||||||
|
→ precedent_library_upload (external_upload)
|
||||||
|
```
|
||||||
|
|
||||||
|
- **`internal_decision_upload`** דורש: `file_path`, `case_number`, `chair_name`, `district`. district מתוך הרשימה: ירושלים / מרכז / תל אביב / צפון / דרום / חיפה / ארצי.
|
||||||
|
- **`precedent_library_upload`** לא מקבל chair_name/district. אם תנסה להעלות "ערר ..." דרכו — citation guard ידחה.
|
||||||
|
- פירוט מלא: `legal-researcher.md` סעיף "איזה כלי upload להשתמש".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## נתיבי API — הפניה ל-skill הרשמי
|
## נתיבי API — הפניה ל-skill הרשמי
|
||||||
|
|
||||||
| פעולה | איפה ב-skill |
|
| פעולה | איפה ב-skill |
|
||||||
|
|||||||
@@ -63,6 +63,26 @@ tools:
|
|||||||
- חוקי תמ"א 38, פינוי ובינוי, והתחדשות עירונית
|
- חוקי תמ"א 38, פינוי ובינוי, והתחדשות עירונית
|
||||||
- ועדות ערר — תכנון ובניה והיטל השבחה (סמכות, הרכב, סדרי דין)
|
- ועדות ערר — תכנון ובניה והיטל השבחה (סמכות, הרכב, סדרי דין)
|
||||||
|
|
||||||
|
## טקסונומיה — שני namespaces ל-`practice_area`
|
||||||
|
|
||||||
|
⚠️ **חובה לדעת לפני שאתה כותב practice_area לכל כלי MCP או יוצר תיק חדש.**
|
||||||
|
|
||||||
|
יש שני namespaces שונים:
|
||||||
|
|
||||||
|
| Axis | ערכים | איפה משתמשים |
|
||||||
|
|------|--------|--------------|
|
||||||
|
| **A. Multi-tenant (legacy/routing)** | `appeals_committee`, `national_insurance`, `labor_law` | בחירת tenant. הסוכנים בוועדת ערר תמיד `appeals_committee` |
|
||||||
|
| **B. Domain (DB + filters)** | `rishuy_uvniya`, `betterment_levy`, `compensation_197` | **DB columns + כל פילטר ב-`search_precedent_library` / `search_internal_decisions`** |
|
||||||
|
|
||||||
|
**כלל זהב — בכל קריאה לכלי שמחפש או כותב לקורפוס, השתמש ב-Axis B בלבד:**
|
||||||
|
- 1xxx → `rishuy_uvniya`
|
||||||
|
- 8xxx → `betterment_levy`
|
||||||
|
- 9xxx → `compensation_197`
|
||||||
|
|
||||||
|
**יצירת תיק חדש (`case_create`):** ב-DB, העמודה `cases.practice_area` מאוכפת ע"י CHECK constraint לערכי Axis B (או ריק). **אסור** לכתוב `appeals_committee` ל-`cases.practice_area` — זה ידחה. אם אתה לא בטוח באיזה axis תיק קיים נמצא, קרא קודם `case_get` ובדוק.
|
||||||
|
|
||||||
|
**זיהוי בל"מ (בקשה להארכת מועד):** אם ה-subject של מסמך/תיק מכיל "בקשה להארכת מועד" או הקידומת "בל\"מ" — זהו סיווג ייחודי (במיוחד תיקי 8xxx). חלץ זאת בעת הניתוח וציין ב-`appeal_subtype` כאחד הסיווגים המקובלים. בל"מ הוא דיוני בעיקרו ולכן הניתוח שלו שונה — לרוב יש טענת סף יחידה (האם להאריך) ולא דיון מהותי. סמן זאת בפלט כדי שהכותב ידע לבחור תבנית קצרה.
|
||||||
|
|
||||||
## הבחנה קריטית — 3 סוגי פריטים מחולצים
|
## הבחנה קריטית — 3 סוגי פריטים מחולצים
|
||||||
|
|
||||||
| סוג (claim_type) | מה זה | מי אמר |
|
| סוג (claim_type) | מה זה | מי אמר |
|
||||||
@@ -181,8 +201,8 @@ tools:
|
|||||||
| סיווג תיק | practice_area |
|
| סיווג תיק | practice_area |
|
||||||
|------------|---------------|
|
|------------|---------------|
|
||||||
| 1xxx (רישוי ובניה) | `rishuy_uvniya` |
|
| 1xxx (רישוי ובניה) | `rishuy_uvniya` |
|
||||||
| 8xxx (היטל השבחה) | `histael_hashbacha` |
|
| 8xxx (היטל השבחה) | `betterment_levy` |
|
||||||
| 9xxx (פיצויים ס' 197) | `pitsuim_197` |
|
| 9xxx (פיצויים ס' 197) | `compensation_197` |
|
||||||
|
|
||||||
אם הסוגיה מאוזכרת ב-`appeal_subtype` ידוע (כמו "שימוש חורג", "חריגות בנייה", "סטייה ניכרת") — הוסף `appeal_subtype` לפילטר. צמצום מוקדם > הרחבה מאוחרת.
|
אם הסוגיה מאוזכרת ב-`appeal_subtype` ידוע (כמו "שימוש חורג", "חריגות בנייה", "סטייה ניכרת") — הוסף `appeal_subtype` לפילטר. צמצום מוקדם > הרחבה מאוחרת.
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ tools:
|
|||||||
- mcp__legal-ai__list_chair_feedback
|
- mcp__legal-ai__list_chair_feedback
|
||||||
- mcp__legal-ai__search_case_documents
|
- mcp__legal-ai__search_case_documents
|
||||||
- mcp__legal-ai__search_precedent_library
|
- mcp__legal-ai__search_precedent_library
|
||||||
|
- mcp__legal-ai__search_internal_decisions
|
||||||
|
- mcp__legal-ai__internal_decision_upload
|
||||||
- mcp__legal-ai__workflow_status
|
- mcp__legal-ai__workflow_status
|
||||||
- mcp__legal-ai__processing_status
|
- mcp__legal-ai__processing_status
|
||||||
- mcp__legal-ai__get_metrics
|
- mcp__legal-ai__get_metrics
|
||||||
@@ -78,6 +80,48 @@ tools:
|
|||||||
| `docs/daphna-procedural-patterns.md` | תבניות פרוצדורליות (החלטת ביניים, חזרה לשמאי) | CEO + writer (8xxx בלבד) |
|
| `docs/daphna-procedural-patterns.md` | תבניות פרוצדורליות (החלטת ביניים, חזרה לשמאי) | CEO + writer (8xxx בלבד) |
|
||||||
| `docs/voice-1130-25.md` | דוגמה עמוקה | writer (אם תיק 1xxx מורכב) |
|
| `docs/voice-1130-25.md` | דוגמה עמוקה | writer (אם תיק 1xxx מורכב) |
|
||||||
|
|
||||||
|
## טקסונומיה — שני namespaces ל-`practice_area` (חובה לדעת)
|
||||||
|
|
||||||
|
⚠️ **קריטי לפני שאתה כותב practice_area לכל כלי MCP — יש שני namespaces שונים שמוגדרים במערכת:**
|
||||||
|
|
||||||
|
| Axis | ערכים | איפה משתמשים |
|
||||||
|
|------|--------|--------------|
|
||||||
|
| **A. Multi-tenant (legacy, routing)** | `appeals_committee`, `national_insurance`, `labor_law` | רק לבחירת ה-tenant ברמת המוצר. הסוכנים בוועדת ערר תמיד `appeals_committee` |
|
||||||
|
| **B. Domain (DB columns + filters)** | `rishuy_uvniya`, `betterment_levy`, `compensation_197` | **כל קריאה ל-`search_precedent_library` / `search_internal_decisions` / `precedent_library_upload` / `internal_decision_upload`** — זה ה-namespace הקובע |
|
||||||
|
|
||||||
|
**המרה אוטומטית:** `to_db_practice_area(multi_tenant_pa, appeal_subtype)` ממירה Axis A → Axis B (משתמש פנימי בלבד).
|
||||||
|
|
||||||
|
**כללי ברזל לכלי MCP:**
|
||||||
|
- בכל קריאה לכלי שמחפש או כותב לקורפוס פסיקה — **השתמש בערכי Axis B בלבד**:
|
||||||
|
- 1xxx (רישוי ובניה) → `rishuy_uvniya`
|
||||||
|
- 8xxx (היטל השבחה) → `betterment_levy`
|
||||||
|
- 9xxx (פיצויים ס' 197) → `compensation_197`
|
||||||
|
- **אסור** לעבור `appeals_committee` כ-`practice_area` ל-`search_precedent_library` — זה ייתן 0 תוצאות (הקורפוס מאוחסן ב-Axis B).
|
||||||
|
- DB constraint `cases_practice_area_check` אוכף: practice_area של תיק חייב להיות אחד מהשלושה ב-Axis B (או ריק).
|
||||||
|
|
||||||
|
## כלי MCP חדשים (יוני 2026) — חובה לקרוא
|
||||||
|
|
||||||
|
### `internal_decision_upload` — העלאת החלטת ועדת ערר לקורפוס
|
||||||
|
|
||||||
|
החלטות של ועדות ערר אחרות (`source_kind='internal_committee'`) עוברות **רק** דרך כלי זה — לא דרך `precedent_library_upload` (citation guard דוחה).
|
||||||
|
|
||||||
|
**חתימה (חובה כל ארבעת השדות):**
|
||||||
|
```
|
||||||
|
internal_decision_upload(
|
||||||
|
file_path=..., # נתיב מלא ל-PDF/DOCX/RTF/TXT/MD
|
||||||
|
case_number=..., # "ערר 1024-25" / "בל\"מ 8126/25" / וכו'
|
||||||
|
chair_name=..., # שם יו"ר — חובה (לחיפוש סלקטיבי)
|
||||||
|
district=..., # ירושלים / מרכז / תל אביב / צפון / דרום / חיפה / ארצי
|
||||||
|
... # case_name, court, decision_date, practice_area, וכו' — אופציונליים
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**מי משתמש בפועל:** ב-`legal-researcher` (ראה `legal-researcher.md`). ה-CEO רק יודע שזה קיים — אם חוקר מדווח שלא הצליח להעלות החלטת ועדת ערר, ה-CEO בודק שה-chair_name + district סופקו.
|
||||||
|
|
||||||
|
### `search_internal_decisions` — חיפוש בהחלטות ועדות ערר
|
||||||
|
|
||||||
|
`search_decisions` = רק החלטות דפנה (style corpus). `search_internal_decisions` = כל ועדות הערר בכל המחוזות, עם פילטרים `chair_name` ו-`district`. ה-CEO משתמש בכלי זה בתרחישי routing מתקדמים — בד"כ ה-researcher ו-analyst הם המשתמשים העיקריים.
|
||||||
|
|
||||||
## הסוכנים שלך
|
## הסוכנים שלך
|
||||||
|
|
||||||
| סוכן | Agent ID | תפקיד |
|
| סוכן | Agent ID | תפקיד |
|
||||||
@@ -597,7 +641,7 @@ ls data/cases/$CASE_NUMBER/documents/research/analysis-and-research.md
|
|||||||
| `proofread` | מגיה | → צור issue למנתח משפטי (ראה תבנית למטה) |
|
| `proofread` | מגיה | → צור issue למנתח משפטי (ראה תבנית למטה) |
|
||||||
| `documents_ready` | מנתח | → שלב A (בדיקות שלמות + שליליות + מתודולוגיה). אם עובר → עדכן ל-`analyst_verified` |
|
| `documents_ready` | מנתח | → שלב A (בדיקות שלמות + שליליות + מתודולוגיה). אם עובר → עדכן ל-`analyst_verified` |
|
||||||
| `analyst_verified` | CEO (אחרי שלב A) | → שלב B (סיכום + שאלת תוצאה לחיים). המנתח כבר ביצע את המחקר כחלק מהניתוח — אין ליצור issue לחוקר. |
|
| `analyst_verified` | CEO (אחרי שלב A) | → שלב B (סיכום + שאלת תוצאה לחיים). המנתח כבר ביצע את המחקר כחלק מהניתוח — אין ליצור issue לחוקר. |
|
||||||
| `research_complete` | (מנתח — legacy, או תרחיש מיוחד עם חוקר) | → שלב B (סיכום + שאלת תוצאה לחיים). בזרימה הרגילה המנתח לא מגדיר סטטוס זה — רק `documents_ready`. אם תראה סטטוס זה, בדוק אם `analysis-and-research.md` קיים לפני §B. |
|
| `research_complete` | מנתח / חוקר תקדימים (valid status — legacy + תרחישים מתקדמים) | → שלב B (סיכום + שאלת תוצאה לחיים). **זה סטטוס תקף**, לא שגיאה. בזרימה הרגילה המנתח מגדיר `documents_ready`, אבל אם החוקר רץ בנפרד (`legal-researcher.md` שלב 5) הוא מעדכן ל-`research_complete`. אם תראה סטטוס זה, בדוק שגם `analysis-and-research.md` וגם `precedent-research.md` קיימים, ואז המשך ל-§B כרגיל. |
|
||||||
| `outcome_set` | CEO (אחרי שחיים בחר) | → האם יש claim_handling? אם לא → שלב B המשך (טבלת bundle/skip). אם כן → שלב C |
|
| `outcome_set` | CEO (אחרי שחיים בחר) | → האם יש claim_handling? אם לא → שלב B המשך (טבלת bundle/skip). אם כן → שלב C |
|
||||||
| `direction_approved` | CEO (אחרי שחיים אישר) | → צור issue למנתח (c26e9439) ל-pass 2: העמקת ניתוח ואימות פסיקה |
|
| `direction_approved` | CEO (אחרי שחיים אישר) | → צור issue למנתח (c26e9439) ל-pass 2: העמקת ניתוח ואימות פסיקה |
|
||||||
| `analysis_enriched` | מנתח (pass 2) | → שלב D2: צור issue לכותב (7ed8686f) |
|
| `analysis_enriched` | מנתח (pass 2) | → שלב D2: צור issue לכותב (7ed8686f) |
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ tools:
|
|||||||
- mcp__legal-ai__workflow_status
|
- mcp__legal-ai__workflow_status
|
||||||
- mcp__legal-ai__search_case_documents
|
- mcp__legal-ai__search_case_documents
|
||||||
- mcp__legal-ai__search_precedent_library
|
- mcp__legal-ai__search_precedent_library
|
||||||
|
- mcp__legal-ai__search_internal_decisions
|
||||||
- mcp__legal-ai__precedent_library_get
|
- mcp__legal-ai__precedent_library_get
|
||||||
|
- mcp__legal-ai__precedent_list
|
||||||
- mcp__legal-ai__halacha_review
|
- mcp__legal-ai__halacha_review
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -145,6 +147,39 @@ tools:
|
|||||||
- האם יש תקדים אישי שלה רלוונטי? אם כן — האם הופנה אליו (חיסכון / דחייה / הבחנה)?
|
- האם יש תקדים אישי שלה רלוונטי? אם כן — האם הופנה אליו (חיסכון / דחייה / הבחנה)?
|
||||||
- **ציטוטי פסיקה חיצונית בבלוק י** — לכל ציטוט (`citation` + `supporting_quote`) שמופיע, חפש ב-`search_precedent_library` (subject_tag הרלוונטי) וודא שהציטוט קיים בקורפוס ושהלכה אושרה. ציטוט שלא תואם להלכה מאושרת = critical.
|
- **ציטוטי פסיקה חיצונית בבלוק י** — לכל ציטוט (`citation` + `supporting_quote`) שמופיע, חפש ב-`search_precedent_library` (subject_tag הרלוונטי) וודא שהציטוט קיים בקורפוס ושהלכה אושרה. ציטוט שלא תואם להלכה מאושרת = critical.
|
||||||
|
|
||||||
|
### 9. צירוף פסיקה ל-DB (`precedent_attach`) — critical
|
||||||
|
|
||||||
|
לכל ציטוט פסיקה בבלוק י (חיצוני או internal_committee), **חייב להיות רישום ב-`case_precedents`** דרך `precedent_attach` של ה-researcher.
|
||||||
|
|
||||||
|
**שיטת בדיקה:**
|
||||||
|
1. הרץ `precedent_list(case_number)` — קבל רשימת כל הציטוטים שנרשמו ל-DB.
|
||||||
|
2. סרוק את בלוק י (וטענות סף) וזהה כל ציטוט פסיקה (citation + quote).
|
||||||
|
3. **לכל ציטוט**: ודא שהוא מופיע ב-`precedent_list`. אם חסר → `qa = fail` (critical, חוסם ייצוא). דווח אילו ציטוטים לא נרשמו.
|
||||||
|
|
||||||
|
**למה זה חשוב:** ה-DOCX exporter ו-Hermes curator קוראים מ-`case_precedents`. ציטוט שנמצא רק בטקסט ולא ב-DB יחמיץ at-export-time validation וניתוח Hermes.
|
||||||
|
|
||||||
|
### 10. מראה מקום מלא בציטוטים — warning
|
||||||
|
|
||||||
|
לכל ציטוט פסיקה בבלוק י, ודא שהוא כולל:
|
||||||
|
- **מספר תיק מלא** (לא רק "פלוני נ' פלמוני")
|
||||||
|
- **ערכאה** (עליון / מנהלי / מחוזי / שלום / ועדת ערר)
|
||||||
|
- **תאריך / `פורסם בנבו`** או `פורסם ב-`
|
||||||
|
- **`page_reference`** כשמדובר בציטוט ארוך מתוך פס"ד
|
||||||
|
|
||||||
|
אם חסר אחד מהשלושה הראשונים → **`qa = warning`**, דווח לחיים בcomment + הצע למלא. (לא חוסם — לא כל פסק דין יש לו פאג'ינציה.)
|
||||||
|
|
||||||
|
### 11. תקפות סטטוס תיק (status_validity) — sanity check
|
||||||
|
|
||||||
|
בדוק `case_get(case_number).status` — הוא צריך להיות בערכים תקפים. הזרימה הכוללת:
|
||||||
|
|
||||||
|
```
|
||||||
|
new → proofread → documents_ready → analyst_verified → research_complete (legacy/optional)
|
||||||
|
→ outcome_set → direction_approved → analysis_enriched → ready_for_writing
|
||||||
|
→ drafted (אתה כאן!) → qa_passed / qa_failed → exported
|
||||||
|
```
|
||||||
|
|
||||||
|
⚠️ **`research_complete` הוא valid status** (לא bug, לא legacy ערומה). ב-`legal-researcher.md` שלב 5 הוא הסטטוס שהחוקר מגדיר בסיום מחקר. אם תיק במצב זה נשלח אליך לפני `drafted` — דווח, אל תכשיל.
|
||||||
|
|
||||||
#### תבנית קבלה (מ-`daphna-acceptance-architecture.md` — אם תוצאה = קבלה)
|
#### תבנית קבלה (מ-`daphna-acceptance-architecture.md` — אם תוצאה = קבלה)
|
||||||
- האם הסיבה לקבלה ברורה: פגם פנימי / החזרה / תיקונים / 8xxx מהותית / שומה?
|
- האם הסיבה לקבלה ברורה: פגם פנימי / החזרה / תיקונים / 8xxx מהותית / שומה?
|
||||||
- האם התבנית הנבחרת (A/B/C/D/E) מתאימה לסיבה?
|
- האם התבנית הנבחרת (A/B/C/D/E) מתאימה לסיבה?
|
||||||
@@ -165,6 +200,9 @@ tools:
|
|||||||
| **שאילתות לקורפוסים** | **critical** | **חוסם ייצוא** |
|
| **שאילתות לקורפוסים** | **critical** | **חוסם ייצוא** |
|
||||||
| מתודולוגיה | critical | חוסם ייצוא |
|
| מתודולוגיה | critical | חוסם ייצוא |
|
||||||
| **קול דפנה** | **critical** | **חוסם ייצוא** |
|
| **קול דפנה** | **critical** | **חוסם ייצוא** |
|
||||||
|
| **צירוף פסיקה ל-DB** | **critical** | **חוסם ייצוא** |
|
||||||
|
| מראה מקום מלא | warning | מדווח, לא חוסם |
|
||||||
|
| תקפות סטטוס | sanity | דיווח בלבד |
|
||||||
|
|
||||||
## תהליך עבודה
|
## תהליך עבודה
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ tools:
|
|||||||
- mcp__legal-ai__precedent_list
|
- mcp__legal-ai__precedent_list
|
||||||
- mcp__legal-ai__precedent_search_library
|
- mcp__legal-ai__precedent_search_library
|
||||||
- mcp__legal-ai__search_precedent_library
|
- mcp__legal-ai__search_precedent_library
|
||||||
|
- mcp__legal-ai__internal_decision_upload
|
||||||
|
- mcp__legal-ai__precedent_library_upload
|
||||||
- mcp__legal-ai__precedent_library_get
|
- mcp__legal-ai__precedent_library_get
|
||||||
- mcp__legal-ai__precedent_library_list
|
- mcp__legal-ai__precedent_library_list
|
||||||
- mcp__legal-ai__precedent_extract_halachot
|
- mcp__legal-ai__precedent_extract_halachot
|
||||||
@@ -70,6 +72,84 @@ tools:
|
|||||||
|
|
||||||
כתבי ערר, תשובות, תגובות — אלה בטיפול סוכן "מנתח משפטי".
|
כתבי ערר, תשובות, תגובות — אלה בטיפול סוכן "מנתח משפטי".
|
||||||
|
|
||||||
|
## ⚠️ חובה לקרוא — איזה כלי upload להשתמש לכל סוג פסיקה
|
||||||
|
|
||||||
|
כשאתה מעלה פסיקה לקורפוס הסמכותי, **יש שני זרמים שונים** והם **לא ניתנים להחלפה**. שגיאה כאן פוגעת בכל המערכת.
|
||||||
|
|
||||||
|
### Flowchart החלטה — איזה כלי?
|
||||||
|
|
||||||
|
```
|
||||||
|
האם ה-citation מתחיל ב-"ערר" או "בל"מ" (החלטת ועדת ערר)?
|
||||||
|
├── כן → internal_decision_upload ✅ (חובה chair_name + district)
|
||||||
|
└── לא →
|
||||||
|
האם מתחיל ב-עע"מ / בר"מ / עמ"נ / בג"ץ / ע"א / ע"פ / רע"א / רע"פ / ת"א / ת"מ
|
||||||
|
(פסיקת בית משפט מנהלי/עליון/מחוזי/שלום)?
|
||||||
|
├── כן → precedent_library_upload ✅ (external_upload)
|
||||||
|
└── לא → דווח לחיים: citation לא מוכר, אל תעלה
|
||||||
|
```
|
||||||
|
|
||||||
|
### זרם A — `precedent_library_upload` (external)
|
||||||
|
|
||||||
|
לפסיקת ערכאות שיפוטיות: עליון (בג"ץ/ע"א/רע"א/ע"פ/רע"פ/דנ"א), מנהלי (עע"מ/בר"מ/עמ"נ), מחוזי (ת"א/ת"מ), שלום.
|
||||||
|
|
||||||
|
```python
|
||||||
|
mcp__legal-ai__precedent_library_upload(
|
||||||
|
file_path="/path/to/file.pdf",
|
||||||
|
citation="עע\"מ 3911/19 פלוני נ' הוועדה המקומית רמת גן (פורסם בנבו, 12.07.2023)",
|
||||||
|
case_name="פלוני נ' הוועדה המקומית רמת גן",
|
||||||
|
court="בית המשפט העליון",
|
||||||
|
decision_date="2023-07-12",
|
||||||
|
practice_area="rishuy_uvniya", # Axis B בלבד
|
||||||
|
subject_tags=["שימוש חורג", "מגרש מסחרי"],
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**הכלי שומר `source_kind='external_upload'`.** Citation guard: אם תנסה להעלות citation שמתחיל ב-"ערר" או "בל\"מ" — הכלי **ידחה** עם שגיאה ויפנה ל-`internal_decision_upload`.
|
||||||
|
|
||||||
|
### זרם B — `internal_decision_upload` (internal_committee) — **חובה לחלק מהפסיקה**
|
||||||
|
|
||||||
|
להחלטות **ועדות ערר** מכל המחוזות (ירושלים, מרכז, תל אביב, צפון, דרום, חיפה, ארצי). כולל גם ערר רגיל וגם בל"מ.
|
||||||
|
|
||||||
|
```python
|
||||||
|
mcp__legal-ai__internal_decision_upload(
|
||||||
|
file_path="/path/to/file.pdf",
|
||||||
|
case_number="ערר (ועדות ערר - תכנון ובנייה ירושלים) 1110/20",
|
||||||
|
chair_name="שרית אריאלי", # חובה!
|
||||||
|
district="ירושלים", # חובה! אחד מ-7
|
||||||
|
case_name="פלוני נ' הוועדה המקומית מודיעין",
|
||||||
|
court="ועדת הערר לתכנון ובנייה — מחוז ירושלים",
|
||||||
|
decision_date="2020-11-15",
|
||||||
|
practice_area="rishuy_uvniya", # Axis B
|
||||||
|
appeal_subtype="building_permit",
|
||||||
|
subject_tags=["שימוש חורג"],
|
||||||
|
is_binding=False, # תמיד False — שכנוע אופקי, לא חוב
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**שדות חובה (הכלי דוחה בלעדיהם):**
|
||||||
|
- `file_path`
|
||||||
|
- `case_number`
|
||||||
|
- `chair_name` — בלעדיו אי-אפשר לחפש סלקטיבית לפי הרכב
|
||||||
|
- `district` — ערכים תקפים: **ירושלים / מרכז / תל אביב / צפון / דרום / חיפה / ארצי** (גם "תל-אביב" עם מקף נקלט)
|
||||||
|
|
||||||
|
**הכלי שומר `source_kind='internal_committee'`.** DB constraint `case_law_internal_district_check` אוכף ש-`district NOT NULL` כשמדובר ב-internal_committee.
|
||||||
|
|
||||||
|
### אם chair_name או district חסר ב-PDF
|
||||||
|
|
||||||
|
- חפש בתוך הטקסט: "בפני: עו\"ד X" / "יו\"ר הוועדה: X" / "מחוז ירושלים" / שם המחוז בכותרת
|
||||||
|
- אם לא מצליח לזהות — **אל תנחש**. דווח לחיים ב-comment: "נמצא PDF של החלטת ערר ללא chair_name/district ברורים — נדרש מילוי ידני". המשך עם שאר העבודה.
|
||||||
|
|
||||||
|
### 2 שכבות חיפוש מקבילות
|
||||||
|
|
||||||
|
לאחר ההעלאות הנכונות:
|
||||||
|
|
||||||
|
| כלי | מטרה | מתי |
|
||||||
|
|-----|------|-----|
|
||||||
|
| `search_precedent_library` | חיפוש פסיקה **חיצונית** (עליון/מנהלי/מחוזי) | כל סוגיה מרכזית — חובה |
|
||||||
|
| `search_internal_decisions` | חיפוש בהחלטות **ועדות ערר** (כל המחוזות) | כשהסוגיה דיונית או כשאין הלכת עליון |
|
||||||
|
|
||||||
|
שניהם מקבלים את אותם הפילטרים: `practice_area` (Axis B), `subject_tag`, וכו'. `search_internal_decisions` מקבל בנוסף `district` ו-`chair_name`.
|
||||||
|
|
||||||
## תהליך עבודה
|
## תהליך עבודה
|
||||||
|
|
||||||
### שלב 1: התמצאות
|
### שלב 1: התמצאות
|
||||||
@@ -104,8 +184,8 @@ tools:
|
|||||||
| סיווג תיק | practice_area |
|
| סיווג תיק | practice_area |
|
||||||
|------------|---------------|
|
|------------|---------------|
|
||||||
| 1xxx (רישוי ובניה) | `rishuy_uvniya` |
|
| 1xxx (רישוי ובניה) | `rishuy_uvniya` |
|
||||||
| 8xxx (היטל השבחה) | `histael_hashbacha` |
|
| 8xxx (היטל השבחה) | `betterment_levy` |
|
||||||
| 9xxx (פיצויים ס' 197) | `pitsuim_197` |
|
| 9xxx (פיצויים ס' 197) | `compensation_197` |
|
||||||
|
|
||||||
אם הסוגיה ב-`appeal_subtype` ידוע (כמו "שימוש חורג", "סטייה ניכרת") — הוסף `appeal_subtype` לפילטר.
|
אם הסוגיה ב-`appeal_subtype` ידוע (כמו "שימוש חורג", "סטייה ניכרת") — הוסף `appeal_subtype` לפילטר.
|
||||||
|
|
||||||
@@ -136,7 +216,7 @@ search_precedent_library(
|
|||||||
```
|
```
|
||||||
search_internal_decisions(
|
search_internal_decisions(
|
||||||
query="...",
|
query="...",
|
||||||
practice_area="histael_hashbacha", # rishuy_uvniya / betterment_levy / compensation_197
|
practice_area="betterment_levy", # rishuy_uvniya / betterment_levy / compensation_197
|
||||||
district="ירושלים", # ריק = כל המחוזות
|
district="ירושלים", # ריק = כל המחוזות
|
||||||
chair_name="", # ריק = כל היו"רים; "דפנה תמיר" = דפנה בלבד (שווה ל-search_decisions)
|
chair_name="", # ריק = כל היו"רים; "דפנה תמיר" = דפנה בלבד (שווה ל-search_decisions)
|
||||||
limit=5
|
limit=5
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ tools:
|
|||||||
- mcp__legal-ai__write_block
|
- mcp__legal-ai__write_block
|
||||||
- mcp__legal-ai__search_decisions
|
- mcp__legal-ai__search_decisions
|
||||||
- mcp__legal-ai__search_precedent_library
|
- mcp__legal-ai__search_precedent_library
|
||||||
|
- mcp__legal-ai__search_internal_decisions
|
||||||
- mcp__legal-ai__precedent_library_get
|
- mcp__legal-ai__precedent_library_get
|
||||||
- mcp__legal-ai__precedent_library_list
|
- mcp__legal-ai__precedent_library_list
|
||||||
- mcp__legal-ai__halacha_review
|
- mcp__legal-ai__halacha_review
|
||||||
@@ -350,6 +351,26 @@ fi
|
|||||||
|
|
||||||
חפש לפי `practice_area` (rishuy_uvniya / betterment_levy / compensation_197) ולפי `subject_tag` רלוונטי. הלכות שלא אושרו ע"י דפנה לא מוחזרות מהכלי — אם החיפוש ריק, חזור ל-`search_decisions` בלבד.
|
חפש לפי `practice_area` (rishuy_uvniya / betterment_levy / compensation_197) ולפי `subject_tag` רלוונטי. הלכות שלא אושרו ע"י דפנה לא מוחזרות מהכלי — אם החיפוש ריק, חזור ל-`search_decisions` בלבד.
|
||||||
|
|
||||||
|
### ⚠️ ניסוח ציטוטי פסיקה בקול ההחלטה — לפי `source_kind`
|
||||||
|
|
||||||
|
כל רשומה בקורפוס נושאת `source_kind` (ראה בפלט של `precedent_library_get` / `search_precedent_library` / `search_internal_decisions`). הניסוח בבלוק י **משתנה לפי הסוג** — לא רק הציטוט, אלא **התפקיד הרטורי** של פסק הדין בהנמקה:
|
||||||
|
|
||||||
|
| source_kind | מקור | מעמד | תבנית ניסוח בבלוק י |
|
||||||
|
|-------------|------|------|----------------------|
|
||||||
|
| `external_upload` | בית משפט (עליון/מנהלי/מחוזי/שלום) | **סמכותי — מחייב או משכנע גבוה** | "בהתאם להלכת **X** ב-עע\"מ NNNN/YY, נקבע כי..." / "כפי שהבהיר בית המשפט העליון ב-בג\"ץ NNN/YY, '...'" |
|
||||||
|
| `internal_committee` (אחר) | ועדת ערר אחרת | **שכנוע אופקי בלבד — לא מחייב** | "כפי שנקבע על-ידי כב' היו\"ר **Y** במחוז Z בערר NNNN/YY, '...'. סוגיה זו עלתה בפנינו, ואנו מסכימים עם הניתוח הנ\"ל..." |
|
||||||
|
| `internal_committee` של דפנה עצמה | החלטה קודמת של דפנה | **עקביות עצמית (ג'וריספרודנציה אישית)** | "כפי שקבעתי בעבר בערר NNNN/YY, '...'. אין מקום לסטות מכך גם בעניין שלפנינו." (קול אישי "אנחנו"/"אני" — לפי מה שמופיע בקורפוס המקור) |
|
||||||
|
|
||||||
|
**עקרון CREAC (Rule + Explanation):**
|
||||||
|
- **Rule (כלל)**: רק מ-`external_upload` (פסיקת ערכאות) או מחוקקה. **אסור** להציג ועדת ערר אחרת כ"כלל מחייב".
|
||||||
|
- **Explanation (הרחבה/שכנוע)**: `internal_committee` יכול לתפוס כאן — אבל **בנפרד** מהכלל, כשכנוע נוסף.
|
||||||
|
- **אם אין הלכת עליון** ויש רק ועדת ערר תומכת — נסח: "לעת הזו, סוגיה זו טרם נדונה בערכאות עליונות. עם זאת, כפי שנקבע ב<ערר>... מצאנו את ההנמקה משכנעת ואנו אומצים אותה."
|
||||||
|
|
||||||
|
**בדיקה לפני שאתה כותב ציטוט:**
|
||||||
|
1. הוצא את ה-`source_kind` מהפלט של `search_precedent_library` או `search_internal_decisions`.
|
||||||
|
2. אם `internal_committee` — בדוק את `chair_name`. אם זו דפנה תמיר → סגנון "כפי שקבעתי בעבר". אחרת → סגנון אופקי עם ציון מחוז.
|
||||||
|
3. אל תערבב — שלוש קטגוריות שונות, שלוש תבניות שונות.
|
||||||
|
|
||||||
### אנטי-דפוסים — בדיקה אחרי כתיבה (חובה)
|
### אנטי-דפוסים — בדיקה אחרי כתיבה (חובה)
|
||||||
|
|
||||||
- [ ] **אין רשימות ממוספרות בתוך פסקה** (`(1)... (2)... (3)...`) — דפנה מעולם לא משתמשת
|
- [ ] **אין רשימות ממוספרות בתוך פסקה** (`(1)... (2)... (3)...`) — דפנה מעולם לא משתמשת
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ mcp = FastMCP(
|
|||||||
from legal_mcp.tools import ( # noqa: E402
|
from legal_mcp.tools import ( # noqa: E402
|
||||||
cases, documents, search, drafting, workflow, precedents,
|
cases, documents, search, drafting, workflow, precedents,
|
||||||
precedent_library as plib,
|
precedent_library as plib,
|
||||||
|
internal_decisions as int_tools,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -662,6 +663,46 @@ async def internal_decision_enrich(
|
|||||||
return _json.dumps(result, ensure_ascii=False, indent=2)
|
return _json.dumps(result, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def internal_decision_upload(
|
||||||
|
file_path: str,
|
||||||
|
case_number: str,
|
||||||
|
chair_name: str,
|
||||||
|
district: str,
|
||||||
|
case_name: str = "",
|
||||||
|
court: str = "",
|
||||||
|
decision_date: str = "",
|
||||||
|
practice_area: str = "",
|
||||||
|
appeal_subtype: str = "",
|
||||||
|
subject_tags: list[str] | None = None,
|
||||||
|
summary: str = "",
|
||||||
|
is_binding: bool = False,
|
||||||
|
) -> str:
|
||||||
|
"""העלאת החלטה של ועדת ערר (internal_committee) לקורפוס הסמכותי.
|
||||||
|
|
||||||
|
שדות חובה: file_path, case_number, chair_name, district.
|
||||||
|
שמירת ההחלטה עוברת דרך ingest_internal_decision — תויג source_kind='internal_committee' אוטומטית.
|
||||||
|
district תקין: ירושלים / מרכז / תל אביב / צפון / דרום / חיפה / ארצי.
|
||||||
|
|
||||||
|
בניגוד ל-precedent_library_upload (שתמיד שומר external_upload),
|
||||||
|
הכלי הזה הוא הנתיב המוסמך להחלטות ועדת ערר ומכריח chair_name+district.
|
||||||
|
"""
|
||||||
|
return await int_tools.internal_decision_upload(
|
||||||
|
file_path=file_path,
|
||||||
|
case_number=case_number,
|
||||||
|
chair_name=chair_name,
|
||||||
|
district=district,
|
||||||
|
case_name=case_name,
|
||||||
|
court=court,
|
||||||
|
decision_date=decision_date,
|
||||||
|
practice_area=practice_area,
|
||||||
|
appeal_subtype=appeal_subtype,
|
||||||
|
subject_tags=subject_tags,
|
||||||
|
summary=summary,
|
||||||
|
is_binding=is_binding,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
async def record_chair_feedback(
|
async def record_chair_feedback(
|
||||||
case_number: str,
|
case_number: str,
|
||||||
|
|||||||
@@ -2,14 +2,34 @@
|
|||||||
|
|
||||||
Two orthogonal axes used to separate legal domains across the system:
|
Two orthogonal axes used to separate legal domains across the system:
|
||||||
|
|
||||||
practice_area — top-level domain (multi-tenant axis). Examples:
|
practice_area — top-level domain. **Two taxonomies coexist** (see below).
|
||||||
appeals_committee, national_insurance, labor_law.
|
appeal_subtype — refines within a domain.
|
||||||
appeal_subtype — refines within a domain. For appeals_committee:
|
|
||||||
building_permit (1xxx), betterment_levy (8xxx),
|
|
||||||
compensation_197 (9xxx), unknown.
|
|
||||||
|
|
||||||
Both columns are denormalized into documents/chunks/decisions/style_corpus
|
⚠️ TWO TAXONOMIES — DO NOT CONFUSE
|
||||||
so vector searches can filter cheaply.
|
==================================
|
||||||
|
|
||||||
|
A. **Multi-tenant axis** (legacy, used in routing logic):
|
||||||
|
- ``appeals_committee`` — the legal-ai instance for Daphna's committee
|
||||||
|
- ``national_insurance`` — future / hypothetical other tenants
|
||||||
|
- ``labor_law`` — future
|
||||||
|
When this axis is used, ``appeal_subtype`` carries the actual domain:
|
||||||
|
``building_permit`` (1xxx), ``betterment_levy`` (8xxx),
|
||||||
|
``compensation_197`` (9xxx).
|
||||||
|
|
||||||
|
B. **Domain axis** (DB columns ``case_law.practice_area``,
|
||||||
|
``cases.practice_area`` — what tests, validators, and CHECK constraints
|
||||||
|
actually use):
|
||||||
|
- ``rishuy_uvniya`` — רישוי ובנייה (1xxx)
|
||||||
|
- ``betterment_levy`` — היטל השבחה (8xxx)
|
||||||
|
- ``compensation_197`` — פיצויים סעיף 197 (9xxx)
|
||||||
|
|
||||||
|
Use ``to_db_practice_area(multi_tenant_pa, appeal_subtype)`` to convert
|
||||||
|
from axis A to axis B before writing to the DB.
|
||||||
|
|
||||||
|
Background: TaskMaster #30 (sub-bug ב) — many ``case_law`` rows stored
|
||||||
|
``appeals_committee`` (axis A) where they should have stored a domain
|
||||||
|
value (axis B). The migration backfill plus CHECK constraints close the
|
||||||
|
gap, and this module now validates **both** namespaces.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -18,12 +38,23 @@ import re
|
|||||||
|
|
||||||
# ── Enums ──────────────────────────────────────────────────────────
|
# ── Enums ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
PRACTICE_AREAS: set[str] = {
|
# Multi-tenant axis (legacy)
|
||||||
|
MULTI_TENANT_PRACTICE_AREAS: set[str] = {
|
||||||
"appeals_committee",
|
"appeals_committee",
|
||||||
"national_insurance",
|
"national_insurance",
|
||||||
"labor_law",
|
"labor_law",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Domain axis (matches DB constraints on case_law/cases)
|
||||||
|
DOMAIN_PRACTICE_AREAS: set[str] = {
|
||||||
|
"rishuy_uvniya",
|
||||||
|
"betterment_levy",
|
||||||
|
"compensation_197",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Union — what ``validate()`` accepts for backward-compat
|
||||||
|
PRACTICE_AREAS: set[str] = MULTI_TENANT_PRACTICE_AREAS | DOMAIN_PRACTICE_AREAS
|
||||||
|
|
||||||
APPEALS_COMMITTEE_SUBTYPES: set[str] = {
|
APPEALS_COMMITTEE_SUBTYPES: set[str] = {
|
||||||
"building_permit",
|
"building_permit",
|
||||||
"betterment_levy",
|
"betterment_levy",
|
||||||
@@ -38,8 +69,42 @@ SUBTYPES_BY_AREA: dict[str, set[str]] = {
|
|||||||
"appeals_committee": APPEALS_COMMITTEE_SUBTYPES,
|
"appeals_committee": APPEALS_COMMITTEE_SUBTYPES,
|
||||||
"national_insurance": {"unknown"},
|
"national_insurance": {"unknown"},
|
||||||
"labor_law": {"unknown"},
|
"labor_law": {"unknown"},
|
||||||
|
# Domain values — subtype is implicit in the value itself
|
||||||
|
"rishuy_uvniya": {"building_permit", "unknown"},
|
||||||
|
"betterment_levy": {"betterment_levy", "unknown"},
|
||||||
|
"compensation_197": {"compensation_197", "unknown"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Mapping: (multi_tenant_pa, appeal_subtype) → domain_pa
|
||||||
|
_SUBTYPE_TO_DOMAIN: dict[str, str] = {
|
||||||
|
"building_permit": "rishuy_uvniya",
|
||||||
|
"betterment_levy": "betterment_levy",
|
||||||
|
"compensation_197": "compensation_197",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def to_db_practice_area(practice_area: str, appeal_subtype: str = "") -> str:
|
||||||
|
"""Convert a multi-tenant practice_area + appeal_subtype to the
|
||||||
|
domain value stored in DB columns (case_law/cases).
|
||||||
|
|
||||||
|
Returns ``""`` when the input cannot be mapped — callers should
|
||||||
|
handle this rather than letting ``""`` propagate silently to the DB.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> to_db_practice_area("appeals_committee", "building_permit")
|
||||||
|
'rishuy_uvniya'
|
||||||
|
>>> to_db_practice_area("rishuy_uvniya")
|
||||||
|
'rishuy_uvniya'
|
||||||
|
>>> to_db_practice_area("appeals_committee")
|
||||||
|
''
|
||||||
|
"""
|
||||||
|
pa = (practice_area or "").strip()
|
||||||
|
if pa in DOMAIN_PRACTICE_AREAS:
|
||||||
|
return pa
|
||||||
|
if pa == "appeals_committee":
|
||||||
|
return _SUBTYPE_TO_DOMAIN.get((appeal_subtype or "").strip(), "")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
# ── Derivation ─────────────────────────────────────────────────────
|
# ── Derivation ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
104
mcp-server/src/legal_mcp/tools/internal_decisions.py
Normal file
104
mcp-server/src/legal_mcp/tools/internal_decisions.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
"""MCP tools for the Internal Decisions corpus.
|
||||||
|
|
||||||
|
Decisions of appeals committees (ועדות ערר) live in the same physical
|
||||||
|
``case_law`` table as court rulings but are distinguished by
|
||||||
|
``source_kind='internal_committee'`` and must carry ``chair_name`` +
|
||||||
|
``district``.
|
||||||
|
|
||||||
|
The existing ``precedent_library_upload`` MCP tool always stores
|
||||||
|
``source_kind='external_upload'`` and does not accept chair/district —
|
||||||
|
which is why **44+ existing appeals-committee decisions were tagged
|
||||||
|
wrong**. This wrapper is the authoritative ingestion path for committee
|
||||||
|
decisions and enforces the required metadata at the tool boundary.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from legal_mcp.services import internal_decisions as int_svc
|
||||||
|
|
||||||
|
# Valid Hebrew district names (matches _COURT_TO_DISTRICT in service)
|
||||||
|
VALID_DISTRICTS = {"ירושלים", "מרכז", "תל אביב", "תל-אביב", "צפון", "דרום", "חיפה", "ארצי"}
|
||||||
|
|
||||||
|
|
||||||
|
def _ok(payload) -> str:
|
||||||
|
return json.dumps(payload, ensure_ascii=False, indent=2, default=str)
|
||||||
|
|
||||||
|
|
||||||
|
def _err(msg: str) -> str:
|
||||||
|
return json.dumps({"error": msg}, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
|
async def internal_decision_upload(
|
||||||
|
file_path: str,
|
||||||
|
case_number: str,
|
||||||
|
chair_name: str,
|
||||||
|
district: str,
|
||||||
|
case_name: str = "",
|
||||||
|
court: str = "",
|
||||||
|
decision_date: str = "",
|
||||||
|
practice_area: str = "",
|
||||||
|
appeal_subtype: str = "",
|
||||||
|
subject_tags: list[str] | None = None,
|
||||||
|
summary: str = "",
|
||||||
|
is_binding: bool = False,
|
||||||
|
) -> str:
|
||||||
|
"""העלאת החלטה של ועדת ערר (internal_committee) לקורפוס הסמכותי.
|
||||||
|
|
||||||
|
Required: file_path, case_number, chair_name, district.
|
||||||
|
The tool enforces chair_name+district so the record cannot be saved
|
||||||
|
in the broken legacy mode (external_upload with empty chair/district).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path: נתיב מלא לקובץ PDF/DOCX/RTF/TXT/MD.
|
||||||
|
case_number: מספר הערר ("ערר (ועדות ערר - תכנון ובנייה ירושלים) 1110/20 ...").
|
||||||
|
chair_name: שם יו"ר הוועדה (חובה).
|
||||||
|
district: מחוז (ירושלים/מרכז/תל אביב/צפון/דרום/חיפה/ארצי) — חובה.
|
||||||
|
case_name: שם קצר.
|
||||||
|
court: ערכאה ("ועדת הערר לתכנון ובנייה — מחוז ירושלים").
|
||||||
|
decision_date: ISO date (YYYY-MM-DD), אופציונלי.
|
||||||
|
practice_area: rishuy_uvniya / betterment_levy / compensation_197.
|
||||||
|
appeal_subtype: building_permit / וכו'.
|
||||||
|
subject_tags: תגיות נושא.
|
||||||
|
is_binding: בד"כ False (ועדת ערר לא מחייבת ועדה אחרת — שכנוע אופקי).
|
||||||
|
|
||||||
|
Returns: JSON עם case_law_id, מספר chunks, halachot_pending.
|
||||||
|
"""
|
||||||
|
if not file_path.strip():
|
||||||
|
return _err("file_path חובה")
|
||||||
|
if not case_number.strip():
|
||||||
|
return _err("case_number חובה")
|
||||||
|
if not chair_name.strip():
|
||||||
|
return _err(
|
||||||
|
"chair_name חובה. החלטות ועדת ערר חייבות שם יו\"ר — "
|
||||||
|
"בלעדיו ההחלטה לא ניתנת לחיפוש סלקטיבי לפי הרכב."
|
||||||
|
)
|
||||||
|
if not district.strip():
|
||||||
|
return _err(
|
||||||
|
"district חובה. ערכים תקפים: " + ", ".join(sorted(VALID_DISTRICTS))
|
||||||
|
)
|
||||||
|
if district.strip() not in VALID_DISTRICTS:
|
||||||
|
return _err(
|
||||||
|
f"district לא תקין: {district!r}. ערכים תקפים: "
|
||||||
|
+ ", ".join(sorted(VALID_DISTRICTS))
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = await int_svc.ingest_internal_decision(
|
||||||
|
case_number=case_number,
|
||||||
|
case_name=case_name,
|
||||||
|
court=court,
|
||||||
|
decision_date=decision_date or None,
|
||||||
|
chair_name=chair_name,
|
||||||
|
district=district,
|
||||||
|
practice_area=practice_area,
|
||||||
|
appeal_subtype=appeal_subtype,
|
||||||
|
subject_tags=subject_tags or [],
|
||||||
|
summary=summary,
|
||||||
|
is_binding=is_binding,
|
||||||
|
file_path=file_path,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return _err(str(e))
|
||||||
|
return _ok(result)
|
||||||
@@ -63,6 +63,18 @@ async def precedent_library_upload(
|
|||||||
"""
|
"""
|
||||||
if not citation.strip():
|
if not citation.strip():
|
||||||
return _err("citation חובה")
|
return _err("citation חובה")
|
||||||
|
# Citation guard: appeals-committee decisions must go through
|
||||||
|
# internal_decision_upload (with chair_name + district). The legacy
|
||||||
|
# path always stored source_kind='external_upload' and left
|
||||||
|
# chair_name/district empty — see TaskMaster #30(ב).
|
||||||
|
_norm = citation.strip()
|
||||||
|
_committee_prefixes = ("ערר ", "ערר(", "ערר ", "בל\"מ ", "בל\"מ(", "ARAR ")
|
||||||
|
if any(_norm.startswith(p) for p in _committee_prefixes):
|
||||||
|
return _err(
|
||||||
|
"ציטוט שמתחיל ב-'ערר' או 'בל\"מ' הוא החלטת ועדת ערר. "
|
||||||
|
"השתמש ב-internal_decision_upload (דורש chair_name + district), "
|
||||||
|
"לא ב-precedent_library_upload."
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
result = await precedent_library.ingest_precedent(
|
result = await precedent_library.ingest_precedent(
|
||||||
file_path=file_path,
|
file_path=file_path,
|
||||||
|
|||||||
Reference in New Issue
Block a user