Files
legal-ai/docs/spec/X8-field-provenance.md
Chaim d95a36f310 feat(extraction): precedent metadata via Gemini Flash + scheduled drainer
The /precedents metadata queue was stuck — 24 rows requested, nothing draining
them — and the agentic claude CLI hit error_max_turns on what is a single
structured text→JSON task (slow + flaky). Metadata extraction is bounded
extraction, the wrong fit for an agentic loop.

- gemini_session.py: query_json drop-in (gemini-2.5-flash, JSON mode, httpx —
  no new SDK dep). Reads GEMINI_API_KEY (~/.env; SoT Infisical
  nautilus:/external-apis/gemini). Host-side only — no LLM from the container.
- precedent_metadata_extractor: claude_session.query_json → gemini_session.
  Validated live: rich, accurate fields (case_name/summary/appeal_subtype/tags).
- process_pending_extractions: kind-aware cooldown — metadata 2s (Gemini, fast),
  halacha keeps 30s (Claude rate limits).
- drain_metadata_queue.py + legal-metadata-drain.config.cjs (pm2 cron */15) so
  the queue never clogs again. SCRIPTS.md.
- X8 INV-FP5 updated: per-task engine choice (Gemini=bounded metadata,
  claude_session=agentic halacha), both host-side, single canonical queue (G2).

