#!/usr/bin/env python3 """Seed knowledge tables from legacy vault data. Imports: lessons_learned, transition_phrases, case_law, statutory_provisions. Sources: docs/legal-decision-lessons.md, skills/decision/SKILL.md """ import asyncio import json import sys from pathlib import Path # Add mcp-server to path so we can reuse db module sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src")) from legal_mcp.services.db import get_pool, init_schema, close_pool # ═══════════════════════════════════════════════════════════════════ # Data: Lessons Learned # ═══════════════════════════════════════════════════════════════════ LESSONS = [ # --- הכט 1180-1181 (rejected, 02.2026) --- { "lesson_title": "Discussion = continuous essay, no sub-headers", "lesson_text": "הדיון נקרא כחיבור משפטי רציף עם סעיפים ממוספרים, לא כמתווה מובנה עם כותרות משנה. הגרסה המפורסמת של הכט השתמשה באפס כותרות משנה בדיון, בעוד הטיוטה שלנו הכילה 6 כותרות H2.", "category": "structure", "applies_to": ["block-yod"], "source_case": "הכט 1180-1181", "severity": "critical", }, { "lesson_title": "Citation through consolidating decision", "lesson_text": "להשתמש בהחלטה מאחדת קודמת (כמו ערר נגאח 1011-03-25) לצטט מספר תקדימים בפסקה אחת ארוכה (~600 מילים), במקום לצטט כל תקדים בפסקה נפרדת.", "category": "style", "applies_to": ["block-yod"], "source_case": "הכט 1180-1181", "severity": "important", }, { "lesson_title": "Paragraph length variation in discussion", "lesson_text": "לא לפרגמנט טיעונים משפטיים ארוכים לפסקאות זהות וקצרות. לגוון אורך פסקאות מ-20 עד 600+ מילים. פסקאות ציטוט מרכזיות ארוכות מאוד.", "category": "style", "applies_to": ["block-yod"], "source_case": "הכט 1180-1181", "severity": "important", }, { "lesson_title": "Opening formula promises both conclusion AND elaboration", "lesson_text": 'פתיחת הדיון צריכה להבטיח גם מסקנה וגם הרחבה: "לאחר שבחנו... החלטנו בשלב ראשון כי... אך יחד עם זאת ועל מנת לא לצאת בחסר... מצאנו להוסיף מספר הערות"', "category": "style", "applies_to": ["block-yod"], "source_case": "הכט 1180-1181", "severity": "important", }, { "lesson_title": 'Summary title is "סיכום"', "lesson_text": 'כותרת פרק הסיכום היא "סיכום" בלבד, לא "סיכום והכרעה" ולא "סוף דבר".', "category": "structure", "applies_to": ["block-yod-alef"], "source_case": "הכט 1180-1181", "severity": "nice-to-have", }, # --- בית הכרם 1126/25 (partial acceptance, 03.2026) --- { "lesson_title": "Threshold question is STRATEGIC, not mandatory", "lesson_text": "שאלת הסף (זכות ערר לפי ס' 152) היא כלי אסטרטגי, לא חובה. כשלתיק יש שאלות מהותיות חזקות (חניה, קווי בניין, שימור), דפנה מעדיפה להתעמק בתוכן על פני חסימה פרוצדורלית. זה גם מחזק את ההחלטה מפני ביקורת שיפוטית.", "category": "process", "applies_to": ["all"], "source_case": "בית הכרם 1126/25", "severity": "critical", }, { "lesson_title": "Concentric circles = rejected appeals only", "lesson_text": 'מודל השכבות (עיגולים קונצנטריים, סעיף 6.3 ב-SKILL) הוא כלי אחד מתוך כמה, לא המסגרת הנדרשת. לעררים שמתקבלים חלקית, דפנה משתמשת בניתוח גמיש נושא-נושא.', "category": "process", "applies_to": ["block-yod"], "source_case": "בית הכרם 1126/25", "severity": "critical", }, { "lesson_title": "New opening type: tension mapping", "lesson_text": 'לקבלה חלקית או תיקים עם סוגיות מורכבות מצטלבות, פתיחת "מיפוי מתחים": רשימה של 6+ מתחים ספציפיים בתבליטים לפני הניתוח. דפוס: "בערר דנן עולות שאלות כיצד והאם..." → רשימת מתחים → "כל הנקודות לעיל עומדות לפנינו..."', "category": "structure", "applies_to": ["block-yod"], "source_case": "בית הכרם 1126/25", "severity": "important", }, { "lesson_title": "Single building weakens TAMA 38 interest", "lesson_text": 'כשתמ"א 38 חלה על בית בודד (לעומת בניין דירות גדול), אינטרס החיזוק מפני רעידת אדמה חלש יותר. זה מצדיק אישור זהיר יותר של זכויות, במיוחד קווי בניין וחניה.', "category": "content", "applies_to": ["block-yod"], "source_case": "בית הכרם 1126/25", "severity": "important", }, { "lesson_title": "Master plan as shield against ad-hoc planning", "lesson_text": 'כשקיימת תכנית אב — לצטט אותה כדי לתת לגיטימציה להיתר בודד. מסקנה: ההיתר "משתלב בחזון כולל קיים" במקום ליצור תקדים אד-הוק.', "category": "content", "applies_to": ["block-yod"], "source_case": "בית הכרם 1126/25", "severity": "important", }, { "lesson_title": "Deep plan provision citations for parking", "lesson_text": "לסוגיות חניה/תשתיות, דפנה נכנסת עמוק להוראות תכנית עם ציטוטים ישירים נרחבים (300+ מילים) וניתוח משולב. כולל מספרי סעיפים ספציפיים (לדוגמה: 6.8(4), 6.8(9), נספח תנועה, 5166b).", "category": "content", "applies_to": ["block-yod", "block-tet"], "source_case": "בית הכרם 1126/25", "severity": "important", }, { "lesson_title": "Ultra-minimal summary for partial acceptance", "lesson_text": "בקבלה חלקית, כל ההנמקה כבר בדיון. סיכום = הוראות אופרטיביות בלבד (בדרך כלל 3 סעיפים קצרים). ללא דיון בהוצאות. ללא סיום חם.", "category": "structure", "applies_to": ["block-yod-alef"], "source_case": "בית הכרם 1126/25", "severity": "important", }, # --- קרית יערים-1 (03.2026) --- { "lesson_title": "Neutral background rule", "lesson_text": 'רקע (בלוק ו) = עובדות אובייקטיביות בלבד. מבחן: האם המשפט מכיל ציטוט ישיר מצד, או מילות ערך/שיפוט (חריג, חטא, בעייתי)? אם כן → שייך בטענות (בלוק ז) או דיון (בלוק י), לא ברקע. החלטות קודמות = עובדה יבשה ("ביום X נדחתה תכנית Y"), ללא נימוקים וציטוטים.', "category": "structure", "applies_to": ["block-vav"], "source_case": "קרית יערים-1 (1130/25)", "severity": "critical", }, { "lesson_title": "12-block mandatory structure", "lesson_text": 'מבנה 12 בלוקים פורמלי חובה עם שלב "טיוטת טרום-דיון". כולל: פתיחה (ה) → רקע (ו) → טענות (ז) → הליכים (ח) → תכניות (ט) → דיון (י) → סיכום (יא). חידוש מאריאלי: "ההליכים בפני ועדת הערר" כפרק נפרד. כל בלוק נכתב כאילו שופט בית משפט מנהלי קורא בפעם הראשונה.', "category": "structure", "applies_to": ["all"], "source_case": "קרית יערים-1 (1130/25)", "severity": "critical", }, # --- Meta-lesson --- { "lesson_title": "Skill was over-indexed on single case type", "lesson_text": "ה-SKILL המקורי היה מבוסס יתר על מקרה אחד (הכט = דחייה). מודל העיגולים, שאלת סף כחובה, וסיום חם — כולם דפוסים מתיק בודד. בית הכרם (קבלה חלקית) חשף שהגישה של דפנה גמישה יותר ממה שתפסנו. צריך להבחין בין דפוסים אוניברסליים לתלויי-תוצאה.", "category": "process", "applies_to": ["all"], "source_case": "בית הכרם 1126/25", "severity": "critical", }, ] # ═══════════════════════════════════════════════════════════════════ # Data: Transition Phrases # ═══════════════════════════════════════════════════════════════════ TRANSITION_PHRASES = [ # From הכט {"phrase": "ועל מנת לא לצאת בחסר", "usage_context": "פתיחת אוביטר דיקטה / הנמקה נוספת", "block_types": ["block-yod"], "source_decision": "הכט 1180-1181"}, {"phrase": "נציין כי טענות אלו נטענו בלשון רפה", "usage_context": "הכרה בטענות חלשות תוך דיון בהן", "block_types": ["block-yod"], "source_decision": "הכט 1180-1181"}, {"phrase": "עינינו הרואות", "usage_context": "סיכום אחרי ציטוט ארוך", "block_types": ["block-yod"], "source_decision": "הכט 1180-1181"}, {"phrase": "נוסיף.", "usage_context": "מעבר קצר ביותר (מילה אחת) לנקודה הבאה", "block_types": ["block-yod"], "source_decision": "הכט 1180-1181"}, {"phrase": "אם כך, לעת הזו", "usage_context": "הסקת מסקנה מציטוטים", "block_types": ["block-yod"], "source_decision": "הכט 1180-1181"}, {"phrase": "למעלה מן הצורך", "usage_context": "דיון לא הכרחי להכרעה אך נכתב מטעמים אסטרטגיים", "block_types": ["block-yod"], "source_decision": "הכט 1180-1181"}, {"phrase": "למיטב הבנתנו", "usage_context": "עמדה זהירה בשאלה משפטית לא מיושבת", "block_types": ["block-yod"], "source_decision": "הכט 1180-1181"}, {"phrase": "נשלים ונציין", "usage_context": "נקודה אחרונה לפני מעבר לסיכום", "block_types": ["block-yod"], "source_decision": "הכט 1180-1181"}, # From בית הכרם {"phrase": "הדברים משליכים על שיקול הדעת ב...", "usage_context": "קישור ממצא למסקנה", "block_types": ["block-yod"], "source_decision": "בית הכרם 1126/25"}, {"phrase": "רוצה לומר כי", "usage_context": "ניסוח חלופי / הסבר", "block_types": ["block-yod"], "source_decision": "בית הכרם 1126/25"}, {"phrase": "נוצר מצב בו", "usage_context": "הצגת מצב עובדתי / בעיה", "block_types": ["block-yod"], "source_decision": "בית הכרם 1126/25"}, {"phrase": "לכך נוסיף כי", "usage_context": "הוספת שכבה נוספת לטיעון", "block_types": ["block-yod"], "source_decision": "בית הכרם 1126/25"}, {"phrase": "יש אולי להצר על כך ש...", "usage_context": "הערה ביקורתית עדינה (כלפי רשות תכנון)", "block_types": ["block-yod"], "source_decision": "בית הכרם 1126/25"}, {"phrase": "עם ההבנה לטענה זו של העוררים, אין בידנו לקבלה", "usage_context": "הכרה רכה בטענה תוך דחייתה", "block_types": ["block-yod"], "source_decision": "בית הכרם 1126/25"}, # General (from SKILL.md) {"phrase": "ברי כי", "usage_context": "מסקנה מובנת מאליה", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "נפנה ל...", "usage_context": "פתיחת ניתוח חוק/פסיקה", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "מכל האמור לעיל", "usage_context": "מעבר לסיכום", "block_types": ["block-yod", "block-yod-alef"], "source_decision": ""}, {"phrase": "נשוב על כך כי", "usage_context": "חזרה מכוונת על עיקרון חשוב", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "דא עקא", "usage_context": "הצגת בעיה מרכזית או סתירה", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "ובמילים אחרות", "usage_context": "הבהרה / ניסוח מחדש", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "הגענו לכלל מסקנה כי", "usage_context": "מסקנה מרכזית (פתיחת דיון)", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "לא נוכל לקבל", "usage_context": "דחיית עמדה / טענה", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "מקובלת עלינו", "usage_context": "קבלת עמדה", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "התרשמנו כי", "usage_context": "מסקנה מדיון / עיון במסמכים", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "נחדד כי", "usage_context": "חידוד נקודה קודמת", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "סיכומם של דברים", "usage_context": "פתיחת סיכום מהותי לפני פרק הסיכום", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "המסקנה מכל האמור היא כי", "usage_context": "מסקנת ביניים מקיפה", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "לעמדתנו", "usage_context": "עמדת הוועדה", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "בנסיבות אלה", "usage_context": "מעבר מעובדות למסקנה", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "נזכיר כי", "usage_context": "תזכורת לעיקרון ידוע", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "מצאנו כי", "usage_context": "קביעה עובדתית", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "שוכנענו כי", "usage_context": "קביעה לאחר בחינה", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "על כן ולו רק מסיבה זו", "usage_context": "נטרול טענה חלשה לפני ניתוח עמוק", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "יחד עם זאת, מצאנו לנכון לדון בשאלה העקרונית", "usage_context": "מעבר לדיון עקרוני למרות דחייה", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "משכך", "usage_context": "הסקת מסקנה מעמדה שהוצגה", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "הדברים מתחדדים שעה ש...", "usage_context": "הבהרה נוספת לאור נסיבות", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "זאת ועוד", "usage_context": "הוספת נימוק", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "יתרה מכך", "usage_context": "חיזוק הנמקה קודמת", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "לאור כל האמור לעיל", "usage_context": "פתיחת סיכום סופי", "block_types": ["block-yod", "block-yod-alef"], "source_decision": ""}, {"phrase": "נפתח בכך כי", "usage_context": "פתיחת דיון (לא מסמך)", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "נפנה בעניין זה להחלטת...", "usage_context": "הפניה לתקדים", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "ברי כי משאב הקרקע יקר לבעליו ולציבור", "usage_context": "הצדקת שימוש יעיל בקרקע", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "נסכם כי", "usage_context": "מעבר לסיכום ביניים", "block_types": ["block-yod"], "source_decision": ""}, {"phrase": "נחזור על כך כי", "usage_context": "חזרה אמפתית על קביעה חשובה", "block_types": ["block-yod"], "source_decision": ""}, ] # ═══════════════════════════════════════════════════════════════════ # Data: Case Law # ═══════════════════════════════════════════════════════════════════ CASE_LAW = [ { "case_number": "עע\"מ 3975/22", "case_name": "ב. קרן-נכסים", "court": "בית המשפט העליון", "subject_tags": ["proprietary_claims", "feasibility"], "summary": "פסק דין מנחה בנושא בדיקת היתכנות קניינית — מתי ועדה צריכה לבחון זכויות קניין לפני מתן היתר.", "key_quote": "", }, { "case_number": "ערר (מרכז) 1011-03-25", "case_name": "נגאח עבד אל קאדר", "court": "ועדת ערר מרכז", "subject_tags": ["proprietary_claims", "consolidating_decision"], "summary": "החלטה מאחדת בנושא טענות קנייניות — ריכזה את כל הפסיקה בנושא.", "key_quote": "", }, { "case_number": "ערר 1071/25", "case_name": "מינץ", "court": "ועדת ערר ירושלים", "subject_tags": ["self_reference", "previous_decision"], "summary": "החלטה קודמת של ועדת הערר עצמה — שימוש כתקדים פנימי.", "key_quote": "", }, { "case_number": "ערר 1192/18", "case_name": "אילן", "court": "ועדת ערר ירושלים", "subject_tags": ["preservation", "nuisance"], "summary": "שימור ומטרדים — איזון בין שימור מבנים לזכויות שכנים.", "key_quote": "", }, { "case_number": "ערר 1009-02-24", "case_name": "מובשוביץ", "court": "ועדת ערר ירושלים", "subject_tags": ["urban_renewal", "tama_38"], "summary": 'התחדשות עירונית — ציטוט נרחב (~400 מילים) בהחלטת בית הכרם.', "key_quote": "", }, { "case_number": "ערר 1156/18", "case_name": "ארד", "court": "ועדת ערר ירושלים", "subject_tags": ["construction_nuisance"], "summary": "מטרדי בנייה — מתי מטרד בנייה מצדיק התערבות.", "key_quote": "", }, { "case_number": "ערר 1169/19", "case_name": "זוהר", "court": "ועדת ערר ירושלים", "subject_tags": ["construction_nuisance"], "summary": "מטרדי בנייה — המשך קו הפסיקה של ערר ארד.", "key_quote": "", }, { "case_number": "ערר (ירושלים) 1078+1083/24", "case_name": "אריאלי", "court": "ועדת ערר ירושלים", "subject_tags": ["structure_example", "proceedings_block"], "summary": "שימשה כמודל מבני — פרק הליכים נפרד (31 סעיפים), מבנה מפורט.", "key_quote": "", }, { "case_number": "ערר אדלר", "case_name": "אדלר", "court": "ועדת ערר ירושלים", "subject_tags": ["consolidating_decision"], "summary": "החלטה מאחדת שצוטטה בבית הכרם — טכניקת ציטוט דרך החלטה מרכזת.", "key_quote": "", }, ] # ═══════════════════════════════════════════════════════════════════ # Data: Statutory Provisions # ═══════════════════════════════════════════════════════════════════ STATUTORY_PROVISIONS = [ { "statute_name": "חוק התכנון והבנייה, תשכ\"ה-1965", "section_number": "152(א)(2)", "section_title": "זכות ערר על אישור תכנית", "full_text": "", "common_usage": "שאלת סף — האם קיימת זכות ערר. כלי אסטרטגי, לא חובה.", "subject_tags": ["threshold", "right_to_appeal"], }, { "statute_name": "חוק התכנון והבנייה, תשכ\"ה-1965", "section_number": "149", "section_title": "הקלה", "full_text": "", "common_usage": "בקשות להקלה — סטייה מתכנית בניין עיר.", "subject_tags": ["deviation", "relief"], }, { "statute_name": "חוק התכנון והבנייה, תשכ\"ה-1965", "section_number": "145", "section_title": "היתר בנייה", "full_text": "", "common_usage": "עררים על סירוב/אישור היתר בנייה.", "subject_tags": ["building_permit"], }, { "statute_name": "חוק התכנון והבנייה, תשכ\"ה-1965", "section_number": "196-198", "section_title": "היטל השבחה", "full_text": "", "common_usage": "עררי היטל השבחה (8xxx) — חיוב בגין עליית שווי מקרקעין.", "subject_tags": ["betterment_levy"], }, { "statute_name": "חוק התכנון והבנייה, תשכ\"ה-1965", "section_number": "197", "section_title": "פיצויים בגין ירידת ערך", "full_text": "", "common_usage": "עררי פיצויים (9xxx) — תביעה בגין ירידת ערך מקרקעין בשל תכנית.", "subject_tags": ["compensation", "depreciation"], }, { "statute_name": "תמ\"א 38", "section_number": "תיקון 2 + 3", "section_title": "חיזוק מבנים מפני רעידות אדמה", "full_text": "", "common_usage": "חיזוק/הריסה ובנייה מחדש. אינטרס חלש יותר בבית בודד.", "subject_tags": ["tama_38", "seismic_reinforcement"], }, { "statute_name": "חוק המקרקעין, תשכ\"ט-1969", "section_number": "71ב(א)(1)", "section_title": "רוב הדרוש לשינוי ברכוש משותף", "full_text": "", "common_usage": "בדיקת היתכנות קניינית — האם יש רוב לשינוי ברכוש משותף.", "subject_tags": ["proprietary_claims", "common_property"], }, ] # ═══════════════════════════════════════════════════════════════════ # Import Logic # ═══════════════════════════════════════════════════════════════════ async def seed_lessons(conn) -> int: count = 0 for l in LESSONS: existing = await conn.fetchval( "SELECT id FROM lessons_learned WHERE lesson_title = $1", l["lesson_title"] ) if existing: continue await conn.execute( """INSERT INTO lessons_learned (lesson_title, lesson_text, category, applies_to, source_case, severity) VALUES ($1, $2, $3, $4, $5, $6)""", l["lesson_title"], l["lesson_text"], l["category"], json.dumps(l["applies_to"]), l["source_case"], l["severity"], ) count += 1 return count async def seed_phrases(conn) -> int: count = 0 for p in TRANSITION_PHRASES: existing = await conn.fetchval( "SELECT id FROM transition_phrases WHERE phrase = $1", p["phrase"] ) if existing: continue await conn.execute( """INSERT INTO transition_phrases (phrase, usage_context, block_types, source_decision) VALUES ($1, $2, $3, $4)""", p["phrase"], p["usage_context"], json.dumps(p["block_types"]), p["source_decision"], ) count += 1 return count async def seed_case_law(conn) -> int: count = 0 for c in CASE_LAW: existing = await conn.fetchval( "SELECT id FROM case_law WHERE case_number = $1", c["case_number"] ) if existing: continue await conn.execute( """INSERT INTO case_law (case_number, case_name, court, subject_tags, summary, key_quote) VALUES ($1, $2, $3, $4, $5, $6)""", c["case_number"], c["case_name"], c["court"], json.dumps(c["subject_tags"]), c["summary"], c.get("key_quote", ""), ) count += 1 return count async def seed_statutes(conn) -> int: count = 0 for s in STATUTORY_PROVISIONS: existing = await conn.fetchval( """SELECT id FROM statutory_provisions WHERE statute_name = $1 AND section_number = $2""", s["statute_name"], s["section_number"], ) if existing: continue await conn.execute( """INSERT INTO statutory_provisions (statute_name, section_number, section_title, full_text, common_usage, subject_tags) VALUES ($1, $2, $3, $4, $5, $6)""", s["statute_name"], s["section_number"], s["section_title"], s["full_text"], s["common_usage"], json.dumps(s["subject_tags"]), ) count += 1 return count async def main(): await init_schema() pool = await get_pool() async with pool.acquire() as conn: n_lessons = await seed_lessons(conn) n_phrases = await seed_phrases(conn) n_case_law = await seed_case_law(conn) n_statutes = await seed_statutes(conn) await close_pool() print(f"✓ lessons_learned: {n_lessons} inserted") print(f"✓ transition_phrases: {n_phrases} inserted") print(f"✓ case_law: {n_case_law} inserted") print(f"✓ statutory_provisions: {n_statutes} inserted") print(f" Total: {n_lessons + n_phrases + n_case_law + n_statutes} records") if __name__ == "__main__": asyncio.run(main())