סוגר את הלולאה — יומון שמצביע על פס"ד בית-משפט שלא בקורפוס מזניק אחזור אוטומטי, וקושר את היומון חזרה אחרי הקליטה (INV-DIG3 + INV-CF2). - digest_library.try_autolink: בכשל-קישור, אם הציטוט מסווג כפס"ד-בימ"ש (supreme/admin) → _enqueue_court_fetch יוצר court_fetch_jobs(pending); ועדת-ערר (skip) לא מוזנק. never-raises (לא שובר קליטת-יומון). - orchestrator.drain_pending(limit): מנקז pending/failed סדרתי (cooldown, INV-CF4), fetch+ingest לכל אחד; בהצלחה מקשר את היומון ל-case_law שנקלט. - כלי-MCP court_fetch_drain + רישום ב-server.py. - X13 spec: עודכן (הפער ב-INV-CF2 סומן כמתוקן). נבדק מול ה-DB: עת"מ 46111-12-22 → job tier=admin pending digest-linked; ערר 1110/20 → לא מוזנק. כלי מקומי בלבד (ingest = claude CLI). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
14 KiB
X13 — אחזור-פסיקה אוטומטי מנט המשפט (Court Verdict Fetch)
כפוף ל-חוקת המערכת. תת-מערכת שירות (לא קורפוס) שמורידה פסקי-דין ציבוריים של בתי-משפט ומזרימה אותם לצינור-הקליטה הקנוני של ספריית-הפסיקה. אחות-מושגית ל-X12 — Digests Radar (הטריגר העיקרי) ול-01-ingest (היעד). אינה קורפוס רביעי ואינה מסלול-ingest מקביל.
0. ייעוד והקשר
יומון (digest) מצביע על פסק-דין נושא (underlying_citation, למשל עת"מ 46111-12-22). כשהפסק
אינו בקורפוס, המערכת מאחזרת אותו אוטומטית ממקור ציבורי, מחלצת טקסט, וקולטת אותו דרך
precedent_library_upload → ingest_precedent. כך הופך פסק-דין מ"מצוטט-בלבד" ל"שמיש לחיפוש
וחילוץ-הלכות".
הבחנת-מקור קריטית: רק פסקי-דין של בתי-משפט ניתנים לאחזור ציבורי. החלטות ועדת-ערר אינן זמינות ציבורית (נדרש נבו) — מסומנות כפער ולא נשלחות לאחזור.
שתי דרכי-מקור ציבוריות:
- עליון (עע"מ/בג"ץ/ע"א/רע"א/בר"מ/דנ"א) →
supremedecisions.court.gov.il— הורדה ישירה (httpx), ללא CAPTCHA. - מנהלי/מחוזי/שלום (עת"מ/עמ"נ/...) → מציג-התיקים של נט המשפט — ASP.NET WebForms
(
__doPostBack/VIEWSTATE), anti-bot של F5, מסמכים מוצגים בצופה-עמודים (turn.js). מחייב דפדפן-אמת (host-side), ולכן שירות-מארח ב-pm2 (כדפוסlegal-chat-service).
אומת end-to-end (2026-06-07) על עת"מ 46111-12-22 — פס"ד 34 עמ' הורד אוטונומית מלא, נטו קוד-פתוח, ללא כרטיס-חכם וללא פתרון-CAPTCHA. ממצאי-המפתח מהכיול:
- החיפוש והניווט לתיק — ללא reCAPTCHA כלל. מסלול: דף-בית →
btnExternalSearchCases→ מילויBamaCaseNumberTextBoxH(=מס' תיק) +BamaMonthYearTextBoxHT(="MM-YY") →CaseDetails.aspx→ לשונית "פסקי דין" →DecisionList.aspx→ צופהNGCSViewerPage.aspx.- reCAPTCHA קיים רק בצופה ורק על שמירה/הדפסה מפורשת — לא על הצגת המסמך. הצופה מגיש את העמודים כ-PNG דרך PageMethod
GetImages(4 עמ'/batch) ללא CAPTCHA. אחזור = לכידתdocumentNumberמהקריאה הראשונה + משיכת כל ה-batches ב-fetchעם הכותרתX-Requested-With: XMLHttpRequest(חובה — ה-WAF חוסם AJAX בלעדיה) → הרכבת PDF (Pillow).- דפדפן: Camoufox דרך חבילת-הפייתון (
camoufox.async_api, in-process — לא שרת-Node). על שרת ללא-מסך נדרש Xvfb (אחרת Firefox קורס). פותר-ה-reCAPTCHA האודיו (Whisper) נשמר כ-fallback למסלול-השמירה-המפורש בלבד; מסלול-התמונות אינו זקוק לו.
1. ארכיטקטורה — שלוש שכבות (tiered)
underlying_citation → [classifier] → tier ∈ {supreme, admin, skip}
skip(ערר/בל"מ) → missing_precedent (נבו ידני) — לא אחזור
supreme → Tier 0: httpx בקונטיינר → supremedecisions — אוטונומי מלא
admin → Tier 1: legal-court-fetch-service (host/pm2 + Xvfb) — אוטונומי-first
→ Camoufox(python) → external-search → CaseDetails → פסקי דין
→ NGCSViewerPage → GetImages(X-Requested-With) → PNGs → PDF
→ Tier 2 fallback: VNC ידני / missing_precedent + התראה — שער-אנושי
(כל ה-tiers) → precedent_library_upload(source_type=court_ruling) → ingest_precedent
→ chunks+embeddings+halachot(pending) → relink digest / close gap
מצב-העבודה מנוהל בטבלת-תור court_fetch_jobs (idempotent, נצפה, retryable).
2. Invariants
INV-CF1: מסלול-קליטה יחיד — אין ingest מקביל
כלל: כל ה-tiers מתנקזים לצינור-הקליטה הקנוני היחיד (precedent_library_upload →
ingest_precedent). המאחזר מספק קובץ+מטא בלבד; אסור לו לכתוב case_law/precedent_chunks/
halachot ישירות או לשכפל לוגיקת-chunking/embedding.
מקור-סמכות: פרויקטלי-תפעולי — מיישם את G2 (מקור-אמת יחיד, אין מסלול מקביל) על תת-מערכת זו.
אכיפה: האורקסטרטור קורא רק ל-API/שירות-הקליטה הקיים; ביקורת-ארכיטקטורה ב-PR.
הפרה ידועה: —
INV-CF2: אין בליעה שקטה — כל אחזור נצפה
כלל: לכל פסק-דין שזוהה לאחזור יש רשומת-job עם סטטוס סופי מפורש
(done/failed/manual). כישלון-אחזור לעולם אינו נבלע — הוא מסומן ומועלה (Tier 2),
לא נזרק בשקט. except: pass אסור.
מקור-סמכות: פרויקטלי-תפעולי — מיישם את G4 וכלל-ההנדסה "אין בליעה שקטה" (§6).
אכיפה: טבלת court_fetch_jobs (status+error+attempts) + לוג-warning בכל כישלון + Tier-2 gate.
הפרה ידועה: הפער ב-X12 — → תוקן: try_autolink שנכשל מחזיר None בשקטtry_autolink שנכשל על ציטוט פס"ד-בימ"ש מזניק job ל-court_fetch_jobs (status=pending); court_fetch_drain מנקז (סדרתי) ומקשר את היומון חזרה בהצלחה.
INV-CF3: אוטונומי-first, שער-אנושי חובה ב-fallback
כלל: האחזור מנסה אוטונומית; אך כש-N נסיונות נכשלים, שער-אנושי (VNC לפתרון-CAPTCHA
חי / סימון missing_precedent + התראה) הוא חובה, לא רשות. המערכת אינה "מוותרת" ואינה
"מסתירה" — היא מסלימה לאדם.
מקור-סמכות: פרויקטלי-תפעולי — מיישם את G10 (המערכת מסייעת; שערים אנושיים = invariant).
אכיפה: מונה-נסיונות בטבלת-התור + מעבר אוטומטי ל-status=manual עם נתיב-פעולה ל-chaim.
הפרה ידועה: —
INV-CF4: אחזור-אחראי (politeness) — סדרתי, מרווח, חתימה-אמיתית
כלל: האחזור מאתר-ממשלתי הוא אחראי: סדרתי (לא מקבילי), עם cooldown בין בקשות,
כיבוד-robots/תנאי-שימוש, ו-rate מתון. אסור flooding/parallel-hammering שעלול לחסום IP
או להעמיס על שירות ציבורי.
מקורות: RFC 9309 (Robots Exclusion Protocol, IETF 2022) · Google Search Central —
Crawler / crawl-rate guidance · OWASP — Automated Threat Handbook (OAT-021 Denial of
Service / responsible automation) | סטטוס: verified
אכיפה: האורקסטרטור והשירות אוכפים serial + INTER_FETCH_COOLDOWN_SEC; Camoufox מספק
חתימת-דפדפן אמיתית (לא spoof-חמדני). מראה לדפוס-התור ב-precedent_library.py.
הפרה ידועה: —
INV-CF5: אחזור idempotent
כלל: אחזור הוא idempotent — מפתח-job דטרמיניסטי לפי case_number מנורמל. אחזור
חוזר של אותו תיק אינו יוצר job כפול ואינו קולט פסק-דין פעמיים (upsert על המפתח הקנוני).
מקור-סמכות: פרויקטלי-תפעולי — מיישם את G3 (ingest idempotent) ו-G1 (מזהה מנורמל בכתיבה).
אכיפה: אילוץ-ייחודיות על court_fetch_jobs.case_number_norm; הקליטה עצמה idempotent דרך ingest_precedent.
הפרה ידועה: —
INV-CF6: שער-סיווג מקור — רק פסקי-דין של בתי-משפט
כלל: רק ציטוט שסווג כפסק-דין של בית-משפט נשלח לאחזור. ועדת-ערר (ערר/בל"מ) לעולם
אינה נשלחת לאחזור-ציבורי (נדרש נבו) — היא מסומנת missing_precedent בלבד. הפריט הנקלט
נושא source_type=court_ruling, source_kind=external_upload, precedent_level לפי הערכאה.
מקור-סמכות: פרויקטלי-תפעולי — מיישם את G5 (metadata מלא + הפרדת-קורפוס)
ותואם את הבחנת-המקור ב-01-ingest (court_ruling מול appeals_committee).
אכיפה: המסווג מחזיר tier=skip ל-ערר/בל"מ; הקליטה אוכפת source_type.
הפרה ידועה: —
INV-CF7: עקיבוּת-מקור + גבול-ToS
כלל: כל אחזור נושם provenance מלא (source_url, tier, זמן, מזהה-job) ב-audit-trail.
האחזור מוגבל למסמכים ציבוריים הזמינים ללא הזדהות (smart-card); אופי המערכת הוא
הורדה-בסיוע (עם שער-אנושי), לא בוט-סמוי לעקיפת בקרת-גישה.
מקור-סמכות: פרויקטלי-תפעולי — מיישם את G9 (עקיבוּת + audit-trail);
גבול-ה-ToS מועלה ליו"ר (חיים) כשיקול-מדיניות (עיקרון-עבודה 4: המשתמש הוא הסמכות).
אכיפה: source_url+tier נשמרים על case_law/court_fetch_jobs; שער-אנושי שומר על אופי בסיוע.
הפרה ידועה: —
3. מודל-נתונים — court_fetch_jobs
| עמודה | טיפוס | תפקיד |
|---|---|---|
id |
UUID PK | מזהה-job |
case_number_norm |
TEXT UNIQUE | מפתח-idempotency קנוני (INV-CF5) |
citation_raw |
TEXT | הציטוט המקורי כפי שזוהה |
tier |
TEXT | supreme | admin | skip |
court |
TEXT | ערכאה שזוהתה |
status |
TEXT | pending | running | done | failed | manual |
attempts |
INT | מונה-נסיונות (ל-Tier 2 gate, INV-CF3) |
error |
TEXT | הודעת-כישלון אחרונה (INV-CF2) |
case_law_id |
UUID FK | הפסק שנקלט (NULL עד done) |
digest_id |
UUID FK | היומון-מקור (NULL לאד-הוק) |
source_url |
TEXT | provenance (INV-CF7) |
created_at / updated_at |
TIMESTAMPTZ |
4. רכיבי-מימוש (מיפוי לקוד)
| רכיב | קובץ | מקור-תבנית / שימוש-חוזר |
|---|---|---|
| מסווג | mcp-server/.../services/court_citation.py |
regex מ-citation_extractor.py:67-132 |
| Tier 0 | services/court_fetch_supreme.py |
httpx; דפוס-cooldown מ-precedent_library.py:176-186 |
| Tier 1 שירות | mcp-server/.../court_fetch_service/server.py |
שכפול chat_service/server.py (aiohttp+Bearer+bind 10.0.1.1) |
| Camoufox client | court_fetch_service/camofox_client.py |
חיקוי ~/.hermes/.../browser_camofox.py |
| reCAPTCHA audio | court_fetch_service/recaptcha_audio.py |
faster-whisper מקומי |
| proxy בקונטיינר | web/court_fetch_proxy.py |
שכפול web/chat_proxy.py |
| pm2 | scripts/legal-court-fetch-service.config.cjs |
שכפול legal-chat-service.config.cjs |
| אורקסטרטור+תור | services/court_fetch_orchestrator.py + db.py (SCHEMA_Vxx) |
דפוס-תור קיים |
| כלי-MCP | tools/court_fetch.py (court_verdict_fetch / court_fetch_status / court_fetch_drain) |
חוזה-envelope X9 |
| טריגר אוטומטי | services/digest_library.py (try_autolink fail → _enqueue_court_fetch) → drain ע"י orchestrator.drain_pending |
X12 |
| סוד | COURT_FETCH_SHARED_SECRET (Infisical + Coolify) |
דפוס LEGAL_CHAT_SHARED_SECRET, X10 |
5. סיכונים (R&D — לעקוב)
- reCAPTCHA נלחם פעיל בפותרי-אודיו → שיעור-כישלון אפשרי גבוה → Tier 2 הוא קו-ההגנה (INV-CF3).
- F5/anti-bot עלול לחסום IP → politeness סדרתי + Camoufox (INV-CF4).
- שבירות מול שינויי-אתר → ריכוז selectors במקום אחד + בדיקות-עשן תקופתיות.
- גבול-ToS על אתר .gov → INV-CF7 + שיקול-יו"ר.
- דליפת-זיכרון מדפדפנים יתומים (fetch שנתקע/נהרג משאיר
camoufox-bin) → שלוש שכבות-הגנה: (א)async withסוגר את הדפדפן בכל exception; (ב)asyncio.wait_forקשיח (COURT_FETCH_HARD_TIMEOUT_S, ברירת-מחדל 180ש') מבטל hang + reap; (ג) reaper שלcamoufox-binיתומים (ppid=1) לפני/אחרי כל fetch + דמוןlegal-reaper(pm2) + תקרתmax_memory_restart. סדרתיות (INV-CF4) מבטיחה שכל דפדפןppid=1הוא שארית בטוחה-להריגה. הערה: הדליפה הגדולה בפועל בשרת היאtask-master-mcp(כלי נפרד), שגם אותו ה-reaper מנקה.