Agentic/voice-sensitive work (writing, analysis, halacha) stays on claude_session
(Daphna's subscription). Gemini cost ≈ $0.10/1M tokens — negligible.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 05:13:49 +00:00

11 KiB
Raw Blame History

X8 — כללי-מילוי-שדות וחילוץ (Field-Population & Extraction Rules)

קובץ-תחום זה כפוף ל-חוקת המערכת והוא ה-SSoT לכללים שכרגע סמויים בקוד: כשמעלים החלטה/פסק-דין/מסמך-תיק — איזה שדה מתמלא מאיזה מקור, ומה הכללים על-גבי זה (אי-דריסת ערך-יו"ר, שער-אישור, ציטוט-verbatim). הכללים האלה חיים היום מפוזרים על-פני 4 שירותים; כאן הם מאוחדים. הוא משלים את 01-ingest.md (הפייפליין) ו-02-data-model.md (הסכמה), ומזין את X6 INV-UI6 (שיקוף-מקור ב-UI).

מודלי-סמכות מעורבים. FP1 ו-FP4 הם הנדסיים (lineage/integrity — ≥3 מקורות). FP2/FP3/FP5 הם פרויקטלי-תפעוליים הנקשרים ל-G10 (שער אנושי) ו-G2.


1. ארבעת מקורות-המילוי

מקור הגדרה דוגמאות
DETERMINISTIC parse של שם-קובץ / מטא-PDF / OCR / regex — ללא LLM full_text, extraction_status, source_kind, chunks, page_number
OPUS-ANALYSIS Claude Opus קורא את כל המסמך, ממלא רק שדה ריק/placeholder, אסינכרוני headnote, summary, key_quote, subject_tags, case_name, court, date, appeal_subtype, precedent_level, source_type, citation_formatted, halachot
CHAIR-MANUAL היו"ר מזין בטופס; חובה או רשות citation/case_number (חובה), והשאר נשאר לעריכה
DERIVED מחושב משדות אחרים district מ-court, proceeding_type מ-appeal_subtype, searchable

2. טבלת-provenance לפי סוג-מסמך (ה-SSoT)

מאומת מול precedent_metadata_extractor.py, halacha_extractor.py, ingest.py, db.py.

2א. פסיקה חיצונית (case_law, source_kind=external_upload)

שדה מקור הערה
case_number (citation) CHAIR (חובה) מפתח idempotency
full_text, extraction_status, source_kind DETERMINISTIC
case_name, court, date, headnote, summary, key_quote, subject_tags, appeal_subtype, precedent_level, source_type, citation_formatted CHAIR או OPUS Opus ממלא רק אם ריק
is_binding CHAIR (default true) קובע prompt-הלכה
chunks (content/section_type/page_number) DETERMINISTIC
embedding (chunks) Voyage (לא-LLM-reasoning) ⚠ לא-GENERATED (gap-audit GAP-09)
כל halachot OPUS נכנס pending_review

2ב. החלטה פנימית (case_law, source_kind=internal_committee)

כמו 2א, ובנוסף: case_number חובה; chair_name/district/proceeding_type — CHAIR או OPUS או DERIVED; source_type = appeals_committee (DETERMINISTIC קבוע). placeholder "(טרם חולץ)" מסומן ל-chair_name/district ריקים ומטופל כריק ע"י ה-extractor.

2ג. מסמך-תיק (documents)

שדה מקור
case_id, title CHAIR
doc_type DETERMINISTIC (local_classifier) → fallback Claude אם confidence<0.8
extracted_text, extraction_status, page_count DETERMINISTIC
chunks + embedding DETERMINISTIC + Voyage
claims / appraiser_facts OPUS (כלי-חילוץ נפרדים — ראה X9)

3. Invariants של התחום

INV-FP1: לכל שדה מקור-מילוי מוצהר — הטבלה היא ה-SSoT

כלל: לכל שדה-מטא יש מקור-מילוי מוצהר (deterministic / opus / chair / derived), במקום יחיד (טבלת §2). אין כללי-מילוי סמויים מפוזרים בין שירותים. מופע של G9 (lineage — מאיפה כל ערך). הנדסי. מקורות: ISO 8000-110 (data quality — provenance) · DAMA-DMBOK2 (data lineage) · OpenLineage spec (https://openlineage.io/) | סטטוס: verified אכיפה: טבלת-provenance מוצהרת (§2) + עמודת-מקור-מילוי לכל שדה-נגזר (יעד; ראה 02-data-model.md). הפרה ידועה: הכללים מפוזרים על precedent_metadata_extractor/halacha_extractor/ingest/recompute_searchable; אין SSoT (gap-audit GAP-35).

INV-FP2: חילוץ-LLM אינו דורס ערך שהוזן ידנית

כלל: חילוץ-Opus ממלא רק שדה ריק/placeholder — ערך שהיו"ר הזין לעולם אינו נדרס. סמכות-התוכן היא היו"ר. מופע של G10. פרויקטלי-תפעולי. מקור-סמכות: precedent_metadata_extractor.py (apply_to_record — compare-to-empty); feedback היו"ר. (משרת G10.) אכיפה: לוגיקת compare-to-empty ב-extractor; convention placeholder מתועד. הפרה ידועה: placeholder "(טרם חולץ)" כמחרוזת-קסם לא-מתועדת/שבירה (gap-audit GAP-37).

INV-FP3: פלט-LLM נכנס כ-pending — רק אישור-יו"ר הופך אותו לשמיש

כלל: פלט-חילוץ של LLM (הלכות; ובהמשך גם טענות-משפטיות) נכנס במצב לא-מאושר (pending_review), ואינו נחשף לחיפוש/החלטה עד אישור-יו. מופע של G10 (שער אנושי) — תואם 05-qa-review.md. פרויקטלי-תפעולי. מקור-סמכות: halacha_extractor.py (review_status); 01-ingest.md. אכיפה: review_status חוסם חיפוש עד approved/published. הפרה ידועה: legal_arguments חסר שער-אישור מקביל (gap-audit GAP-39; 02-data-model.md).

INV-FP4: supporting_quote חייב להיות verbatim

כלל: כל ציטוט-תומך (supporting_quote של הלכה, key_quote) חייב להופיע מילה-במילה בטקסט-המקור; אחרת מסומן (quote_verified=false). מופע של G9 (integrity). הנדסי. מקורות: ISO 15489-1:2016 (records integrity/authenticity) · RAG attribution (Lewis et al., 2020, NeurIPS) · NCSC/JTC — AI in Courts (verifiable citation) | סטטוס: verified אכיפה: proofreader.verify_quote בעת חילוץ → quote_verified. הפרה ידועה: — (קיים; ה-flag נכתב, אך אין חיווי ב-UI — ראה X6 INV-UI6).

INV-FP5: חילוץ אסינכרוני, מתור, צד-מארח (לא מהקונטיינר)

כלל: חילוץ-LLM (מטא, הלכות) רץ אסינכרוני, מתור, מצד-המארח — לא חוסם את ה-web ולא קורא ל-LLM מהקונטיינר. בחירת-מנוע לפי אופי-המשימה (לא מסלול מקביל): חילוץ-מטא הוא משימה תחומה (טקסט→JSON) ולכן רץ על Gemini Flash (gemini_session, structured JSON) — ה-claude CLI ה-agentic פגע ב- error_max_turns; חילוץ-הלכות (רגיש-קול/agentic) נשאר על claude_session (CLI מקומי, מנוי דפנה). שני המנועים מתנקזים לתור-החילוץ הקנוני היחיד (G2). פרויקטלי-תפעולי. מקור-סמכות: ingest.py (queue → process_pending_extractions); gemini_session.py (מטא); legal-ai/CLAUDE.md (claude_session local-only להלכות). GEMINI_API_KEY בצד-המארח בלבד — לא בקונטיינר (תואם feedback_claude_session_local_only: אין קריאות-LLM מהקונטיינר). אכיפה: queue + precedent_process_pending + drainers מתוזמנים (legal-metadata-drain/CEO); קריאות-LLM רק מצד-המארח. הפרה ידועה: תור-החילוץ סמוי (אין הבחנה pending-initial מול pending-review; אין extraction-job table) (gap-audit GAP-45; X9).


4. חוזה-searchable (תזכורת — מוגדר ב-02)

רשומת case_law היא searchable רק כשמתקיים חוזה-השלמות (G4, 02-data-model.md, FU-2a): ≥1 chunk עם embedding · extraction_status='completed' · case_number/source_kind לא-ריקים · practice_area (לפנימי) · ≥1 שדה-מטא ({headnote/summary/subject_tags}). ה-UI חייב לשקף את ה-flag הזה (X6 INV-UI6).


5. הפניות-אחיות