Add docs, scripts, skills, commands, and taskmaster config to repo
Includes: - docs/: architecture, block-schema, migration-plan, product-specification - scripts/: bidi_table, decompose-decisions, extract-claims, seed-knowledge, etc. - skill-legal-decision/: SKILL.md + references + block-schema - skill-legal-assistant/: SKILL.md - skill-legal-docx/: SKILL.md + references - .claude/commands/: bidi-table skill - .taskmaster/: task config + PRDs - .gitignore: exclude legacy/, kiryat-yearim/, node_modules/, memory/ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
31
.claude/commands/bidi-table.md
Normal file
31
.claude/commands/bidi-table.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
יצירת טבלה מעוצבת עם תמיכה מלאה בעברית ואנגלית מעורבת.
|
||||||
|
|
||||||
|
כאשר המשתמש מבקש טבלה בכל הקשר — תכנית עבודה, סיכום, השוואה, רשימה — השתמש בפונקציה `bidi_table()` מ-`scripts/bidi_table.py`.
|
||||||
|
|
||||||
|
## הוראות
|
||||||
|
|
||||||
|
1. **תמיד** השתמש ב-Bash כדי להריץ את הסקריפט — אל תנסה לייצר טבלת box-drawing ידנית כי ה-BiDi ישבור אותה.
|
||||||
|
|
||||||
|
2. הרץ כך:
|
||||||
|
```bash
|
||||||
|
python3 -c "
|
||||||
|
import sys; sys.path.insert(0, '/home/chaim/legal-ai')
|
||||||
|
from scripts.bidi_table import bidi_table
|
||||||
|
print(bidi_table(
|
||||||
|
['Header1', 'Header2', 'Header3'],
|
||||||
|
[
|
||||||
|
['value1', 'ערך בעברית', 'mixed ערבוב'],
|
||||||
|
['value2', 'ערך נוסף', 'עוד שורה'],
|
||||||
|
],
|
||||||
|
))
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. כותרות עמודות — עדיף באנגלית (כי שורת הכותרת הכי רגישה ל-BiDi).
|
||||||
|
|
||||||
|
4. תוכן בעברית, באנגלית, או מעורב — הכל עובד בגוף הטבלה.
|
||||||
|
|
||||||
|
5. אם המשתמש מבקש טבלה כחלק ממסמך MD שנכתב לקובץ (לא לטרמינל) — אפשר להשתמש ב-markdown רגיל כי קוראי MD מטפלים ב-RTL בעצמם.
|
||||||
|
|
||||||
|
## $ARGUMENTS
|
||||||
|
תוכן הטבלה — כותרות ושורות. אם לא צוין, שאל את המשתמש מה להציג.
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,8 +1,14 @@
|
|||||||
data/uploads/
|
data/uploads/
|
||||||
data/cases/
|
data/cases/
|
||||||
|
data/training/
|
||||||
|
data/exports/
|
||||||
mcp-server/.venv/
|
mcp-server/.venv/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
.env
|
.env
|
||||||
data/training/
|
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
|
legacy/
|
||||||
|
kiryat-yearim/
|
||||||
|
continuation-prompt.md
|
||||||
|
memory/
|
||||||
|
node_modules/
|
||||||
|
|||||||
44
.taskmaster/config.json
Normal file
44
.taskmaster/config.json
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"models": {
|
||||||
|
"main": {
|
||||||
|
"provider": "anthropic",
|
||||||
|
"modelId": "claude-opus-4-20250514",
|
||||||
|
"maxTokens": 64000,
|
||||||
|
"temperature": 0.2
|
||||||
|
},
|
||||||
|
"research": {
|
||||||
|
"provider": "anthropic",
|
||||||
|
"modelId": "claude-sonnet-4-20250514",
|
||||||
|
"maxTokens": 64000,
|
||||||
|
"temperature": 0.1
|
||||||
|
},
|
||||||
|
"fallback": {
|
||||||
|
"provider": "anthropic",
|
||||||
|
"modelId": "claude-sonnet-4-20250514",
|
||||||
|
"maxTokens": 64000,
|
||||||
|
"temperature": 0.2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"global": {
|
||||||
|
"logLevel": "info",
|
||||||
|
"debug": false,
|
||||||
|
"defaultNumTasks": 10,
|
||||||
|
"defaultSubtasks": 5,
|
||||||
|
"defaultPriority": "medium",
|
||||||
|
"projectName": "Legal Decision Assistant",
|
||||||
|
"ollamaBaseURL": "http://localhost:11434/api",
|
||||||
|
"bedrockBaseURL": "https://bedrock.us-east-1.amazonaws.com",
|
||||||
|
"responseLanguage": "Hebrew",
|
||||||
|
"enableCodebaseAnalysis": true,
|
||||||
|
"enableProxy": false,
|
||||||
|
"anonymousTelemetry": false,
|
||||||
|
"userId": "1234567890"
|
||||||
|
},
|
||||||
|
"claudeCode": {},
|
||||||
|
"codexCli": {},
|
||||||
|
"grokCli": {
|
||||||
|
"timeout": 120000,
|
||||||
|
"workingDirectory": null,
|
||||||
|
"defaultModel": "grok-4-latest"
|
||||||
|
}
|
||||||
|
}
|
||||||
58
.taskmaster/docs/prd-fixes.txt
Normal file
58
.taskmaster/docs/prd-fixes.txt
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# תיקוני איפיון מוצר — ממצאי סקירת מומחה
|
||||||
|
|
||||||
|
## 4 ממצאים קריטיים
|
||||||
|
|
||||||
|
### תיקון 1: הוספת שלב 6 (הגהת דפנה) לדרישות הפונקציונליות
|
||||||
|
Priority: critical.
|
||||||
|
שלב 6 חסר מסעיף הדרישות הפונקציונליות. צריך להגדיר: איך דפנה מקבלת את הטיוטה (DOCX), איך מחזירה הערות/תיקונים, מי מעלה את הגרסה הסופית ללולאת הלמידה.
|
||||||
|
|
||||||
|
### תיקון 2: שינוי "אפס הזיות" למנגנון grounding + ולידציה
|
||||||
|
Priority: critical.
|
||||||
|
אף LLM לא יכול להבטיח 0 הזיות. צריך להחליף את הדרישה ב: (1) מנגנון grounding שמקשר כל הפניה למסמך מקור, (2) ולידציה אוטומטית שבודקת כל ציטוט/הפניה מול המסמכים שסופקו, (3) מדד: שיעור הפניות שלא עוברות ולידציה = 0 (לא שאין הזיות, אלא שכל הזיה נתפסת).
|
||||||
|
|
||||||
|
### תיקון 3: הוספת סיכון context window overflow
|
||||||
|
Priority: critical.
|
||||||
|
תיק מורכב עם 50+ מסמכים יחרוג מ-context window. צריך: דרישה למדידת גודל חומרים, אסטרטגיית chunking/summarization, סף התראה.
|
||||||
|
|
||||||
|
### תיקון 4: הגדרה מתמטית של "אחוז שינוי"
|
||||||
|
Priority: critical.
|
||||||
|
צריך להגדיר בדיוק: edit distance על מילים? תווים? סעיפים? מה נספר כ"שינוי"? הגדרה ברורה עם דוגמאות.
|
||||||
|
|
||||||
|
## 9 ממצאים חשובים
|
||||||
|
|
||||||
|
### תיקון 5: הוספת דרישות לבלוקים א-ד ויב
|
||||||
|
Priority: high. בלוקים א-ד (כותרת, הרכב, צדדים) ויב (חתימות) חסרים מהדרישות.
|
||||||
|
|
||||||
|
### תיקון 6: דרישת שמירת מצב ביניים (persistence)
|
||||||
|
Priority: high. מה קורה אם חיים רוצה להמשיך מחר? recovery מנפילה?
|
||||||
|
|
||||||
|
### תיקון 7: תיקון ספירת שלבים בטבלת מעקב
|
||||||
|
Priority: high. טבלה כותבת "7 שלבים" אבל דרישות מכסות רק 6.
|
||||||
|
|
||||||
|
### תיקון 8: הכרה ב-MVP de facto לרישוי והשבחה
|
||||||
|
Priority: high. אין נתוני אימון לפיצויים — צריך להכיר שגרסה ראשונה מכסה רק רישוי+השבחה.
|
||||||
|
|
||||||
|
### תיקון 9: בחינה מחדש של יעד 98%
|
||||||
|
Priority: high. לפי Endsley מומחים תמיד משנים — 98% אולי לא ריאלי מסיבות פסיכולוגיות.
|
||||||
|
|
||||||
|
### תיקון 10: הגדרת מנגנון לולאת למידה
|
||||||
|
Priority: high. מה מעדכנים? fine-tuning? prompt engineering? RAG? few-shot?
|
||||||
|
|
||||||
|
### תיקון 11: הוספת סיכון prompt injection ממסמכי מקור
|
||||||
|
Priority: high. מסמכים מצדדים חיצוניים יכולים להכיל טקסט שמשפיע על ה-LLM.
|
||||||
|
|
||||||
|
### תיקון 12: הוספת מנגנון back-flows (חזרה אחורה בתהליך)
|
||||||
|
Priority: high. מה אם חיים רוצה לשכתב בלוק קודם? מה אם דפנה משנה כיוון?
|
||||||
|
|
||||||
|
### תיקון 13: הוספת שלב QA/ולידציה לפני שליחה לדפנה
|
||||||
|
Priority: high. checklist אוטומטי לפני הפלט הסופי.
|
||||||
|
|
||||||
|
## 7 הערות
|
||||||
|
|
||||||
|
### תיקון 14: ניהול גרסאות של בלוקים
|
||||||
|
### תיקון 15: טיפול באיחוד תיקים (כמו אריאלי 1078+1083)
|
||||||
|
### תיקון 16: תיקון LOA של סיעור מוחות (ב ולא ג)
|
||||||
|
### תיקון 17: סיעור מוחות אופציונלי גם כשיש נימוק
|
||||||
|
### תיקון 18: ניטרליות מבנית (לא רק לקסיקלית)
|
||||||
|
### תיקון 19: מיפוי פרסורמן 4 stages (לא רק LOA)
|
||||||
|
### תיקון 20: דרישת ביצועים per-block וסינכרוני/אסינכרוני
|
||||||
46
.taskmaster/docs/prd-paperclip-workflow.txt
Normal file
46
.taskmaster/docs/prd-paperclip-workflow.txt
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# PRD — אינטגרציית Paperclip AI + תהליך תיק חדש
|
||||||
|
|
||||||
|
## הקשר
|
||||||
|
שתי משימות מחוברות שנגזרות מאיפיון המוצר (docs/product-specification.md) ומניתוח הפלאגין הקיים (/home/chaim/plugin-legal-ai/).
|
||||||
|
|
||||||
|
## משימות
|
||||||
|
|
||||||
|
### משימה: הרחבת DB schema לתהליך מלא
|
||||||
|
Priority: critical. Dependencies: none.
|
||||||
|
הוספת שדות וטבלאות חסרים: direction_doc JSONB ו-outcome_reasoning TEXT בטבלת decisions. הרחבת status בטבלת cases ל-13 ערכים (new, uploading, processing, documents_ready, outcome_set, brainstorming, direction_approved, drafting, qa_review, drafted, exported, reviewed, final). יצירת טבלת qa_results. כל זה ב-db.py כ-migration.
|
||||||
|
|
||||||
|
### משימה: הוספת 5 API endpoints חדשים ב-MCP server
|
||||||
|
Priority: critical. Dependencies: DB schema.
|
||||||
|
POST /api/cases/{case_number}/outcome — הזנת תוצאה + נימוק. GET /api/cases/{case_number}/claims — טענות מחולצות. POST /api/cases/{case_number}/direction — שמירת מסמך כיוון. POST /api/cases/{case_number}/qa — הרצת QA ולידציה. POST /api/cases/{case_number}/learn — הפעלת לולאת למידה.
|
||||||
|
|
||||||
|
### משימה: הוספת 8 tools חדשים לפלאגין Paperclip
|
||||||
|
Priority: high. Dependencies: API endpoints.
|
||||||
|
בקובץ src/worker.ts: legal_document_upload, legal_document_list, legal_document_text, legal_search_case, legal_find_similar, legal_set_outcome, legal_get_claims, legal_style_guide. בקובץ src/legal-api.ts: 8 methods חדשים. בקובץ plugin.json: עדכון רשימת tools.
|
||||||
|
|
||||||
|
### משימה: שיפור status sync ב-Paperclip
|
||||||
|
Priority: high. Dependencies: DB schema.
|
||||||
|
מיפוי 13 סטטוסים (במקום 5→3). הוספת comments מפורטים ב-Paperclip בכל מעבר סטטוס. עדכון job sync-case-status.
|
||||||
|
|
||||||
|
### משימה: כתיבת SOUL.md לסוכנים
|
||||||
|
Priority: high. Dependencies: none.
|
||||||
|
CEO Agent: הוראות בעברית — ניהול תהליך החלטה, מתי להתריע לחיים, מיפוי סטטוסים. Case Analyst Agent: הוראות בעברית — ניתוח מסמכים, חילוץ טענות, חיפוש תקדימים.
|
||||||
|
|
||||||
|
### משימה: יישום skill /brainstorm
|
||||||
|
Priority: critical. Dependencies: API endpoints.
|
||||||
|
Skill חדש ב-Claude Code: מציג טענות מרכזיות (ס-1), מציע 2-3 כיוונים (ס-2), מנהל שיח עם חיים (ס-3), מייצר מסמך כיוון JSON (ס-4), שומר ב-DB. כלל: לא מתחילים דיון בלי כיוון מאושר (ס-5).
|
||||||
|
|
||||||
|
### משימה: שיפור skill /draft-decision לכתיבה בלוק-אחרי-בלוק
|
||||||
|
Priority: critical. Dependencies: brainstorm skill, DB schema.
|
||||||
|
עכשיו הוא stub. צריך: כתיבה בלוק-אחרי-בלוק (ה→ו→ז→ח→ט→י→יא), שמירה ב-DB אחרי כל בלוק (כ-12), recovery ממצב שנפל (כ-13), חזרה אחורה (כ-14). בלוק י: CREAC + Opus + thinking + מסמך כיוון. פרמטרי עיבוד (temperature, model) לפי block-schema.
|
||||||
|
|
||||||
|
### משימה: יישום skill /qa-validate
|
||||||
|
Priority: critical. Dependencies: draft-decision.
|
||||||
|
Skill חדש: grounding check (כל הפניה מול מסמכים), מענה לכל טענה, רקע ניטרלי, משקלות בטווח, מספור רציף, הגדרות להלן. אם נכשל — חוסם ייצוא. דוח שגיאות מפורט.
|
||||||
|
|
||||||
|
### משימה: אינטגרציה E2E וחיבור Paperclip events
|
||||||
|
Priority: high. Dependencies: all skills.
|
||||||
|
חיבור Paperclip events ל-Claude Code (trigger כתיבה דרך issue comment). E2E test על תיק הכט: העלאת חומרים → הזנת תוצאה (דחייה) → כתיבה → QA → DOCX. השוואה להחלטה הסופית.
|
||||||
|
|
||||||
|
### משימה: מבחן הסמכה
|
||||||
|
Priority: critical. Dependencies: E2E integration.
|
||||||
|
שלב ב מסעיף 8 באיפיון: המערכת כותבת החלטה לתיק שכבר יש לו החלטה סופית. השוואת טיוטה להחלטה — פער ≤10%. שלב ג: תיק חי — דפנה בודקת.
|
||||||
47
.taskmaster/docs/prd-phase2.txt
Normal file
47
.taskmaster/docs/prd-phase2.txt
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# PRD Phase 2 — משימות חסרות שנלמדו במהלך ההקמה
|
||||||
|
|
||||||
|
## הקשר
|
||||||
|
המשימות הבאות חסרות ב-TaskMaster הנוכחי. חלקן כבר בוצעו (צריך לסמן done), חלקן עתידיות.
|
||||||
|
|
||||||
|
## משימות שכבר בוצעו (לתיעוד בלבד)
|
||||||
|
|
||||||
|
### משימה: הקמת תשתית DB
|
||||||
|
16 טבלאות ב-4 שכבות (Core, Decision, Knowledge, RAG) + טבלת appeal_type_rules + טבלת decision_definitions. כולל pgvector, indexes, migrations. סטטוס: done.
|
||||||
|
|
||||||
|
### משימה: ייבוא ידע ראשוני מ-vault
|
||||||
|
75 רשומות: 15 לקחים, 44 ביטויי מעבר, 9 תקדימים (הורחב ל-49), 7 הוראות חוק. סקריפטים: seed-knowledge.py, seed-appeals.py. סטטוס: done.
|
||||||
|
|
||||||
|
### משימה: ייבוא 20 תיקי ערר
|
||||||
|
מטאדטה של 20 תיקים מהvault (3 פעילים, 17 ארכיון). כולל appeal_type classification. סטטוס: done.
|
||||||
|
|
||||||
|
### משימה: הפרדת סוגי עררים ב-DB
|
||||||
|
הוספת appeal_type לטבלאות cases, decisions, lessons_learned, transition_phrases. יצירת appeal_type_rules עם 30 כללים + 23 יחסי זהב. כולל הבדלי טון, מבנה, משקלות. סטטוס: done.
|
||||||
|
|
||||||
|
### משימה: התקנת שרתי MCP
|
||||||
|
Infisical MCP (גלובלי), TaskMaster AI (פרויקט). סטטוס: done.
|
||||||
|
|
||||||
|
## משימות עתידיות חדשות
|
||||||
|
|
||||||
|
### משימה: ייבוא חומרי מקור מלאים
|
||||||
|
Priority: medium. Dependencies: task 2.
|
||||||
|
ייבוא כל חומרי המקור מה-vault ל-DB — לא רק החלטות סופיות אלא גם כתבי ערר, כתבי תשובה, פרוטוקולים, שומות, חוות דעת. לכל 20 תיקים. כולל חילוץ טקסט מ-MD שכבר קיימים ו-OCR ל-PDF סרוקים. ~444 קבצים סה"כ.
|
||||||
|
|
||||||
|
### משימה: חשיפת פונקציות חיפוש וולידציה כ-MCP tools
|
||||||
|
Priority: high. Dependencies: tasks 7, 9.
|
||||||
|
להוסיף ל-MCP server tools חדשים: search_precedents (חיפוש סמנטי בפסיקה והחלטות), validate_decision (בדיקת החלטה מול כללי block-schema), get_golden_ratios (קבלת יחסי זהב לפי סוג ערר ותוצאה), get_appeal_type_rules (כללים לפי סוג). כולל סינון לפי appeal_type.
|
||||||
|
|
||||||
|
### משימה: יישום סגנון כתיבה מותאם לסוג ערר
|
||||||
|
Priority: high. Dependencies: appeal_type_rules.
|
||||||
|
לוודא שכל כלי הכתיבה (draft_section ב-MCP) משתמש ב-appeal_type_rules כדי להתאים: טון (חם/קר), מבנה פתיחה (רחב/ישיר), מספור (כותרות/אותיות), פתיחת דיון (שכבות/נושאי/ישיר), סיום (חם/יבש), משקלות בלוקים.
|
||||||
|
|
||||||
|
### משימה: עדכון PRD ו-CLAUDE.md עם מצב נוכחי
|
||||||
|
Priority: low.
|
||||||
|
לעדכן את CLAUDE.md עם: 18 טבלאות ב-DB, 7 החלטות מפורקות, 212 טענות, 49 פסיקות, 131 embeddings, 30 כללי סוג ערר, 23 יחסי זהב. לעדכן את docs/architecture.md עם הטבלאות והסקריפטים החדשים.
|
||||||
|
|
||||||
|
### משימה: שיפור parser להחלטות עם כיסוי נמוך
|
||||||
|
Priority: medium. Dependencies: task 4.
|
||||||
|
שטרית (167% חפיפה) ומבורך (133%) מראים חפיפה בין בלוקים. צריך לשפר את decompose-decisions-v2.py: טיפול בחפיפה, זיהוי טוב יותר של גבולות בלוקים כשאין כותרות מפורשות, הוספת סוג ערר פיצויים (9xxx) ל-parser.
|
||||||
|
|
||||||
|
### משימה: Gitea — push קוד לrepository
|
||||||
|
Priority: medium. Dependencies: none.
|
||||||
|
לדחוף את כל הקוד (scripts, MCP server, docs) ל-Gitea repository שכבר מוגדר ב-gitea.nautilus.marcusgroup.org/Chaim/ezer-mishpati. כולל .gitignore מתאים (לא legacy vault, לא .env, לא node_modules).
|
||||||
132
.taskmaster/docs/prd.txt
Normal file
132
.taskmaster/docs/prd.txt
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
# PRD — Legal Decision Assistant (עוזר משפטי)
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
AI-powered system to assist the Chair of the Jerusalem District Planning Appeals Committee (Adv. Dafna Tamir) in writing formal legal decisions. The system migrates knowledge from a legacy Obsidian vault to a structured PostgreSQL + pgvector + n8n platform on the Nautilus server.
|
||||||
|
|
||||||
|
## Current State (What Already Exists)
|
||||||
|
|
||||||
|
### Infrastructure (Completed)
|
||||||
|
- PostgreSQL with pgvector on Nautilus (legal-ai-postgres)
|
||||||
|
- 16 database tables in 4 layers: Core, Decision, Knowledge, RAG
|
||||||
|
- MCP server (legal-ai) with document upload, case management, search, style analysis
|
||||||
|
- Web upload interface (ezer-mishpati-web) at legal-ai.nautilus.marcusgroup.org
|
||||||
|
- Voyage AI embeddings (voyage-3-large, dim=1024) — 323 existing embeddings from 4 training decisions
|
||||||
|
- Coolify, Gitea, Redis, n8n (empty), Infisical on Nautilus
|
||||||
|
|
||||||
|
### Data Already Imported
|
||||||
|
- 19 appeal cases with basic metadata (case numbers, titles, parties, addresses, status)
|
||||||
|
- 15 lessons learned from 3 analyzed decisions (הכט, בית הכרם, קרית יערים)
|
||||||
|
- 44 transition phrases from Dafna's writing style
|
||||||
|
- 9 case law references (precedents)
|
||||||
|
- 7 statutory provisions
|
||||||
|
- 4 training decisions in style corpus with 90 style patterns
|
||||||
|
|
||||||
|
### Legacy Vault (Read-Only Reference)
|
||||||
|
Located at legacy/dafna-tamir/. Contains:
|
||||||
|
- 16 archived case folders with source materials (~280 documents total)
|
||||||
|
- 3 active case folders
|
||||||
|
- 9 completed decisions (PDF/DOCX)
|
||||||
|
- Original SKILL.md style guide
|
||||||
|
- Original Claude Code skills
|
||||||
|
|
||||||
|
## What Needs to Be Done
|
||||||
|
|
||||||
|
### Phase 1: Full Case Audit (Priority: HIGH)
|
||||||
|
Systematically audit all 19 case folders in the legacy vault:
|
||||||
|
- For each case folder: list every document, classify by type (appeal/response/decision/exhibit/protocol/expert-opinion), record dates and page counts
|
||||||
|
- Identify completed decisions vs. in-progress vs. not-started
|
||||||
|
- Identify gaps (missing documents, incomplete metadata)
|
||||||
|
- Produce audit report per case
|
||||||
|
|
||||||
|
### Phase 2: Document Import (Priority: HIGH)
|
||||||
|
Import all documents from legacy vault to the database:
|
||||||
|
- Register each document in the `documents` table with correct case_id, doc_type, title, file_path
|
||||||
|
- Track which documents have been imported vs. pending
|
||||||
|
- Priority: completed cases first (הכט, בית הכרם, אפרים אבי, etc.)
|
||||||
|
|
||||||
|
### Phase 3: Text Extraction (Priority: HIGH)
|
||||||
|
Extract text from all imported documents:
|
||||||
|
- PDF extraction using PyMuPDF (already in MCP server dependencies)
|
||||||
|
- DOCX extraction
|
||||||
|
- Hebrew OCR for scanned PDFs (Claude Vision or Tesseract)
|
||||||
|
- Store extracted text in documents.extracted_text
|
||||||
|
- Update extraction_status for each document
|
||||||
|
|
||||||
|
### Phase 4: Decision Decomposition (Priority: HIGH)
|
||||||
|
Parse the 9 completed decisions into the 12-block structure:
|
||||||
|
- For each completed decision: create a `decisions` record
|
||||||
|
- Identify and extract each of the 12 blocks (alef through yod-bet)
|
||||||
|
- Store blocks in `decision_blocks` with correct block_id, content, word counts, weights
|
||||||
|
- Extract individual paragraphs to `decision_paragraphs` with paragraph numbers
|
||||||
|
- Track citations within paragraphs (case law references)
|
||||||
|
- This is critical training data for the system
|
||||||
|
|
||||||
|
### Phase 5: Claims Extraction (Priority: MEDIUM)
|
||||||
|
Extract party claims from appeal documents and responses:
|
||||||
|
- Parse appeal letters (כתבי ערר) to extract appellant claims
|
||||||
|
- Parse responses (כתבי תשובה) to extract respondent/committee claims
|
||||||
|
- Store in `claims` table with party_role, claim_text, source_document
|
||||||
|
- Link claims to paragraphs in discussion blocks where they are addressed (addressed_in_paragraph)
|
||||||
|
|
||||||
|
### Phase 6: Embeddings & RAG (Priority: MEDIUM)
|
||||||
|
Generate embeddings for all extracted content:
|
||||||
|
- Chunk extracted document text (600 tokens, 100 overlap — already configured)
|
||||||
|
- Generate Voyage embeddings for document chunks
|
||||||
|
- Generate embeddings for decision paragraphs → paragraph_embeddings
|
||||||
|
- Generate embeddings for case law summaries → case_law_embeddings
|
||||||
|
- Build semantic search functions in MCP server
|
||||||
|
- Test: "find similar precedents for this case"
|
||||||
|
|
||||||
|
### Phase 7: n8n Workflow Automation (Priority: LOW)
|
||||||
|
Create automated workflows:
|
||||||
|
- Document upload → classify document type → store in DB → generate embeddings
|
||||||
|
- New appeal creation → auto-create 12-block structure → generate DOCX template
|
||||||
|
- Precedent search → RAG query → return ranked results
|
||||||
|
- Draft validation → check against block-schema constraints
|
||||||
|
|
||||||
|
### Phase 8: Enhanced Web UI (Priority: LOW)
|
||||||
|
Extend ezer-mishpati-web:
|
||||||
|
- Case management dashboard (list all cases, status, documents)
|
||||||
|
- Decision writing interface (block-by-block with live preview)
|
||||||
|
- Precedent search interface with semantic results
|
||||||
|
- Style guide reference panel
|
||||||
|
- DOCX export from decision blocks
|
||||||
|
|
||||||
|
## Technical Architecture
|
||||||
|
|
||||||
|
### Database: 4 Layers, 16 Tables
|
||||||
|
Layer 1 (Core): cases, documents, document_chunks, style_corpus, style_patterns
|
||||||
|
Layer 2 (Decision): decisions, decision_blocks, decision_paragraphs, claims
|
||||||
|
Layer 3 (Knowledge): case_law, case_law_citations, statutory_provisions, transition_phrases, lessons_learned
|
||||||
|
Layer 4 (RAG): paragraph_embeddings, case_law_embeddings
|
||||||
|
|
||||||
|
### Key Design Decisions
|
||||||
|
- Embedding model: Voyage voyage-3-large (1024 dimensions)
|
||||||
|
- Chunk size: 600 tokens with 100 overlap
|
||||||
|
- Decision structure: 12 blocks based on CREAC/DITA/Akoma Ntoso/Federal Judicial Center
|
||||||
|
- All Hebrew content — RTL support required in DOCX export
|
||||||
|
- Style guide: SKILL.md (Dafna's writing patterns, tone per appeal type, transition phrases)
|
||||||
|
|
||||||
|
### MCP Server Stack
|
||||||
|
- Python asyncpg for PostgreSQL
|
||||||
|
- FastMCP for tool registration
|
||||||
|
- PyMuPDF for PDF extraction
|
||||||
|
- Anthropic API for Claude Vision OCR (scanned PDFs)
|
||||||
|
|
||||||
|
## Critical Rules
|
||||||
|
1. "Judge Test" — every decision readable by a judge unfamiliar with the case
|
||||||
|
2. "Neutral Background" — Block ו contains only objective facts, no party quotes or value judgments
|
||||||
|
3. "No Duplication" — Block י references previous blocks, doesn't repeat them
|
||||||
|
4. "Original Claims Only" — Block ז uses only original appeal/response documents; supplements go to Block ח
|
||||||
|
5. 12-Block Architecture — see docs/block-schema.md for full specification
|
||||||
|
6. Work methodically — audit before import, validate after each step, no shortcuts
|
||||||
|
|
||||||
|
## File Locations
|
||||||
|
- Project root: /home/chaim/legal-ai/
|
||||||
|
- Legacy vault: legacy/dafna-tamir/ (read-only)
|
||||||
|
- MCP server: mcp-server/src/legal_mcp/
|
||||||
|
- Documentation: docs/ (architecture.md, block-schema.md, migration-plan.md)
|
||||||
|
- Scripts: scripts/ (seed-knowledge.py, seed-appeals.py)
|
||||||
|
- Style guide: skill-legal-decision/SKILL.md
|
||||||
|
- Lessons: memory/legal-decision-lessons.md
|
||||||
718
.taskmaster/tasks/tasks.json
Normal file
718
.taskmaster/tasks/tasks.json
Normal file
@@ -0,0 +1,718 @@
|
|||||||
|
{
|
||||||
|
"master": {
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"id": "32",
|
||||||
|
"title": "הקמת סביבת פיתוח ותשתית בסיסית",
|
||||||
|
"description": "הקמת סביבת הפיתוח הבסיסית עם Python, FastAPI, PostgreSQL ו-Infisical לניהול סודות",
|
||||||
|
"details": "יצירת פרויקט Python עם FastAPI כשרת API, PostgreSQL כמסד נתונים, ו-Infisical לניהול סודות. הגדרת Docker containers לפיתוח מקומי. יצירת מבנה תיקיות: /src, /tests, /docs, /data. הגדרת requirements.txt עם כל התלויות הנדרשות: fastapi, uvicorn, sqlalchemy, psycopg2, python-multipart, python-docx, PyPDF2, anthropic, infisical-python. הגדרת משתני סביבה דרך Infisical.",
|
||||||
|
"testStrategy": "בדיקת התחברות למסד נתונים, טעינת משתני סביבה מ-Infisical, הרצת שרת FastAPI בסיסי",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T08:53:33.842Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "33",
|
||||||
|
"title": "מודול קליטה ועיבוד מסמכים",
|
||||||
|
"description": "פיתוח מודול לקליטת קבצי PDF, DOCX, MD וחילוץ טקסט כולל OCR",
|
||||||
|
"details": "יצירת מחלקה DocumentProcessor שמטפלת בקבצים מסוגים שונים. עבור PDF: שימוש ב-PyPDF2 לטקסט רגיל ו-pytesseract לOCR של קבצים סרוקים. עבור DOCX: שימוש ב-python-docx. עבור MD: קריאה ישירה. הוספת זיהוי אוטומטי של קבצים סרוקים. יצירת API endpoint POST /documents/upload שמקבל קבצים ומחזיר טקסט מחולץ. שמירת מטא-דאטה של כל מסמך במסד הנתונים.",
|
||||||
|
"testStrategy": "בדיקה עם קבצי PDF רגילים וסרוקים, קבצי DOCX עם עברית RTL, קבצי MD. וידוא חילוץ טקסט נכון ושמירת מטא-דאטה",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"32"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:38:55.716Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "34",
|
||||||
|
"title": "מודול סיווג מסמכים וזיהוי צדדים",
|
||||||
|
"description": "פיתוח מודול לסיווג מסמכים לסוגים (ערר, תשובה, פרוטוקול וכו') וזיהוי צדדים",
|
||||||
|
"details": "יצירת מחלקה DocumentClassifier שמשתמשת ב-Claude API לסיווג מסמכים. הגדרת prompt מובנה שמזהה: סוג מסמך (ערר/תשובה/תגובה/פרוטוקול/תכנית/היתר/פסק דין/החלטה), צדדים (עוררים, משיבים, ועדה, מבקשי היתר), סוג ערר לפי מספר תיק (1xxx=רישוי, 8xxx=השבחה, 9xxx=פיצויים). יצירת מבנה נתונים מובנה לשמירת המידע המסווג. הוספת ולידציה לתוצאות הסיווג.",
|
||||||
|
"testStrategy": "בדיקה עם מסמכים מכל הסוגים, וידוא זיהוי נכון של צדדים וסוג ערר, בדיקת טיפול במסמכים לא ברורים",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"33"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:43:02.411Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "35",
|
||||||
|
"title": "מודול חילוץ טענות",
|
||||||
|
"description": "פיתוח מודול לחילוץ וסיכום טענות מכתבי טענות לפי צד",
|
||||||
|
"details": "יצירת מחלקה ClaimsExtractor שמחלצת טענות מכתבי ערר ותשובה. שימוש ב-Claude API עם prompt מיוחד שמזהה טענות לפי צד ומסכם אותן בצורה נאמנה למקור. יצירת מבנה נתונים שמקשר בין טענה למסמך המקור ולמיקום בו. הוספת מנגנון לזיהוי טענות חוזרות או דומות. שמירת הטענות במסד הנתונים עם קישור לתיק ולצד.",
|
||||||
|
"testStrategy": "בדיקה עם כתבי ערר מורכבים, וידוא נאמנות לטקסט המקור, בדיקת זיהוי טענות לפי צד",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"34"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:45:38.799Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "36",
|
||||||
|
"title": "מודול זיהוי תכניות ופסיקה",
|
||||||
|
"description": "פיתוח מודול לזיהוי תכניות חלות על המקרקעין ופסיקה מצוטטת במסמכים",
|
||||||
|
"details": "יצירת מחלקה LegalReferencesExtractor שמזהה: תכניות (תב\"ע, תמ\"א, תכניות מקומיות), פסיקה מצוטטת (עם מספרי תיק ושנה), חקיקה רלוונטית. שימוש ב-regex patterns לזיהוי דפוסים נפוצים ו-Claude API לאימות ועידון. יצירת מאגר מקומי של תכניות ופסיקה שכבר זוהו. הוספת מנגנון לולידציה של הפניות שזוהו.",
|
||||||
|
"testStrategy": "בדיקה עם מסמכים המכילים הפניות לתכניות ופסיקה, וידוא זיהוי מדויק ואי-זיהוי של הפניות שגויות",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"34"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:48:16.636Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "37",
|
||||||
|
"title": "ממשק הזנת תוצאה וסיעור מוחות",
|
||||||
|
"description": "פיתוח ממשק CLI להזנת תוצאה (דחייה/קבלה/חלקית) ומנגנון סיעור מוחות",
|
||||||
|
"details": "יצירת CLI interface עם typer שמאפשר לחיים להזין: סוג תוצאה (דחייה/קבלה/קבלה חלקית), נימוק (אופציונלי). אם לא הוזן נימוק - הפעלת מודול BrainstormingEngine שמציג טענות מרכזיות ומציע 2-3 כיוונים אפשריים. יצירת שיח אינטראקטיבי בין חיים למערכת עד הגעה לכיוון מוסכם. שמירת מסמך הכיוון הסופי. הוספת מנגנון מניעה מכתיבת דיון ללא כיוון מאושר.",
|
||||||
|
"testStrategy": "בדיקת תרחישים עם ובלי נימוק, וידוא איכות הצעות הכיוון, בדיקת מניעת כתיבה ללא אישור",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"35",
|
||||||
|
"36"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:55:06.069Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "38",
|
||||||
|
"title": "מנוע כתיבת בלוק הפתיחה (בלוק ה)",
|
||||||
|
"description": "פיתוח מנוע לכתיבת בלוק הפתיחה בסגנון דפנה",
|
||||||
|
"details": "יצירת מחלקה OpeningBlockWriter שכותבת את בלוק הפתיחה. ניתוח דפוסי הפתיחה מ-7 ההחלטות הקיימות (\"לפנינו\" vs \"עניינה של החלטה זו\"). יצירת prompt מובנה שמתאים את הפתיחה לסוג הערר ולמורכבות התיק. הוספת מנגנון לבחירת נוסח הפתיחה המתאים. שמירת תבניות פתיחה במסד הנתונים.",
|
||||||
|
"testStrategy": "בדיקה עם סוגי ערר שונים, השוואה לפתיחות בהחלטות הקיימות, וידוא התאמה לסגנון דפנה",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"37"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:58:34.296Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "39",
|
||||||
|
"title": "מנוע כתיבת בלוק הרקע (בלוק ו)",
|
||||||
|
"description": "פיתוח מנוע לכתיבת בלוק הרקע בצורה ניטרלית",
|
||||||
|
"details": "יצירת מחלקה BackgroundBlockWriter שכותבת רקע ניטרלי. הגדרת כללי ניטרליות: אין ציטוטים מצדדים, אין מילות שיפוט, הצגת עובדות בלבד. יצירת רשימת מילים אסורות ומנגנון ולידציה. שימוש במידע מהמסמכים המסווגים לבניית הרקע. הוספת מנגנון לקביעת אורך הרקע לפי מורכבות התיק (3%-18% מההחלטה).",
|
||||||
|
"testStrategy": "בדיקת ניטרליות הטקסט, וידוא היעדר מילות שיפוט, בדיקת אורך מתאים לפי מורכבות",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"38"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:58:34.300Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "40",
|
||||||
|
"title": "מנוע כתיבת בלוק הטענות (בלוק ז)",
|
||||||
|
"description": "פיתוח מנוע לכתיבת סיכום טענות הצדדים בגוף שלישי",
|
||||||
|
"details": "יצירת מחלקה ClaimsBlockWriter שמסכמת טענות בגוף שלישי. שימוש בטענות שחולצו במודול חילוץ הטענות. הבטחת נאמנות מוחלטת למקור - אין שינוי מילים או קיצור ללא ציון. יצירת מבנה לוגי של הצגת הטענות לפי צד. הוספת מנגנון לקישור כל טענה למקור המדויק במסמך.",
|
||||||
|
"testStrategy": "השוואת הטענות המסוכמות לטקסט המקור, וידוא נאמנות מוחלטת, בדיקת מבנה לוגי",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"39"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:58:34.303Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "41",
|
||||||
|
"title": "מנוע כתיבת בלוק ההליכים (בלוק ח)",
|
||||||
|
"description": "פיתוח מנוע לכתיבת בלוק ההליכים (רק כשהיו הליכים מעבר לדיון פשוט)",
|
||||||
|
"details": "יצירת מחלקה ProceduresBlockWriter שכותבת תיעוד כרונולוגי של הליכים. זיהוי אוטומטי מתי נדרש הבלוק (סיור, השלמות טיעון, החלטות ביניים). יצירת ציר זמן של האירועים מהמסמכים. הבטחת דיוק עובדתי ומבנה כרונולוגי. הוספת מנגנון להחלטה אוטומטית האם הבלוק נדרש.",
|
||||||
|
"testStrategy": "בדיקה עם תיקים עם ובלי הליכים מורכבים, וידוא דיוק כרונולוגי, בדיקת החלטה נכונה על נחיצות הבלוק",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"40"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:58:34.305Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "42",
|
||||||
|
"title": "מנוע כתיבת בלוק התכניות (בלוק ט)",
|
||||||
|
"description": "פיתוח מנוע לכתיבת בלוק התכניות והמסגרת הנורמטיבית",
|
||||||
|
"details": "יצירת מחלקה PlansBlockWriter שמטפלת ברישום תכניות. הגדרת כללי החלטה מתי נדרש פרק נפרד (מורכבות תכנונית, שאלה משפטית כמו ס' 152). שימוש במידע התכניות שזוהו במודול זיהוי התכניות. יצירת מבנה הירכי של התכניות (ארציות, מחוזיות, מקומיות). הוספת מנגנון לקביעת עומק הפירוט הנדרש.",
|
||||||
|
"testStrategy": "בדיקה עם תיקים בעלי מורכבות תכנונית שונה, וידוא החלטה נכונה על צורת ההצגה, בדיקת דיוק המידע",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"41"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:58:34.308Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "43",
|
||||||
|
"title": "מנוע כתיבת בלוק הדיון (בלוק י) - ליבת המערכת",
|
||||||
|
"description": "פיתוח מנוע הכתיבה המרכזי לבלוק הדיון בשיטת CREAC",
|
||||||
|
"details": "יצירת מחלקה DiscussionBlockWriter - הליבה של המערכת. יישום שיטת CREAC: מסקנה בפתיחה, כלל משפטי, הסבר, יישום על המקרה, מסקנה. הבטחת מענה לכל טענה מבלוק ז. שימוש בכיוון שנקבע בשלב סיעור המוחות. הוספת מנגנון למניעת כפילויות והפניות לבלוקים קודמים. יצירת מבנה לוגי של הנימוקים לפי סדר חשיבות.",
|
||||||
|
"testStrategy": "בדיקת כיסוי כל הטענות, וידוא מבנה CREAC, בדיקת התאמה לכיוון שנקבע, בדיקת היעדר כפילויות",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"42"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:58:34.311Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "44",
|
||||||
|
"title": "מנוע כתיבת בלוק הסיכום (בלוק יא)",
|
||||||
|
"description": "פיתוח מנוע לכתיבת בלוק הסיכום עם הוראות אופרטיביות",
|
||||||
|
"details": "יצירת מחלקה SummaryBlockWriter שכותבת הוראות אופרטיביות. גזירת ההוראות מהדיון שנכתב בבלוק י. הבטחת התאמה מדויקת להכרעה שנקבעה. יצירת מבנה ברור של ההוראות (מה מתקבל, מה נדחה, מה התנאים). הוספת מנגנון לולידציה של עקביות בין הדיון לסיכום.",
|
||||||
|
"testStrategy": "בדיקת התאמה בין הדיון לסיכום, וידוא בהירות ההוראות, בדיקת עקביות עם ההכרעה",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"43"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:58:34.313Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "45",
|
||||||
|
"title": "מנוע ייצוא DOCX מעוצב",
|
||||||
|
"description": "פיתוח מנוע לייצוא ההחלטה לקובץ DOCX מעוצב בעברית RTL",
|
||||||
|
"details": "יצירת מחלקה DocxExporter שמייצרת DOCX מעוצב. הגדרת גופן David, כיוון RTL, כותרות מעוצבות, מספור סעיפים רציף. יצירת תבנית DOCX בסיסית עם הגדרות העיצוב. הוספת מנגנון לסימון מקומות תמונה (GIS, תשריט, סיור). הבטחת תמיכה מלאה בעברית ובכיוון RTL. יצירת מבנה היררכי של כותרות וסעיפים.",
|
||||||
|
"testStrategy": "בדיקת פתיחה נכונה של הקובץ ב-Word, וידוא עיצוב RTL, בדיקת גופנים וכותרות, בדיקת מספור",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"44"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T10:12:36.842Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "46",
|
||||||
|
"title": "מנגנון בקרת איכות ווולידציה",
|
||||||
|
"description": "פיתוח מנגנון בקרת איכות לוולידציה של ההחלטה לפני הפלט",
|
||||||
|
"details": "יצירת מחלקה QualityController שבודקת: אפס הזיות (כל הפניה מול מסמכים שסופקו), מענה לכל טענה, רקע ניטרלי (ללא מילות שיפוט), משקלות בלוקים בטווח יחסי הזהב ±10%, ציטוטים נאמנים למקור. יצירת דוח ולידציה מפורט. הוספת מנגנון למניעת פלט במקרה של כשלון ולידציה קריטי.",
|
||||||
|
"testStrategy": "בדיקה עם החלטות תקינות ופגומות, וידוא זיהוי בעיות, בדיקת דיוק הולידציה",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"45"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T10:14:00.311Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "47",
|
||||||
|
"title": "מודול לולאת למידה",
|
||||||
|
"description": "פיתוח מודול לקליטת גרסה סופית והשוואה לטיוטה ללמידה",
|
||||||
|
"details": "יצירת מחלקה LearningLoop שמקבלת את הגרסה הסופית שדפנה חתמה. השוואת הטיוטה לגרסה הסופית וזיהוי הבדלים. חילוץ לקחים: ביטויים חדשים, דפוסים שהשתנו, שגיאות חוזרות. עדכון מודל הסגנון על בסיס הלקחים. יצירת דוח למידה לחיים. שמירת הלקחים במסד הנתונים לשיפור עתידי.",
|
||||||
|
"testStrategy": "בדיקה עם גרסאות סופיות שונות, וידוא זיהוי נכון של הבדלים, בדיקת איכות הלקחים שחולצו",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"46"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T10:15:14.639Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "48",
|
||||||
|
"title": "מודול מדדי הצלחה ודשבורד",
|
||||||
|
"description": "פיתוח מודול למדידת KPIs ויצירת דשבורד מעקב",
|
||||||
|
"details": "יצירת מחלקה MetricsTracker שמודדת: אחוז שינוי (השוואת טיוטה לגרסה סופית), זמן לטיוטה (מקצה לקצה), אפס הזיות (ספירת הפניות לא תקינות), מענה לכל טענה, משקלות בלוקים, רקע ניטרלי. יצירת דשבורד פשוט עם הצגת המדדים לאורך זמן. הוספת התראות כשמדד יורד מתחת לסף המינימום.",
|
||||||
|
"testStrategy": "בדיקת דיוק המדידות, וידוא עבודת הדשבורד, בדיקת התראות",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"47"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T10:16:10.708Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "49",
|
||||||
|
"title": "מנגנון ניהול סודות ואבטחה",
|
||||||
|
"description": "יישום מנגנון אבטחה מלא עם Infisical וניהול סודות",
|
||||||
|
"details": "הגדרת Infisical לניהול כל הסודות: Anthropic API key, מחרוזות חיבור למסד נתונים, מפתחות הצפנה. יצירת מנגנון הצפנה לחומרי התיקים במסד הנתונים. הגדרת מדיניות גישה והרשאות. יצירת מנגנון audit log לכל הפעולות. הבטחת שחומרי התיקים לא נשלחים לשירותים חיצוניים מלבד Anthropic API.",
|
||||||
|
"testStrategy": "בדיקת טעינת סודות מ-Infisical, וידוא הצפנה של נתונים רגישים, בדיקת audit log",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"32"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T10:17:43.954Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "50",
|
||||||
|
"title": "מנגנון גיבוי ושחזור",
|
||||||
|
"description": "יישום מנגנון גיבוי יומי אוטומטי ושחזור מסד הנתונים",
|
||||||
|
"details": "יצירת סקריפט גיבוי יומי אוטומטי למסד הנתונים PostgreSQL. הגדרת cron job לביצוע הגיבוי בשעות הלילה. יצירת מנגנון שחזור מגיבוי. שמירת הגיבויים במיקום מאובטח. הוספת מנגנון לבדיקת תקינות הגיבויים. יצירת תיעוד לתהליכי גיבוי ושחזור.",
|
||||||
|
"testStrategy": "בדיקת ביצוע גיבוי אוטומטי, בדיקת שחזור מגיבוי, וידוא תקינות הנתונים לאחר שחזור",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"49"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T10:18:18.247Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "51",
|
||||||
|
"title": "ממשק CLI מלא ותיעוד",
|
||||||
|
"description": "פיתוח ממשק CLI מלא עם כל הפקודות הנדרשות ותיעוד מקיף",
|
||||||
|
"details": "יצירת CLI מקיף עם typer שכולל: העלאת מסמכים, הזנת תוצאה, סיעור מוחות, יצירת טיוטה, הזנת גרסה סופית, הצגת מדדים. הוספת help מפורט לכל פקודה. יצירת תיעוד מקיף למשתמש עם דוגמאות שימוש. הוספת מנגנון לולידציה של קלטים. יצירת מנגנון לטיפול בשגיאות ומסרי שגיאה ברורים בעברית.",
|
||||||
|
"testStrategy": "בדיקת כל הפקודות, וידוא הודעות עזרה ברורות, בדיקת טיפול בשגיאות, בדיקת תיעוד",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"48",
|
||||||
|
"50"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T10:19:20.241Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "52",
|
||||||
|
"title": "בדיקות אינטגרציה ומבחן הסמכה",
|
||||||
|
"description": "יצירת חבילת בדיקות מקיפה ומבחן הסמכה על תיק אמיתי",
|
||||||
|
"details": "יצירת בדיקות אינטגרציה לכל התהליך מקצה לקצה. בדיקה עם תיק הכט (תיק שכבר יש לו החלטה סופית) - השוואת הטיוטה שהמערכת מייצרת להחלטה הסופית. מדידת פער ווידוא שהוא קטן מ-10%. יצירת מבחן הסמכה מובנה לפני שימוש מבצעי. הוספת בדיקות ביצועים - וידוא שהמערכת מייצרת טיוטה תוך יום עבודה.",
|
||||||
|
"testStrategy": "הרצת מבחן הסמכה על תיק הכט, מדידת זמן ביצוע, השוואה להחלטה הסופית, וידוא עמידה בכל הדרישות",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"51"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-04T07:50:59.998Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "53",
|
||||||
|
"title": "הוספת שלב 6 - הגהת דפנה לדרישות הפונקציונליות",
|
||||||
|
"description": "הגדרת שלב הגהת דפנה החסר מהדרישות הפונקציונליות, כולל זרימת העבודה והממשקים",
|
||||||
|
"details": "יש להגדיר בדרישות הפונקציונליות: (1) איך דפנה מקבלת את הטיוטה בפורמט DOCX, (2) איך מחזירה הערות ותיקונים (ממשק או פורמט מובנה), (3) מי מעלה את הגרסה הסופית ללולאת הלמידה. כולל הגדרת API endpoints לקבלת הטיוטה ולהחזרת הערות, ומנגנון עדכון המודל על בסיס הפידבק.",
|
||||||
|
"testStrategy": "בדיקת זרימת העבודה המלאה מהעברת טיוטה לדפנה ועד עדכון המודל. וולידציה של פורמטים ותקינות הממשקים.",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T20:58:19.827Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "54",
|
||||||
|
"title": "החלפת דרישת 'אפס הזיות' במנגנון grounding ווולידציה",
|
||||||
|
"description": "החלפת הדרישה הלא ריאלית של אפס הזיות במנגנון grounding מתקדם ומערכת וולידציה אוטומטית",
|
||||||
|
"details": "יישום מנגנון grounding שמקשר כל הפניה למסמך מקור ספציפי עם citation tracking. פיתוח מערכת וולידציה אוטומטית שבודקת כל ציטוט/הפניה מול המסמכים שסופקו. הגדרת מדד: שיעור הפניות שלא עוברות וולידציה = 0. כולל מנגנון flagging של הפניות חשודות ודרישה לאישור ידני.",
|
||||||
|
"testStrategy": "בדיקת דיוק הקישור בין הפניות למסמכי מקור. טסטים על מקרי קצה של הפניות שגויות וולידציה שהמערכת תופסת אותן.",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T20:58:55.741Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "55",
|
||||||
|
"title": "הוספת ניהול context window overflow",
|
||||||
|
"description": "פיתוח מנגנון לטיפול בתיקים מורכבים שחורגים מ-context window של המודל",
|
||||||
|
"details": "יישום מדידת גודל חומרים בטוקנים, אסטרטגיית chunking חכמה ו/או summarization של מסמכים ארוכים. הגדרת סף התראה כשמתקרבים לגבול context window. פיתוח אלגוריתם לסדר עדיפויות של מסמכים והחלטה איזה חלקים לכלול בהקשר הנוכחי.",
|
||||||
|
"testStrategy": "בדיקה עם תיקים של 50+ מסמכים. וולידציה שהמערכת מזהה overflow ומפעילה אסטרטגיות הפחתה מתאימות.",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T20:59:34.704Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "56",
|
||||||
|
"title": "הגדרה מתמטית מדויקת של 'אחוז שינוי'",
|
||||||
|
"description": "הגדרה ברורה ומתמטית של מדד אחוז השינוי עם דוגמאות קונקרטיות",
|
||||||
|
"details": "הגדרת מדד אחוז שינוי מבוסס edit distance על מילים (לא תווים). ספירת שינויים: הוספה, מחיקה, החלפה של מילים. נוסחה: (מספר שינויים / סך מילים בטקסט המקורי) * 100. כולל דוגמאות מפורטות ומקרי קצה כמו שינוי סדר מילים, שינויי פיסוק, וטיפול בסעיפים חדשים.",
|
||||||
|
"testStrategy": "בדיקת חישוב המדד על דוגמאות ידועות. השוואה עם מדדי edit distance סטנדרטיים כמו Levenshtein.",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:00:03.477Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "57",
|
||||||
|
"title": "הוספת דרישות לבלוקים א-ד ויב",
|
||||||
|
"description": "הגדרת דרישות פונקציונליות לבלוקים החסרים: כותרת, הרכב, צדדים וחתימות",
|
||||||
|
"details": "הגדרת דרישות מפורטות לבלוק א (כותרת התיק), בלוק ב (הרכב בית הדין), בלוק ג (זיהוי הצדדים), בלוק ד (פרטים נוספים על הצדדים), ובלוק יב (חתימות). כולל פורמט הפלט, מקורות המידע, וכללי עיבוד לכל בלוק. התאמה לתבנית הפסיקה הסטנדרטית.",
|
||||||
|
"testStrategy": "וולידציה של פורמט הפלט לכל בלוק מול תבניות פסיקה קיימות. בדיקת שלמות המידע והתאמה לדרישות משפטיות.",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"53"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T20:58:19.831Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "58",
|
||||||
|
"title": "יישום מנגנון שמירת מצב ביניים (persistence)",
|
||||||
|
"description": "פיתוח מערכת לשמירת מצב העבודה ו-recovery מנפילות מערכת",
|
||||||
|
"details": "יישום מנגנון auto-save שמשמר את מצב העבודה כל כמה דקות. שמירת גרסאות ביניים של כל בלוק, מעקב אחר השלב הנוכחי בתהליך, ומנגנון recovery שמאפשר המשך עבודה מהנקודה האחרונה שנשמרה. כולל ממשק למשתמש לבחירת נקודת שחזור.",
|
||||||
|
"testStrategy": "סימולציה של נפילות מערכת בשלבים שונים ובדיקת יכולת השחזור. וולידציה של שלמות הנתונים לאחר recovery.",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:01:07.799Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "59",
|
||||||
|
"title": "תיקון ספירת שלבים בטבלת מעקב",
|
||||||
|
"description": "עדכון טבלת המעקב להתאמה למספר השלבים בפועל",
|
||||||
|
"details": "עדכון הטבלה לציון 7 שלבים במקום 6, כולל השלב החדש של הגהת דפנה. עדכון כל הרפרנסים למספר השלבים במסמכי הדרישות והתיעוד. וידוא עקביות בין כל המסמכים.",
|
||||||
|
"testStrategy": "סקירה מקיפה של כל המסמכים לוידוא עקביות במספר השלבים. בדיקת התאמה בין הטבלה לדרישות הפונקציונליות.",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"53"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:01:45.876Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "60",
|
||||||
|
"title": "הכרה ב-MVP לרישוי והשבחה בלבד",
|
||||||
|
"description": "הגדרת גרסה ראשונה שמכסה רק רישוי והשבחה בשל חוסר נתוני אימון לפיצויים",
|
||||||
|
"details": "הגדרת MVP שמתמקד ברישוי והשבחה בלבד. תיעוד המגבלות הנוכחיות בנוגע לפיצויים ותכנית לאיסוף נתוני אימון עתידיים. הגדרת קריטריונים להרחבה לפיצויים בגרסאות עתידיות. עדכון מטריקות הצלחה בהתאם למגבלות הגרסה הראשונה.",
|
||||||
|
"testStrategy": "וולידציה שהמערכת מטפלת נכון רק בתיקי רישוי והשבחה. בדיקת התנהגות נכונה כשמתקבל תיק פיצויים.",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:01:45.879Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "61",
|
||||||
|
"title": "בחינה מחדש של יעד 98% שיעור שינוי",
|
||||||
|
"description": "הערכה מחדש של ריאליות יעד 98% בהתבסס על מחקר Endsley על התנהגות מומחים",
|
||||||
|
"details": "ניתוח מחקרי על התנהגות מומחים ונטייתם לבצע שינויים. הגדרת יעד ריאלי יותר המתחשב בגורמים פסיכולוגיים. הצעת מדדי הצלחה חלופיים כמו שיעור שינויים משמעותיים או שביעות רצון המומחים. כולל הגדרת baseline מתוך נתונים היסטוריים אם קיימים.",
|
||||||
|
"testStrategy": "ניתוח סטטיסטי של נתוני שינויים מהמערכת הנוכחית (אם קיימת). השוואה ליעדים דומים במערכות אחרות.",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:02:13.446Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "62",
|
||||||
|
"title": "הגדרת מנגנון לולאת למידה",
|
||||||
|
"description": "פיתוח מנגנון עדכון המודל על בסיס פידבק מדפנה ומשתמשים",
|
||||||
|
"details": "הגדרת אסטרטגיית עדכון המודל: fine-tuning מול prompt engineering מול עדכון RAG. יישום מנגנון איסוף פידבק מובנה, עיבוד הנתונים לפורמט מתאים לאימון, ותהליך עדכון אוטומטי או חצי-אוטומטי. כולל מנגנון A/B testing לבדיקת שיפורים.",
|
||||||
|
"testStrategy": "בדיקת יעילות מנגנון העדכון על דוגמאות ידועות. מדידת שיפור ביצועים לאחר עדכונים.",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"53",
|
||||||
|
"58"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:02:32.651Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "63",
|
||||||
|
"title": "הוספת הגנה מפני prompt injection",
|
||||||
|
"description": "יישום מנגנון הגנה מפני prompt injection ממסמכי מקור חיצוניים",
|
||||||
|
"details": "פיתוח מנגנון סינון וסניטיזציה של מסמכי קלט לזיהוי ניסיונות prompt injection. יישום validation של תוכן המסמכים, הפרדה בין הוראות המערכת לתוכן המסמכים, ומנגנון flagging של מסמכים חשודים. כולל רשימה שחורה של דפוסים מסוכנים.",
|
||||||
|
"testStrategy": "בדיקות חדירה עם מסמכים המכילים ניסיונות prompt injection ידועים. וולידציה שהמערכת מזהה ומנטרלת איומים.",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"54"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:02:49.768Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "64",
|
||||||
|
"title": "הוספת מנגנון back-flows בתהליך",
|
||||||
|
"description": "יישום יכולת חזרה אחורה בתהליך לעריכת בלוקים קודמים או שינוי כיוון",
|
||||||
|
"details": "פיתוח ממשק לחזרה לשלבים קודמים בתהליך. מנגנון לעריכת בלוקים שכבר הושלמו, עדכון אוטומטי של בלוקים תלויים, ומעקב אחר שינויים. כולל אזהרות למשתמש על השפעת שינויים על בלוקים אחרים ואפשרות לביטול פעולות.",
|
||||||
|
"testStrategy": "בדיקת זרימת עבודה עם חזרות אחורה. וולידציה של עקביות הנתונים לאחר שינויים בבלוקים קודמים.",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"58"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:01:07.801Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "65",
|
||||||
|
"title": "הוספת שלב QA/ולידציה לפני שליחה לדפנה",
|
||||||
|
"description": "יישום checklist אוטומטי ומנגנון QA לפני הפלט הסופי",
|
||||||
|
"details": "פיתוח checklist אוטומטי שבודק שלמות כל הבלוקים, תקינות הפורמט, נוכחות כל הרכיבים הנדרשים, ועקביות פנימית. מנגנון וולידציה של ציטוטים והפניות, בדיקת איכות השפה, ואזהרות על בעיות פוטנציאליות. כולל דוח QA מפורט למשתמש.",
|
||||||
|
"testStrategy": "בדיקת יעילות ה-checklist על פסיקות עם בעיות ידועות. וולידציה שהמערכת תופסת שגיאות נפוצות.",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"54",
|
||||||
|
"57"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:03:09.658Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "66",
|
||||||
|
"title": "יישום ניהול גרסאות של בלוקים",
|
||||||
|
"description": "פיתוח מערכת ניהול גרסאות לכל בלוק בנפרד",
|
||||||
|
"details": "יישום version control לכל בלוק בנפרד, שמירת היסטוריית שינויים, יכולת השוואה בין גרסאות, ואפשרות לחזרה לגרסה קודמת של בלוק ספציפי. כולל ממשק גרפי להצגת ההבדלים בין גרסאות ומטא-דאטה על כל שינוי (זמן, משתמש, סיבה).",
|
||||||
|
"testStrategy": "בדיקת שמירה ושחזור של גרסאות שונות. וולידציה של דיוק ההשוואות בין גרסאות.",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"58"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:04:33.961Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "67",
|
||||||
|
"title": "טיפול באיחוד תיקים",
|
||||||
|
"description": "פיתוח מנגנון לטיפול באיחוד תיקים כמו במקרה אריאלי 1078+1083",
|
||||||
|
"details": "יישום לוגיקה לזיהוי תיקים הקשורים זה לזה ומנגנון איחוד אוטומטי או חצי-אוטומטי. טיפול בחפיפות מידע, פתרון קונפליקטים, ושמירת קישוריות בין התיקים המאוחדים. כולל ממשק למשתמש לאישור ועריכת האיחוד המוצע.",
|
||||||
|
"testStrategy": "בדיקה על מקרי איחוד ידועים. וולידציה של שלמות המידע לאחר איחוד ותקינות הקישורים.",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"57",
|
||||||
|
"66"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:04:33.964Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "68",
|
||||||
|
"title": "תיקון LOA של סיעור מוחות",
|
||||||
|
"description": "תיקון רמת האוטומציה של סיעור מוחות מרמה ג' לרמה ב'",
|
||||||
|
"details": "עדכון הגדרת רמת האוטומציה (LOA) של תהליך סיעור המוחות מרמה ג' (אוטומציה מלאה) לרמה ב' (אוטומציה עם פיקוח אנושי). עדכון כל המסמכים והממשקים הרלוונטיים. הבטחת התאמה לרמת הביקורת הנדרשת.",
|
||||||
|
"testStrategy": "סקירת כל המסמכים לוידוא עדכון עקבי של רמת האוטומציה. בדיקת התאמה לדרישות הביקורת.",
|
||||||
|
"priority": "low",
|
||||||
|
"dependencies": [],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:04:33.967Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "69",
|
||||||
|
"title": "הגדרת סיעור מוחות כאופציונלי",
|
||||||
|
"description": "שינוי הגדרת סיעור המוחות לאופציונלי גם במקרים שיש נימוק קיים",
|
||||||
|
"details": "עדכון הלוגיקה כך שסיעור מוחות יהיה אופציונלי בכל המקרים, כולל כאשר קיים נימוק בסיסי. הוספת אפשרות למשתמש לבחור האם להפעיל סיעור מוחות או לדלג עליו. עדכון ממשק המשתמש והדרישות בהתאם.",
|
||||||
|
"testStrategy": "בדיקת התנהגות המערכת במקרים שונים של נוכחות או היעדר נימוק. וולידציה של חופש הבחירה של המשתמש.",
|
||||||
|
"priority": "low",
|
||||||
|
"dependencies": [
|
||||||
|
"68"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:04:33.969Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "70",
|
||||||
|
"title": "הוספת ניטרליות מבנית",
|
||||||
|
"description": "הרחבת דרישות הניטרליות מלקסיקלית למבנית",
|
||||||
|
"details": "הגדרת כללים לניטרליות מבנית בנוסף ללקסיקלית: סדר הצגת הטיעונים, אורך היחסי של סעיפים, מיקום המידע, ומבנה הפסיקה. פיתוח מנגנון בדיקה אוטומטית לזיהוי הטיה מבנית ואזהרות למשתמש. כולל הנחיות לכתיבה מאוזנת.",
|
||||||
|
"testStrategy": "ניתוח פסיקות לזיהוי דפוסי הטיה מבנית. בדיקת יעילות המנגנון בזיהוי וטיפול בהטיות.",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"57"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:04:33.973Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "71",
|
||||||
|
"title": "מיפוי פרסורמן 4 stages",
|
||||||
|
"description": "הרחבת המיפוי מ-LOA בלבד לכלל 4 השלבים של מודל פרסורמן",
|
||||||
|
"details": "מיפוי מלא של התהליך לפי 4 השלבים של פרסורמן: Information acquisition, Information analysis, Decision selection, Action implementation. הגדרת רמת האוטומציה לכל שלב בנפרד ולא רק LOA כללי. עדכון התיעוד והדרישות בהתאם.",
|
||||||
|
"testStrategy": "וולידציה של המיפוי מול מודל פרסורמן המקורי. בדיקת עקביות ההגדרות בין השלבים השונים.",
|
||||||
|
"priority": "low",
|
||||||
|
"dependencies": [
|
||||||
|
"68"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:04:33.976Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "72",
|
||||||
|
"title": "הגדרת דרישות ביצועים per-block וסינכרוני/אסינכרוני",
|
||||||
|
"description": "הגדרת דרישות ביצועים מפורטות לכל בלוק ובחירה בין עיבוד סינכרוני לאסינכרוני",
|
||||||
|
"details": "הגדרת SLA ספציפי לכל בלוק: זמני תגובה מקסימליים, throughput נדרש, ושיעור זמינות. החלטה על ארכיטקטורת עיבוד: סינכרונית לבלוקים קריטיים, אסינכרונית לבלוקים כבדים. יישום מנגנון ניטור ביצועים ואזהרות על חריגה מהסטנדרטים.",
|
||||||
|
"testStrategy": "בדיקות עומס לכל בלוק בנפרד. מדידת זמני תגובה ותפוקה בתנאים שונים. וולידציה של עמידה ב-SLA.",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"57"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-02T21:04:33.980Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "73",
|
||||||
|
"title": "הרחבת DB schema לתהליך מלא",
|
||||||
|
"description": "הוספת שדות וטבלאות חסרים לתמיכה בתהליך המלא של כתיבת החלטות משפטיות",
|
||||||
|
"details": "בקובץ db.py:\n1. הוספת שדות לטבלת decisions:\n - direction_doc JSONB - לשמירת מסמך הכיוון\n - outcome_reasoning TEXT - לנימוק התוצאה\n2. הרחבת enum של status בטבלת cases ל-13 ערכים:\n ['new', 'uploading', 'processing', 'documents_ready', 'outcome_set', 'brainstorming', 'direction_approved', 'drafting', 'qa_review', 'drafted', 'exported', 'reviewed', 'final']\n3. יצירת טבלת qa_results חדשה:\n - id SERIAL PRIMARY KEY\n - case_number VARCHAR REFERENCES cases\n - validation_type VARCHAR\n - passed BOOLEAN\n - errors JSONB\n - created_at TIMESTAMP\n4. יישום כ-migration עם Alembic",
|
||||||
|
"testStrategy": "1. בדיקת migration up/down\n2. וידוא שכל השדות החדשים נוצרו\n3. בדיקת constraints ו-foreign keys\n4. בדיקת ערכי enum החדשים\n5. בדיקת insert/update על השדות החדשים",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T08:54:55.256Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "74",
|
||||||
|
"title": "הוספת 5 API endpoints חדשים ב-MCP server",
|
||||||
|
"description": "יצירת endpoints חדשים לתמיכה בתהליך כתיבת ההחלטות",
|
||||||
|
"details": "בקובץ server.py או בקבצי API:\n1. POST /api/cases/{case_number}/outcome\n - קבלת: {outcome: string, reasoning: string}\n - שמירה ב-DB\n - עדכון סטטוס ל-outcome_set\n2. GET /api/cases/{case_number}/claims\n - החזרת טענות מחולצות מה-JSONB\n3. POST /api/cases/{case_number}/direction\n - קבלת מסמך כיוון כ-JSON\n - שמירה בשדה direction_doc\n - עדכון סטטוס ל-direction_approved\n4. POST /api/cases/{case_number}/qa\n - הרצת בדיקות QA\n - שמירה בטבלת qa_results\n - החזרת תוצאות\n5. POST /api/cases/{case_number}/learn\n - הפעלת לולאת למידה\n - עדכון מודלים/פרמטרים",
|
||||||
|
"testStrategy": "1. בדיקת כל endpoint עם Postman/pytest\n2. בדיקת validations על הקלט\n3. בדיקת error handling\n4. בדיקת עדכוני סטטוס\n5. בדיקת permissions/auth",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"73"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T08:55:56.839Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "75",
|
||||||
|
"title": "הוספת 8 tools חדשים לפלאגין Paperclip",
|
||||||
|
"description": "הרחבת הפלאגין עם כלים חדשים לאינטראקציה עם המערכת המשפטית",
|
||||||
|
"details": "1. בקובץ src/worker.ts - הוספת 8 tools:\n - legal_document_upload: העלאת מסמך\n - legal_document_list: רשימת מסמכים\n - legal_document_text: קריאת טקסט ממסמך\n - legal_search_case: חיפוש תיק\n - legal_find_similar: מציאת תקדימים\n - legal_set_outcome: הגדרת תוצאה\n - legal_get_claims: קבלת טענות\n - legal_style_guide: קבלת הנחיות סגנון\n\n2. בקובץ src/legal-api.ts - יישום 8 methods:\n ```typescript\n async uploadDocument(caseNumber: string, file: File) {...}\n async listDocuments(caseNumber: string) {...}\n async getDocumentText(docId: string) {...}\n async searchCase(query: string) {...}\n async findSimilar(caseNumber: string) {...}\n async setOutcome(caseNumber: string, outcome: string, reasoning: string) {...}\n async getClaims(caseNumber: string) {...}\n async getStyleGuide() {...}\n ```\n\n3. בקובץ plugin.json - עדכון manifest",
|
||||||
|
"testStrategy": "1. בדיקת כל tool בנפרד\n2. בדיקת error handling\n3. בדיקת response format\n4. בדיקת אינטגרציה עם Claude\n5. בדיקת performance",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"74"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T08:59:27.838Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "76",
|
||||||
|
"title": "שיפור status sync ב-Paperclip",
|
||||||
|
"description": "מיפוי מלא של 13 סטטוסים והוספת comments מפורטים",
|
||||||
|
"details": "1. עדכון מיפוי סטטוסים:\n ```javascript\n const statusMapping = {\n 'new': 'תיק חדש',\n 'uploading': 'העלאת מסמכים',\n 'processing': 'עיבוד מסמכים',\n 'documents_ready': 'מסמכים מוכנים',\n 'outcome_set': 'תוצאה הוגדרה',\n 'brainstorming': 'גיבוש כיוון',\n 'direction_approved': 'כיוון אושר',\n 'drafting': 'כתיבת החלטה',\n 'qa_review': 'בדיקת איכות',\n 'drafted': 'טיוטה מוכנה',\n 'exported': 'יוצאה ל-DOCX',\n 'reviewed': 'נבדקה ע\"י עו\"ד',\n 'final': 'סופית'\n }\n ```\n\n2. הוספת comments אוטומטיים ב-Paperclip:\n - בכל מעבר סטטוס\n - עם timestamp\n - עם פירוט הפעולה\n\n3. עדכון job sync-case-status",
|
||||||
|
"testStrategy": "1. בדיקת כל מעבר סטטוס\n2. וידוא comments נוצרים\n3. בדיקת sync דו-כיווני\n4. בדיקת edge cases\n5. בדיקת performance עם הרבה עדכונים",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"73"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T09:00:19.243Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "77",
|
||||||
|
"title": "כתיבת SOUL.md לסוכנים",
|
||||||
|
"description": "יצירת קבצי הנחיות לסוכני AI בעברית",
|
||||||
|
"details": "1. CEO Agent SOUL.md:\n ```markdown\n # CEO Agent - סוכן מנהל\n \n ## תפקיד\n ניהול תהליך כתיבת החלטה משפטית מקצה לקצה\n \n ## הנחיות\n - עבוד בעברית תמיד\n - נהל את התהליך לפי 13 הסטטוסים\n - התרע לחיים במקרים: תקלה טכנית, החלטה מורכבת, חריגה מזמנים\n - וודא שכל שלב הושלם לפני מעבר לבא\n \n ## מיפוי סטטוסים\n [רשימת 13 סטטוסים עם הסבר לכל אחד]\n ```\n\n2. Case Analyst Agent SOUL.md:\n ```markdown\n # Case Analyst - סוכן מנתח\n \n ## תפקיד\n ניתוח מסמכים משפטיים וחילוץ מידע\n \n ## הנחיות\n - נתח מסמכים בעברית\n - חלץ טענות מרכזיות\n - זהה תקדימים רלוונטיים\n - סכם עובדות מהותיות\n ```",
|
||||||
|
"testStrategy": "1. בדיקת קריאות והבנה\n2. בדיקת שהסוכנים פועלים לפי ההנחיות\n3. בדיקת תגובות בעברית\n4. בדיקת זיהוי מצבי התראה\n5. בדיקת מעברי סטטוס",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T08:57:14.984Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "78",
|
||||||
|
"title": "יישום skill /brainstorm",
|
||||||
|
"description": "יצירת skill לגיבוש כיוון ההחלטה בשיתוף עם המשתמש",
|
||||||
|
"details": "בקובץ skills/brainstorm.ts:\n```typescript\nexport async function brainstorm(caseNumber: string) {\n // שלב 1: הצגת טענות מרכזיות\n const claims = await api.getClaims(caseNumber);\n displayClaims(claims);\n \n // שלב 2: הצעת 2-3 כיוונים\n const directions = generateDirections(claims);\n displayDirections(directions);\n \n // שלב 3: דיון אינטראקטיבי\n let approved = false;\n while (!approved) {\n const feedback = await getUserFeedback();\n if (feedback.type === 'approve') {\n approved = true;\n } else {\n directions = refineDirections(directions, feedback);\n }\n }\n \n // שלב 4: יצירת מסמך כיוון\n const directionDoc = {\n mainDirection: directions.selected,\n keyPoints: directions.keyPoints,\n precedents: directions.precedents,\n approvedBy: 'user',\n timestamp: new Date()\n };\n \n // שלב 5: שמירה ועדכון סטטוס\n await api.saveDirection(caseNumber, directionDoc);\n}\n```",
|
||||||
|
"testStrategy": "1. בדיקת תצוגת טענות\n2. בדיקת יצירת כיוונים\n3. בדיקת אינטראקציה\n4. בדיקת שמירת מסמך כיוון\n5. בדיקת חסימה - אין התקדמות בלי אישור",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"74"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T10:16:24.667Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "79",
|
||||||
|
"title": "שיפור skill /draft-decision לכתיבה בלוק-אחרי-בלוק",
|
||||||
|
"description": "שדרוג מ-stub לכתיבה מלאה עם 12 בלוקים",
|
||||||
|
"details": "בקובץ skills/draft-decision.ts:\n```typescript\nconst BLOCKS = [\n {id: 'ה', name: 'כותרת', temperature: 0.3},\n {id: 'ו', name: 'פתיח', temperature: 0.5},\n {id: 'ז', name: 'רקע', temperature: 0.4},\n {id: 'ח', name: 'טענות הצדדים', temperature: 0.3},\n {id: 'ט', name: 'תמצית', temperature: 0.6},\n {id: 'י', name: 'דיון והכרעה', temperature: 0.7, model: 'opus'},\n {id: 'יא', name: 'סוף דבר', temperature: 0.5}\n];\n\nexport async function draftDecision(caseNumber: string) {\n const direction = await api.getDirection(caseNumber);\n const lastBlock = await getLastCompletedBlock(caseNumber);\n \n for (let i = getBlockIndex(lastBlock) + 1; i < BLOCKS.length; i++) {\n const block = BLOCKS[i];\n \n // כתיבת בלוק\n const content = await writeBlock(block, {\n direction,\n previousBlocks: await getPreviousBlocks(caseNumber, i),\n temperature: block.temperature,\n model: block.model || 'default'\n });\n \n // שמירה מיידית\n await saveBlock(caseNumber, block.id, content);\n \n // בלוק י - CREAC + thinking\n if (block.id === 'י') {\n await applyCREAC(content);\n await addThinkingTags(content);\n }\n }\n}\n\n// Recovery function\nexport async function recoverDraft(caseNumber: string) {\n const lastBlock = await getLastCompletedBlock(caseNumber);\n return draftDecision(caseNumber); // ממשיך מאיפה שנפל\n}\n```",
|
||||||
|
"testStrategy": "1. בדיקת כתיבה רציפה של כל הבלוקים\n2. בדיקת recovery אחרי נפילה\n3. בדיקת CREAC בבלוק י\n4. בדיקת שמירה אחרי כל בלוק\n5. בדיקת פרמטרים שונים לכל בלוק",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"78",
|
||||||
|
"73"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T10:16:24.670Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "80",
|
||||||
|
"title": "יישום skill /qa-validate",
|
||||||
|
"description": "בדיקות איכות אוטומטיות על ההחלטה",
|
||||||
|
"details": "בקובץ skills/qa-validate.ts:\n```typescript\nexport async function qaValidate(caseNumber: string) {\n const decision = await api.getDecision(caseNumber);\n const documents = await api.getDocuments(caseNumber);\n const claims = await api.getClaims(caseNumber);\n \n const checks = [\n {\n name: 'grounding_check',\n fn: () => validateGrounding(decision, documents),\n critical: true\n },\n {\n name: 'claims_coverage',\n fn: () => validateClaimsCoverage(decision, claims),\n critical: true\n },\n {\n name: 'neutral_background',\n fn: () => validateNeutrality(decision.background),\n critical: false\n },\n {\n name: 'weights_range',\n fn: () => validateWeightsInRange(decision),\n critical: true\n },\n {\n name: 'sequential_numbering',\n fn: () => validateNumbering(decision),\n critical: false\n },\n {\n name: 'definitions',\n fn: () => validateDefinitions(decision),\n critical: false\n }\n ];\n \n const results = [];\n let hasErrors = false;\n \n for (const check of checks) {\n const result = await check.fn();\n results.push({...result, name: check.name});\n if (!result.passed && check.critical) {\n hasErrors = true;\n }\n }\n \n // שמירת תוצאות\n await api.saveQAResults(caseNumber, results);\n \n // חסימת ייצוא אם יש שגיאות קריטיות\n if (hasErrors) {\n await api.blockExport(caseNumber);\n throw new Error('QA failed - export blocked');\n }\n \n return results;\n}\n```",
|
||||||
|
"testStrategy": "1. בדיקת כל validation בנפרד\n2. בדיקת חסימת ייצוא\n3. בדיקת דוח שגיאות מפורט\n4. בדיקת false positives\n5. בדיקת performance",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"79"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T10:16:24.673Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "81",
|
||||||
|
"title": "אינטגרציה E2E וחיבור Paperclip events",
|
||||||
|
"description": "חיבור מלא בין Paperclip ל-Claude Code עם trigger אוטומטי",
|
||||||
|
"details": "1. חיבור Paperclip events:\n```javascript\n// בקובץ paperclip-integration.js\npaperclip.on('issue.comment.created', async (event) => {\n if (event.comment.includes('/draft')) {\n await claudeCode.trigger('draft-decision', {\n caseNumber: event.issue.number\n });\n }\n});\n```\n\n2. E2E test על תיק הכט:\n```javascript\ntest('full flow - Hecht case', async () => {\n // העלאת חומרים\n await uploadDocuments('hecht', ['doc1.pdf', 'doc2.pdf']);\n \n // הזנת תוצאה\n await setOutcome('hecht', 'rejected', 'אין עילה');\n \n // כתיבה\n await triggerDraft('hecht');\n await waitForStatus('drafted');\n \n // QA\n const qaResults = await runQA('hecht');\n expect(qaResults.passed).toBe(true);\n \n // ייצוא\n const docx = await exportToDocx('hecht');\n \n // השוואה\n const similarity = await compareToFinal(docx, 'hecht-final.docx');\n expect(similarity).toBeGreaterThan(0.9);\n});\n```",
|
||||||
|
"testStrategy": "1. בדיקת trigger מ-Paperclip\n2. בדיקת flow מלא על תיק אמיתי\n3. בדיקת error handling\n4. בדיקת recovery\n5. השוואה להחלטה סופית",
|
||||||
|
"priority": "medium",
|
||||||
|
"dependencies": [
|
||||||
|
"75",
|
||||||
|
"76",
|
||||||
|
"77",
|
||||||
|
"78",
|
||||||
|
"79",
|
||||||
|
"80"
|
||||||
|
],
|
||||||
|
"status": "deferred",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T10:19:26.776Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "82",
|
||||||
|
"title": "מבחן הסמכה",
|
||||||
|
"description": "בדיקת המערכת על תיק עם החלטה קיימת והשוואת איכות",
|
||||||
|
"details": "שלב ב - בדיקה על תיק עם החלטה:\n```javascript\nexport async function certificationTest() {\n // בחירת תיק עם החלטה סופית\n const testCase = await selectTestCase();\n \n // הסתרת ההחלטה המקורית\n await hideOriginalDecision(testCase.number);\n \n // הרצת המערכת\n await runFullFlow(testCase.number);\n \n // השוואה\n const draft = await getDecision(testCase.number);\n const original = testCase.originalDecision;\n \n const comparison = {\n structure: compareStructure(draft, original),\n content: compareContent(draft, original),\n reasoning: compareReasoning(draft, original),\n outcome: compareOutcome(draft, original)\n };\n \n // חישוב ציון כולל\n const score = calculateScore(comparison);\n \n // בדיקת סף - 90%\n if (score < 0.9) {\n throw new Error(`Score ${score} is below threshold`);\n }\n \n return {score, comparison};\n}\n\n// שלב ג - תיק חי\nexport async function liveTest() {\n const liveCase = await getLiveCase();\n await runFullFlow(liveCase.number);\n \n // שליחה לדפנה לבדיקה\n await sendForReview('dafna@law.firm', liveCase.number);\n}\n```",
|
||||||
|
"testStrategy": "1. בדיקת בחירת תיק מתאים\n2. בדיקת הסתרת החלטה מקורית\n3. בדיקת אלגוריתם השוואה\n4. בדיקת חישוב ציון\n5. בדיקת תהליך review עם דפנה",
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": [
|
||||||
|
"81"
|
||||||
|
],
|
||||||
|
"status": "deferred",
|
||||||
|
"subtasks": [],
|
||||||
|
"updatedAt": "2026-04-03T10:19:26.779Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lastModified": "2026-04-04T07:50:59.999Z",
|
||||||
|
"taskCount": 51,
|
||||||
|
"completedCount": 49,
|
||||||
|
"tags": [
|
||||||
|
"master"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
| Redis | תור משימות | `legal-ai-redis` |
|
| Redis | תור משימות | `legal-ai-redis` |
|
||||||
| n8n | אוטומציית workflows | להגדרה |
|
| n8n | אוטומציית workflows | להגדרה |
|
||||||
| Gitea | מאגר קוד | `gitea.nautilus.marcusgroup.org/ezer-mishpati` |
|
| Gitea | מאגר קוד | `gitea.nautilus.marcusgroup.org/ezer-mishpati` |
|
||||||
| ezer-mishpati-web | ממשק העלאת מסמכים | `upload.nautilus.marcusgroup.org` |
|
| ezer-mishpati-web | ממשק העלאת מסמכים | `legal-ai.nautilus.marcusgroup.org` |
|
||||||
| Infisical | ניהול סודות | `secret.dev.marcus-law.co.il` |
|
| Infisical | ניהול סודות | `secret.dev.marcus-law.co.il` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
38
TASKS.md
Normal file
38
TASKS.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# משימות הקמת המערכת
|
||||||
|
|
||||||
|
## שלב 1: תשתית (Infrastructure)
|
||||||
|
- [x] יצירת סכמת DB ב-PostgreSQL (4 שכבות, 16 טבלאות) ✅ 2026-03-31
|
||||||
|
- [x] אימות pgvector עם embedding — 323 embeddings קיימים, Voyage API מוגדר ✅ 2026-03-31
|
||||||
|
- [ ] הגדרת Gitea repository לקוד הפרויקט
|
||||||
|
- [ ] הגדרת n8n עם workflow בסיסי
|
||||||
|
|
||||||
|
## שלב 2: ייבוא ידע (Knowledge Transfer)
|
||||||
|
- [x] ייבוא lessons_learned — 15 לקחים מ-3 תיקים ✅ 2026-03-31
|
||||||
|
- [x] ייבוא transition_phrases — 44 ביטויי מעבר ✅ 2026-03-31
|
||||||
|
- [x] ייבוא case_law — 9 תקדימים ✅ 2026-03-31
|
||||||
|
- [x] ייבוא statutory_provisions — 7 הוראות חוק ✅ 2026-03-31
|
||||||
|
|
||||||
|
## שלב 3: ייבוא תיקים (Appeals Import)
|
||||||
|
- [x] ייבוא מטאדטה של עררים — 19 תיקים (3 פעילים, 16 ארכיון) ✅ 2026-03-31
|
||||||
|
- [ ] ייבוא קטלוג מסמכים (נתיבים, סוגים, תאריכים)
|
||||||
|
- [ ] ייבוא טענות (לפי צד, לפי ערר)
|
||||||
|
- [ ] ייבוא בלוקי החלטה (לתיקים שהושלמו: הכט, בית הכרם)
|
||||||
|
|
||||||
|
## שלב 4: RAG & Embeddings
|
||||||
|
- [x] בחירת מודל embedding — Voyage voyage-3-large (dim=1024) ✅ כבר מוגדר
|
||||||
|
- [x] יצירת chunks ממסמכי אימון — 323 chunks מ-4 החלטות ✅ כבר קיים
|
||||||
|
- [ ] הפקת embeddings לפסיקה חדשה ב-case_law
|
||||||
|
- [ ] בניית חיפוש סמנטי לפסיקה
|
||||||
|
- [ ] בניית חיפוש סמנטי להחלטות תקדימיות
|
||||||
|
|
||||||
|
## שלב 5: אוטומציה (n8n)
|
||||||
|
- [ ] workflow: העלאת מסמך → סיווג → אחסון ב-DB
|
||||||
|
- [ ] workflow: ערר חדש → יצירת מבנה → DOCX
|
||||||
|
- [ ] workflow: חיפוש תקדימים → RAG → תוצאות
|
||||||
|
- [ ] workflow: בדיקת טיוטה מול block-schema
|
||||||
|
|
||||||
|
## שלב 6: ממשק משתמש
|
||||||
|
- [ ] הרחבת ezer-mishpati-web עם ניהול תיקים
|
||||||
|
- [ ] ממשק כתיבת החלטה
|
||||||
|
- [ ] ממשק חיפוש תקדימים
|
||||||
|
- [ ] דשבורד מעקב סטטוס תיקים
|
||||||
82
docs/architecture.md
Normal file
82
docs/architecture.md
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# System Architecture — Legal Decision Assistant
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────┐
|
||||||
|
│ Nautilus Server │
|
||||||
|
│ 158.178.131.193 │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
|
||||||
|
│ │ Coolify │ │ Traefik │ │ ezer-mishpati-web│ │
|
||||||
|
│ │ (manage) │ │ (proxy) │ │ (upload UI) │ │
|
||||||
|
│ └──────────┘ └──────────┘ └──────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────────────┐ ┌──────────────────────────┐ │
|
||||||
|
│ │ PostgreSQL │ │ Redis │ │
|
||||||
|
│ │ + pgvector │ │ (task queue) │ │
|
||||||
|
│ │ (legal-ai-postgres│ │ (legal-ai-redis) │ │
|
||||||
|
│ └──────────────────┘ └──────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────┐ ┌──────────┐ │
|
||||||
|
│ │ Gitea │ │ n8n │ │
|
||||||
|
│ │ (code) │ │ (automate│ │
|
||||||
|
│ └──────────┘ └──────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────────────────────────────────────────┐ │
|
||||||
|
│ │ Claude Code (via SSH or API) │ │
|
||||||
|
│ │ — Skills: legal-decision, legal-docx │ │
|
||||||
|
│ │ — MCP: postgres, n8n, cloudflare, chrome │ │
|
||||||
|
│ └──────────────────────────────────────────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
External:
|
||||||
|
← Claude API (embeddings, analysis)
|
||||||
|
← Cloudflare DNS (*.nautilus.marcusgroup.org)
|
||||||
|
← User (Putty SSH / Browser)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Document Upload
|
||||||
|
User → ezer-mishpati-web → file storage → n8n trigger
|
||||||
|
→ classify document → store metadata in PostgreSQL
|
||||||
|
→ generate embeddings → store in pgvector
|
||||||
|
|
||||||
|
2. Decision Writing
|
||||||
|
Claude Code → read source materials from DB
|
||||||
|
→ generate structure DOCX (12 blocks)
|
||||||
|
→ write each block with appropriate model/parameters
|
||||||
|
→ validate against block-schema
|
||||||
|
→ export final DOCX
|
||||||
|
|
||||||
|
3. Precedent Search (RAG)
|
||||||
|
Query → generate embedding → pgvector similarity search
|
||||||
|
→ return relevant paragraphs/decisions
|
||||||
|
→ Claude analyzes relevance → present to user
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database Schema — 4 Layers
|
||||||
|
|
||||||
|
### Layer 1: Core
|
||||||
|
appeals, parties, panels, documents
|
||||||
|
|
||||||
|
### Layer 2: Decision
|
||||||
|
decisions, decision_blocks, decision_paragraphs, claims
|
||||||
|
|
||||||
|
### Layer 3: Legal Knowledge
|
||||||
|
case_law, case_law_citations, statutory_provisions, transition_phrases, lessons_learned
|
||||||
|
|
||||||
|
### Layer 4: Semantic Search (RAG)
|
||||||
|
document_embeddings, paragraph_embeddings, case_law_embeddings
|
||||||
|
(all using pgvector vector(1536) columns)
|
||||||
|
|
||||||
|
## Technology Choices
|
||||||
|
- **Database**: PostgreSQL 15 + pgvector 0.8.1
|
||||||
|
- **Embedding model**: TBD (Claude/OpenAI ada-002/local)
|
||||||
|
- **Automation**: n8n (workflow engine)
|
||||||
|
- **Code repository**: Gitea (self-hosted)
|
||||||
|
- **Deployment**: Coolify (Docker management)
|
||||||
|
- **Proxy**: Traefik v3.6 (auto-SSL)
|
||||||
|
- **Frontend**: ezer-mishpati-web (static HTML + API)
|
||||||
125
docs/audit-report.md
Normal file
125
docs/audit-report.md
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
# דוח ביקורת תיקים — עוזר משפטי
|
||||||
|
**תאריך:** 2 באפריל 2026
|
||||||
|
**סורק:** Claude Code + סריקה אוטומטית של legacy vault
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סיכום כללי
|
||||||
|
|
||||||
|
| נתון | ערך |
|
||||||
|
|------|-----|
|
||||||
|
| סה"כ תיקים | 19 |
|
||||||
|
| תיקים בארכיון | 16 |
|
||||||
|
| תיקים פעילים | 3 |
|
||||||
|
| סה"כ קבצים (ארכיון) | 319~ |
|
||||||
|
| סה"כ קבצים (פעילים) | 125~ |
|
||||||
|
| תיקים עם החלטה סופית | 6 |
|
||||||
|
| תיקים עם טיוטה בלבד | 5 |
|
||||||
|
| תיקים ללא החלטה | 8 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סטטוס תיקים
|
||||||
|
|
||||||
|
### תיקים עם החלטה סופית (6)
|
||||||
|
|
||||||
|
| תיק | מספר | סוג | תוצאה | קבצים |
|
||||||
|
|-----|------|-----|-------|-------|
|
||||||
|
| הכט | 1180-1181 | רישוי | דחייה | 12 |
|
||||||
|
| אפרים אבי | 8255-25 | היטל השבחה | דחייה | 17 |
|
||||||
|
| עומר דרוויש | 8007-24 | היטל השבחה | — | 17 |
|
||||||
|
| אייל מבורך | 1113/25 | רישוי | — | 18 |
|
||||||
|
| שטרית | 1128/25 | רישוי | — | 26 |
|
||||||
|
| קרית יערים-2 | 1194/25+1199/25 | רישוי | — | 32 |
|
||||||
|
|
||||||
|
### תיקים עם טיוטה בלבד (5)
|
||||||
|
|
||||||
|
| תיק | מספר | סוג | הערות | קבצים |
|
||||||
|
|-----|------|-----|-------|-------|
|
||||||
|
| בית הכרם | 1126/25+1141/25 | תמ"א 38 | טיוטה 9 (סופית למעשה) | 31 |
|
||||||
|
| אזורים | 8141-23 | היטל השבחה | טיוטה | 8 |
|
||||||
|
| אבו זאהריה | 8107-25 | היטל השבחה | טיוטה | 32 |
|
||||||
|
| רמת שלמה | 9005-24 | פיצויים ס' 197 | טיוטות | 35 |
|
||||||
|
| קרית יערים-1 | 1130/25 | רישוי | טיוטת מבנה | 70+ |
|
||||||
|
|
||||||
|
### תיקים ללא החלטה (8)
|
||||||
|
|
||||||
|
| תיק | מספר | סוג | קבצים |
|
||||||
|
|-----|------|-----|-------|
|
||||||
|
| משכן אליהו | 8047-24 | היטל השבחה | 15 |
|
||||||
|
| ערר 8070-25 | 8070-25 | היטל השבחה | 24 |
|
||||||
|
| מרפסות שירות | 8136-24 | היטל השבחה | 13 |
|
||||||
|
| רישוי 1184-25 | 1184/25 | רישוי | 8 |
|
||||||
|
| ערר 1195-25 | 1195-25 | רישוי | 6 |
|
||||||
|
| ערר 1200-25 | 1200/25 | רישוי | 6 |
|
||||||
|
| בלוי | 1107/06/25 | תמ"א 38 | 25 |
|
||||||
|
| תחכמוני | 8027-25 | היטל השבחה | 23 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## התפלגות לפי סוג ערר
|
||||||
|
|
||||||
|
| סוג | כמות | עם החלטה | ללא החלטה |
|
||||||
|
|-----|------|---------|----------|
|
||||||
|
| רישוי ובנייה (1xxx) | 9 | 4 | 5 |
|
||||||
|
| היטל השבחה (8xxx) | 8 | 2 | 6 |
|
||||||
|
| תמ"א 38 | 2 | 0 | 2 |
|
||||||
|
| פיצויים ס' 197 (9xxx) | 1 | 0 | 1 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## התפלגות סוגי מסמכים (ארכיון)
|
||||||
|
|
||||||
|
| סוג מסמך | כמות | הערות |
|
||||||
|
|----------|------|-------|
|
||||||
|
| החלטות (סופיות + ביניים + טיוטות) | 70~ | כולל כל הגרסאות |
|
||||||
|
| כתבי ערר | 49~ | חלקם כפולים (PDF + MD) |
|
||||||
|
| כתבי תשובה / תגובות | 47~ | כולל השלמות טיעון |
|
||||||
|
| פרוטוקולים ותמלולים | 23~ | ועדה מקומית + ערר |
|
||||||
|
| שומות | 17~ | בעיקר תיקי היטל השבחה |
|
||||||
|
| חוות דעת מומחים | 5~ | אדריכל, מהנדס, רעש |
|
||||||
|
| תכניות | 1~ | — |
|
||||||
|
| הגשות | 2~ | — |
|
||||||
|
| אחר (ניתוחים, קטלוגים, MD) | 106~ | — |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## פערים שזוהו
|
||||||
|
|
||||||
|
### פערים קריטיים
|
||||||
|
1. **בית הכרם** — מסווג כ"טיוטה" אבל למעשה טיוטה 9 היא הגרסה הסופית. צריך לעדכן סטטוס ל-final
|
||||||
|
2. **קרית יערים-2** — יש החלטה מוגמרת ב-01_Projects אבל לא ב-04_Archive. צריך לוודא שזו הגרסה הסופית
|
||||||
|
|
||||||
|
### פערים במטאדטה
|
||||||
|
3. **הכט, הכרם** — חסרים שמות צדדים ב-DB (appellants/respondents ריקים)
|
||||||
|
4. **8 תיקים** — חסרים תאריכי דיון (hearing_date) ותאריכי החלטה (decision_date)
|
||||||
|
5. **כל התיקים** — חסר permit_number
|
||||||
|
|
||||||
|
### כפילויות
|
||||||
|
6. **רוב המסמכים קיימים בשני פורמטים** — PDF + MD. ה-MD הוא טקסט מחולץ. עדיף לייבא את שני הפורמטים: PDF כקובץ מקורי, MD כטקסט מחולץ מוכן
|
||||||
|
|
||||||
|
### מסמכים גדולים (דורשים תשומת לב ב-OCR)
|
||||||
|
7. כתב ערר אזורים 8141-23 — 9.2MB
|
||||||
|
8. כתב ערר מבורך 1113-25 — 9.3MB
|
||||||
|
9. כתב ערר קובר (קרית יערים-1) — 8.6MB
|
||||||
|
10. חוות דעת אדריכל רמת שלמה — 7.4MB
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## המלצות לשלב הבא
|
||||||
|
|
||||||
|
### עדיפות ראשונה — תיקים עם החלטה סופית
|
||||||
|
לייבא קודם את 6 התיקים עם החלטות סופיות + בית הכרם (טיוטה 9):
|
||||||
|
1. הכט 1180-1181
|
||||||
|
2. בית הכרם 1126/25
|
||||||
|
3. אפרים אבי 8255-25
|
||||||
|
4. עומר דרוויש 8007-24
|
||||||
|
5. אייל מבורך 1113/25
|
||||||
|
6. שטרית 1128/25
|
||||||
|
7. קרית יערים-2 1194/25+1199/25
|
||||||
|
|
||||||
|
### עדיפות שנייה — ניצול קבצי MD
|
||||||
|
רוב המסמכים כבר מחולצים ל-Markdown. זה חוסך OCR — אפשר לייבא את ה-MD ישירות כ-extracted_text
|
||||||
|
|
||||||
|
### עדיפות שלישית — עדכון מטאדטה
|
||||||
|
להשלים שמות צדדים, תאריכים, ומספרי היתר לכל 19 התיקים
|
||||||
574
docs/block-schema.md
Normal file
574
docs/block-schema.md
Normal file
@@ -0,0 +1,574 @@
|
|||||||
|
# Block Schema — ארכיטקטורת מסמך החלטת ועדת ערר
|
||||||
|
|
||||||
|
מסמך זה מגדיר את המבנה הפורמלי של החלטת ועדת ערר לתכנון ובניה. הוא משמש כמקור סמכותי להגדרת בלוקים, משקלות, פרמטרי עיבוד, וכללי ולידציה.
|
||||||
|
|
||||||
|
**הפניה:** SKILL.md סעיפים 11-12 מכילים סיכום מהיר והנחיות תהליך. מסמך זה מכיל את ההגדרות המלאות.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. יסודות תיאורטיים
|
||||||
|
|
||||||
|
ארכיטקטורת המסמך מבוססת על שילוב של ארבעה frameworks מוכרים:
|
||||||
|
|
||||||
|
### CREAC — מתודולוגיית כתיבה משפטית
|
||||||
|
Conclusion → Rule → Explanation → Application → Conclusion.
|
||||||
|
מקור: Columbia Law School, Legal Writing methodology.
|
||||||
|
**מיפוי:** חל על בלוק י (דיון) ובלוק יא (סיכום). בלוק י פותח במסקנה (C), מציג כלל משפטי (R), מסביר באמצעות פסיקה (E), מיישם על העובדות (A), וחוזר למסקנה (C). בלוק יא = C אחרון בלבד.
|
||||||
|
|
||||||
|
### Federal Judicial Center — Judicial Writing Manual
|
||||||
|
מגדיר תפקוד פונקציונלי לכל חלק בהחלטה שיפוטית:
|
||||||
|
- **Orientation** (אוריינטציה) — מי, מה, איפה → בלוקים א-ה
|
||||||
|
- **Framing** (מסגור) — הקשר עובדתי ותכנוני → בלוק ו
|
||||||
|
- **Argumentation** (טיעון) — עמדות הצדדים → בלוק ז
|
||||||
|
- **Procedural record** (תיעוד הליכי) — מה עשינו → בלוק ח
|
||||||
|
- **Deliberation** (דיון) — ניתוח משפטי → בלוקים ט-י
|
||||||
|
- **Disposition** (החלטה) — תוצאה אופרטיבית → בלוק יא
|
||||||
|
|
||||||
|
### DITA — Darwin Information Typing Architecture
|
||||||
|
סטנדרט OASIS להגדרת סוגי תוכן מובנים. מספק:
|
||||||
|
- **Content model** — אילו אלמנטים מותרים בכל בלוק
|
||||||
|
- **Constraints** — מה אסור (חשוב יותר ממה שמותר)
|
||||||
|
- **Specialization** — ירושה מסוג בסיסי עם התאמות
|
||||||
|
- **Relationships** — תלויות בין בלוקים
|
||||||
|
|
||||||
|
### Akoma Ntoso / LegalDocumentML
|
||||||
|
סטנדרט OASIS בינלאומי למסמכים משפטיים מובנים (UN/DESA). מספק:
|
||||||
|
- **Semantic mapping** — כל בלוק ממופה לרכיב מוכר בסטנדרט
|
||||||
|
- **Document class** — "judgment" (פסק דין / החלטה)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. הגדרות בלוקים
|
||||||
|
|
||||||
|
### Block א: כותרת מוסדית / Institutional Header
|
||||||
|
|
||||||
|
**ID:** `block-alef`
|
||||||
|
**Akoma Ntoso:** `meta > identification`
|
||||||
|
**CREAC role:** none
|
||||||
|
**Functional purpose (JWM):** Orientation — מזהה את המוסד, התיק והגורם המחליט.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: template-field
|
||||||
|
- Elements: טבלה 2 טורים (מוסד | מספרי תיק)
|
||||||
|
- Sources: מערכת ניהול תיקים
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: שם מוסד, מספר תיק, מספר תכנית/בקשה
|
||||||
|
- MUST NOT: תוכן מהותי כלשהו
|
||||||
|
- Dependencies: none
|
||||||
|
|
||||||
|
**Weight:** 1% (קבוע, לא משתנה בין סוגי עררים)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: template-fill
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: min | Model: script
|
||||||
|
|
||||||
|
|
||||||
|
### Block ב: הרכב הוועדה / Panel Composition
|
||||||
|
|
||||||
|
**ID:** `block-bet`
|
||||||
|
**Akoma Ntoso:** `meta > references > TLCPerson`
|
||||||
|
**CREAC role:** none
|
||||||
|
**Functional purpose (JWM):** Orientation — מזהה את ההרכב המחליט. חשוב לביקורת שיפוטית (הרכב כשיר).
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: template-field
|
||||||
|
- Elements: "בפני:" + יו"ר + חברים
|
||||||
|
- Sources: מערכת ניהול
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: יו"ר + לפחות חבר אחד
|
||||||
|
- MUST NOT: תוכן מהותי
|
||||||
|
- Dependencies: none
|
||||||
|
|
||||||
|
**Weight:** 1% (קבוע)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: template-fill
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: min | Model: script
|
||||||
|
|
||||||
|
|
||||||
|
### Block ג: צדדים / Parties
|
||||||
|
|
||||||
|
**ID:** `block-gimel`
|
||||||
|
**Akoma Ntoso:** `meta > references > TLCPerson` (appellants, respondents)
|
||||||
|
**CREAC role:** none
|
||||||
|
**Functional purpose (JWM):** Orientation — מזהה את הצדדים וב"כ. מגדיר את מסגרת הדיון.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: template-field
|
||||||
|
- Elements: עוררים + "נגד" + משיבים + ב"כ
|
||||||
|
- Sources: כתב ערר, כתב תשובה
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: שם כל צד, "נגד" כמפריד
|
||||||
|
- MUST NOT: תוכן מהותי, תיאור הערר
|
||||||
|
- Dependencies: none
|
||||||
|
|
||||||
|
**Weight:** 1% (קבוע)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: template-fill
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: min | Model: script
|
||||||
|
|
||||||
|
|
||||||
|
### Block ד: כותרת "החלטה" / Decision Title
|
||||||
|
|
||||||
|
**ID:** `block-dalet`
|
||||||
|
**Akoma Ntoso:** `body > judgment > header`
|
||||||
|
**CREAC role:** none
|
||||||
|
**Functional purpose (JWM):** Orientation — סימון פורמלי של תחילת ההחלטה.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: template-field
|
||||||
|
- Elements: מילה אחת: "החלטה"
|
||||||
|
- Sources: none
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: David 16pt, bold, מרכז
|
||||||
|
- Dependencies: none
|
||||||
|
|
||||||
|
**Weight:** 0% (שורה אחת)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: template-fill
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: min | Model: script
|
||||||
|
|
||||||
|
|
||||||
|
### Block ה: פתיחה / Opening
|
||||||
|
|
||||||
|
**ID:** `block-he`
|
||||||
|
**Akoma Ntoso:** `body > judgment > introduction`
|
||||||
|
**CREAC role:** C (מסקנה ראשונית — הצגת מה לפנינו)
|
||||||
|
**Functional purpose (JWM):** Orientation — מכוון את הקורא למהות הערר במשפט אחד. מגדיר "להלן" מרכזיים.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative (1-2 סעיפים)
|
||||||
|
- Elements: numbered-para עם הגדרות "להלן"
|
||||||
|
- Sources: כתב ערר, החלטת ועדה מקומית
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: "לפנינו...", הגדרת הוועדה המקומית, הגדרת התכנית/הבקשה, הגדרת המגרש
|
||||||
|
- MUST NOT: ניתוח, ערכי שיפוט, ציטוטים מצדדים
|
||||||
|
- Dependencies: block-gimel (שמות צדדים להגדרות)
|
||||||
|
|
||||||
|
**Weight:** 1% (קבוע — 1-2 סעיפים)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: paraphrase
|
||||||
|
- Temperature: 0.2 | Thinking: low | Effort: low | Model: sonnet
|
||||||
|
|
||||||
|
|
||||||
|
### Block ו: רקע עובדתי / Factual Background ("פתח דבר")
|
||||||
|
|
||||||
|
**ID:** `block-vav`
|
||||||
|
**Akoma Ntoso:** `body > judgment > background`
|
||||||
|
**CREAC role:** none (עובדות בלבד, לא ניתוח)
|
||||||
|
**Functional purpose (JWM):** Framing — מספק את התשתית העובדתית שעליה נבנה הדיון. השופט חייב להבין את המציאות בשטח לפני שקורא טענות.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative, citation-block, image-placeholder
|
||||||
|
- Elements: numbered-para, blockquote (ציטוט מפרוטוקול), image-box
|
||||||
|
- Sources: כתבי טענות, תשריטים, פרוטוקולים, החלטות קודמות, GIS
|
||||||
|
|
||||||
|
**סדר תוכן פנימי:**
|
||||||
|
1. מקרקעין — מיקום, שטח, מאפיינים
|
||||||
|
2. סביבת מקרקעין — בנייה סמוכה, אופי
|
||||||
|
3. 📷 תמונה: מיקום GIS
|
||||||
|
4. היסטוריה תכנונית — תכניות, החלטות (עובדות יבשות בלבד)
|
||||||
|
5. מהות הבקשה/תכנית
|
||||||
|
6. 📷 תמונה: תשריט
|
||||||
|
7. ציטוט מפרוטוקול ועדה מקומית
|
||||||
|
8. החלטת הוועדה + תנאים
|
||||||
|
9. 📷 תמונה: צילום אוויר (אופציונלי)
|
||||||
|
10. הגשת הערר
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: מקרקעין, מהות הבקשה, החלטת הוועדה, הגשת הערר
|
||||||
|
- MUST: לפחות 2 תמונות (מיקום + תשריט)
|
||||||
|
- MUST: ציטוט מפרוטוקול הוועדה המקומית
|
||||||
|
- ⚠️ **MUST NOT ("רקע ניטרלי"):** ציטוטים ישירים מצדדים, מילות ערך/שיפוט ("חריג", "חטא", "בעייתי"). החלטות קודמות = עובדה יבשה ("ביום X נדחתה תכנית Y"), ללא נימוקים וציטוטים מהן.
|
||||||
|
- Dependencies: block-he (הגדרות "להלן")
|
||||||
|
|
||||||
|
**Weight:**
|
||||||
|
|
||||||
|
| סוג ערר | משקל | הערות |
|
||||||
|
|---------|------|-------|
|
||||||
|
| רישוי — דחייה | 15-25% | רקע מפורט עם הקשר תכנוני |
|
||||||
|
| רישוי — קבלה | 30-40% | כולל ציטוט מפרוטוקול |
|
||||||
|
| רישוי — קבלה חלקית | 25-35% | כולל ציטוט מפרוטוקול |
|
||||||
|
| היטל השבחה | 6-18% | רקע מצומצם |
|
||||||
|
|
||||||
|
**Weight methodology:**
|
||||||
|
- Communicative weight (40%): גבוה — מספק את "התמונה" לשופט שלא מכיר את התיק
|
||||||
|
- Reader attention (20%): בינוני-גבוה — primacy effect, הקורא קשוב בהתחלה
|
||||||
|
- Judicial review (25%): גבוה — שופט בודק שהעובדות מלאות ומדויקות
|
||||||
|
- Empirical (15%): מבוסס על מדידת החלטות דפנה (3.2 ב-SKILL.md)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: reproduction (העתקה נאמנה ממקורות)
|
||||||
|
- Cognitive complexity: lookup (ארגון, לא ניתוח)
|
||||||
|
- Accuracy: high-precision
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: low | Model: sonnet
|
||||||
|
|
||||||
|
|
||||||
|
### Block ז: טענות הצדדים / Parties' Claims
|
||||||
|
|
||||||
|
**ID:** `block-zayin`
|
||||||
|
**Akoma Ntoso:** `body > judgment > arguments`
|
||||||
|
**CREAC role:** none (הצגת טענות, לא ניתוח)
|
||||||
|
**Functional purpose (JWM):** Argumentation — מציג את עמדות הצדדים בנאמנות, כך שהקורא יבין את המחלוקת לפני שקורא את ההכרעה.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative
|
||||||
|
- Elements: section-heading ("תמצית טענות הצדדים"), sub-headings (לכל צד), numbered-para
|
||||||
|
- Sources: כתב ערר, כתב תשובה — **כתבי טענות מקוריים בלבד** (לא השלמות טיעון)
|
||||||
|
|
||||||
|
**סדר קבוע:**
|
||||||
|
1. כותרת: "תמצית טענות הצדדים"
|
||||||
|
2. "טענות העוררים" (אם כמה עוררים — תתי-כותרות לכל אחד)
|
||||||
|
3. "עמדת הוועדה המקומית"
|
||||||
|
4. "עמדת מבקשי ההיתר" / "עמדת מגישי התכנית"
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: כל טענה בסעיף נפרד, גוף שלישי ("העורר טוען כי...")
|
||||||
|
- MUST: כל צד בפרק נפרד, סדר קבוע
|
||||||
|
- MUST NOT: ניתוח, מסקנות, הערכת הוועדה ("טענה זו חלשה...")
|
||||||
|
- MUST NOT: תוכן מהשלמות טיעון (→ block-chet)
|
||||||
|
- Dependencies: block-vav (מספור רציף)
|
||||||
|
|
||||||
|
**Weight:**
|
||||||
|
|
||||||
|
| סוג ערר | משקל | הערות |
|
||||||
|
|---------|------|-------|
|
||||||
|
| רישוי — דחייה | 30-40% | טענות מפורטות |
|
||||||
|
| רישוי — קבלה | 20-30% | כולל השלמות |
|
||||||
|
| רישוי — קבלה חלקית | 25-30% | |
|
||||||
|
| היטל השבחה | 13-25% | |
|
||||||
|
|
||||||
|
**Weight methodology:**
|
||||||
|
- Communicative weight (40%): בינוני — הצגה, לא הכרעה
|
||||||
|
- Reader attention (20%): נמוך-בינוני — scanning attention, הקורא מחפש טענות ספציפיות
|
||||||
|
- Judicial review (25%): גבוה — שופט בודק ש"נשמעו כל הצדדים"
|
||||||
|
- Empirical (15%): מבוסס על מדידת החלטות דפנה
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: paraphrase (סיכום נאמן בשפה של דפנה)
|
||||||
|
- Cognitive complexity: medium-synthesis (קיבוץ וסידור טענות)
|
||||||
|
- Accuracy: high-precision (לא לפספס טענה, לא לעוות)
|
||||||
|
- Temperature: 0.1 | Thinking: low | Effort: medium | Model: sonnet
|
||||||
|
|
||||||
|
|
||||||
|
### Block ח: הליכים בפני ועדת הערר / Proceedings
|
||||||
|
|
||||||
|
**ID:** `block-chet`
|
||||||
|
**Akoma Ntoso:** `body > judgment > proceedings` (custom extension)
|
||||||
|
**CREAC role:** none (תיעוד, לא ניתוח)
|
||||||
|
**Functional purpose (JWM):** Procedural record — מתעד שהוועדה פעלה כדין ונתנה מלוא יום בבית דין. קריטי ל"מבחן השופט" — שופט בעתמ"ם בודק שהצדדים קיבלו הזדמנות הוגנת.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative, image-placeholder
|
||||||
|
- Elements: section-heading ("ההליכים בפני ועדת הערר"), numbered-para, image-box
|
||||||
|
- Sources: פרוטוקול דיון, תמונות סיור, החלטות ביניים, השלמות טיעון
|
||||||
|
|
||||||
|
**סדר כרונולוגי:**
|
||||||
|
1. דיון — תאריך, נוכחים
|
||||||
|
2. סיור — תאריך, תיאור
|
||||||
|
3. 📷 תמונה: צילומים מהסיור
|
||||||
|
4. השלמות טיעון — עם תוכן מפורט (כל השלמה = סעיף נפרד)
|
||||||
|
5. החלטות ביניים
|
||||||
|
6. תגובות לתגובות — כרונולוגי
|
||||||
|
7. 📷 תמונה: הדמיות/חתכים (אם צורפו)
|
||||||
|
8. עררים מקבילים (אם יש)
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: תאריכים מדויקים, כרונולוגיה ברורה
|
||||||
|
- MUST: תוכן השלמות טיעון מפורט — כל השלמה בסעיף נפרד עם תמצית תוכן
|
||||||
|
- MUST NOT: ניתוח או הערכה של ההשלמות ("טענה חזקה/חלשה")
|
||||||
|
- Dependencies: block-zayin (מספור רציף)
|
||||||
|
- References: block-zayin (הפניה לטענות מקוריות כשיש חפיפה)
|
||||||
|
|
||||||
|
**Weight:**
|
||||||
|
|
||||||
|
| סוג ערר | משקל | הערות |
|
||||||
|
|---------|------|-------|
|
||||||
|
| ערר פשוט (ללא השלמות) | 3-5% | דיון + סיור בלבד |
|
||||||
|
| ערר מורכב (השלמות רבות) | 8-15% | כמו אריאלי: 31 סעיפים |
|
||||||
|
| היטל השבחה | 2-4% | בדרך כלל מינימלי |
|
||||||
|
|
||||||
|
**Weight methodology:**
|
||||||
|
- Communicative weight (40%): נמוך-בינוני — תיעוד, לא הכרעה
|
||||||
|
- Reader attention (20%): נמוך — scanning, אלא אם יש ממצאים חדשים מסיור/השלמות
|
||||||
|
- Judicial review (25%): **גבוה מאוד** — שופט בודק שנתנו procedural fairness
|
||||||
|
- Empirical (15%): מגוון רחב — תלוי בכמות ההשלמות
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: reproduction + paraphrase (תאריכים מדויקים + תמצית תוכן)
|
||||||
|
- Cognitive complexity: low (סידור כרונולוגי)
|
||||||
|
- Accuracy: high-precision (תאריכים, שמות מסמכים)
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: low | Model: sonnet
|
||||||
|
|
||||||
|
|
||||||
|
### Block ט: תכניות חלות / Applicable Plans (אופציונלי)
|
||||||
|
|
||||||
|
**ID:** `block-tet`
|
||||||
|
**Akoma Ntoso:** `body > judgment > motivation > background` (extended)
|
||||||
|
**CREAC role:** R (Rule — הצגת הכללים המשפטיים/תכנוניים)
|
||||||
|
**Functional purpose (JWM):** Deliberation (preliminary) — מציג את המסגרת הנורמטיבית שלאורה ייבחנו הטענות. בלוק גשר בין עובדות לניתוח.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative, citation-block
|
||||||
|
- Elements: section-heading, numbered-para, blockquote (ציטוט מהוראות תכנית)
|
||||||
|
- Sources: הוראות תכנית (PDF), נספחי בינוי, החלטות מרכזות
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: ציטוט ישיר מהוראות תכנית עם הדגשת (bold) מילים מכריעות
|
||||||
|
- MUST NOT: ניתוח מעמיק (→ block-yod), הכרעה בין פרשנויות
|
||||||
|
- Dependencies: block-chet (מספור), block-vav (הגדרות תכניות)
|
||||||
|
- Condition: **אופציונלי** — רק כשיש מורכבות תכנונית (תכניות סותרות, תמ"א 38 + שימור, פרשנות)
|
||||||
|
|
||||||
|
**Weight:**
|
||||||
|
|
||||||
|
| מתי קיים | משקל |
|
||||||
|
|----------|------|
|
||||||
|
| תמ"א 38 + שימור | 8-12% |
|
||||||
|
| פרשנות תכנית | 5-10% |
|
||||||
|
| לא קיים | 0% |
|
||||||
|
|
||||||
|
**Weight methodology:**
|
||||||
|
- Communicative weight (40%): בינוני — הנחת תשתית נורמטיבית
|
||||||
|
- Reader attention (20%): נמוך — טכני, אלא אם פרשנות שנויה במחלוקת
|
||||||
|
- Judicial review (25%): בינוני — שופט בודק שהוועדה הבינה את הדין
|
||||||
|
- Empirical (15%): אריאלי — 14 סעיפים; בית הכרם — משולב בדיון
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: guided-synthesis (ציטוט + ניתוח ראשוני)
|
||||||
|
- Cognitive complexity: medium (פרשנות טקסט משפטי)
|
||||||
|
- Accuracy: precision + interpretation
|
||||||
|
- Temperature: 0.2 | Thinking: medium | Effort: medium | Model: opus
|
||||||
|
|
||||||
|
|
||||||
|
### Block י: דיון והכרעה / Discussion and Decision
|
||||||
|
|
||||||
|
**ID:** `block-yod`
|
||||||
|
**Akoma Ntoso:** `body > judgment > motivation`
|
||||||
|
**CREAC role:** **full-CREAC** — C (מסקנה בפתיחה) → R (כלל משפטי) → E (ציטוט פסיקה) → A (יישום על העובדות) → C (מסקנת ביניים)
|
||||||
|
**Functional purpose (JWM):** Deliberation — ליבת ההחלטה. כאן הוועדה מנתחת, מאזנת, ומכריעה. זהו ה-ratio decidendi.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative, citation-block, image-placeholder
|
||||||
|
- Elements: numbered-para (אסה רציפה ללא כותרות משנה), blockquote (ציטוטי פסיקה ותכנית), image-box
|
||||||
|
- Sources: **כל** הבלוקים הקודמים + פסיקה + skill
|
||||||
|
|
||||||
|
**מבנה פנימי (לפי סוג ערר — ראה SKILL.md סעיף 7.3):**
|
||||||
|
- דחייה: שכבות הגנה (concentric circles)
|
||||||
|
- קבלה: נימוק-נימוק
|
||||||
|
- קבלה חלקית: מיפוי מתחים + ניתוח נושאי
|
||||||
|
- היטל השבחה: פתיחה ישירה עם מסקנה
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: מסקנה בפתיחת הדיון (לא בסוף)
|
||||||
|
- MUST: מענה לכל טענה שהוצגה בבלוק ז
|
||||||
|
- MUST: ציטוט פסיקה בבלוקים ארוכים (200-600 מילים)
|
||||||
|
- ⚠️ **MUST NOT ("ללא כפילות"):** חזרה על עובדות/טענות מבלוקים קודמים. השתמש בהפניות: "כאמור בסעיף X לעיל", "כפי שפורט", "כפי שציינו"
|
||||||
|
- MUST NOT: כותרות משנה (חריג: נושאים נפרדים לחלוטין)
|
||||||
|
- Dependencies: **ALL** previous blocks (ה-ט)
|
||||||
|
|
||||||
|
**Weight:**
|
||||||
|
|
||||||
|
| סוג ערר | משקל | הערות |
|
||||||
|
|---------|------|-------|
|
||||||
|
| רישוי — דחייה | 37-50% | פתיחה רחבה + שכבות |
|
||||||
|
| רישוי — קבלה | 35-45% | נימוק-נימוק |
|
||||||
|
| רישוי — קבלה חלקית | 40-47% | מיפוי מתחים + ניתוח נושאי |
|
||||||
|
| היטל השבחה | 32-48% | ציטוטי פסיקה מרובים |
|
||||||
|
|
||||||
|
**Weight methodology:**
|
||||||
|
- Communicative weight (40%): **מקסימלי** — זהו ה-ratio decidendi, תכלית ההחלטה
|
||||||
|
- Reader attention (20%): **גבוה** — deep reading, הקורא מחפש את הנימוקים
|
||||||
|
- Judicial review (25%): **מקסימלי** — שופט בוחן סבירות, מידתיות, התייחסות לטענות
|
||||||
|
- Empirical (15%): 35-50% באופן עקבי בכל החלטות דפנה
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: **rhetorical-construction** (בניית טיעון, איזון, רטוריקה)
|
||||||
|
- Cognitive complexity: **high-reasoning** (CREAC מלא, שכבות, חידוד)
|
||||||
|
- Accuracy: **precision + creativity** (ניתוח מדויק + ביטוי אלגנטי)
|
||||||
|
- Temperature: **0.4** | Thinking: **max (budget 16K+)** | Effort: **max** | Model: **opus בלבד**
|
||||||
|
|
||||||
|
|
||||||
|
### Block יא: סיכום / סוף דבר / Summary
|
||||||
|
|
||||||
|
**ID:** `block-yod-alef`
|
||||||
|
**Akoma Ntoso:** `body > judgment > decision`
|
||||||
|
**CREAC role:** C (Conclusion אחרון — תמצית אופרטיבית)
|
||||||
|
**Functional purpose (JWM):** Disposition — ההוראה האופרטיבית שמבצעים. זה מה שהצדדים צריכים לדעת "מה עכשיו."
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative
|
||||||
|
- Elements: section-heading ("סיכום"/"סוף דבר"), numbered-para, sub-items (א. ב. ג.)
|
||||||
|
- Sources: block-yod (מסקנות)
|
||||||
|
|
||||||
|
**מבנה לפי תוצאה (ראה SKILL.md סעיף 8):**
|
||||||
|
- דחייה: "הערר נדחה" + תתי-סעיפים + פסקה חמה (רישוי בלבד)
|
||||||
|
- קבלה: "הערר מתקבל בכפוף ל..." + פרוזה
|
||||||
|
- קבלה חלקית: "הערר מתקבל באופן חלקי" + 2-3 הוראות אופרטיביות
|
||||||
|
- היטל השבחה: יבש
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: תוצאה ברורה (נדחה/מתקבל/מתקבל חלקית)
|
||||||
|
- MUST NOT (בקבלה חלקית): חזרה על נימוקים — ההנמקה כבר בדיון
|
||||||
|
- Dependencies: block-yod (מסקנות)
|
||||||
|
|
||||||
|
**Weight:**
|
||||||
|
|
||||||
|
| סוג ערר | משקל |
|
||||||
|
|---------|------|
|
||||||
|
| דחייה | 2-9% |
|
||||||
|
| קבלה | 3-5% |
|
||||||
|
| קבלה חלקית | 2-3% |
|
||||||
|
| היטל השבחה | 3-4% |
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: paraphrase (עיבוד מסקנות בלוק י)
|
||||||
|
- Cognitive complexity: low
|
||||||
|
- Accuracy: high-precision (הוראות חייבות להיות חד-משמעיות)
|
||||||
|
- Temperature: 0.1 | Thinking: low | Effort: low | Model: sonnet
|
||||||
|
|
||||||
|
|
||||||
|
### Block יב: חתימות / Signatures
|
||||||
|
|
||||||
|
**ID:** `block-yod-bet`
|
||||||
|
**Akoma Ntoso:** `conclusions > signature`
|
||||||
|
**CREAC role:** none
|
||||||
|
**Functional purpose (JWM):** Authentication — אישור פורמלי של ההחלטה.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: template-field
|
||||||
|
- Elements: "ניתנה פה אחד" + תאריך עברי/לועזי + טבלת חתימות
|
||||||
|
- Sources: none
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: "ניתנה פה אחד", תאריך, יו"ר + מזכיר/ה
|
||||||
|
- Dependencies: none
|
||||||
|
|
||||||
|
**Weight:** 1% (קבוע)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: template-fill
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: min | Model: script
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. כללי גזירת פרמטרים
|
||||||
|
|
||||||
|
פרמטרי העיבוד נגזרים ממאפייני התוכן, לא נקבעים שרירותית:
|
||||||
|
|
||||||
|
### Temperature — נגזר מסוג הייצור
|
||||||
|
|
||||||
|
| Generation type | Temperature | נימוק |
|
||||||
|
|----------------|-------------|-------|
|
||||||
|
| template-fill | 0 | אין צורך בשפה — מילוי שדות |
|
||||||
|
| reproduction | 0 | נאמנות מוחלטת למקור. אפס יצירתיות |
|
||||||
|
| paraphrase | 0.1 | מרווח מינימלי לניסוח בשפה של דפנה |
|
||||||
|
| guided-synthesis | 0.2 | גמישות בארגון וחיבור מקורות, לא בתוכן |
|
||||||
|
| analytical-reasoning | 0.3-0.4 | צריך ליצור קשרים בין עקרונות משפטיים |
|
||||||
|
| rhetorical-construction | 0.4-0.5 | טווח ביטוי רחב לכתיבה משכנעת ואלגנטית |
|
||||||
|
|
||||||
|
### Thinking budget — נגזר ממורכבות קוגניטיבית
|
||||||
|
|
||||||
|
| Cognitive task | Budget | נימוק |
|
||||||
|
|---------------|--------|-------|
|
||||||
|
| template-fill / lookup | off | אין צורך בחשיבה |
|
||||||
|
| sequential-extraction | low | חילוץ מידע חד-שלבי |
|
||||||
|
| multi-source-integration | medium | צריך להצליב מקורות |
|
||||||
|
| legal-analysis-with-CREAC | max (16K+) | חשיבה רב-שלבית: מסקנה → כלל → הסבר → יישום |
|
||||||
|
|
||||||
|
### Model — נגזר מדרישת דיוק
|
||||||
|
|
||||||
|
| Accuracy profile | Model | נימוק |
|
||||||
|
|-----------------|-------|-------|
|
||||||
|
| factual-precision | sonnet | מהיר, מדויק לחילוץ עובדות |
|
||||||
|
| precision + interpretation | opus | נדרש לפרשנות תכנית / ציטוט מובנה |
|
||||||
|
| precision + creativity | opus | נדרש לניתוח משפטי מורכב ורטוריקה |
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. מתודולוגיית משקלות
|
||||||
|
|
||||||
|
משקל כל בלוק נקבע על ידי שקלול 4 גורמים:
|
||||||
|
|
||||||
|
### 4.1 Communicative Weight (40%)
|
||||||
|
מה חלקו של הבלוק בתכלית ההחלטה? ההחלטה באה לעשות דבר אחד: להכריע במחלוקת ולנמק. בלוק י (דיון) הוא ליבת התכלית. בלוקים א-ד (כותרות) הם עטיפה.
|
||||||
|
|
||||||
|
### 4.2 Reader Attention Distribution (20%)
|
||||||
|
מבוסס על מחקרי F-pattern ו-primacy/recency:
|
||||||
|
- **פתיחה** (בלוקים ה-ו): קשב גבוה (primacy effect)
|
||||||
|
- **אמצע** (בלוקים ז-ח): scanning — הקורא מחפש טענות ספציפיות
|
||||||
|
- **דיון** (בלוק י): deep reading — הקורא מחפש נימוקים
|
||||||
|
- **סיום** (בלוק יא): קשב גבוה (recency effect)
|
||||||
|
|
||||||
|
### 4.3 Judicial Review Requirement (25%)
|
||||||
|
מה שופט בבית משפט לעניינים מנהליים יבדוק ("מבחן השופט"):
|
||||||
|
- **תשתית עובדתית** (בלוק ו): מלאה ומדויקת?
|
||||||
|
- **שמיעת צדדים** (בלוקים ז-ח): נתנו מלוא יום בבית דין?
|
||||||
|
- **סבירות ומידתיות** (בלוק י): ההכרעה מנומקת ומאוזנת?
|
||||||
|
- **התייחסות לטענות** (בלוק י): כל טענה קיבלה מענה?
|
||||||
|
|
||||||
|
### 4.4 Empirical Basis (15%)
|
||||||
|
מבוסס על מדידה מהחלטות שפורסמו:
|
||||||
|
- הכט 1180-1181 (דחייה, 02.2026)
|
||||||
|
- בית הכרם 1126/25 (קבלה חלקית, 03.2026)
|
||||||
|
- אריאלי 1078+1083 (קבלה, 03.2026)
|
||||||
|
|
||||||
|
המשקלות ב-SKILL.md סעיף 3.2 (יחסי הזהב) משמשים כבסיס אמפירי שאומת על ידי שלושת הגורמים האנליטיים.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. כללי ולידציה
|
||||||
|
|
||||||
|
### 5.1 סדר בלוקים
|
||||||
|
- בלוקים חייבים להופיע בסדר א עד יב
|
||||||
|
- בלוקים א-ה ויב נדרשים בכל החלטה
|
||||||
|
- בלוק ט אופציונלי (רק כשיש מורכבות תכנונית)
|
||||||
|
|
||||||
|
### 5.2 Content Constraints
|
||||||
|
- **רקע ניטרלי (בלוק ו):** אם סעיף מכיל ציטוט ישיר מצד או מילת שיפוט → לא שייך כאן
|
||||||
|
- **טענות מקוריות בלבד (בלוק ז):** רק מכתבי ערר/תשובה. השלמות → בלוק ח
|
||||||
|
- **ללא כפילות (בלוק י):** הפניה לבלוקים קודמים, לא חזרה. חריג: "נשוב על כך כי..." (חזרה מכוונת עם שכבה חדשה)
|
||||||
|
- **הליכים ללא הערכה (בלוק ח):** תיעוד מה הוגש, לא הערכה של חוזק הטענות
|
||||||
|
|
||||||
|
### 5.3 Weight Compliance
|
||||||
|
- משקל כל בלוק (ספירת מילים / סה"כ) צריך להיות בטווח המוגדר **±10%**
|
||||||
|
- אם בלוק י < 30% → flag: דיון לא מפותח מספיק
|
||||||
|
- אם בלוק ו > 35% → flag: רקע מנופח, בדוק שאין תוכן טענתי
|
||||||
|
|
||||||
|
### 5.4 Structural Integrity
|
||||||
|
- מספור סעיפים רציף מ-1 עד הסוף, ללא איפוס בין בלוקים
|
||||||
|
- כל הגדרת "להלן" חייבת להופיע לפני השימוש הראשון בה
|
||||||
|
- כל טענה בבלוק ז חייבת לקבל מענה בבלוק י (ישיר או "למעלה מן הצורך")
|
||||||
|
- כותרות פרקים: David 14pt, bold, קו תחתון, מרכז
|
||||||
|
- כותרות משנה: David 12pt, bold, מרכז, ללא קו תחתון
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. גרף תלויות בין בלוקים
|
||||||
|
|
||||||
|
```
|
||||||
|
א (כותרת) → עצמאי
|
||||||
|
ב (הרכב) → עצמאי
|
||||||
|
ג (צדדים) → עצמאי
|
||||||
|
ד (כותרת) → עצמאי
|
||||||
|
ה (פתיחה) → תלוי ב: ג (שמות צדדים להגדרות "להלן")
|
||||||
|
ו (רקע) → תלוי ב: ה (הגדרות). מספור ממשיך מ-ה.
|
||||||
|
ז (טענות) → תלוי ב: ו (מספור). מפנה ל: ה, ו (הגדרות)
|
||||||
|
ח (הליכים) → תלוי ב: ז (מספור). מפנה ל: ז (טענות מקוריות)
|
||||||
|
ט (תכניות) → תלוי ב: ח (מספור). אופציונלי. מפנה ל: ו (הגדרות תכניות)
|
||||||
|
י (דיון) → תלוי ב: **כל** הבלוקים ה-ט. מפנה ל: כולם.
|
||||||
|
יא (סיכום) → תלוי ב: י (מסקנות). מפנה ל: י בלבד.
|
||||||
|
יב (חתימות) → עצמאי
|
||||||
|
```
|
||||||
43
docs/case-migration-tracker.md
Normal file
43
docs/case-migration-tracker.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# מעקב העברת תיקים מ-Legacy למערכת החדשה
|
||||||
|
|
||||||
|
נוצר: 2026-04-04
|
||||||
|
|
||||||
|
## תיקים עם החלטה סופית
|
||||||
|
|
||||||
|
| # | מספר תיק | שם | סוג | חומרי מקור | הועבר? | הערות |
|
||||||
|
|---|----------|-----|------|------------|--------|-------|
|
||||||
|
| 1 | 1180-1181 | הכט | רישוי | ערר(2), תשובה(3), פרוטוקול(1) | V | |
|
||||||
|
| 2 | 1126-25 | בית הכרם תמ"א 38 | רישוי | ערר(4), תשובה(6), פרוטוקול(5) | V | |
|
||||||
|
| 3 | 8255-25 | אפרים אבי | בל"מ | ערר(1), תשובה(1), פסיקה(2) | | |
|
||||||
|
| 4 | 8047-24 | משכן אליהו | היטל השבחה | ערר(2), תשובה(2), פרוטוקול(2) | | |
|
||||||
|
| 5 | 8007-24 | עומר דרוויש | שומה מכריעת | ערר(2), תשובה(2), פרוטוקול(2) | | |
|
||||||
|
| 6 | 8141-23 | אזורים | היטל השבחה | ערר(1), תשובה(1), פרוטוקול(1) | | |
|
||||||
|
| 7 | 9005-24 | רמת שלמה | פיצויים | ערר(4), תשובה(4), פרוטוקול(2), חוו"ד(3), פסיקה(2) | | |
|
||||||
|
| 8 | 1113-25 | אייל מבורך | רישוי | פרוטוקול(2) | | |
|
||||||
|
| 9 | 1128-25 | שטרית | רישוי | ערר(1), תשובה(2), פרוטוקול(1), פסיקה(3) | | |
|
||||||
|
| 10 | 1130-25 | קרית יערים-1 | רישוי | ערר(4), תשובה(16), פרוטוקול(28) | | |
|
||||||
|
| 11 | 1194+1199 | קרית יערים-2 | רישוי | ערר(10), תשובה(8), פרוטוקול(7) | | |
|
||||||
|
| 12 | 1130-25 | ליבמן | רישוי | ערר(2), תשובה(6), פרוטוקול(4) | | |
|
||||||
|
|
||||||
|
## תיקים בטיוטה / בתהליך
|
||||||
|
|
||||||
|
| # | מספר תיק | שם | סוג | חומרי מקור | הועבר? | הערות |
|
||||||
|
|---|----------|-----|------|------------|--------|-------|
|
||||||
|
| 1 | 8107-25 | אבו זאהריה | היטל השבחה | ערר(6), תשובה(8), פרוטוקול(4) | | טיוטה + הערות נאוה |
|
||||||
|
| 2 | 8027-25 | תחכמוני 20 | היטל השבחה | ערר(7), תשובה(1), פרוטוקול(2) | | טיוטת DOCX + תכנון מפורט |
|
||||||
|
| 3 | 8070-25 | — | היטל השבחה | ערר(1), תשובה(2), פרוטוקול(2) | | |
|
||||||
|
| 4 | 8136-24 | מרפסות שירות | היטל השבחה | ערר(1), תשובה(1), פרוטוקול(1) | | |
|
||||||
|
| 5 | 1184-25 | — | רישוי | ערר(1), תשובה(2), פרוטוקול(1) | | |
|
||||||
|
| 6 | 1195-25 | — | רישוי | ערר(1), תשובה(2) | | |
|
||||||
|
| 7 | 1200-25 | — | רישוי | ערר(1), תשובה(2) | | |
|
||||||
|
| 8 | 1107-25 | בלוי | רישוי | ערר(2), תשובה(4), פרוטוקול(1), פסיקה(8) | | חומר פסיקתי עשיר |
|
||||||
|
|
||||||
|
## סיכום
|
||||||
|
|
||||||
|
| מדד | כמות |
|
||||||
|
|-----|------|
|
||||||
|
| סה"כ תיקים | 20 |
|
||||||
|
| עם החלטה סופית | 12 |
|
||||||
|
| בטיוטה/תהליך | 8 |
|
||||||
|
| הועברו | 2 |
|
||||||
|
| ממתינים | 18 |
|
||||||
148
docs/decision-block-mapping.md
Normal file
148
docs/decision-block-mapping.md
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
# מיפוי מדויק של 3 החלטות לבלוקים
|
||||||
|
|
||||||
|
**תאריך:** 2 באפריל 2026
|
||||||
|
**שיטה:** קריאה מלאה מילה-במילה עם אימות ספירת מילים
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. הכט 1180-1181 (דפנה תמיר, דחייה, רישוי)
|
||||||
|
|
||||||
|
**מקור:** data/training/היתר בניה-בית שמש-1180+1181-החלטה.docx
|
||||||
|
**שורות:** 105 | **מילים:** 4,433
|
||||||
|
|
||||||
|
| שורות | בלוק | תוכן | הערות |
|
||||||
|
|-------|------|------|-------|
|
||||||
|
| שורה 1 | ה — פתיחה | "לפנינו שני עררים..." הגדרות להלן | פתיחה קלאסית |
|
||||||
|
| שורות 2-11 | ו — רקע | הבניין, התכנית, הבקשה, חתימות, התנגדויות, תקנה 37 | רקע מינימלי ~470 מילים |
|
||||||
|
| שורה 12 | ז — כותרת | "תמצית טענות הצדדים" | — |
|
||||||
|
| שורות 13-24 | ז — טענות עוררים | 11 טענות: המצאה, לובי, זכויות, מדרגות, חניות, עץ, רוב, סדובסקי, חזרה מחתימה, הידברות | — |
|
||||||
|
| שורות 25-34 | ז — עמדת ועדה + משיבים | "עמדת המשיבים" → "הוועדה המקומית" (8 טענות): תואמת תכנית, רוב, היבטים תכנוניים, המצאה, חזרה, תכנית אושרה, חניות, עץ | — |
|
||||||
|
| שורות 35-46 | ז — מבקשי היתר | 11 טענות: המצאה, חתימות, לובי, רוב, תכנית, זכויות, חניות, עץ, הידברות | — |
|
||||||
|
| שורה 47 | י — כותרת | "דיון והכרעה" | — |
|
||||||
|
| שורות 48-96 | י — דיון | פתיחה עם מסקנה → ס' 152 → פסיקה (נגאח, הימנותא, דסטגר, קרן-נכסים) → סטייה מתכנית → מדרגות, דלת, עץ, חניות → סמכות ועדה מקומית → פנייה לעוררת | **אין בלוק ט נפרד** — ניתוח ס' 152 והפסיקה משולב בדיון |
|
||||||
|
| שורה 97 | יא — כותרת | "סיכום" | — |
|
||||||
|
| שורות 98-104 | יא — סיכום | 6 תתי-סעיפים אופרטיביים: אין זכות ערר, תואמת תכנית, אין סטיה, לא נפל פגם, טענות קנייניות, עץ | — |
|
||||||
|
| שורה 105 | יב — חתימות | "ניתנה פה אחד היום, כ"ב שבט תשפ"ו, 09 פברואר 2026" | — |
|
||||||
|
|
||||||
|
**בלוקים קיימים:** ה, ו, ז, י, יא, יב
|
||||||
|
**בלוקים חסרים:** ח (הליכים), ט (תכניות — משולב בדיון)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. בית הכרם 1126/25+1141/25 (דפנה תמיר, קבלה חלקית, רישוי)
|
||||||
|
|
||||||
|
**מקור:** data/uploads/ARAR-25-08-1126.docx (גרסה סופית מנבו)
|
||||||
|
**שורות:** 183 | **מילים:** 6,249
|
||||||
|
|
||||||
|
| שורות | בלוק | תוכן | הערות |
|
||||||
|
|-------|------|------|-------|
|
||||||
|
| שורות 1-7 | — מטא-דאטה נבו | ספרות, חקיקה שאוזכרה | **לא חלק מההחלטה** |
|
||||||
|
| שורה 8 | ה — פתיחה | "לפנינו שני עררים..." + הגדרות | — |
|
||||||
|
| שורה 9 | ו — כותרת | "רקע" | — |
|
||||||
|
| שורות 10-56 | ו — רקע | מקרקעין, תכניות (911, 10038, 16000), בקשה להיתר, החלטת ועדת משנה + התנגדויות (מצוטטות), תיקונים, שטחים, מרפסות, פיתוח, נגישות | רקע מפורט מאוד ~1,100 מילים. **כולל ציטוט מפרוטוקול ועדת המשנה** |
|
||||||
|
| שורות 57-59 | ח — הליכים | דיון 9.12.2025, החלטת ביניים, השלמת טיעון 3.2.2026 | **בלוק ח קיים!** אבל קצר (3 שורות). מופיע **לפני** הטענות |
|
||||||
|
| שורה 60 | ז — כותרת | "תמצית טענות הצדדים" | — |
|
||||||
|
| שורות 61-76 | ז — טענות עוררים | מרכז קהילתי (ראייה אזורית, חניה, עיר גנים), תושבים (פגמי פרסום, חריגת שטחים, ס' 6.5 תמ"א 38, שימור, עצים, בור מים, חניה, פרטיות) | — |
|
||||||
|
| שורות 77-84 | ז — עמדת ועדה מקומית | תואמת 10038, חניה (מגרש כלוא, כופר חניה), שטחים, שימור | — |
|
||||||
|
| שורות 85-91 | ז — מבקשי היתר | היקף 126%, תואמת, צמצום 42%, חניה, שימור, ראייה אזורית | — |
|
||||||
|
| שורה 92 | י — כותרת | "דיון והכרעה" | — |
|
||||||
|
| שורות 93-102 | י — **מיפוי מתחים** | 6 מתחים: בית בודד, מדיניות, שימור, קווי בניין, מגרש כלוא, חריג לסביבה | **פתיחה ייחודית לקבלה חלקית** |
|
||||||
|
| שורות 103-113 | י — ניתוח תכניות | 10038, 16000 (תכנית אב), 911, שימור, ס' 4.1.2.2(5), ס' 6.5.9 | **אין בלוק ט נפרד** — משולב בדיון |
|
||||||
|
| שורות 114-149 | י — ניתוח נושאי | חניה (5166ב, כופר, מגרש כלוא, רכבת קלה), קווי בניין (שימור vs מרחק), מטרדי בנייה (ערר 1192/18, ערר 1156/18), עצים, בור מים | — |
|
||||||
|
| שורות 150-177 | י — ציטוט ערר מובשוביץ + התחדשות עירונית | ציטוט נרחב (~400 מילים) מערר מובשוביץ, ספרות (גדרון ונמדר), פסיקה (לזובסקי, ערר 76/14) | — |
|
||||||
|
| שורה 178 | יא — כותרת | "סיכום" | — |
|
||||||
|
| שורות 179-181 | יא — סיכום | "מתקבל באופן חלקי" + 2 הוראות: בחינת מרווח, תכנית ארגון אתר | **סיכום מינימלי** — 88 מילים |
|
||||||
|
| שורות 182-183 | — מטא-דאטה נבו | "נוסח מסמך זה כפוף..." | **לא חלק מההחלטה** |
|
||||||
|
|
||||||
|
**בלוקים קיימים:** ה, ו, ח (קצר, לפני טענות), ז, י, יא
|
||||||
|
**בלוקים חסרים:** ט (משולב בדיון)
|
||||||
|
|
||||||
|
**ממצאים ייחודיים:**
|
||||||
|
- ח מופיע **לפני** ז (שונה מהכט ואריאלי)
|
||||||
|
- פתיחת דיון = "מיפוי מתחים" — 6 מתחים בתבליטים
|
||||||
|
- סיכום מינימלי — הוראות אופרטיביות בלבד
|
||||||
|
- ציטוט ארוך מערר מובשוביץ (~400 מילים)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. אריאלי 1078+1083/24 (שרית אריאלי, קבלה, רישוי)
|
||||||
|
|
||||||
|
**מקור:** data/uploads/ARAR-24-1078-44.docx (גרסה מנבו)
|
||||||
|
**שורות:** 171 | **מילים:** 10,748
|
||||||
|
|
||||||
|
| שורות | בלוק | תוכן | הערות |
|
||||||
|
|-------|------|------|-------|
|
||||||
|
| שורות 1-13 | א-ד — כותרת | הרכב, צדדים, חקיקה, "החלטה" | — |
|
||||||
|
| שורות 15-16 | ה — פתיחה | "עניינה של החלטה זו..." + הגדרות | **שונה מדפנה** — לא "לפנינו" |
|
||||||
|
| שורה 17 | ו — כותרת | **"פתח דבר"** | **כותרת ייחודית לאריאלי** |
|
||||||
|
| שורות 18-32 | ו — רקע | מקרקעין (מוסררה), היסטוריה תכנונית (2015, 2017, 2020, 2023), שימור (אתר 3890), סביבה (GIS), עוררים | רקע מפורט ~1,500 מילים |
|
||||||
|
| שורה 33 | ז — כותרת | "טענות הצדדים" | **לא** "תמצית טענות הצדדים" |
|
||||||
|
| שורות 34-39 | ז — עוררים 1083 | שימור, מסה, תמ"א 38, ועדת שימור, מרחב ציבורי | — |
|
||||||
|
| שורות 40-42 | ז — עורר 1078 | נוף להר הבית, גובה | — |
|
||||||
|
| שורות 43-49 | ז — ועדה מקומית | תואמת, שימור, חניה, מקלט | — |
|
||||||
|
| שורות 50-55 | ז — **עמדת ועדת שימור** | לא עקבית, שינוי עמדות | **צד נוסף** שלא קיים בדפנה |
|
||||||
|
| שורות 56-62 | ז — מבקש היתר | מגרש ייחודי, מרחקים, מקלט, סטודנטים | — |
|
||||||
|
| שורה 63 | ח — כותרת | **"ההליכים בפני וועדת הערר"** | — |
|
||||||
|
| שורות 64-66 | ח — דיון | דיון 10.11.2024, טענות, מבקש היתר | — |
|
||||||
|
| שורות 67-69 | ח — סיור | סיור 18.3.2025, אדריכלית דינור, תצפית | — |
|
||||||
|
| שורות 70-75 | ח — החלטת ביניים + עמדת שימור | חתכי בינוי, חלופה, עמדת שימור 31.12.2025 | — |
|
||||||
|
| שורות 76-86 | ח — השלמות טיעון | מבקש היתר 1.1.2026, השוואת בניינים ברחוב הע"ח, חלופה להנמכה, תגובת עוררים 12.1.26, עמדת שימור 1.2.26 | — |
|
||||||
|
| שורות 87-92 | ח — תגובות נוספות | תגובת עוררים להשלמה, עמדת שימור סופית | **ח = 30 שורות, ~2,900 מילים** |
|
||||||
|
| שורה 93 | ט — כותרת | **"התכניות החלות על המקרקעין"** | — |
|
||||||
|
| שורות 94-97 | ט — תכניות סטטוטוריות | 3188 (1985), 3188א (1993), 3188ב (1995) | — |
|
||||||
|
| שורות 98-104 | ט — ערר מעלומי | ציטוט נרחב מערר מעלומי על אופי שימורי | — |
|
||||||
|
| שורות 105-113 | ט — תמ"א 38 + 10038 + רבדים | סעיף 19, שלושה רבדים של שימור, שיקול דעת | **ט = 21 שורות, ~1,800 מילים** |
|
||||||
|
| שורה 114 | י — כותרת | **"דיון והכרעה:"** | נקודתיים בסוף — ייחודי |
|
||||||
|
| שורות 115-117 | י — מסקנה בפתיחה | "שוכנענו כי הבקשה מהווה בינוי מאסיבי..." | CREAC — מסקנה קודם |
|
||||||
|
| שורות 118-149 | י — ניתוח | אינטרס חיזוק, סבירות, חזית חמישית, דירוג, שימור חזיתות, ערר אדלר, מובשוביץ | — |
|
||||||
|
| שורות 150-157 | י — תקדים שלילי + דרך המלך | תכנית נקודתית, התנהלות גורמי מקצוע | — |
|
||||||
|
| שורות 158-164 | י — נושאים נוספים | נוף (עורר 1078), מקלט, זכות עמידה, פרסום | — |
|
||||||
|
| שורה 165 | יא — כותרת | **"סוף דבר"** | **לא** "סיכום" — שונה מדפנה |
|
||||||
|
| שורות 166-168 | יא — סיכום | "העררים מתקבלים" + הוראות: בקשה מתוקנת, גובה, קווי בניין, יח"ד | — |
|
||||||
|
| שורה 169 | יב — חתימות | "ניתנה פה אחד, ט"ו ניסן תשפ"ו, 02 אפריל 2026" | — |
|
||||||
|
| שורות 170-171 | — מטא-דאטה נבו | "נוסח מסמך זה כפוף..." | **לא חלק מההחלטה** |
|
||||||
|
|
||||||
|
**בלוקים קיימים:** ה, ו, ז, ח (מורחב — 30 שורות), ט (נפרד), י, יא, יב
|
||||||
|
**כל הבלוקים המהותיים קיימים — זו ההחלטה השלמה ביותר**
|
||||||
|
|
||||||
|
**ממצאים ייחודיים:**
|
||||||
|
- פתיחה "עניינה של החלטה זו" (לא "לפנינו")
|
||||||
|
- כותרת רקע "פתח דבר" (לא "רקע")
|
||||||
|
- כותרת טענות "טענות הצדדים" (לא "תמצית טענות הצדדים")
|
||||||
|
- כותרת סיכום "סוף דבר" (לא "סיכום")
|
||||||
|
- בלוק ח מורחב (30 שורות) — דיון + סיור + השלמות + תגובות
|
||||||
|
- בלוק ט נפרד — תכניות + רבדי שימור + תמ"א 38
|
||||||
|
- צד נוסף בטענות: "עמדת ועדת שימור"
|
||||||
|
- CREAC מפורש בדיון — מסקנה בפתיחה ("שוכנענו כי...")
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סיכום השוואתי
|
||||||
|
|
||||||
|
### סדר בלוקים
|
||||||
|
|
||||||
|
| בלוק | הכט (דחייה) | בית הכרם (חלקית) | אריאלי (קבלה) |
|
||||||
|
|------|------------|-----------------|---------------|
|
||||||
|
| ה — פתיחה | "לפנינו" | "לפנינו" | "עניינה של" |
|
||||||
|
| ו — רקע | "רקע" (אין כותרת) | "רקע" | "פתח דבר" |
|
||||||
|
| ח — הליכים | **לא קיים** | **לפני ז** (3 שורות) | **אחרי ז** (30 שורות) |
|
||||||
|
| ז — טענות | "תמצית טענות הצדדים" | "תמצית טענות הצדדים" | "טענות הצדדים" |
|
||||||
|
| ט — תכניות | **משולב בדיון** | **משולב בדיון** | **נפרד** |
|
||||||
|
| י — דיון | מסקנה → ס' 152 → פסיקה → יישום | מיפוי מתחים → ניתוח נושאי | CREAC מפורש |
|
||||||
|
| יא — סיכום | "סיכום" (6 סעיפים) | "סיכום" (2 הוראות) | "סוף דבר" (הוראות) |
|
||||||
|
|
||||||
|
### מה קובע אילו בלוקים קיימים
|
||||||
|
|
||||||
|
| בלוק | כלל | פירוט |
|
||||||
|
|------|-----|-------|
|
||||||
|
| ח — הליכים | **מותנה** — רק כשהיו הליכים מעבר לדיון פשוט | סיור = סמן חזק לבלוק ח מפורט. השלמות טיעון רבות / החלטות ביניים = בלוק ח קצר. דיון פשוט (הצדדים טענו ונגמר) = אין בלוק ח |
|
||||||
|
| ט — תכניות | **תמיד קיים** — רישום התכניות החלות הוא חובה | רישום התכניות: תמיד, כחלק מהרקע (ו) או כפרק נפרד. ניתוח התכניות: בדיון (י), רק כשרלוונטי. פרק ט נפרד רק כשהמורכבות התכנונית מצדיקה ניתוח מקדים (כמו באריאלי — 3 תכניות שימור + 3 רבדים) |
|
||||||
|
|
||||||
|
### מה צריך לתקן ב-parser
|
||||||
|
|
||||||
|
1. פתיחה: לזהות גם "עניינה של" ולא רק "לפנינו"
|
||||||
|
2. רקע: לזהות גם "פתח דבר" כנוסף ל-"רקע"
|
||||||
|
3. טענות: לזהות גם "טענות הצדדים" בלי "תמצית"
|
||||||
|
4. סיכום: לזהות גם "סוף דבר"
|
||||||
|
5. מטא-דאטה נבו: לסנן שורות 1-7 ו-182-183 של בית הכרם, 170-171 של אריאלי
|
||||||
|
6. ח לפני ז: בבית הכרם ח מופיע לפני ז — ה-parser צריך לתמוך בזה
|
||||||
50
docs/migration-plan.md
Normal file
50
docs/migration-plan.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Migration Plan — Dafna Vault → Nautilus
|
||||||
|
|
||||||
|
## Source
|
||||||
|
- Obsidian vault at `/opt/apps/vaults/dafna-tamir/`
|
||||||
|
- Claude memory at `/home/chaim/.claude/projects/-opt-apps-vaults-dafna-tamir/memory/`
|
||||||
|
- 229MB compressed (excluding node_modules, .git)
|
||||||
|
|
||||||
|
## Target
|
||||||
|
- PostgreSQL on Nautilus (legal-ai-postgres)
|
||||||
|
- File storage on Nautilus
|
||||||
|
- Gitea repository for code/scripts
|
||||||
|
|
||||||
|
## What to Migrate
|
||||||
|
|
||||||
|
### Knowledge (Priority 1 — enables RAG immediately)
|
||||||
|
| Source | Target Table | Records |
|
||||||
|
|--------|-------------|---------|
|
||||||
|
| memory/legal-decision-lessons.md | lessons_learned | ~12 lessons |
|
||||||
|
| SKILL.md section 5.2 | transition_phrases | ~30 phrases |
|
||||||
|
| Published decisions (citations) | case_law | ~20 cases |
|
||||||
|
| SKILL.md section 6.9 | statutory_provisions | ~10 statutes |
|
||||||
|
|
||||||
|
### Appeals (Priority 2)
|
||||||
|
| Source | Target Table | Records |
|
||||||
|
|--------|-------------|---------|
|
||||||
|
| 01_Projects/*/README.md | appeals | 3 active |
|
||||||
|
| 04_Archive/*/README.md | appeals | 14 archived |
|
||||||
|
| All case headers | parties | ~50 |
|
||||||
|
| All case headers | panels | ~17 |
|
||||||
|
|
||||||
|
### Documents (Priority 3)
|
||||||
|
| Source | Target Table | Records |
|
||||||
|
|--------|-------------|---------|
|
||||||
|
| */חומרי-מקור/**/*.pdf | documents | ~200 PDFs |
|
||||||
|
| */חומרי-מקור/**/*.md | documents | ~100 MDs |
|
||||||
|
| */החלטה/*.docx | documents | ~10 DOCXs |
|
||||||
|
|
||||||
|
### Decisions (Priority 4)
|
||||||
|
| Source | Target Table | Records |
|
||||||
|
|--------|-------------|---------|
|
||||||
|
| הכט published PDF | decisions + blocks + paragraphs | 1 complete |
|
||||||
|
| בית הכרם Draft 9 | decisions + blocks + paragraphs | 1 complete |
|
||||||
|
| קרית יערים draft | decisions + blocks | 1 in progress |
|
||||||
|
|
||||||
|
### Embeddings (Priority 5)
|
||||||
|
| Source | Target Table | Records |
|
||||||
|
|--------|-------------|---------|
|
||||||
|
| All MD source docs | document_embeddings | ~500 chunks |
|
||||||
|
| Decision paragraphs | paragraph_embeddings | ~300 paragraphs |
|
||||||
|
| Case law summaries | case_law_embeddings | ~20 summaries |
|
||||||
566
docs/product-specification.md
Normal file
566
docs/product-specification.md
Normal file
@@ -0,0 +1,566 @@
|
|||||||
|
# איפיון מוצר — עוזר משפטי
|
||||||
|
|
||||||
|
## מסמך זה
|
||||||
|
מסמך איפיון מוצר (Product Specification) למערכת "עוזר משפטי" — כלי AI לכתיבת החלטות ועדת ערר לתכנון ובניה.
|
||||||
|
|
||||||
|
**מצב:** הושלם — עבר סקירת מומחה ותוקן
|
||||||
|
**תאריך התחלה:** 2 באפריל 2026
|
||||||
|
**בעל המוצר:** חיים מרכוס
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סעיף 0: בחירת מתודולוגיית איפיון
|
||||||
|
|
||||||
|
### השאלה
|
||||||
|
מי המומחה המתאים להגדיר מוצר AI שמבצע עבודה מקצועית מורכבת (כתיבת החלטות משפטיות)?
|
||||||
|
|
||||||
|
### שתי הגישות
|
||||||
|
|
||||||
|
#### גישה א: מנהל מוצר (Product Manager)
|
||||||
|
**מתמחה ב:** הגדרת "מה" — user stories, features, prioritization, go-to-market.
|
||||||
|
**מתודולוגיות:** Lean Product, Jobs To Be Done (JTBD), Design Thinking.
|
||||||
|
**חוזק:** מתרגם צורך עסקי למפרט טכני. מגדיר MVP. מתעדף features.
|
||||||
|
**חולשה:** לא מתמחה בניתוח תהליכי עבודה מורכבים, לא מודד יעילות, לא מתכנן workflow אופטימלי.
|
||||||
|
|
||||||
|
#### גישה ב: מהנדס תעשייה וניהול (Industrial & Systems Engineer)
|
||||||
|
**מתמחה ב:** הגדרת "איך" — ניתוח תהליכים, מדידת זמנים, זיהוי צווארי בקבוק, אופטימיזציה.
|
||||||
|
**מתודולוגיות:** Systems Engineering (INCOSE SE Handbook), Business Process Modeling (BPMN), Value Stream Mapping, Human-Machine Teaming.
|
||||||
|
**חוזק:** מפרק תהליך מורכב לשלבים מדידים. מזהה איפה AI מוסיף ערך ואיפה לא. מתכנן ממשק אדם-מכונה. מודד KPIs.
|
||||||
|
**חולשה:** פחות מתמחה בחוויית משתמש (UX) ובתעדוף עסקי.
|
||||||
|
|
||||||
|
### ההמלצה: גישה משולבת עם דגש על הנדסת מערכות
|
||||||
|
|
||||||
|
**הנימוק:**
|
||||||
|
המוצר שלנו הוא לא אפליקציה צרכנית אלא **כלי עבודה מקצועי** שמחליף/מסייע בתהליך מורכב. הבעיה המרכזית היא לא "אילו features לבנות" אלא **"איך דפנה עובדת ואיפה AI נכנס לתהליך"**. זו בדיוק ההתמחות של הנדסת תעשייה ומערכות.
|
||||||
|
|
||||||
|
**סימוכין אקדמיים:**
|
||||||
|
|
||||||
|
1. **INCOSE Systems Engineering Handbook (2023, 5th ed.)** — מגדיר שכלי AI מקצועי דורש קודם כל "Operational Concept" — תיאור מלא של תהליך העבודה לפני ואחרי הכנסת המערכת (Chapter 4.2: Stakeholder Needs and Requirements).
|
||||||
|
|
||||||
|
2. **Parasuraman, R., Sheridan, T.B., & Wickens, C.D. (2000). "A Model for Types and Levels of Human Interaction with Automation."** IEEE Transactions on Systems, Man, and Cybernetics. — מגדיר 10 רמות אוטומציה (LOA) בין "האדם עושה הכל" ל-"המכונה עושה הכל". המפתח: לכל שלב בתהליך צריך להגדיר את רמת האוטומציה הנכונה. לא הכל צריך להיות אוטומטי.
|
||||||
|
|
||||||
|
3. **Daugherty, P.R. & Wilson, H.J. (2018). "Human + Machine: Reimagining Work in the Age of AI."** Harvard Business Review Press. — מגדיר מודל "collaborative intelligence" שבו AI ואדם משלימים זה את זה. רלוונטי כי דפנה לא רוצה שה-AI יחליף אותה — היא רוצה שיעזור לה.
|
||||||
|
|
||||||
|
4. **Endsley, M.R. (2017). "From Here to Autonomy: Lessons Learned from Human-Automation Research."** Human Factors. — מזהיר מ-"automation complacency" — כשאנשים סומכים יותר מדי על AI ומפסיקים לבדוק. קריטי בהקשר משפטי שבו דפנה חייבת לקרוא ולאשר כל מילה.
|
||||||
|
|
||||||
|
**מסקנה:** נשתמש בגישת **Systems Engineering** כמסגרת ראשית, עם רכיבים מ-Product Management לתעדוף ו-MVP.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## טבלת מעקב איפיון
|
||||||
|
|
||||||
|
| סעיף | נושא | סטטוס | הערות |
|
||||||
|
|------|------|-------|-------|
|
||||||
|
| סעיף 0 | בחירת מתודולוגיה | ✅ מלא | הנדסת מערכות + ניהול מוצר |
|
||||||
|
| סעיף 1 | חזון המוצר | ✅ מלא | בעיה, חזון, פתרון, משתמשים, מדדי הצלחה, scope |
|
||||||
|
| סעיף 2 | בעלי עניין | ✅ מלא | חיים (מפעיל), דפנה (מגיהה+חותמת), שופט (מבחן עליון), חברי ועדה, מזכירות, צדדים |
|
||||||
|
| סעיף 3 | תהליך עבודה נוכחי | ✅ מלא | נקודת כניסה, חומרים, תהליך, זמנים, צוואר בקבוק |
|
||||||
|
| סעיף 4 | תהליך עבודה עתידי | ✅ מלא | 7 שלבים: קלט → עיבוד → תוצאה → סיעור מוחות (אם צריך) → כתיבה → פלט → למידה |
|
||||||
|
| סעיף 5 | רמות אוטומציה | ✅ מלא | 3 רמות (אוטומטי/שיתופי/אנושי), מיפוי 11 שלבים, 7 עקרונות עיצוב, 4 סיכונים |
|
||||||
|
| סעיף 6 | דרישות פונקציונליות | ✅ מלא | 40 דרישות ב-8 שלבים (כולל שלב 6 הגהת דפנה), כולן מבוססות על סעיפים 1-5 |
|
||||||
|
| סעיף 7 | דרישות לא-פונקציונליות | ✅ מלא | 12 דרישות: שפה, ביצועים, דיוק, אבטחה, זמינות, ממשק |
|
||||||
|
| סעיף 8 | גרסה מינימלית (MVP) | ✅ מלא | אין MVP — מוצר מלא בלבד. תוכנית הסמכה ב-4 שלבים |
|
||||||
|
| סעיף 9 | מדדי הצלחה | ✅ מלא | 6 מדדים: אחוז שינוי, זמן, אפס הזיות, מענה לטענות, משקלות, ניטרליות |
|
||||||
|
| סעיף 10 | סיכונים ומגבלות | ✅ מלא | 10 סיכונים עם מנגנוני הגנה, 4 מגבלות ידועות |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סעיף 1: חזון המוצר (Product Vision)
|
||||||
|
|
||||||
|
### טבלת מעקב שאלות — סעיף 1
|
||||||
|
|
||||||
|
| שאלה | סטטוס | תשובה |
|
||||||
|
|------|-------|-------|
|
||||||
|
| מה הבעיה שהמוצר פותר? | ✅ מלא | חיים (עו"ד, עוזר משפטי של דפנה) לא מצליח להתאים את סגנון הכתיבה שלו לסגנון של דפנה. צריך כלי AI שכותב בדיוק כמו דפנה |
|
||||||
|
| מי המשתמש העיקרי? | ✅ מלא | חיים — מפעיל המערכת מהתחלה עד טיוטה סופית. דפנה רק מגיהה ומתקנת אחרי. הגרסה הסופית שדפנה מפיצה חוזרת למערכת ללמידה |
|
||||||
|
| מה התוצר הסופי שיוצא מהמערכת? | ✅ מלא | קובץ DOCX מעוצב, כמעט מוכן לחתימה. עיצוב עברי RTL עם כותרות — skill קיים לייצור DOCX. נדרשות התאמות קטנות |
|
||||||
|
| מה "הצלחה" נראית? | ✅ מלא | מצב תקין: דפנה משנה/מוסיפה עד 10% מהטקסט. הצלחה מלאה: 98% מהטקסט נשאר כמו שהמערכת כתבה |
|
||||||
|
| מה מחוץ ל-scope? | ✅ מלא | המערכת רק כותבת החלטות. לא ניהול תיקים, לא תזמון, לא מיילים. מקבלת קבצים (PDF/DOCX/MD) ומסתמכת **רק** על מה שקיבלה — אסור לה להמציא מקורות או לצטט דברים שלא במסמכים |
|
||||||
|
|
||||||
|
### הבעיה
|
||||||
|
דפנה תמיר, יו"ר ועדת ערר לתכנון ובניה מחוז ירושלים, נושאת עומס תיקים רב. חיים מרכוס הוא העוזר המשפטי שלה — עורך דין שמנסח עבורה טיוטות החלטות שדפנה עוברת עליהן, מתקנת, מגיהה ומתאימה לסגנונה לפני שהיא חותמת.
|
||||||
|
|
||||||
|
**הבעיה המרכזית:** לחיים יש סגנון כתיבה משפטי משלו שלא תואם את הסגנון הייחודי של דפנה. הפער בסגנון גורם לדפנה לבזבז זמן רב על תיקון והתאמה — בדיוק הזמן שהעוזר אמור לחסוך לה.
|
||||||
|
|
||||||
|
**מה שצריך:** כלי AI שמחליף את שלב הכתיבה הראשוני של חיים — כותב טיוטה ראשונית **בדיוק בסגנון של דפנה**, כך שדפנה מקבלת טיוטה שדורשת מינימום תיקונים.
|
||||||
|
|
||||||
|
**העיקרון:** מינימום זמן, מקסימום תוצר.
|
||||||
|
|
||||||
|
### משפט חזון
|
||||||
|
כלי AI שכותב טיוטות החלטות ועדת ערר **בדיוק בסגנון של דפנה תמיר** — מקבל חומרי מקור ומוציא DOCX מעוצב כמעט מוכן לחתימה, כך שדפנה צריכה לשנות מינימום.
|
||||||
|
|
||||||
|
### הפתרון
|
||||||
|
מערכת "עוזר משפטי" שמחליפה את שלב כתיבת הטיוטה הראשונית:
|
||||||
|
|
||||||
|
**קלט:** קבצים (PDF/DOCX/MD) מסוג כתבי בי-דין — ערר, תשובה, תגובה, פרוטוקול, תכנית, היתר, פסקי דין, החלטות.
|
||||||
|
|
||||||
|
**תהליך:** המערכת קוראת את החומר, מנתחת, ומנסחת החלטה בסגנון דפנה לפי ארכיטקטורת 12 בלוקים.
|
||||||
|
|
||||||
|
**פלט:** קובץ DOCX מעוצב — טיוטה כמעט מוכנה לחתימה.
|
||||||
|
|
||||||
|
**כלל ברזל:** המערכת מסתמכת **רק** על מסמכים שקיבלה בפועל. אסור לה להמציא מקורות, לצטט דברים שלא במסמכים, או להוסיף פסיקה שלא סופקה.
|
||||||
|
|
||||||
|
**לולאת למידה:** הגרסה הסופית שדפנה מפיצה (אחרי הגהה ותיקונים) חוזרת למערכת — כך המערכת לומדת מהפער בין הטיוטה שלה לגרסה הסופית ומשתפרת עם הזמן.
|
||||||
|
|
||||||
|
### משתמשים
|
||||||
|
- **משתמש ראשי:** חיים מרכוס (עו"ד, עוזר משפטי) — מפעיל את המערכת מהתחלה עד טיוטה סופית
|
||||||
|
- **משתמש עקיף:** דפנה תמיר (עו"ד, יו"ר ועדת ערר) — מקבלת את הטיוטה, מגיהה, מתקנת, חותמת
|
||||||
|
|
||||||
|
### מדדי הצלחה
|
||||||
|
- **מצב תקין (target):** דפנה משנה/מוסיפה עד 10% מהטקסט
|
||||||
|
- **הצלחה מלאה (stretch):** עד 5% שינוי
|
||||||
|
|
||||||
|
**הערה:** לפי מחקר Endsley (2017), מומחים בדרגת ההזדהות של דפנה כמעט תמיד ישנו ניסוחים — לא כי הם שגויים, אלא כי זו הדרך שלהם "לאמץ" את הטקסט. לכן יעד 2% לא ריאלי. יעד 5% מאפשר לדפנה מרחב אישי תוך שמירה על יעילות גבוהה. המדד יתכייל לאחר 5 החלטות ראשונות.
|
||||||
|
|
||||||
|
### מחוץ ל-scope
|
||||||
|
- ניהול תיקים, תזמון דיונים, שליחת מיילים
|
||||||
|
- חיפוש פסיקה באינטרנט — רק מה שסופק כמסמך
|
||||||
|
- החלטה אוטונומית — דפנה תמיד קוראת, מגיהה וחותמת
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סעיף 2: בעלי עניין (Stakeholders)
|
||||||
|
|
||||||
|
### טבלת מעקב שאלות — סעיף 2
|
||||||
|
|
||||||
|
| שאלה | סטטוס | תשובה |
|
||||||
|
|------|-------|-------|
|
||||||
|
| מי מעורב בתהליך מלבד חיים ודפנה? | ✅ מלא | השופט — בעל עניין שקט. כל החלטה עלולה לעמוד לביקורת שיפוטית בעתמ"ם ובעליון |
|
||||||
|
| מה השופט בודק? | ✅ מלא | הנמקה מלאה, תשתית עובדתית, סבירות ומידתיות, פרוצדורה תקינה, ציטוט מדויק |
|
||||||
|
| האם יש עוד בעלי עניין? | ✅ מלא | מזכירות (מפיצה בלבד), חברי ועדה (דיון לפני הכתיבה, לא מעורבים בכתיבה), צדדים (רואים רק אחרי פרסום) |
|
||||||
|
|
||||||
|
### בעלי עניין
|
||||||
|
|
||||||
|
| תפקיד | שם | מעורבות | צורך עיקרי |
|
||||||
|
|-------|-----|---------|-----------|
|
||||||
|
| מפעיל המערכת | חיים מרכוס, עו"ד | מפעיל יום-יום — מהקמת תיק עד טיוטה סופית | טיוטה בסגנון דפנה, מינימום זמן, מקסימום תוצר |
|
||||||
|
| יו"ר ועדת הערר | דפנה תמיר, עו"ד | מקבלת טיוטה, מגיהה, מתקנת, חותמת | טיוטה שדורשת מינימום שינויים (יעד: עד 10%) |
|
||||||
|
| **בעל עניין שקט: השופט** | שופט בית משפט מנהלי | לא משתמש במערכת, אבל כל החלטה חייבת לעמוד בביקורתו | — |
|
||||||
|
|
||||||
|
### "מבחן השופט" — הדרישה העליונה של המוצר
|
||||||
|
|
||||||
|
כל החלטה שהמערכת מייצרת חייבת לעמוד בביקורת שיפוטית של שופט בית משפט לעניינים מנהליים (ובערעור — בית המשפט העליון). בפועל השופט בודק:
|
||||||
|
|
||||||
|
1. **הנמקה מלאה** — כל טענה שהועלתה קיבלה מענה. התעלמות מטענה = עילת ביטול.
|
||||||
|
2. **תשתית עובדתית** — העובדות מוצגות נכון, מלאות, לא מוטות. רקע לא ניטרלי = חשש למשוא פנים.
|
||||||
|
3. **סבירות ומידתיות** — ההכרעה סבירה לאור הטענות והעובדות. לא מספיק "נדחה" — צריך להסביר למה ולמה זה מידתי.
|
||||||
|
4. **פרוצדורה תקינה** — כל הצדדים קיבלו הזדמנות להשמיע קולם. דיון התקיים. הזדמנויות לטעון ניתנו.
|
||||||
|
5. **ציטוט מדויק** — כל הפניה לפסיקה, חקיקה או מסמך חייבת להיות מדויקת ומבוססת על מה שסופק בפועל.
|
||||||
|
|
||||||
|
**זו לא דרישה סגנונית — זו הדרישה העליונה של המוצר.**
|
||||||
|
|
||||||
|
### בעלי עניין נוספים (לא משתמשים במערכת)
|
||||||
|
|
||||||
|
| תפקיד | מעורבות | השלכה על המוצר |
|
||||||
|
|-------|---------|---------------|
|
||||||
|
| חברי ועדת הערר | דיון פרונטלי לפני הכתיבה — לא מעורבים בכתיבה עצמה | המערכת צריכה לקלוט את פרוטוקול הדיון כקלט |
|
||||||
|
| מזכירות הוועדה | מפיצה את ההחלטה הסופית בלבד | אין השלכה על המוצר |
|
||||||
|
| הצדדים (עוררים/משיבים) | רואים את ההחלטה רק אחרי פרסום | אין השלכה ישירה, אבל הם אלה שעלולים לעתור — חוזר ל"מבחן השופט" |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סעיף 3: תהליך העבודה הנוכחי (As-Is Process)
|
||||||
|
|
||||||
|
### טבלת מעקב שאלות — סעיף 3
|
||||||
|
|
||||||
|
| שאלה | סטטוס | תשובה |
|
||||||
|
|------|-------|-------|
|
||||||
|
| מתי המערכת נכנסת לתמונה? | ✅ מלא | אחרי שהדיון הסתיים — כל הצדדים טענו בכתב ובעל פה, הוועדה דנה, ועכשיו צריך לכתוב החלטה |
|
||||||
|
| מה החומרים שעל השולחן ברגע הזה? | ✅ מלא | כל מסמך שנמסר לוועדה: כתב ערר, כתב תשובה (ועדה מקומית + משיבים), פרוטוקולים, השלמות טיעון |
|
||||||
|
| מה אתה (חיים) עושה היום צעד אחרי צעד כשאתה כותב טיוטה? | ✅ מלא | קורא את כל החומר → כותב פתח דבר/רקע → ממשיך צעד אחרי צעד. סדר הפרקים משתנה לפי סוג ההחלטה |
|
||||||
|
| כמה זמן התהליך לוקח היום? | ✅ מלא | שבוע לטיוטה שלמה. יעד: יום אחד |
|
||||||
|
| מה הכי קשה / לוקח הכי הרבה זמן? | ✅ מלא | סיכום הטענות והדיון. בעיקר הדיון (בלוק י) — הוא צוואר הבקבוק |
|
||||||
|
|
||||||
|
### נקודת הכניסה
|
||||||
|
המערכת נכנסת לתמונה **אחרי** שכל השלבים הבאים הסתיימו:
|
||||||
|
- כתבי הערר הוגשו ✅
|
||||||
|
- כתבי תשובה/תגובה הוגשו ✅
|
||||||
|
- השלמות טיעון (אם היו) הוגשו ✅
|
||||||
|
- דיון פרונטלי בוועדת הערר התקיים ✅
|
||||||
|
- הוועדה דנה פנימית והחליטה על הכיוון ✅
|
||||||
|
|
||||||
|
**עכשיו** — צריך לכתוב את ההחלטה. כאן המערכת נכנסת.
|
||||||
|
|
||||||
|
### תהליך העבודה הנוכחי (ללא המערכת)
|
||||||
|
|
||||||
|
1. **קריאת כל החומר** — כתבי ערר, תשובות, פרוטוקולים, השלמות
|
||||||
|
2. **כתיבת פתיחה ורקע** (בלוקים ה-ו) — הגדרות, עובדות, תכניות
|
||||||
|
3. **סיכום טענות** (בלוק ז) — לכל צד בנפרד — **לוקח הרבה זמן**
|
||||||
|
4. **הליכים** (בלוק ח) — אם היו סיור/השלמות/החלטות ביניים
|
||||||
|
5. **דיון** (בלוק י) — **צוואר הבקבוק** — ניתוח משפטי, פסיקה, יישום, הכרעה
|
||||||
|
6. **סיכום** (בלוק יא) — הוראות אופרטיביות
|
||||||
|
7. **שליחה לדפנה** — דפנה מגיהה, מתקנת, חותמת
|
||||||
|
|
||||||
|
**זמן נוכחי:** שבוע לטיוטה שלמה
|
||||||
|
**יעד:** יום אחד
|
||||||
|
|
||||||
|
### ניתוח מבנה 3 החלטות — ממצאים
|
||||||
|
|
||||||
|
מניתוח הכט (דחייה), בית הכרם (קבלה חלקית), אריאלי (קבלה) עולה:
|
||||||
|
|
||||||
|
**בלוקים קבועים (תמיד קיימים):**
|
||||||
|
- ה — פתיחה (אבל בניסוחים שונים: "לפנינו" / "עניינה של החלטה זו")
|
||||||
|
- ו — רקע / "פתח דבר" (היקף משתנה: 3% עד 18%)
|
||||||
|
- ז — טענות הצדדים
|
||||||
|
- י — דיון והכרעה
|
||||||
|
- יא — סיכום / סוף דבר
|
||||||
|
- יב — חתימות
|
||||||
|
|
||||||
|
**בלוקים מותנים (תלויים בתיק):**
|
||||||
|
- ח — הליכים: קיים כשהיו הליכים מורכבים (דיון + סיור + השלמות רבות). באריאלי = 27% מההחלטה
|
||||||
|
- ט — תכניות/מסגרת נורמטיבית: קיים כשיש מורכבות תכנונית או שאלה משפטית (ס' 152). בהכט = 32%
|
||||||
|
|
||||||
|
**⚠ ממצא טכני:** ה-parser הנוכחי לא זיהה את בלוקים ה ו-ו של אריאלי כי הפתיחה שלה ("עניינה של החלטה זו") שונה מ-"לפנינו", וכותרת הרקע ("פתח דבר") לא הייתה בדפוסי החיפוש. דורש תיקון.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סעיף 4: תהליך העבודה העתידי (To-Be Process)
|
||||||
|
|
||||||
|
### טבלת מעקב שאלות — סעיף 4
|
||||||
|
|
||||||
|
| שאלה | סטטוס | תשובה |
|
||||||
|
|------|-------|-------|
|
||||||
|
| איך אתה רואה את התהליך עם המערכת? | ✅ מלא | מינימום ממשק, אבל חייב man-in-the-middle לפני הדיון |
|
||||||
|
| מה השלב שחייב אדם? | ✅ מלא | הזנת התוצאה שדפנה קבעה (דחייה/קבלה/חלקית) — לפני שהמערכת כותבת את הדיון |
|
||||||
|
| מי קובע את התוצאה? | ✅ מלא | דפנה — היא השופטת. היא מעבירה לחיים את ההחלטה |
|
||||||
|
| מה דפנה מעבירה? | ✅ מלא | לא קבוע — לפעמים רק "נדחה/התקבל", לפעמים מנומק יותר |
|
||||||
|
| מה קורה עם הנימוקים של דפנה? | ✅ מלא | אם דפנה נותנת נימוק — ישר לכתיבה. אם רק תוצאה — סיעור מוחות בין חיים למערכת על בסיס החומר המשפטי כדי לגבש את הכיוון. לא מתחילים לכתוב דיון לפני שיש כיוון מדויק |
|
||||||
|
|
||||||
|
### תהליך העבודה העתידי
|
||||||
|
|
||||||
|
**שלב 1 — קלט (חיים)**
|
||||||
|
חיים מעלה למערכת את כל המסמכים שנמסרו לוועדה (PDF/DOCX/MD).
|
||||||
|
|
||||||
|
**שלב 2 — עיבוד אוטומטי (מערכת)**
|
||||||
|
המערכת קוראת את כל החומר, מזהה צדדים, מסווגת מסמכים, מחלצת טענות.
|
||||||
|
|
||||||
|
**שלב 3 — הזנת תוצאה (חיים) ← man-in-the-middle**
|
||||||
|
חיים מזין את התוצאה שדפנה קבעה:
|
||||||
|
- סוג: דחייה / קבלה / קבלה חלקית
|
||||||
|
- נימוק: אם דפנה נתנה → ישר לשלב 4ב
|
||||||
|
|
||||||
|
**שלב 4א — סיעור מוחות (חיים + מערכת) ← רק אם אין נימוק**
|
||||||
|
אם דפנה נתנה רק תוצאה בלי נימוק — המערכת וחיים מנהלים שיח:
|
||||||
|
- המערכת מציגה את הטענות המרכזיות מהחומר
|
||||||
|
- חיים והמערכת דנים על בסיס מה מגיעים לתוצאה
|
||||||
|
- **לא מתחילים לכתוב דיון לפני שיש כיוון מדויק**
|
||||||
|
- התוצר: מסמך כיוון קצר — מה הנימוקים המרכזיים, באיזה סדר, מה הפסיקה הרלוונטית
|
||||||
|
|
||||||
|
**שלב 4ב — כתיבת טיוטה (מערכת)**
|
||||||
|
המערכת כותבת את ההחלטה בלוק אחרי בלוק, בסגנון דפנה, לפי התוצאה והכיוון שנקבעו.
|
||||||
|
|
||||||
|
**שלב 5 — פלט (חיים)**
|
||||||
|
חיים מקבל DOCX מעוצב — טיוטה כמעט מוכנה.
|
||||||
|
|
||||||
|
**שלב 6 — הגהה ותיקונים (דפנה)**
|
||||||
|
דפנה קוראת, מתקנת, מגיהה, חותמת.
|
||||||
|
|
||||||
|
**שלב 7 — לולאת למידה (מערכת)**
|
||||||
|
הגרסה הסופית שדפנה מפיצה חוזרת למערכת — המערכת לומדת מהפער.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סעיף 5: רמות אוטומציה (Levels of Automation)
|
||||||
|
|
||||||
|
### בסיס אקדמי
|
||||||
|
|
||||||
|
הניתוח מבוסס על 9 מקורות אקדמיים (ביבליוגרפיה מלאה בנספח):
|
||||||
|
|
||||||
|
| מקור | תרומה |
|
||||||
|
|------|-------|
|
||||||
|
| פרסורמן, שרידן וויקנס (2000) | מודל 10 רמות אוטומציה × 4 שלבי עיבוד מידע |
|
||||||
|
| אנדסלי (2017) | סיכוני שאננות אוטומציה — דווקא מומחים רגישים יותר |
|
||||||
|
| קאמינגס (2004) | הטיית אוטומציה — commission errors ו-omission errors |
|
||||||
|
| סורדין (2018) | שלוש רמות AI במשפט: תומך / מחליף / משבש |
|
||||||
|
| רילינג (2020) | הבחנה בין פרוצדורלי (אוטומטי) לשיקול דעת (אנושי) |
|
||||||
|
| CEPEJ (2018) | חמישה עקרונות אתיים ל-AI בשיפוט — "under user control" |
|
||||||
|
| INCOSE (2023) | הקצאת פונקציות דינמית — לפי מורכבות, סיכון, עומס |
|
||||||
|
|
||||||
|
### שלוש רמות אוטומציה
|
||||||
|
|
||||||
|
| רמה | שם | תיאור | LOA (פרסורמן) |
|
||||||
|
|------|-----|-------|--------------|
|
||||||
|
| **א — אוטומטי** | המערכת מבצעת, מדווחת לאדם | 7-9 |
|
||||||
|
| **ב — שיתופי** | המערכת מנסחת טיוטה, האדם מאשר/עורך/דוחה | 4-5 |
|
||||||
|
| **ג — אנושי** | האדם מבצע, המערכת מספקת מידע בלבד | 1-3 |
|
||||||
|
|
||||||
|
### מיפוי דו-ממדי: רמות אוטומציה × שלבי עיבוד מידע (Parasuraman 2000)
|
||||||
|
|
||||||
|
| שלב עבודה | שלב עיבוד (Parasuraman) | רמה |
|
||||||
|
|-----------|------------------------|-----|
|
||||||
|
| קריאת מסמכים וסיווג | Information Acquisition | א — אוטומטי |
|
||||||
|
| חילוץ טענות | Information Acquisition + Analysis | ב — שיתופי |
|
||||||
|
| חיפוש תקדימים | Information Analysis | ב — שיתופי |
|
||||||
|
| גיבוש נימוקים | Information Analysis + Decision Selection | ב — שיתופי |
|
||||||
|
| **קביעת תוצאה** | **Decision Selection** | **ג — אנושי** |
|
||||||
|
| כתיבת בלוקים ה-ח | Action Implementation | ב — שיתופי |
|
||||||
|
| כתיבת דיון (י) | Action Implementation (high-stakes) | ב — שיתופי |
|
||||||
|
| ייצוא DOCX | Action Implementation (low-stakes) | א — אוטומטי |
|
||||||
|
|
||||||
|
### מיפוי שלבי העבודה לרמות אוטומציה
|
||||||
|
|
||||||
|
| שלב | תוכן | רמה | נימוק |
|
||||||
|
|-----|-------|-----|-------|
|
||||||
|
| קריאת מסמכים וסיווג | זיהוי סוג מסמך, חילוץ מטא-דאטה | **א — אוטומטי** | פרוצדורלי, ניתן לביקורת, סיכון נמוך |
|
||||||
|
| חילוץ טענות | סיכום טענות מכתבי טענות | **ב — שיתופי** | דורש נאמנות למקור — AI מנסח, אדם מוודא |
|
||||||
|
| כתיבת רקע (בלוק ו) | עובדות, תכניות | **ב — שיתופי** | חובת ניטרליות — AI מנסח, אדם בודק |
|
||||||
|
| כתיבת טענות (בלוק ז) | סיכום טענות בגוף שלישי | **ב — שיתופי** | נאמנות למקור |
|
||||||
|
| כתיבת הליכים (בלוק ח) | תיעוד כרונולוגי | **ב — שיתופי** | בעיקר עובדתי אבל דורש דיוק |
|
||||||
|
| חיפוש תקדימים | RAG — מציאת פסיקה דומה | **ב — שיתופי** | AI מציע 3-5 חלופות, אדם בוחר (קאמינגס) |
|
||||||
|
| **קביעת תוצאה** | דחייה/קבלה/חלקית | **ג — אנושי בלבד** | **החלטה שיפוטית — דפנה בלבד** |
|
||||||
|
| **גיבוש נימוקים** | סיעור מוחות על הכיוון | **ב — שיתופי** | AI מציג טענות ומציע כיוונים, חיים מחליט. אופציונלי גם כשיש נימוק |
|
||||||
|
| כתיבת דיון (בלוק י) | ניתוח משפטי, CREAC | **ב — שיתופי** | AI מנסח על בסיס הכיוון שנקבע, אדם עורך |
|
||||||
|
| כתיבת סיכום (בלוק יא) | הוראות אופרטיביות | **ב — שיתופי** | נגזר מהדיון, אבל חייב לשקף הכרעה מדויקת |
|
||||||
|
| ייצוא DOCX | עיצוב מסמך | **א — אוטומטי** | טכני לחלוטין |
|
||||||
|
|
||||||
|
### עקרונות עיצוב (מבוססי מחקר)
|
||||||
|
|
||||||
|
| עיקרון | מקור | יישום |
|
||||||
|
|--------|------|-------|
|
||||||
|
| **"אדם בלולאה"** | אנדסלי (2017) | דפנה קובעת תוצאה, חיים מאשר כיוון — לפני שהמערכת כותבת |
|
||||||
|
| **שקיפות** | אנדסלי (2017), CEPEJ (2018) | כל טיוטה מציגה מקורות. רמת ודאות ליד תקדימים |
|
||||||
|
| **מעורבות אקטיבית** | אנדסלי (2017) | חובת מעבר מבלוק לבלוק — אין "ייצר הכל" בלחיצה |
|
||||||
|
| **הצגת חלופות** | קאמינגס (2004) | חיפוש תקדימים מחזיר 3-5 חלופות, לא "התקדים הנכון" |
|
||||||
|
| **כפייה קוגניטיבית** | קאמינגס (2004) | חיים מזין כיוון **לפני** שרואה טיוטת דיון |
|
||||||
|
| **אחריותיות** | CEPEJ (2018) | החלטה נושאת חתימת דפנה. תיעוד שנעשה שימוש ב-AI |
|
||||||
|
| **הקצאה דינמית** | INCOSE (2023) | ככל שהמשימה קרובה יותר להכרעה — פחות אוטומציה |
|
||||||
|
|
||||||
|
### סיכונים שזוהו
|
||||||
|
|
||||||
|
| סיכון | מקור | מנגנון הגנה |
|
||||||
|
|-------|------|------------|
|
||||||
|
| **שאננות אוטומציה** — דפנה מפסיקה לבדוק טיוטות | אנדסלי | לולאת למידה: השוואת טיוטה לגרסה סופית מודדת כמה דפנה שינתה |
|
||||||
|
| **הטיית אוטומציה** — חיים מאמץ תקדים שגוי | קאמינגס | כלל ברזל: רק מה שסופק כמסמך. + הצגת חלופות |
|
||||||
|
| **שחיקת מיומנות** — חיים מפסיק ללמוד לכתוב | פרסורמן | סיעור מוחות חובה לפני כל דיון |
|
||||||
|
| **לולאת חיזוק** — החלטות עתידיות ידמו לעבר | אלטרס (2016) | כל החלטה חדשה מבוססת על חומרי המקור, לא על תבנית |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סעיף 6: דרישות פונקציונליות
|
||||||
|
|
||||||
|
### טבלת מעקב שאלות — סעיף 6
|
||||||
|
|
||||||
|
| שאלה | סטטוס | תשובה |
|
||||||
|
|------|-------|-------|
|
||||||
|
| מה פורמטי הקלט? | ✅ מלא | PDF, DOCX, MD — כל מסמך שנמסר לוועדה (מסעיף 1) |
|
||||||
|
| מה סוגי המסמכים? | ✅ מלא | ערר, תשובה, תגובה, פרוטוקול, תכנית, היתר, פסקי דין, החלטות (מסעיף 1) |
|
||||||
|
| מה הפלט? | ✅ מלא | DOCX מעוצב RTL, כמעט מוכן לחתימה (מסעיף 1) |
|
||||||
|
| מה סוגי הערר? | ✅ מלא | רישוי (1xxx), היטל השבחה (8xxx), פיצויים (9xxx) — סגנון שונה לכל אחד |
|
||||||
|
| מה שלבי התהליך? | ✅ מלא | 7 שלבים כולל man-in-the-middle (מסעיף 4) |
|
||||||
|
| מה רמות האוטומציה? | ✅ מלא | 3 רמות: אוטומטי/שיתופי/אנושי (מסעיף 5) |
|
||||||
|
|
||||||
|
### דרישות פונקציונליות — לפי שלבי התהליך
|
||||||
|
|
||||||
|
#### שלב 1: קלט מסמכים
|
||||||
|
|
||||||
|
| מזהה | דרישה | עדיפות |
|
||||||
|
|------|-------|--------|
|
||||||
|
| ק-1 | המערכת מקבלת קבצי PDF, DOCX, MD | חובה |
|
||||||
|
| ק-2 | המערכת מחלצת טקסט מלא מכל מסמך (כולל OCR לסרוקים) | חובה |
|
||||||
|
| ק-3 | המערכת מסווגת כל מסמך לסוג (ערר/תשובה/פרוטוקול וכו') | חובה |
|
||||||
|
| ק-4 | המערכת מזהה את הצדדים (עוררים, משיבים, ועדה, מבקשי היתר) | חובה |
|
||||||
|
| ק-5 | המערכת מזהה את סוג הערר (רישוי/השבחה/פיצויים) לפי מספר התיק | חובה |
|
||||||
|
| ק-6 | המערכת מודדת גודל כל החומרים בטוקנים ומתריעה אם חורגים מ-80% של context window | חובה |
|
||||||
|
| ק-7 | כשחומרים חורגים — המערכת מפעילה אסטרטגיית סיכום/חלוקה עם סדר עדיפויות (ערר ותשובה קודם לנספחים) | חובה |
|
||||||
|
| ק-8 | **הגנת prompt injection** — הפרדה בין הוראות מערכת לתוכן מסמכים. סניטיזציה של קלט ממסמכי צדדים חיצוניים | חובה |
|
||||||
|
| ק-9 | **איחוד תיקים** — המערכת תומכת בתיק שמאחד כמה עררים (כמו 1078+1083). בלוק ה מגדיר כמה מספרי תיק, בלוק ז מכסה טענות של כל העוררים | רצוי |
|
||||||
|
|
||||||
|
#### שלב 2: עיבוד וניתוח
|
||||||
|
|
||||||
|
| מזהה | דרישה | עדיפות |
|
||||||
|
|------|-------|--------|
|
||||||
|
| ע-1 | המערכת מחלצת טענות מכתבי טענות — לפי צד | חובה |
|
||||||
|
| ע-2 | המערכת מזהה תכניות חלות על המקרקעין | חובה |
|
||||||
|
| ע-3 | המערכת מזהה פסיקה שמצוטטת במסמכים | חובה |
|
||||||
|
| ע-4 | המערכת מציגה סיכום חומרים לחיים לפני כתיבה | חובה |
|
||||||
|
|
||||||
|
#### שלב 3: הזנת תוצאה (man-in-the-middle)
|
||||||
|
|
||||||
|
| מזהה | דרישה | עדיפות |
|
||||||
|
|------|-------|--------|
|
||||||
|
| ת-1 | חיים מזין את התוצאה שדפנה קבעה: דחייה / קבלה / קבלה חלקית | חובה |
|
||||||
|
| ת-2 | חיים מזין נימוק (אם דפנה נתנה) — טקסט חופשי | חובה |
|
||||||
|
| ת-3 | אם אין נימוק — המערכת מפעילה שלב סיעור מוחות (שלב 4א). גם אם יש נימוק — חיים יכול לבקש סיעור מוחות כאופציה | חובה |
|
||||||
|
|
||||||
|
#### שלב 4א: סיעור מוחות (כשאין נימוק)
|
||||||
|
|
||||||
|
| מזהה | דרישה | עדיפות |
|
||||||
|
|------|-------|--------|
|
||||||
|
| ס-1 | המערכת מציגה את הטענות המרכזיות מהחומר | חובה |
|
||||||
|
| ס-2 | המערכת מציעה 2-3 כיוונים אפשריים לנימוק (לא המלצה אחת) | חובה |
|
||||||
|
| ס-3 | חיים והמערכת מנהלים שיח עד שמגיעים לכיוון מוסכם | חובה |
|
||||||
|
| ס-4 | התוצר: מסמך כיוון — נימוקים מרכזיים, סדר, פסיקה רלוונטית | חובה |
|
||||||
|
| ס-5 | **לא מתחילים לכתוב דיון לפני שיש כיוון מאושר** | חובה |
|
||||||
|
|
||||||
|
#### שלב 4ב: כתיבת טיוטה
|
||||||
|
|
||||||
|
| מזהה | דרישה | עדיפות |
|
||||||
|
|------|-------|--------|
|
||||||
|
| כ-0 | המערכת ממלאת אוטומטית בלוקים א-ד (כותרת, הרכב, צדדים, "החלטה") ויב (חתימות) ממטא-דאטה של התיק | חובה |
|
||||||
|
| כ-1 | המערכת כותבת בלוק אחרי בלוק לפי סדר: ה → ו → ז → ח → ט → י → יא | חובה |
|
||||||
|
| כ-2 | כל בלוק נכתב בסגנון דפנה — טון, ביטויי מעבר, מבנה | חובה |
|
||||||
|
| כ-3 | סגנון הכתיבה מותאם לסוג הערר (חם לרישוי, קר להשבחה) | חובה |
|
||||||
|
| כ-4 | בלוק ח נכתב רק אם היו הליכים מעבר לדיון פשוט (סיור/השלמות) | חובה |
|
||||||
|
| כ-5 | בלוק ט — רישום תכניות תמיד. פרק נפרד רק כשמורכבות תכנונית מצדיקה | חובה |
|
||||||
|
| כ-6 | בלוק י — CREAC: מסקנה בפתיחה, כלל, הסבר, יישום, מסקנה | חובה |
|
||||||
|
| כ-7 | בלוק י — מענה לכל טענה שהוצגה בבלוק ז | חובה |
|
||||||
|
| כ-8 | **כלל ברזל: המערכת מצטטת רק מה שסופק כמסמך** | חובה |
|
||||||
|
| כ-9 | רקע ניטרלי (בלוק ו) — ניטרליות לקסיקלית (אין מילות שיפוט) **וגם** מבנית (סדר הצגת עובדות מאוזן, אורך יחסי של סעיפים לא מטה, בחירת עובדות לא סלקטיבית) | חובה |
|
||||||
|
| כ-10 | ללא כפילות (בלוק י) — הפניות לבלוקים קודמים, לא חזרה | חובה |
|
||||||
|
| כ-11 | משקלות בלוקים לפי יחסי הזהב (סוג ערר × תוצאה) | חובה |
|
||||||
|
| כ-12 | **שמירת מצב ביניים** — אחרי כל בלוק שנכתב, המצב נשמר ב-DB. חיים יכול להפסיק ולהמשיך מחר | חובה |
|
||||||
|
| כ-13 | **recovery** — אם המערכת נופלת, חיים ממשיך מהבלוק האחרון שנשמר | חובה |
|
||||||
|
| כ-14 | **חזרה אחורה** — חיים יכול לחזור לבלוק קודם ולכתוב אותו מחדש. בלוקים תלויים מתעדכנים בהתאם | חובה |
|
||||||
|
| כ-15 | **ניהול גרסאות** — כל בלוק שומר היסטוריית גרסאות. חיים יכול לחזור לגרסה קודמת של בלוק ספציפי | רצוי |
|
||||||
|
|
||||||
|
#### שלב 5: פלט
|
||||||
|
|
||||||
|
| מזהה | דרישה | עדיפות |
|
||||||
|
|------|-------|--------|
|
||||||
|
| פ-0 | **בדיקת QA אוטומטית לפני ייצוא** — ולידציה של: כל הפניה מוולדת (grounding), כל טענה נענתה, רקע ניטרלי, משקלות בטווח, מספור רציף. אם נכשל — לא מייצא, מציג דוח שגיאות | חובה |
|
||||||
|
| פ-1 | ייצוא DOCX מעוצב — גופן David, RTL, כותרות, מספור סעיפים רציף | חובה |
|
||||||
|
| פ-2 | מקומות תמונה מסומנים (GIS, תשריט, סיור) | רצוי |
|
||||||
|
| פ-3 | הגדרות "להלן" מופיעות לפני השימוש הראשון | חובה |
|
||||||
|
|
||||||
|
#### שלב 6: הגהת דפנה ותיקונים
|
||||||
|
|
||||||
|
| מזהה | דרישה | עדיפות |
|
||||||
|
|------|-------|--------|
|
||||||
|
| ה-1 | חיים שולח את ה-DOCX לדפנה (מייל / שיתוף קובץ — מחוץ למערכת) | חובה |
|
||||||
|
| ה-2 | דפנה מגיהה ומתקנת ב-Word — עם track changes | חובה |
|
||||||
|
| ה-3 | חיים מעלה את הגרסה הסופית (DOCX שדפנה חתמה) בחזרה למערכת | חובה |
|
||||||
|
| ה-4 | המערכת מזהה שזו גרסה סופית (לא טיוטה) ומפעילה את לולאת הלמידה | חובה |
|
||||||
|
| ה-5 | שמירת הגרסה הסופית ב-DB עם קישור לטיוטה המקורית | חובה |
|
||||||
|
|
||||||
|
#### שלב 7: לולאת למידה
|
||||||
|
|
||||||
|
| מזהה | דרישה | עדיפות |
|
||||||
|
|------|-------|--------|
|
||||||
|
| ל-1 | קליטת גרסה סופית (שדפנה חתמה) בחזרה למערכת | חובה |
|
||||||
|
| ל-2 | השוואת טיוטה לגרסה סופית — זיהוי מה שונה | חובה |
|
||||||
|
| ל-3 | חילוץ לקחים — ביטויי מעבר חדשים, דפוסי כתיבה שהשתנו, שגיאות חוזרות | חובה |
|
||||||
|
| ל-4 | עדכון בסיס הידע: הוספת ביטויים חדשים ל-transition_phrases, עדכון יחסי זהב, עדכון דוגמאות ב-RAG | חובה |
|
||||||
|
| ל-5 | **מנגנון עדכון:** לא fine-tuning אלא עדכון RAG index + few-shot examples + prompt engineering. הגרסה הסופית הופכת לדוגמה שה-prompt מפנה אליה | חובה |
|
||||||
|
| ל-6 | מנגנון rollback — אם עדכון מדרדר איכות (אחוז שינוי עולה), חזרה למצב קודם | חובה |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סעיף 7: דרישות לא-פונקציונליות
|
||||||
|
|
||||||
|
| מזהה | קטגוריה | דרישה | עדיפות |
|
||||||
|
|------|---------|-------|--------|
|
||||||
|
| לפ-1 | שפה | כל הממשק, הפלט והשיח בעברית | חובה |
|
||||||
|
| לפ-2 | שפה | תמיכה מלאה ב-RTL — בממשק, ב-DOCX, ובטבלאות | חובה |
|
||||||
|
| לפ-3 | ביצועים | טיוטה שלמה תוך שעות (לא ימים) — יעד: יום עבודה אחד כולל סיעור מוחות | חובה |
|
||||||
|
| לפ-4 | ביצועים | חיפוש תקדימים (RAG) — תשובה תוך 10 שניות | רצוי |
|
||||||
|
| לפ-4א | ביצועים | כתיבת בלוק בודד — עד 5 דקות לבלוקים ה-ט, עד 15 דקות לבלוק י (opus + thinking) | רצוי |
|
||||||
|
| לפ-4ב | ביצועים | כתיבה אסינכרונית — חיים מפעיל כתיבת בלוק וממשיך לעבוד. התראה כשהבלוק מוכן | רצוי |
|
||||||
|
| לפ-5 | דיוק | **מנגנון grounding** — כל הפניה לפסיקה/חקיקה/מסמך מקושרת למסמך מקור ספציפי עם citation tracking | חובה |
|
||||||
|
| לפ-5א | דיוק | **ולידציה אוטומטית** — כל ציטוט/הפניה נבדק מול המסמכים שסופקו. הפניה שלא עוברת ולידציה = נחסמת (לא נכנסת לטיוטה) | חובה |
|
||||||
|
| לפ-5ב | דיוק | **מדד: 0% הפניות לא מוולדות** — לא שאין הזיות, אלא שכל הזיה נתפסת לפני שנכנסת לטיוטה | חובה |
|
||||||
|
| לפ-6 | דיוק | ציטוטים — נאמנות מוחלטת למקור. לא לשנות מילים, לא לקצר בלי לציין | חובה |
|
||||||
|
| לפ-7 | אבטחה | חומרי התיקים חסויים — לא נשלחים לשירותים חיצוניים מלבד Anthropic API | חובה |
|
||||||
|
| לפ-8 | אבטחה | ניהול סודות דרך Infisical — לא hardcoded | חובה |
|
||||||
|
| לפ-9 | זמינות | המערכת רצה על שרת Nautilus — זמינה 24/7 | רצוי |
|
||||||
|
| לפ-10 | תחזוקה | גיבוי DB יומי אוטומטי | חובה |
|
||||||
|
| לפ-11 | ממשק | מינימום ממשק — עבודה דרך Claude Code (CLI), לא דרך web UI | חובה |
|
||||||
|
| לפ-12 | מעקב | כל פעולה מתועדת — מי הזין, מתי, מה שונה | רצוי |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סעיף 8: MVP — גרסה מינימלית
|
||||||
|
|
||||||
|
### אין MVP — מוצר מלא בלבד
|
||||||
|
|
||||||
|
**אין גרסה מצומצמת.** כל הדרישות הפונקציונליות והלא-פונקציונליות הכרחיות. המערכת עובדת במלואה או לא עובדת.
|
||||||
|
|
||||||
|
**הנימוק:** המוצר פועל בסביבת אמת — החלטות משפטיות שעומדות לביקורת שיפוטית. טעות (ציטוט שגוי, טענה שלא נענתה, רקע לא ניטרלי) היא לא באג שאפשר לתקן בגרסה הבאה — היא עלולה להגיע לבית המשפט העליון.
|
||||||
|
|
||||||
|
### מגבלת scope גרסה ראשונה
|
||||||
|
|
||||||
|
**הגרסה הראשונה מכסה רישוי ובנייה (1xxx) והיטל השבחה (8xxx) בלבד.**
|
||||||
|
|
||||||
|
אין נתוני אימון לפיצויים (9xxx) — המערכת לא תקבל תיקי פיצויים עד שנלמד מהחלטות מהסוג הזה. כשתיק פיצויים מוזן — המערכת מתריעה ומסרבת לכתוב.
|
||||||
|
|
||||||
|
**קריטריונים להרחבה לפיצויים:**
|
||||||
|
- לפחות 3 החלטות סופיות מסוג 9xxx נקלטו ופורקו
|
||||||
|
- parser מכויל לסוג הזה
|
||||||
|
- יחסי זהב מוגדרים
|
||||||
|
|
||||||
|
### תוכנית השקה — לא MVP אלא מבחן הסמכה
|
||||||
|
|
||||||
|
במקום "MVP → שיפור" — תהליך של **מבחן הסמכה** לפני שימוש אמיתי:
|
||||||
|
|
||||||
|
| שלב | תוכן | קריטריון מעבר |
|
||||||
|
|-----|-------|--------------|
|
||||||
|
| שלב א — פיתוח | בניית כל 42 הדרישות | כל הדרישות ממומשות |
|
||||||
|
| שלב ב — מבחן על תיק שהושלם | המערכת כותבת החלטה לתיק שכבר יש לו החלטה סופית (למשל הכט) | השוואת הטיוטה להחלטה הסופית — פער קטן מ-10% |
|
||||||
|
| שלב ג — מבחן על תיק חי | המערכת כותבת טיוטה לתיק אמיתי שדפנה טרם כתבה | דפנה בודקת — אם שינתה פחות מ-10% → עובר |
|
||||||
|
| שלב ד — שימוש מבצעי | שימוש שוטף עם לולאת למידה | יעד: 98% ללא שינוי |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סעיף 9: מדדי הצלחה (KPIs)
|
||||||
|
|
||||||
|
| מדד | תקין | הצלחה | מדידה |
|
||||||
|
|-----|------|-------|-------|
|
||||||
|
| **אחוז שינוי** — כמה דפנה משנה מהטיוטה | עד 10% | עד 5% | ראה הגדרה מתמטית למטה. יתכייל אחרי 5 החלטות |
|
||||||
|
|
||||||
|
### הגדרה מתמטית: אחוז שינוי
|
||||||
|
|
||||||
|
**שיטת מדידה:** word-level edit distance (Levenshtein על מילים, לא תווים)
|
||||||
|
|
||||||
|
**נוסחה:**
|
||||||
|
```
|
||||||
|
אחוז_שינוי = (מספר_מילים_שהשתנו / סך_מילים_בטיוטה_המקורית) × 100
|
||||||
|
```
|
||||||
|
|
||||||
|
**מה נספר כ"שינוי":**
|
||||||
|
- **הוספת מילה** = 1 שינוי
|
||||||
|
- **מחיקת מילה** = 1 שינוי
|
||||||
|
- **החלפת מילה** = 1 שינוי
|
||||||
|
- **הוספת סעיף שלם** = מספר המילים בסעיף החדש
|
||||||
|
- **מחיקת סעיף שלם** = מספר המילים בסעיף שנמחק
|
||||||
|
|
||||||
|
**מה לא נספר:**
|
||||||
|
- שינויי פיסוק (נקודה, פסיק) = 0
|
||||||
|
- שינויי רווח/שורה חדשה = 0
|
||||||
|
- שינוי סדר סעיפים (ללא שינוי תוכן) = 0
|
||||||
|
|
||||||
|
**דוגמה:**
|
||||||
|
- טיוטה: 5,000 מילים
|
||||||
|
- דפנה שינתה 400 מילים (200 מחיקות, 100 הוספות, 100 החלפות)
|
||||||
|
- אחוז שינוי: 400/5,000 × 100 = **8%** → עומד ביעד (≤10%)
|
||||||
|
| **זמן לטיוטה** — מרגע העלאת חומרים עד DOCX | יום עבודה | חצי יום | מדידת זמן מקצה לקצה |
|
||||||
|
| **הפניות לא מוולדות** — ציטוטים/מקורות שלא עברו ולידציה מול מסמכים שסופקו | 0% | 0% | ולידציה אוטומטית עם grounding — כל הפניה מקושרת למסמך מקור |
|
||||||
|
| **מענה לכל טענה** — כל טענה בבלוק ז מקבלת מענה בבלוק י | 100% | 100% | בדיקת קישור טענה ← מענה |
|
||||||
|
| **משקלות בלוקים** — בטווח יחסי הזהב ±10% | עומד | עומד | ספירת מילים אוטומטית |
|
||||||
|
| **רקע ניטרלי** — בלוק ו ללא מילות שיפוט או ציטוטי צדדים | עובר ולידציה | עובר ולידציה | סקריפט ולידציה אוטומטי |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סעיף 10: סיכונים ומגבלות
|
||||||
|
|
||||||
|
| סיכון | חומרה | הסתברות | מנגנון הגנה |
|
||||||
|
|-------|-------|---------|------------|
|
||||||
|
| **הזיית מקור** — המערכת מצטטת פסק דין שלא קיים | קריטית | בינונית | כלל ברזל: רק מה שסופק. ולידציה אוטומטית של כל הפניה |
|
||||||
|
| **רקע לא ניטרלי** — מילות שיפוט ברקע | גבוהה | בינונית | סקריפט ולידציה + רשימת מילים אסורות |
|
||||||
|
| **טענה ללא מענה** — טענה מבלוק ז שלא נענתה בבלוק י | גבוהה | בינונית | קישור אוטומטי טענה ← מענה + בדיקת כיסוי |
|
||||||
|
| **שאננות אוטומציה** — דפנה מפסיקה לבדוק טיוטות | גבוהה | גבוהה | מדידת אחוז שינוי בלולאת למידה — אם יורד מתחת ל-1% → התראה |
|
||||||
|
| **הטיית אוטומציה** — חיים מאמץ תקדים שגוי | גבוהה | בינונית | הצגת 3-5 חלופות, לא המלצה אחת |
|
||||||
|
| **סגנון לא מתאים** — המערכת כותבת בסגנון חיים ולא בסגנון דפנה | גבוהה | גבוהה בהתחלה | למידה מ-7 החלטות סופיות + לולאת למידה מתמשכת |
|
||||||
|
| **שינוי פסיקה** — תקדים שהמערכת מסתמכת עליו בוטל/שונה | גבוהה | נמוכה | המערכת מסתמכת רק על מה שסופק — לא מחפשת באינטרנט |
|
||||||
|
| **תלות ב-API** — Anthropic API לא זמין | בינונית | נמוכה | אין workaround — המערכת לא עובדת בלי API |
|
||||||
|
| **חוסר בנתוני אימון** — אין החלטות לפיצויים (9xxx) | בינונית | ודאי | צריך להמתין עד שיהיו החלטות מהסוג הזה |
|
||||||
|
| **מורכבות חריגה** — תיק עם 10+ צדדים או 50+ מסמכים | בינונית | נמוכה | אין מגבלה טכנית אבל אין ניסיון — צריך בדיקה |
|
||||||
|
| **חריגת context window** — תיק מורכב עם חומרים רבים שחורגים מ-context window | קריטית | בינונית-גבוהה | מדידת גודל חומרים בטוקנים לפני עיבוד. אסטרטגיית chunking/summarization למסמכים ארוכים. סף התראה כשמתקרבים ל-80% מה-context. סדר עדיפויות: מסמכים קריטיים (ערר, תשובה) לפני נספחים |
|
||||||
|
| **prompt injection ממסמכי מקור** — מסמכים מצדדים חיצוניים יכולים להכיל טקסט שמשפיע על ה-LLM | גבוהה | נמוכה | הפרדה בין הוראות מערכת לתוכן מסמכים. סניטיזציה של קלט. flagging של דפוסים חשודים |
|
||||||
|
|
||||||
|
### מגבלות ידועות
|
||||||
|
|
||||||
|
| מגבלה | השלכה |
|
||||||
|
|-------|-------|
|
||||||
|
| אין החלטות פיצויים (9xxx) לאימון | המערכת לא תוכל לכתוב החלטות פיצויים עד שנלמד מהן |
|
||||||
|
| רק 7 החלטות סופיות לאימון | הסגנון עלול להיות לא מדויק — ישתפר עם כל החלטה שחוזרת מדפנה |
|
||||||
|
| המערכת לא בודקת עדכניות פסיקה | אם תקדים בוטל — המערכת לא תדע. חיים אחראי לבדוק |
|
||||||
|
| המערכת לא מחפשת פסיקה באינטרנט | רק מה שסופק כמסמך — יתרון (אין הזיות) וחיסרון (עלולה לפספס) |
|
||||||
62
scripts/bidi_table.py
Normal file
62
scripts/bidi_table.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""BiDi-safe box-drawing table renderer for mixed Hebrew/English terminal output.
|
||||||
|
|
||||||
|
Uses LRM (Left-to-Right Mark, U+200E) before box-drawing characters to prevent
|
||||||
|
the BiDi algorithm from breaking table alignment when Hebrew text is present.
|
||||||
|
|
||||||
|
Usage as module:
|
||||||
|
from scripts.bidi_table import bidi_table
|
||||||
|
print(bidi_table(['Col1', 'Col2'], [['val1', 'ערך2']]))
|
||||||
|
|
||||||
|
Usage from CLI:
|
||||||
|
python3 scripts/bidi_table.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
LRM = "\u200E" # Left-to-Right Mark — invisible, prevents BiDi reordering
|
||||||
|
|
||||||
|
|
||||||
|
def bidi_table(headers: list[str], rows: list[list[str]]) -> str:
|
||||||
|
"""Render a box-drawing table safe for mixed RTL/LTR terminal display."""
|
||||||
|
ncols = len(headers)
|
||||||
|
|
||||||
|
# Calculate column widths
|
||||||
|
col_widths = [len(h) for h in headers]
|
||||||
|
for row in rows:
|
||||||
|
for i, cell in enumerate(row[:ncols]):
|
||||||
|
col_widths[i] = max(col_widths[i], len(cell))
|
||||||
|
|
||||||
|
def hline(left: str, mid: str, right: str) -> str:
|
||||||
|
return left + mid.join("─" * (w + 2) for w in col_widths) + right
|
||||||
|
|
||||||
|
def dataline(cells: list[str]) -> str:
|
||||||
|
parts = []
|
||||||
|
for i in range(ncols):
|
||||||
|
cell = cells[i] if i < len(cells) else ""
|
||||||
|
padded = cell + " " * max(0, col_widths[i] - len(cell))
|
||||||
|
parts.append(" " + padded + " ")
|
||||||
|
return LRM + "│" + (LRM + "│").join(parts) + LRM + "│"
|
||||||
|
|
||||||
|
lines = [hline("┌", "┬", "┐")]
|
||||||
|
lines.append(dataline(headers))
|
||||||
|
lines.append(hline("├", "┼", "┤"))
|
||||||
|
for row in rows:
|
||||||
|
lines.append(dataline(row))
|
||||||
|
lines.append(hline("└", "┴", "┘"))
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
table = bidi_table(
|
||||||
|
["File", "Description", "Model", "Step"],
|
||||||
|
[
|
||||||
|
["claims_extractor.py", "חילוץ טענות מכתבי טענות", "Sonnet", "שלב 3 — הבא בתור"],
|
||||||
|
["brainstorm.py", "סיעור מוחות — כיווני נימוק", "Sonnet", "שלב 4"],
|
||||||
|
["block_writer.py", "כתיבת בלוקים של החלטה", "Sonnet/Opus", "שלב 5"],
|
||||||
|
["qa_validator.py", "בדיקת איכות QA", "Sonnet", "שלב 6"],
|
||||||
|
["style_analyzer.py", "ניתוח סגנון דפנה", "Opus", "חד-פעמי"],
|
||||||
|
["learning_loop.py", "למידה מהחלטה סופית", "Sonnet", "סוף תהליך"],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
print(table)
|
||||||
289
scripts/decompose-decisions-v2.py
Normal file
289
scripts/decompose-decisions-v2.py
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Decompose final decisions into 12-block structure — V2 calibrated on הכט.
|
||||||
|
|
||||||
|
Key insight: DOCX extraction strips header blocks (א-ד). The real content
|
||||||
|
starts at block ה (opening "לפנינו"). We identify blocks by known section
|
||||||
|
headers and line-by-line analysis.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src"))
|
||||||
|
|
||||||
|
from legal_mcp.services.db import get_pool, init_schema, close_pool
|
||||||
|
|
||||||
|
|
||||||
|
BLOCK_DEFS = [
|
||||||
|
("block-alef", 1, "כותרת מוסדית", "template-fill"),
|
||||||
|
("block-bet", 2, "הרכב הוועדה", "template-fill"),
|
||||||
|
("block-gimel", 3, "צדדים", "template-fill"),
|
||||||
|
("block-dalet", 4, "כותרת החלטה", "template-fill"),
|
||||||
|
("block-he", 5, "פתיחה", "paraphrase"),
|
||||||
|
("block-vav", 6, "רקע עובדתי", "reproduction"),
|
||||||
|
("block-zayin", 7, "טענות הצדדים", "paraphrase"),
|
||||||
|
("block-chet", 8, "הליכים בפני ועדת הערר", "reproduction"),
|
||||||
|
("block-tet", 9, "תכניות חלות", "guided-synthesis"),
|
||||||
|
("block-yod", 10, "דיון והכרעה", "rhetorical-construction"),
|
||||||
|
("block-yod-alef", 11, "סיכום", "paraphrase"),
|
||||||
|
("block-yod-bet", 12, "חתימות", "template-fill"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def find_line(lines: list[str], pattern: str, start: int = 0) -> int:
|
||||||
|
"""Find first line matching pattern (substring or regex). Returns -1 if not found."""
|
||||||
|
pat = re.compile(pattern)
|
||||||
|
for i in range(start, len(lines)):
|
||||||
|
if pat.search(lines[i]):
|
||||||
|
return i
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
def slice_text(lines: list[str], start: int, end: int) -> str:
|
||||||
|
"""Join lines[start:end] into text."""
|
||||||
|
if start < 0 or end <= start:
|
||||||
|
return ""
|
||||||
|
return "\n".join(lines[start:end]).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def count_words(text: str) -> int:
|
||||||
|
return len(text.split()) if text else 0
|
||||||
|
|
||||||
|
|
||||||
|
def decompose(text: str) -> dict[str, str]:
|
||||||
|
"""Parse decision into blocks. Returns {block_id: content}."""
|
||||||
|
lines = text.split("\n")
|
||||||
|
n = len(lines)
|
||||||
|
blocks = {}
|
||||||
|
|
||||||
|
# Find key section headers
|
||||||
|
# Style 1: רישוי — descriptive headers ("תמצית טענות הצדדים", "דיון והכרעה")
|
||||||
|
# Style 2: היטל השבחה — numbered headers ("א. רקע עובדתי", "ו. דיון והכרעה")
|
||||||
|
opening = find_line(lines, r"^לפנינו\s|^בפנינו\s|^בפני\s*ועדת|^בפני\s*בקשה")
|
||||||
|
|
||||||
|
claims = find_line(lines, r"תמצית\s*טענות|טענות\s*הצדדים|טענות\s*העוררי")
|
||||||
|
if claims == -1:
|
||||||
|
claims = find_line(lines, r"^טענות\s*העוררי")
|
||||||
|
if claims == -1:
|
||||||
|
# היטל השבחה style: "ב. טענות העורר"
|
||||||
|
claims = find_line(lines, r"^[א-ת][\.\)]\s*טענות")
|
||||||
|
|
||||||
|
background = find_line(lines, r"^[א-ת][\.\)]\s*רקע\s*עובדתי")
|
||||||
|
|
||||||
|
proceedings = find_line(lines, r"ההליכים\s*בפני|הליכים\s*בפני|הדיון\s*בפני\s*ועדת\s*הערר")
|
||||||
|
if proceedings == -1:
|
||||||
|
# היטל השבחה: "ד. הבהרות השמאית" or similar procedural sections
|
||||||
|
proceedings = find_line(lines, r"^[א-ת][\.\)]\s*הבהרות|^[א-ת][\.\)]\s*ההליך")
|
||||||
|
|
||||||
|
plans = find_line(lines, r"תכניות\s*חלות|המסגרת\s*הנורמטיבית|הוראות\s*התכנית")
|
||||||
|
if plans == -1:
|
||||||
|
plans = find_line(lines, r"^[א-ת][\.\)]\s*המסגרת\s*הנורמטיבית")
|
||||||
|
|
||||||
|
discussion = find_line(lines, r"^דיון\s*והכרעה|^דיון$|^הכרעה$")
|
||||||
|
if discussion == -1:
|
||||||
|
discussion = find_line(lines, r"^[א-ת][\.\)]\s*דיון\s*והכרעה")
|
||||||
|
|
||||||
|
summary = find_line(lines, r"^סיכום\s*$|^סוף\s*דבר\s*$")
|
||||||
|
if summary == -1:
|
||||||
|
summary = find_line(lines, r"^[א-ת][\.\)]\s*סיכום")
|
||||||
|
signature = find_line(lines, r"^ניתנה?\s*(היום|פה\s*אחד|ביום)")
|
||||||
|
|
||||||
|
# If no explicit discussion header, look for the opening formula
|
||||||
|
if discussion == -1:
|
||||||
|
discussion = find_line(lines, r"לאחר\s*שבחנו\s*את\s*טענות")
|
||||||
|
|
||||||
|
# ── Header blocks (א-ד): everything before opening ──
|
||||||
|
if opening >= 0:
|
||||||
|
header_text = slice_text(lines, 0, opening)
|
||||||
|
if header_text:
|
||||||
|
# Try to split header, but usually DOCX extraction loses these
|
||||||
|
blocks["block-alef"] = header_text
|
||||||
|
else:
|
||||||
|
blocks["block-alef"] = ""
|
||||||
|
else:
|
||||||
|
blocks["block-alef"] = ""
|
||||||
|
|
||||||
|
blocks["block-bet"] = "" # Usually lost in extraction
|
||||||
|
blocks["block-gimel"] = ""
|
||||||
|
blocks["block-dalet"] = "החלטה"
|
||||||
|
|
||||||
|
# ── Block ה: Opening — first 1-3 paragraphs from "לפנינו" ──
|
||||||
|
if opening >= 0:
|
||||||
|
next_section = claims if claims > opening else discussion if discussion > opening else n
|
||||||
|
opening_end = opening + 1
|
||||||
|
for i in range(opening + 1, min(opening + 5, next_section)):
|
||||||
|
line = lines[i].strip()
|
||||||
|
if not line:
|
||||||
|
break
|
||||||
|
opening_end = i + 1
|
||||||
|
blocks["block-he"] = slice_text(lines, opening, opening_end)
|
||||||
|
else:
|
||||||
|
blocks["block-he"] = ""
|
||||||
|
|
||||||
|
# ── Block ו: Background ──
|
||||||
|
# Style 1 (רישוי): after opening, before claims
|
||||||
|
# Style 2 (היטל השבחה): explicit "א. רקע עובדתי" section
|
||||||
|
if background >= 0:
|
||||||
|
# Explicit background header (היטל השבחה style)
|
||||||
|
bg_end = claims if claims > background else (proceedings if proceedings > background else (discussion if discussion > background else n))
|
||||||
|
blocks["block-vav"] = slice_text(lines, background, bg_end)
|
||||||
|
# In this case, opening (ה) might not exist — "לפנינו" may be absent
|
||||||
|
elif opening >= 0 and claims > opening:
|
||||||
|
bg_start = opening + 1
|
||||||
|
he_lines = count_words(blocks.get("block-he", ""))
|
||||||
|
if he_lines > 0:
|
||||||
|
he_end = opening
|
||||||
|
for i in range(opening, min(opening + 5, claims)):
|
||||||
|
if lines[i].strip():
|
||||||
|
he_end = i + 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
bg_start = he_end
|
||||||
|
blocks["block-vav"] = slice_text(lines, bg_start, claims)
|
||||||
|
elif opening >= 0 and discussion > opening:
|
||||||
|
blocks["block-vav"] = slice_text(lines, opening + 1, discussion)
|
||||||
|
else:
|
||||||
|
blocks["block-vav"] = ""
|
||||||
|
|
||||||
|
# ── Block ז: Claims — from claims header to next section ──
|
||||||
|
if claims >= 0:
|
||||||
|
claims_end = min(
|
||||||
|
x for x in [proceedings, plans, discussion, summary, n]
|
||||||
|
if x > claims
|
||||||
|
)
|
||||||
|
blocks["block-zayin"] = slice_text(lines, claims, claims_end)
|
||||||
|
else:
|
||||||
|
blocks["block-zayin"] = ""
|
||||||
|
|
||||||
|
# ── Block ח: Proceedings (optional) ──
|
||||||
|
if proceedings >= 0:
|
||||||
|
proc_end = min(
|
||||||
|
x for x in [plans, discussion, summary, n]
|
||||||
|
if x > proceedings
|
||||||
|
)
|
||||||
|
blocks["block-chet"] = slice_text(lines, proceedings, proc_end)
|
||||||
|
else:
|
||||||
|
blocks["block-chet"] = ""
|
||||||
|
|
||||||
|
# ── Block ט: Plans (optional) ──
|
||||||
|
if plans >= 0 and (discussion == -1 or plans < discussion):
|
||||||
|
plans_end = min(
|
||||||
|
x for x in [discussion, summary, n]
|
||||||
|
if x > plans
|
||||||
|
)
|
||||||
|
blocks["block-tet"] = slice_text(lines, plans, plans_end)
|
||||||
|
else:
|
||||||
|
blocks["block-tet"] = ""
|
||||||
|
|
||||||
|
# ── Block י: Discussion ──
|
||||||
|
if discussion >= 0:
|
||||||
|
disc_end = summary if summary > discussion else (signature if signature > discussion else n)
|
||||||
|
blocks["block-yod"] = slice_text(lines, discussion, disc_end)
|
||||||
|
else:
|
||||||
|
blocks["block-yod"] = ""
|
||||||
|
|
||||||
|
# ── Block יא: Summary ──
|
||||||
|
if summary >= 0:
|
||||||
|
summ_end = signature if signature > summary else n
|
||||||
|
blocks["block-yod-alef"] = slice_text(lines, summary, summ_end)
|
||||||
|
else:
|
||||||
|
blocks["block-yod-alef"] = ""
|
||||||
|
|
||||||
|
# ── Block יב: Signatures ──
|
||||||
|
if signature >= 0:
|
||||||
|
blocks["block-yod-bet"] = slice_text(lines, signature, n)
|
||||||
|
else:
|
||||||
|
blocks["block-yod-bet"] = ""
|
||||||
|
|
||||||
|
return blocks
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await init_schema()
|
||||||
|
pool = await get_pool()
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
decisions = await conn.fetch(
|
||||||
|
"""SELECT d.id as decision_id, c.case_number, c.title,
|
||||||
|
doc.extracted_text
|
||||||
|
FROM decisions d
|
||||||
|
JOIN cases c ON c.id = d.case_id
|
||||||
|
JOIN documents doc ON doc.case_id = d.case_id AND doc.doc_type = 'decision'
|
||||||
|
WHERE d.status = 'final'
|
||||||
|
ORDER BY c.case_number"""
|
||||||
|
)
|
||||||
|
|
||||||
|
for dec in decisions:
|
||||||
|
decision_id = dec["decision_id"]
|
||||||
|
case_number = dec["case_number"]
|
||||||
|
text = dec["extracted_text"]
|
||||||
|
total_words = count_words(text)
|
||||||
|
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"מפרק: {case_number} — {dec['title']}")
|
||||||
|
print(f"סה\"כ מילים: {total_words}")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
|
||||||
|
parsed = decompose(text)
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
# Delete existing blocks
|
||||||
|
await conn.execute(
|
||||||
|
"DELETE FROM decision_blocks WHERE decision_id = $1", decision_id
|
||||||
|
)
|
||||||
|
|
||||||
|
total_parsed_words = 0
|
||||||
|
for block_id, block_index, title, gen_type in BLOCK_DEFS:
|
||||||
|
content = parsed.get(block_id, "")
|
||||||
|
wc = count_words(content)
|
||||||
|
weight = round(wc / total_words * 100, 1) if total_words > 0 and wc > 0 else 0
|
||||||
|
status = "final" if wc > 0 else "empty"
|
||||||
|
total_parsed_words += wc
|
||||||
|
|
||||||
|
await conn.execute(
|
||||||
|
"""INSERT INTO decision_blocks
|
||||||
|
(decision_id, block_id, block_index, title, content,
|
||||||
|
word_count, weight_percent, generation_type, status)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)""",
|
||||||
|
decision_id, block_id, block_index, title,
|
||||||
|
content, wc, weight, gen_type, status,
|
||||||
|
)
|
||||||
|
|
||||||
|
marker = "✅" if wc > 0 else "⬜"
|
||||||
|
print(f" {marker} {block_id:18s} | {title:25s} | {wc:5d} מילים | {weight:5.1f}%")
|
||||||
|
|
||||||
|
# Update decision totals
|
||||||
|
disc_words = count_words(parsed.get("block-yod", ""))
|
||||||
|
disc_paras = len([p for p in parsed.get("block-yod", "").split("\n") if p.strip() and len(p.strip()) > 20])
|
||||||
|
await conn.execute(
|
||||||
|
"UPDATE decisions SET total_words = $1, total_paragraphs = $2, updated_at = now() WHERE id = $3",
|
||||||
|
total_words, disc_paras, decision_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
coverage = round(total_parsed_words / total_words * 100, 1) if total_words > 0 else 0
|
||||||
|
print(f" --- כיסוי: {total_parsed_words}/{total_words} מילים ({coverage}%)")
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
stats = await conn.fetch(
|
||||||
|
"""SELECT block_id, count(*) as decisions,
|
||||||
|
avg(word_count) as avg_words,
|
||||||
|
avg(weight_percent) as avg_weight
|
||||||
|
FROM decision_blocks
|
||||||
|
WHERE word_count > 0
|
||||||
|
GROUP BY block_id ORDER BY block_id"""
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print("סטטיסטיקה לפי בלוק (רק בלוקים עם תוכן):")
|
||||||
|
for s in stats:
|
||||||
|
print(f" {s['block_id']:18s} | {s['decisions']} החלטות | ממוצע {s['avg_words']:.0f} מילים | {s['avg_weight']:.1f}%")
|
||||||
|
|
||||||
|
await close_pool()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
323
scripts/decompose-decisions.py
Normal file
323
scripts/decompose-decisions.py
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Decompose 6 final decisions into 12-block structure.
|
||||||
|
|
||||||
|
Uses heuristic parsing based on known section headers in Dafna's decisions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src"))
|
||||||
|
|
||||||
|
from legal_mcp.services.db import get_pool, init_schema, close_pool
|
||||||
|
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════
|
||||||
|
# Block definitions with detection patterns
|
||||||
|
# ═══════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
BLOCKS = [
|
||||||
|
{
|
||||||
|
"block_id": "block-alef",
|
||||||
|
"block_index": 1,
|
||||||
|
"title": "כותרת מוסדית",
|
||||||
|
"generation_type": "template-fill",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"block_id": "block-bet",
|
||||||
|
"block_index": 2,
|
||||||
|
"title": "הרכב הוועדה",
|
||||||
|
"generation_type": "template-fill",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"block_id": "block-gimel",
|
||||||
|
"block_index": 3,
|
||||||
|
"title": "צדדים",
|
||||||
|
"generation_type": "template-fill",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"block_id": "block-dalet",
|
||||||
|
"block_index": 4,
|
||||||
|
"title": "כותרת החלטה",
|
||||||
|
"generation_type": "template-fill",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"block_id": "block-he",
|
||||||
|
"block_index": 5,
|
||||||
|
"title": "פתיחה",
|
||||||
|
"generation_type": "paraphrase",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"block_id": "block-vav",
|
||||||
|
"block_index": 6,
|
||||||
|
"title": "רקע עובדתי",
|
||||||
|
"generation_type": "reproduction",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"block_id": "block-zayin",
|
||||||
|
"block_index": 7,
|
||||||
|
"title": "טענות הצדדים",
|
||||||
|
"generation_type": "paraphrase",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"block_id": "block-chet",
|
||||||
|
"block_index": 8,
|
||||||
|
"title": "הליכים בפני ועדת הערר",
|
||||||
|
"generation_type": "reproduction",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"block_id": "block-tet",
|
||||||
|
"block_index": 9,
|
||||||
|
"title": "תכניות חלות",
|
||||||
|
"generation_type": "guided-synthesis",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"block_id": "block-yod",
|
||||||
|
"block_index": 10,
|
||||||
|
"title": "דיון והכרעה",
|
||||||
|
"generation_type": "rhetorical-construction",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"block_id": "block-yod-alef",
|
||||||
|
"block_index": 11,
|
||||||
|
"title": "סיכום",
|
||||||
|
"generation_type": "paraphrase",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"block_id": "block-yod-bet",
|
||||||
|
"block_index": 12,
|
||||||
|
"title": "חתימות",
|
||||||
|
"generation_type": "template-fill",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Section header patterns (Hebrew)
|
||||||
|
SECTION_PATTERNS = {
|
||||||
|
"claims": re.compile(r"תמצית\s*טענות\s*הצדדים|טענות\s*הצדדים|טענות\s*העוררי"),
|
||||||
|
"proceedings": re.compile(r"ההליכים\s*בפני\s*ועדת\s*הערר|הליכים\s*בפני\s*הוועדה|הדיון\s*בפני\s*ועדת\s*הערר"),
|
||||||
|
"plans": re.compile(r"תכניות\s*חלות|המסגרת\s*התכנונית|הוראות\s*התכנית"),
|
||||||
|
"discussion": re.compile(r"דיון\s*והכרעה|דיון|הכרעה"),
|
||||||
|
"summary": re.compile(r"^סיכום$|^סוף\s*דבר$", re.MULTILINE),
|
||||||
|
"appellant_claims": re.compile(r"טענות\s*העוררי|טענות\s*העורר"),
|
||||||
|
"respondent_claims": re.compile(r"עמדת\s*הוועדה\s*המקומית|תגובת\s*המשיבה|עמדת\s*המשיב"),
|
||||||
|
"permit_applicant": re.compile(r"עמדת\s*מבקש|עמדת\s*מגיש|עמדת\s*היזם"),
|
||||||
|
"panel": re.compile(r"בפני[:\s]|יו\"ר"),
|
||||||
|
"parties_vs": re.compile(r"\s*נגד\s*"),
|
||||||
|
"decision_title": re.compile(r"^החלטה$", re.MULTILINE),
|
||||||
|
"opening": re.compile(r"^לפנינו\s|^בפנינו\s"),
|
||||||
|
"signature": re.compile(r"ניתנה?\s*(היום|פה\s*אחד|ביום)|חתימ"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def find_section_start(text: str, pattern: re.Pattern) -> int:
|
||||||
|
"""Find the character position where a section starts."""
|
||||||
|
match = pattern.search(text)
|
||||||
|
return match.start() if match else -1
|
||||||
|
|
||||||
|
|
||||||
|
def decompose_decision(text: str) -> list[dict]:
|
||||||
|
"""Parse decision text into blocks based on section headers."""
|
||||||
|
lines = text.split("\n")
|
||||||
|
total_len = len(text)
|
||||||
|
|
||||||
|
# Find key section boundaries
|
||||||
|
pos_claims = find_section_start(text, SECTION_PATTERNS["claims"])
|
||||||
|
pos_proceedings = find_section_start(text, SECTION_PATTERNS["proceedings"])
|
||||||
|
pos_plans = find_section_start(text, SECTION_PATTERNS["plans"])
|
||||||
|
pos_discussion = find_section_start(text, SECTION_PATTERNS["discussion"])
|
||||||
|
pos_summary = find_section_start(text, SECTION_PATTERNS["summary"])
|
||||||
|
pos_signature = find_section_start(text, SECTION_PATTERNS["signature"])
|
||||||
|
pos_opening = find_section_start(text, SECTION_PATTERNS["opening"])
|
||||||
|
pos_decision_title = find_section_start(text, SECTION_PATTERNS["decision_title"])
|
||||||
|
pos_panel = find_section_start(text, SECTION_PATTERNS["panel"])
|
||||||
|
pos_parties = find_section_start(text, SECTION_PATTERNS["parties_vs"])
|
||||||
|
|
||||||
|
# Build blocks based on what we found
|
||||||
|
blocks = []
|
||||||
|
|
||||||
|
# Blocks א-ד: Header area (before the opening "לפנינו")
|
||||||
|
header_end = pos_opening if pos_opening > 0 else pos_claims if pos_claims > 0 else 500
|
||||||
|
header_text = text[:header_end].strip()
|
||||||
|
|
||||||
|
# Try to split header into institutional header, panel, parties, title
|
||||||
|
if pos_panel > 0 and pos_panel < header_end:
|
||||||
|
blocks.append({"block_id": "block-alef", "content": text[:pos_panel].strip()})
|
||||||
|
|
||||||
|
if pos_parties > 0 and pos_parties < header_end:
|
||||||
|
blocks.append({"block_id": "block-bet", "content": text[pos_panel:pos_parties].strip()})
|
||||||
|
if pos_decision_title > 0 and pos_decision_title < header_end:
|
||||||
|
blocks.append({"block_id": "block-gimel", "content": text[pos_parties:pos_decision_title].strip()})
|
||||||
|
blocks.append({"block_id": "block-dalet", "content": "החלטה"})
|
||||||
|
else:
|
||||||
|
blocks.append({"block_id": "block-gimel", "content": text[pos_parties:header_end].strip()})
|
||||||
|
blocks.append({"block_id": "block-dalet", "content": "החלטה"})
|
||||||
|
else:
|
||||||
|
blocks.append({"block_id": "block-bet", "content": text[pos_panel:header_end].strip()})
|
||||||
|
blocks.append({"block_id": "block-gimel", "content": ""})
|
||||||
|
blocks.append({"block_id": "block-dalet", "content": "החלטה"})
|
||||||
|
else:
|
||||||
|
# Can't split — put everything in alef
|
||||||
|
blocks.append({"block_id": "block-alef", "content": header_text})
|
||||||
|
blocks.append({"block_id": "block-bet", "content": ""})
|
||||||
|
blocks.append({"block_id": "block-gimel", "content": ""})
|
||||||
|
blocks.append({"block_id": "block-dalet", "content": "החלטה"})
|
||||||
|
|
||||||
|
# Block ה: Opening — from "לפנינו" to claims section
|
||||||
|
if pos_opening > 0:
|
||||||
|
opening_end = pos_claims if pos_claims > pos_opening else pos_discussion if pos_discussion > pos_opening else total_len
|
||||||
|
# Opening is usually just 1-3 paragraphs
|
||||||
|
opening_text = text[pos_opening:min(pos_opening + 1000, opening_end)].strip()
|
||||||
|
# Find end of first few paragraphs
|
||||||
|
para_breaks = [i for i, c in enumerate(opening_text) if c == '\n' and i > 50]
|
||||||
|
if len(para_breaks) >= 2:
|
||||||
|
opening_text = opening_text[:para_breaks[1]].strip()
|
||||||
|
blocks.append({"block_id": "block-he", "content": opening_text})
|
||||||
|
|
||||||
|
# Block ו: Background — from after opening to claims
|
||||||
|
if pos_claims > pos_opening:
|
||||||
|
bg_start = pos_opening + len(opening_text)
|
||||||
|
blocks.append({"block_id": "block-vav", "content": text[bg_start:pos_claims].strip()})
|
||||||
|
else:
|
||||||
|
blocks.append({"block_id": "block-vav", "content": ""})
|
||||||
|
else:
|
||||||
|
blocks.append({"block_id": "block-he", "content": ""})
|
||||||
|
blocks.append({"block_id": "block-vav", "content": ""})
|
||||||
|
|
||||||
|
# Block ז: Claims
|
||||||
|
if pos_claims > 0:
|
||||||
|
claims_end = pos_proceedings if pos_proceedings > pos_claims else pos_discussion if pos_discussion > pos_claims else pos_summary if pos_summary > pos_claims else total_len
|
||||||
|
blocks.append({"block_id": "block-zayin", "content": text[pos_claims:claims_end].strip()})
|
||||||
|
else:
|
||||||
|
blocks.append({"block_id": "block-zayin", "content": ""})
|
||||||
|
|
||||||
|
# Block ח: Proceedings (optional)
|
||||||
|
if pos_proceedings > 0:
|
||||||
|
proc_end = pos_plans if pos_plans > pos_proceedings else pos_discussion if pos_discussion > pos_proceedings else pos_summary if pos_summary > pos_proceedings else total_len
|
||||||
|
blocks.append({"block_id": "block-chet", "content": text[pos_proceedings:proc_end].strip()})
|
||||||
|
else:
|
||||||
|
blocks.append({"block_id": "block-chet", "content": ""})
|
||||||
|
|
||||||
|
# Block ט: Plans (optional)
|
||||||
|
if pos_plans > 0 and pos_plans < (pos_discussion if pos_discussion > 0 else total_len):
|
||||||
|
plans_end = pos_discussion if pos_discussion > pos_plans else pos_summary if pos_summary > pos_plans else total_len
|
||||||
|
blocks.append({"block_id": "block-tet", "content": text[pos_plans:plans_end].strip()})
|
||||||
|
else:
|
||||||
|
blocks.append({"block_id": "block-tet", "content": ""})
|
||||||
|
|
||||||
|
# Block י: Discussion
|
||||||
|
if pos_discussion > 0:
|
||||||
|
disc_end = pos_summary if pos_summary > pos_discussion else pos_signature if pos_signature > pos_discussion else total_len
|
||||||
|
blocks.append({"block_id": "block-yod", "content": text[pos_discussion:disc_end].strip()})
|
||||||
|
else:
|
||||||
|
blocks.append({"block_id": "block-yod", "content": ""})
|
||||||
|
|
||||||
|
# Block יא: Summary
|
||||||
|
if pos_summary > 0:
|
||||||
|
summ_end = pos_signature if pos_signature > pos_summary else total_len
|
||||||
|
blocks.append({"block_id": "block-yod-alef", "content": text[pos_summary:summ_end].strip()})
|
||||||
|
else:
|
||||||
|
blocks.append({"block_id": "block-yod-alef", "content": ""})
|
||||||
|
|
||||||
|
# Block יב: Signatures
|
||||||
|
if pos_signature > 0:
|
||||||
|
blocks.append({"block_id": "block-yod-bet", "content": text[pos_signature:].strip()})
|
||||||
|
else:
|
||||||
|
blocks.append({"block_id": "block-yod-bet", "content": ""})
|
||||||
|
|
||||||
|
return blocks
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await init_schema()
|
||||||
|
pool = await get_pool()
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
decisions = await conn.fetch(
|
||||||
|
"""SELECT d.id as decision_id, c.case_number, c.title, d.total_words,
|
||||||
|
doc.extracted_text
|
||||||
|
FROM decisions d
|
||||||
|
JOIN cases c ON c.id = d.case_id
|
||||||
|
JOIN documents doc ON doc.case_id = d.case_id AND doc.doc_type = 'decision'
|
||||||
|
WHERE d.status = 'final'
|
||||||
|
ORDER BY c.case_number"""
|
||||||
|
)
|
||||||
|
|
||||||
|
for dec in decisions:
|
||||||
|
decision_id = dec["decision_id"]
|
||||||
|
case_number = dec["case_number"]
|
||||||
|
text = dec["extracted_text"]
|
||||||
|
total_words = len(text.split())
|
||||||
|
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"מפרק: {case_number} — {dec['title']}")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
|
||||||
|
# Decompose
|
||||||
|
blocks = decompose_decision(text)
|
||||||
|
|
||||||
|
# Merge with block metadata
|
||||||
|
block_data = []
|
||||||
|
for block_def in BLOCKS:
|
||||||
|
matching = [b for b in blocks if b["block_id"] == block_def["block_id"]]
|
||||||
|
content = matching[0]["content"] if matching else ""
|
||||||
|
word_count = len(content.split()) if content else 0
|
||||||
|
weight = round((word_count / total_words * 100), 2) if total_words > 0 and word_count > 0 else 0
|
||||||
|
|
||||||
|
block_data.append({
|
||||||
|
**block_def,
|
||||||
|
"content": content,
|
||||||
|
"word_count": word_count,
|
||||||
|
"weight_percent": weight,
|
||||||
|
"status": "final" if content else "empty",
|
||||||
|
})
|
||||||
|
|
||||||
|
# Print summary
|
||||||
|
for b in block_data:
|
||||||
|
status = "✅" if b["word_count"] > 0 else "⬜"
|
||||||
|
print(f" {status} {b['block_id']:18s} | {b['title']:25s} | {b['word_count']:5d} מילים | {b['weight_percent']:5.1f}%")
|
||||||
|
|
||||||
|
# Store in DB
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
# Delete existing blocks for this decision
|
||||||
|
await conn.execute(
|
||||||
|
"DELETE FROM decision_blocks WHERE decision_id = $1", decision_id
|
||||||
|
)
|
||||||
|
|
||||||
|
for b in block_data:
|
||||||
|
await conn.execute(
|
||||||
|
"""INSERT INTO decision_blocks
|
||||||
|
(decision_id, block_id, block_index, title, content,
|
||||||
|
word_count, weight_percent, generation_type, status)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)""",
|
||||||
|
decision_id,
|
||||||
|
b["block_id"], b["block_index"], b["title"],
|
||||||
|
b["content"], b["word_count"], b["weight_percent"],
|
||||||
|
b["generation_type"], b["status"],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Count paragraphs in discussion block
|
||||||
|
discussion = [b for b in block_data if b["block_id"] == "block-yod"][0]
|
||||||
|
if discussion["content"]:
|
||||||
|
paragraphs = [p.strip() for p in discussion["content"].split("\n") if p.strip() and len(p.strip()) > 20]
|
||||||
|
await conn.execute(
|
||||||
|
"UPDATE decisions SET total_paragraphs = $1 WHERE id = $2",
|
||||||
|
len(paragraphs), decision_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Final summary
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
block_count = await conn.fetchval("SELECT count(*) FROM decision_blocks")
|
||||||
|
non_empty = await conn.fetchval("SELECT count(*) FROM decision_blocks WHERE status = 'final'")
|
||||||
|
|
||||||
|
await close_pool()
|
||||||
|
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"✅ סה\"כ בלוקים: {block_count} ({non_empty} עם תוכן)")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
139
scripts/export-decision-docx.py
Normal file
139
scripts/export-decision-docx.py
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Export a decision from DB to DOCX using the CJS template generator.
|
||||||
|
|
||||||
|
Usage: python export-decision-docx.py <case_number> [output.docx]
|
||||||
|
|
||||||
|
Pulls decision blocks from DB, generates structure JSON,
|
||||||
|
invokes create-decision-structure.cjs to produce DOCX.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src"))
|
||||||
|
|
||||||
|
from legal_mcp.services.db import get_pool, init_schema, close_pool
|
||||||
|
|
||||||
|
CJS_SCRIPT = Path(__file__).parent.parent / "skill-legal-decision" / "scripts" / "create-decision-structure.cjs"
|
||||||
|
|
||||||
|
|
||||||
|
def block_id_to_hebrew(block_id: str) -> str:
|
||||||
|
"""Map block_id to Hebrew letter label."""
|
||||||
|
mapping = {
|
||||||
|
"block-alef": "א", "block-bet": "ב", "block-gimel": "ג",
|
||||||
|
"block-dalet": "ד", "block-he": "ה", "block-vav": "ו",
|
||||||
|
"block-zayin": "ז", "block-chet": "ח", "block-tet": "ט",
|
||||||
|
"block-yod": "י", "block-yod-alef": "יא", "block-yod-bet": "יב",
|
||||||
|
}
|
||||||
|
return mapping.get(block_id, "")
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("שימוש: python export-decision-docx.py <מספר_תיק> [output.docx]")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
case_number = sys.argv[1]
|
||||||
|
output_path = sys.argv[2] if len(sys.argv) > 2 else f"החלטה-{case_number}.docx"
|
||||||
|
|
||||||
|
await init_schema()
|
||||||
|
pool = await get_pool()
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
# Get case info
|
||||||
|
case = await conn.fetchrow(
|
||||||
|
"SELECT * FROM cases WHERE case_number = $1", case_number
|
||||||
|
)
|
||||||
|
if not case:
|
||||||
|
print(f"תיק {case_number} לא נמצא")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Get decision
|
||||||
|
decision = await conn.fetchrow(
|
||||||
|
"SELECT * FROM decisions WHERE case_id = $1 AND status = 'final'",
|
||||||
|
case["id"],
|
||||||
|
)
|
||||||
|
if not decision:
|
||||||
|
print(f"אין החלטה סופית לתיק {case_number}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Get blocks
|
||||||
|
blocks = await conn.fetch(
|
||||||
|
"""SELECT block_id, block_index, title, content, word_count
|
||||||
|
FROM decision_blocks
|
||||||
|
WHERE decision_id = $1
|
||||||
|
ORDER BY block_index""",
|
||||||
|
decision["id"],
|
||||||
|
)
|
||||||
|
|
||||||
|
await close_pool()
|
||||||
|
|
||||||
|
# Build structure JSON for CJS script
|
||||||
|
appellants = json.loads(case["appellants"]) if isinstance(case["appellants"], str) else case["appellants"]
|
||||||
|
respondents = json.loads(case["respondents"]) if isinstance(case["respondents"], str) else case["respondents"]
|
||||||
|
|
||||||
|
structure = {
|
||||||
|
"metadata": {
|
||||||
|
"case_number": case["case_number"],
|
||||||
|
"title": case["title"],
|
||||||
|
"subject": case["subject"],
|
||||||
|
"property_address": case["property_address"],
|
||||||
|
"committee": case["committee_type"],
|
||||||
|
"outcome": decision["outcome"] or "",
|
||||||
|
"decision_date": str(decision["decision_date"]) if decision["decision_date"] else "",
|
||||||
|
"author": decision["author"],
|
||||||
|
},
|
||||||
|
"parties": {
|
||||||
|
"appellants": [{"name": a} for a in appellants],
|
||||||
|
"respondents": [{"name": r} for r in respondents],
|
||||||
|
},
|
||||||
|
"blocks": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
for block in blocks:
|
||||||
|
content = block["content"] or ""
|
||||||
|
# Skip empty header blocks
|
||||||
|
if block["block_id"] in ("block-alef", "block-bet", "block-gimel", "block-dalet") and not content:
|
||||||
|
continue
|
||||||
|
|
||||||
|
paragraphs = [p.strip() for p in content.split("\n") if p.strip()]
|
||||||
|
|
||||||
|
structure["blocks"].append({
|
||||||
|
"id": block["block_id"],
|
||||||
|
"index": block["block_index"],
|
||||||
|
"title": block["title"],
|
||||||
|
"hebrew_letter": block_id_to_hebrew(block["block_id"]),
|
||||||
|
"word_count": block["word_count"],
|
||||||
|
"paragraphs": paragraphs,
|
||||||
|
})
|
||||||
|
|
||||||
|
# Write JSON (absolute paths)
|
||||||
|
output_abs = Path(output_path).resolve()
|
||||||
|
json_path = output_abs.with_suffix(".json")
|
||||||
|
json_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
with open(json_path, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(structure, f, ensure_ascii=False, indent=2)
|
||||||
|
print(f"JSON נוצר: {json_path}")
|
||||||
|
|
||||||
|
# Run CJS script with absolute paths
|
||||||
|
result = subprocess.run(
|
||||||
|
["node", str(CJS_SCRIPT), str(json_path), str(output_abs)],
|
||||||
|
capture_output=True, text=True,
|
||||||
|
cwd=str(CJS_SCRIPT.parent),
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(f"✅ DOCX נוצר: {output_path}")
|
||||||
|
else:
|
||||||
|
print(f"❌ שגיאה ביצירת DOCX:")
|
||||||
|
print(result.stderr)
|
||||||
|
# JSON is still available for manual processing
|
||||||
|
print(f"ה-JSON זמין: {json_path}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
134
scripts/extract-citations.py
Normal file
134
scripts/extract-citations.py
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Extract case law citations from block-yod and link to case_law table."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src"))
|
||||||
|
|
||||||
|
from legal_mcp.services.db import get_pool, init_schema, close_pool
|
||||||
|
|
||||||
|
# Patterns for Israeli case law citations
|
||||||
|
CITATION_PATTERNS = [
|
||||||
|
# עע"מ, בג"ץ, ע"א, etc.
|
||||||
|
re.compile(r'(עע"מ|בג"ץ|ע"א|בר"ם|עת"מ|עמ"נ|ע"ע|רע"א|דנ"א|בש"א)\s*(\d[\d/\-]+)'),
|
||||||
|
# ערר with number
|
||||||
|
re.compile(r'ערר\s*\(?\s*(?:מרכז|ירושלים|חי\'?|ת"א|דרום|צפון)?\s*\)?\s*(\d[\d/\-]+)'),
|
||||||
|
# ערר without district
|
||||||
|
re.compile(r'ערר\s+(\d{3,5}[\-/]\d{2,4})'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def extract_citations_from_text(text: str) -> list[dict]:
|
||||||
|
"""Find all case law citations in text."""
|
||||||
|
citations = []
|
||||||
|
seen = set()
|
||||||
|
|
||||||
|
for pattern in CITATION_PATTERNS:
|
||||||
|
for match in pattern.finditer(text):
|
||||||
|
full_match = match.group(0)
|
||||||
|
if full_match in seen:
|
||||||
|
continue
|
||||||
|
seen.add(full_match)
|
||||||
|
|
||||||
|
# Get surrounding context (50 chars before and after)
|
||||||
|
start = max(0, match.start() - 50)
|
||||||
|
end = min(len(text), match.end() + 100)
|
||||||
|
context = text[start:end].replace("\n", " ")
|
||||||
|
|
||||||
|
citations.append({
|
||||||
|
"citation_text": full_match,
|
||||||
|
"context": context,
|
||||||
|
})
|
||||||
|
|
||||||
|
return citations
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await init_schema()
|
||||||
|
pool = await get_pool()
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
# Get all block-yod content with decision info
|
||||||
|
blocks = await conn.fetch(
|
||||||
|
"""SELECT db.content, d.id as decision_id, c.case_number
|
||||||
|
FROM decision_blocks db
|
||||||
|
JOIN decisions d ON d.id = db.decision_id
|
||||||
|
JOIN cases c ON c.id = d.case_id
|
||||||
|
WHERE db.block_id = 'block-yod' AND db.word_count > 0
|
||||||
|
ORDER BY c.case_number"""
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get existing case_law for matching
|
||||||
|
case_laws = await conn.fetch("SELECT id, case_number, case_name FROM case_law")
|
||||||
|
case_law_map = {}
|
||||||
|
for cl in case_laws:
|
||||||
|
# Index by various forms of the case number
|
||||||
|
case_law_map[cl["case_number"]] = cl["id"]
|
||||||
|
# Also index by short number (e.g., "3975/22" from "עע"מ 3975/22")
|
||||||
|
parts = cl["case_number"].split()
|
||||||
|
if len(parts) > 1:
|
||||||
|
case_law_map[parts[-1]] = cl["id"]
|
||||||
|
|
||||||
|
total_citations = 0
|
||||||
|
total_linked = 0
|
||||||
|
|
||||||
|
for block in blocks:
|
||||||
|
case_number = block["case_number"]
|
||||||
|
decision_id = block["decision_id"]
|
||||||
|
text = block["content"]
|
||||||
|
|
||||||
|
citations = extract_citations_from_text(text)
|
||||||
|
|
||||||
|
if not citations:
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"\n{case_number}: {len(citations)} ציטוטים נמצאו")
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
for cit in citations:
|
||||||
|
total_citations += 1
|
||||||
|
|
||||||
|
# Try to match to case_law table
|
||||||
|
case_law_id = None
|
||||||
|
for key, cl_id in case_law_map.items():
|
||||||
|
if key in cit["citation_text"] or cit["citation_text"] in key:
|
||||||
|
case_law_id = cl_id
|
||||||
|
break
|
||||||
|
|
||||||
|
if case_law_id:
|
||||||
|
# Check if already exists
|
||||||
|
existing = await conn.fetchval(
|
||||||
|
"""SELECT id FROM case_law_citations
|
||||||
|
WHERE case_law_id = $1 AND decision_id = $2""",
|
||||||
|
case_law_id, decision_id,
|
||||||
|
)
|
||||||
|
if not existing:
|
||||||
|
await conn.execute(
|
||||||
|
"""INSERT INTO case_law_citations
|
||||||
|
(case_law_id, decision_id, citation_type, context_text)
|
||||||
|
VALUES ($1, $2, 'support', $3)""",
|
||||||
|
case_law_id, decision_id, cit["context"],
|
||||||
|
)
|
||||||
|
total_linked += 1
|
||||||
|
print(f" ✅ {cit['citation_text'][:40]} → קושר לפסיקה")
|
||||||
|
else:
|
||||||
|
print(f" ⬜ {cit['citation_text'][:40]} — לא נמצא ב-DB")
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
total_in_db = await conn.fetchval("SELECT count(*) FROM case_law_citations")
|
||||||
|
|
||||||
|
await close_pool()
|
||||||
|
|
||||||
|
print(f"\n{'='*50}")
|
||||||
|
print(f"סה\"כ ציטוטים שנמצאו: {total_citations}")
|
||||||
|
print(f"סה\"כ קושרו לפסיקה ב-DB: {total_linked}")
|
||||||
|
print(f"סה\"כ ב-case_law_citations: {total_in_db}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
228
scripts/extract-claims.py
Normal file
228
scripts/extract-claims.py
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Extract individual claims from block-zayin of each decision.
|
||||||
|
|
||||||
|
Identifies party sub-sections and individual claims (paragraphs).
|
||||||
|
Stores in the claims table with party_role classification.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src"))
|
||||||
|
|
||||||
|
from legal_mcp.services.db import get_pool, init_schema, close_pool
|
||||||
|
|
||||||
|
|
||||||
|
# Party role detection patterns
|
||||||
|
PARTY_PATTERNS = [
|
||||||
|
# Appellants
|
||||||
|
(r"טענות\s*העוררי[םן]|טענות\s*העורר\b|טענות\s*המבקש|טענות\s*המערער", "appellant"),
|
||||||
|
# Respondent - local committee
|
||||||
|
(r"עמדת\s*הוועדה\s*המקומית|עמדת\s*המשיבה|טענות\s*המשיבה|תגובת\s*המשיבה|הוועדה\s*המקומית$", "committee"),
|
||||||
|
# Respondent - general
|
||||||
|
(r"עמדת\s*המשיבי[םן]|עמדת\s*המשיב\b|טענות\s*המשיבי[םן]|טענות\s*המשיב\b", "respondent"),
|
||||||
|
# Permit applicant
|
||||||
|
(r"מבקשי\s*ההיתר|עמדת\s*מבקש|עמדת\s*היזם|מגישי\s*התכנית", "permit_applicant"),
|
||||||
|
# Appraiser clarifications (היטל השבחה)
|
||||||
|
(r"הבהרות\s*השמא|התייחסות\s*הצדדים", "appraiser"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def detect_party_role(line: str) -> str | None:
|
||||||
|
"""Detect if a line is a party section header. Returns role or None."""
|
||||||
|
for pattern, role in PARTY_PATTERNS:
|
||||||
|
if re.search(pattern, line):
|
||||||
|
return role
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def is_section_header(line: str) -> bool:
|
||||||
|
"""Check if line is a section/sub-section header (not a claim)."""
|
||||||
|
line = line.strip()
|
||||||
|
if not line:
|
||||||
|
return False
|
||||||
|
# Very short lines that are headers
|
||||||
|
if len(line) < 50 and (
|
||||||
|
detect_party_role(line) is not None
|
||||||
|
or re.match(r"^תמצית\s*טענות", line)
|
||||||
|
or re.match(r"^[א-ת][\.\)]\s*טענות", line)
|
||||||
|
or re.match(r"^[א-ת][\.\)]\s*כללי", line)
|
||||||
|
or re.match(r"^\d+\.\s*$", line) # just a number
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def is_numbered_sub_header(line: str) -> bool:
|
||||||
|
"""Check if line is a numbered topic header within claims (e.g., '2. שיעור ההפקעה')."""
|
||||||
|
return bool(re.match(r"^\d+\.\s+\S.{3,40}$", line.strip()))
|
||||||
|
|
||||||
|
|
||||||
|
def extract_claims_from_block(text: str) -> list[dict]:
|
||||||
|
"""Extract individual claims grouped by party from block-zayin text."""
|
||||||
|
lines = text.split("\n")
|
||||||
|
claims = []
|
||||||
|
current_role = "appellant" # default if no header found
|
||||||
|
current_claim_lines = []
|
||||||
|
claim_index = 0
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
stripped = line.strip()
|
||||||
|
if not stripped:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check for party header — must be a SHORT line (header, not claim content)
|
||||||
|
role = detect_party_role(stripped) if len(stripped.split()) <= 8 else None
|
||||||
|
if role:
|
||||||
|
# Save accumulated claim
|
||||||
|
if current_claim_lines:
|
||||||
|
claim_text = "\n".join(current_claim_lines).strip()
|
||||||
|
if len(claim_text) > 30:
|
||||||
|
claims.append({
|
||||||
|
"party_role": current_role,
|
||||||
|
"claim_text": claim_text,
|
||||||
|
"claim_index": claim_index,
|
||||||
|
})
|
||||||
|
claim_index += 1
|
||||||
|
current_claim_lines = []
|
||||||
|
current_role = role
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Skip generic section headers
|
||||||
|
if is_section_header(stripped):
|
||||||
|
# Save accumulated claim before skipping header
|
||||||
|
if current_claim_lines:
|
||||||
|
claim_text = "\n".join(current_claim_lines).strip()
|
||||||
|
if len(claim_text) > 30:
|
||||||
|
claims.append({
|
||||||
|
"party_role": current_role,
|
||||||
|
"claim_text": claim_text,
|
||||||
|
"claim_index": claim_index,
|
||||||
|
})
|
||||||
|
claim_index += 1
|
||||||
|
current_claim_lines = []
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Numbered sub-header in היטל השבחה style (e.g., "2. שיעור ההפקעה")
|
||||||
|
# starts a new claim
|
||||||
|
if is_numbered_sub_header(stripped):
|
||||||
|
if current_claim_lines:
|
||||||
|
claim_text = "\n".join(current_claim_lines).strip()
|
||||||
|
if len(claim_text) > 30:
|
||||||
|
claims.append({
|
||||||
|
"party_role": current_role,
|
||||||
|
"claim_text": claim_text,
|
||||||
|
"claim_index": claim_index,
|
||||||
|
})
|
||||||
|
claim_index += 1
|
||||||
|
current_claim_lines = [stripped]
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Each substantial paragraph is a separate claim
|
||||||
|
# Save previous accumulated claim first
|
||||||
|
if current_claim_lines:
|
||||||
|
claim_text = "\n".join(current_claim_lines).strip()
|
||||||
|
if len(claim_text) > 30:
|
||||||
|
claims.append({
|
||||||
|
"party_role": current_role,
|
||||||
|
"claim_text": claim_text,
|
||||||
|
"claim_index": claim_index,
|
||||||
|
})
|
||||||
|
claim_index += 1
|
||||||
|
current_claim_lines = [stripped]
|
||||||
|
|
||||||
|
# Save last claim
|
||||||
|
if current_claim_lines:
|
||||||
|
claim_text = "\n".join(current_claim_lines).strip()
|
||||||
|
if len(claim_text) > 30:
|
||||||
|
claims.append({
|
||||||
|
"party_role": current_role,
|
||||||
|
"claim_text": claim_text,
|
||||||
|
"claim_index": claim_index,
|
||||||
|
})
|
||||||
|
|
||||||
|
return claims
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await init_schema()
|
||||||
|
pool = await get_pool()
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
# Get all block-zayin with content
|
||||||
|
rows = await conn.fetch(
|
||||||
|
"""SELECT c.id as case_id, c.case_number, c.title,
|
||||||
|
db.content
|
||||||
|
FROM decision_blocks db
|
||||||
|
JOIN decisions d ON d.id = db.decision_id
|
||||||
|
JOIN cases c ON c.id = d.case_id
|
||||||
|
WHERE db.block_id = 'block-zayin' AND db.word_count > 0
|
||||||
|
ORDER BY c.case_number"""
|
||||||
|
)
|
||||||
|
|
||||||
|
total_claims = 0
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
case_id = row["case_id"]
|
||||||
|
case_number = row["case_number"]
|
||||||
|
text = row["content"]
|
||||||
|
|
||||||
|
claims = extract_claims_from_block(text)
|
||||||
|
|
||||||
|
print(f"\n{'='*50}")
|
||||||
|
print(f"תיק: {case_number} — {row['title']}")
|
||||||
|
print(f"{'='*50}")
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
# Delete existing claims for this case
|
||||||
|
await conn.execute("DELETE FROM claims WHERE case_id = $1", case_id)
|
||||||
|
|
||||||
|
role_counts = {}
|
||||||
|
for claim in claims:
|
||||||
|
role = claim["party_role"]
|
||||||
|
role_counts[role] = role_counts.get(role, 0) + 1
|
||||||
|
|
||||||
|
await conn.execute(
|
||||||
|
"""INSERT INTO claims (case_id, party_role, claim_text, claim_index, source_document)
|
||||||
|
VALUES ($1, $2, $3, $4, $5)""",
|
||||||
|
case_id,
|
||||||
|
claim["party_role"],
|
||||||
|
claim["claim_text"],
|
||||||
|
claim["claim_index"],
|
||||||
|
"block-zayin",
|
||||||
|
)
|
||||||
|
|
||||||
|
for role, count in sorted(role_counts.items()):
|
||||||
|
role_heb = {
|
||||||
|
"appellant": "עוררים",
|
||||||
|
"committee": "ועדה מקומית",
|
||||||
|
"respondent": "משיבים",
|
||||||
|
"permit_applicant": "מבקשי היתר",
|
||||||
|
"appraiser": "שמאי",
|
||||||
|
}.get(role, role)
|
||||||
|
print(f" {role_heb:20s} — {count} טענות")
|
||||||
|
|
||||||
|
total_claims += len(claims)
|
||||||
|
print(f" סה\"כ: {len(claims)} טענות")
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
total = await conn.fetchval("SELECT count(*) FROM claims")
|
||||||
|
by_role = await conn.fetch(
|
||||||
|
"SELECT party_role, count(*) as cnt FROM claims GROUP BY party_role ORDER BY cnt DESC"
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"\n{'='*50}")
|
||||||
|
print(f"סיכום כללי — {total} טענות מ-{len(rows)} החלטות")
|
||||||
|
for r in by_role:
|
||||||
|
print(f" {r['party_role']:20s} — {r['cnt']}")
|
||||||
|
|
||||||
|
await close_pool()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
177
scripts/generate-embeddings.py
Normal file
177
scripts/generate-embeddings.py
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Generate embeddings for decision blocks and case law.
|
||||||
|
|
||||||
|
Creates:
|
||||||
|
- paragraph_embeddings: for each decision block with content
|
||||||
|
- case_law_embeddings: for each case law summary
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src"))
|
||||||
|
|
||||||
|
from legal_mcp.services.db import get_pool, init_schema, close_pool
|
||||||
|
from legal_mcp.services.embeddings import embed_texts
|
||||||
|
from legal_mcp import config
|
||||||
|
|
||||||
|
|
||||||
|
async def generate_block_embeddings(conn) -> int:
|
||||||
|
"""Generate embeddings for decision blocks.
|
||||||
|
|
||||||
|
First creates decision_paragraphs records from block content,
|
||||||
|
then generates embeddings in paragraph_embeddings.
|
||||||
|
"""
|
||||||
|
blocks = await conn.fetch(
|
||||||
|
"""SELECT db.id as block_id, db.decision_id, db.block_id as block_type,
|
||||||
|
db.content, db.word_count, c.case_number
|
||||||
|
FROM decision_blocks db
|
||||||
|
JOIN decisions d ON d.id = db.decision_id
|
||||||
|
JOIN cases c ON c.id = d.case_id
|
||||||
|
WHERE db.word_count > 10
|
||||||
|
AND db.block_id NOT IN ('block-alef', 'block-bet', 'block-gimel', 'block-dalet')
|
||||||
|
ORDER BY c.case_number, db.block_index"""
|
||||||
|
)
|
||||||
|
|
||||||
|
if not blocks:
|
||||||
|
print(" אין בלוקים ליצירת embeddings")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
print(f" מעבד {len(blocks)} בלוקים...")
|
||||||
|
|
||||||
|
# Create paragraphs and collect texts for embedding
|
||||||
|
para_records = []
|
||||||
|
para_number = 1
|
||||||
|
|
||||||
|
for block in blocks:
|
||||||
|
content = block["content"]
|
||||||
|
words = content.split()
|
||||||
|
|
||||||
|
# Split into chunks for embedding
|
||||||
|
if len(words) <= 600:
|
||||||
|
chunk_texts = [content]
|
||||||
|
else:
|
||||||
|
chunk_texts = []
|
||||||
|
for start in range(0, len(words), 400):
|
||||||
|
chunk_words = words[start:start + 500]
|
||||||
|
if len(chunk_words) > 50:
|
||||||
|
chunk_texts.append(" ".join(chunk_words))
|
||||||
|
|
||||||
|
for chunk_text in chunk_texts:
|
||||||
|
# Create decision_paragraph record
|
||||||
|
para_id = await conn.fetchval(
|
||||||
|
"""INSERT INTO decision_paragraphs
|
||||||
|
(block_id, paragraph_number, content, word_count)
|
||||||
|
VALUES ($1, $2, $3, $4)
|
||||||
|
ON CONFLICT DO NOTHING
|
||||||
|
RETURNING id""",
|
||||||
|
block["block_id"],
|
||||||
|
para_number,
|
||||||
|
chunk_text,
|
||||||
|
len(chunk_text.split()),
|
||||||
|
)
|
||||||
|
if para_id:
|
||||||
|
para_records.append({
|
||||||
|
"para_id": para_id,
|
||||||
|
"text": chunk_text,
|
||||||
|
"case_number": block["case_number"],
|
||||||
|
})
|
||||||
|
para_number += 1
|
||||||
|
|
||||||
|
if not para_records:
|
||||||
|
print(" אין פסקאות חדשות")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
print(f" {len(para_records)} פסקאות נוצרו, מייצר embeddings...")
|
||||||
|
|
||||||
|
# Generate embeddings in batches
|
||||||
|
texts = [p["text"] for p in para_records]
|
||||||
|
embeddings = await embed_texts(texts, input_type="document")
|
||||||
|
|
||||||
|
# Store embeddings
|
||||||
|
count = 0
|
||||||
|
for para, embedding in zip(para_records, embeddings):
|
||||||
|
await conn.execute(
|
||||||
|
"""INSERT INTO paragraph_embeddings (paragraph_id, embedding)
|
||||||
|
VALUES ($1, $2)""",
|
||||||
|
para["para_id"],
|
||||||
|
embedding,
|
||||||
|
)
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
async def generate_case_law_embeddings(conn) -> int:
|
||||||
|
"""Generate embeddings for case law summaries."""
|
||||||
|
cases = await conn.fetch(
|
||||||
|
"""SELECT id, case_number, case_name, summary, key_quote
|
||||||
|
FROM case_law
|
||||||
|
WHERE summary != '' OR key_quote != ''"""
|
||||||
|
)
|
||||||
|
|
||||||
|
# Filter out existing
|
||||||
|
existing = await conn.fetch("SELECT case_law_id FROM case_law_embeddings")
|
||||||
|
existing_ids = {r["case_law_id"] for r in existing}
|
||||||
|
|
||||||
|
to_embed = [c for c in cases if c["id"] not in existing_ids]
|
||||||
|
|
||||||
|
if not to_embed:
|
||||||
|
print(" אין פסיקה חדשה ליצירת embeddings")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
print(f" מייצר embeddings ל-{len(to_embed)} תקדימים...")
|
||||||
|
|
||||||
|
texts = []
|
||||||
|
for c in to_embed:
|
||||||
|
# Combine case info into a searchable text
|
||||||
|
text = f"{c['case_number']} {c['case_name']}: {c['summary']}"
|
||||||
|
if c["key_quote"]:
|
||||||
|
text += f" ציטוט: {c['key_quote']}"
|
||||||
|
texts.append(text)
|
||||||
|
|
||||||
|
embeddings = await embed_texts(texts, input_type="document")
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for case, embedding in zip(to_embed, embeddings):
|
||||||
|
await conn.execute(
|
||||||
|
"""INSERT INTO case_law_embeddings (case_law_id, chunk_text, embedding)
|
||||||
|
VALUES ($1, $2, $3)""",
|
||||||
|
case["id"],
|
||||||
|
f"{case['case_number']} {case['case_name']}: {case['summary']}",
|
||||||
|
embedding,
|
||||||
|
)
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await init_schema()
|
||||||
|
pool = await get_pool()
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
print("שלב 1: embeddings לבלוקי החלטה")
|
||||||
|
block_count = await generate_block_embeddings(conn)
|
||||||
|
print(f" ✅ {block_count} embeddings נוצרו")
|
||||||
|
|
||||||
|
print("\nשלב 2: embeddings לפסיקה")
|
||||||
|
cl_count = await generate_case_law_embeddings(conn)
|
||||||
|
print(f" ✅ {cl_count} embeddings נוצרו")
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
para_total = await conn.fetchval("SELECT count(*) FROM paragraph_embeddings")
|
||||||
|
cl_total = await conn.fetchval("SELECT count(*) FROM case_law_embeddings")
|
||||||
|
|
||||||
|
await close_pool()
|
||||||
|
|
||||||
|
print(f"\nסיכום:")
|
||||||
|
print(f" סה\"כ paragraph_embeddings: {para_total}")
|
||||||
|
print(f" סה\"כ case_law_embeddings: {cl_total}")
|
||||||
|
print(f" מודל: {config.VOYAGE_MODEL}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
202
scripts/import-final-decisions.py
Normal file
202
scripts/import-final-decisions.py
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Import 6 final signed decisions: extract text, store in DB."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from datetime import date
|
||||||
|
from pathlib import Path
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src"))
|
||||||
|
|
||||||
|
import fitz # PyMuPDF
|
||||||
|
from docx import Document as DocxDocument
|
||||||
|
|
||||||
|
from legal_mcp.services.db import get_pool, init_schema, close_pool
|
||||||
|
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════
|
||||||
|
# 6 Final Decisions
|
||||||
|
# ═══════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
FINAL_DECISIONS = [
|
||||||
|
{
|
||||||
|
"case_number": "1180-1181",
|
||||||
|
"file_path": "legacy/dafna-tamir/04_Archive/ערר 1180-1181 הכט/החלטה/הכט 1180-1181.pdf",
|
||||||
|
"title": "החלטה סופית — הכט 1180-1181",
|
||||||
|
"outcome": "rejected",
|
||||||
|
"decision_date": date(2026, 2, 5),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "8255-25",
|
||||||
|
"file_path": "legacy/dafna-tamir/04_Archive/בל\"מ 8255-25 אפרים אבי נ' הוועדה המקומית לתכנון ובניה/החלטה/אליהו הרנון - להפצה.docx",
|
||||||
|
"title": "החלטה סופית — אפרים אבי 8255-25",
|
||||||
|
"outcome": "rejected",
|
||||||
|
"decision_date": None,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "8007-24",
|
||||||
|
"file_path": "legacy/dafna-tamir/04_Archive/ערר 8007-24-עומר דרוויש-ערר על שומה מכרעת/החלטה/החלטה-סופית.docx",
|
||||||
|
"title": "החלטה סופית — עומר דרוויש 8007-24",
|
||||||
|
"outcome": "",
|
||||||
|
"decision_date": None,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "1113/25",
|
||||||
|
"file_path": "legacy/dafna-tamir/04_Archive/ערר-1113-25-אייל-מבורך/החלטה/החלטה-1113-25-טיוטה-סופית.docx",
|
||||||
|
"title": "החלטה סופית — מבורך 1113-25",
|
||||||
|
"outcome": "",
|
||||||
|
"decision_date": None,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "1126/25+1141/25",
|
||||||
|
"file_path": "legacy/dafna-tamir/04_Archive/ערר-1126-25-תמא-38-בית-הכרם/החלטה/בית הכרם-טיוטת החלטה-9.pdf",
|
||||||
|
"title": "החלטה סופית — בית הכרם 1126/25",
|
||||||
|
"outcome": "partial",
|
||||||
|
"decision_date": date(2026, 3, 1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "1128/25",
|
||||||
|
"file_path": "legacy/dafna-tamir/04_Archive/ערר-1128-25-שטרית/החלטה/1128-25 החלטה להפצה.pdf",
|
||||||
|
"title": "החלטה סופית — שטרית 1128-25",
|
||||||
|
"outcome": "",
|
||||||
|
"decision_date": None,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
PROJECT_ROOT = Path(__file__).parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
def extract_pdf_text(file_path: Path) -> str:
|
||||||
|
"""Extract text from PDF using PyMuPDF."""
|
||||||
|
doc = fitz.open(str(file_path))
|
||||||
|
text_parts = []
|
||||||
|
for page in doc:
|
||||||
|
text_parts.append(page.get_text())
|
||||||
|
doc.close()
|
||||||
|
return "\n".join(text_parts)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_docx_text(file_path: Path) -> str:
|
||||||
|
"""Extract text from DOCX."""
|
||||||
|
doc = DocxDocument(str(file_path))
|
||||||
|
return "\n".join(p.text for p in doc.paragraphs if p.text.strip())
|
||||||
|
|
||||||
|
|
||||||
|
def extract_text(file_path: Path) -> str:
|
||||||
|
"""Extract text based on file extension."""
|
||||||
|
suffix = file_path.suffix.lower()
|
||||||
|
if suffix == ".pdf":
|
||||||
|
return extract_pdf_text(file_path)
|
||||||
|
elif suffix == ".docx":
|
||||||
|
return extract_docx_text(file_path)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unsupported format: {suffix}")
|
||||||
|
|
||||||
|
|
||||||
|
def count_words(text: str) -> int:
|
||||||
|
return len(text.split())
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await init_schema()
|
||||||
|
pool = await get_pool()
|
||||||
|
|
||||||
|
for d in FINAL_DECISIONS:
|
||||||
|
file_path = PROJECT_ROOT / d["file_path"]
|
||||||
|
if not file_path.exists():
|
||||||
|
print(f"❌ קובץ לא נמצא: {file_path}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Extract text
|
||||||
|
print(f"\nמחלץ טקסט: {d['title']}...")
|
||||||
|
text = extract_text(file_path)
|
||||||
|
word_count = count_words(text)
|
||||||
|
print(f" {word_count} מילים, {len(text)} תווים")
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
# Get case_id
|
||||||
|
case_id = await conn.fetchval(
|
||||||
|
"SELECT id FROM cases WHERE case_number = $1", d["case_number"]
|
||||||
|
)
|
||||||
|
if not case_id:
|
||||||
|
print(f" ⚠ תיק {d['case_number']} לא נמצא ב-DB — מדלג")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Register document
|
||||||
|
existing_doc = await conn.fetchval(
|
||||||
|
"SELECT id FROM documents WHERE file_path = $1",
|
||||||
|
str(file_path),
|
||||||
|
)
|
||||||
|
if existing_doc:
|
||||||
|
doc_id = existing_doc
|
||||||
|
print(f" מסמך כבר קיים ב-DB: {doc_id}")
|
||||||
|
# Update text
|
||||||
|
await conn.execute(
|
||||||
|
"""UPDATE documents SET extracted_text = $1, extraction_status = 'completed'
|
||||||
|
WHERE id = $2""",
|
||||||
|
text, doc_id,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
doc_id = await conn.fetchval(
|
||||||
|
"""INSERT INTO documents (case_id, doc_type, title, file_path, extracted_text, extraction_status, page_count)
|
||||||
|
VALUES ($1, 'decision', $2, $3, $4, 'completed', $5)
|
||||||
|
RETURNING id""",
|
||||||
|
case_id, d["title"], str(file_path), text,
|
||||||
|
len(fitz.open(str(file_path))) if file_path.suffix == ".pdf" else None,
|
||||||
|
)
|
||||||
|
print(f" מסמך נרשם: {doc_id}")
|
||||||
|
|
||||||
|
# Create/update decision record
|
||||||
|
existing_decision = await conn.fetchval(
|
||||||
|
"SELECT id FROM decisions WHERE case_id = $1", case_id
|
||||||
|
)
|
||||||
|
if existing_decision:
|
||||||
|
await conn.execute(
|
||||||
|
"""UPDATE decisions SET status = 'final', outcome = $1, total_words = $2,
|
||||||
|
decision_date = $3, updated_at = now() WHERE id = $4""",
|
||||||
|
d["outcome"], word_count, d["decision_date"], existing_decision,
|
||||||
|
)
|
||||||
|
decision_id = existing_decision
|
||||||
|
print(f" החלטה עודכנה: {decision_id}")
|
||||||
|
else:
|
||||||
|
decision_id = await conn.fetchval(
|
||||||
|
"""INSERT INTO decisions (case_id, version, status, outcome, outcome_summary,
|
||||||
|
total_words, decision_date, author)
|
||||||
|
VALUES ($1, 1, 'final', $2, $3, $4, $5, 'דפנה תמיר')
|
||||||
|
RETURNING id""",
|
||||||
|
case_id, d["outcome"], d["title"], word_count, d["decision_date"],
|
||||||
|
)
|
||||||
|
print(f" החלטה נוצרה: {decision_id}")
|
||||||
|
|
||||||
|
# Update case status
|
||||||
|
await conn.execute(
|
||||||
|
"UPDATE cases SET status = 'final', expected_outcome = $1, updated_at = now() WHERE id = $2",
|
||||||
|
d["outcome"], case_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f" ✅ הושלם: {d['case_number']}")
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
doc_count = await conn.fetchval(
|
||||||
|
"SELECT count(*) FROM documents WHERE doc_type = 'decision' AND extraction_status = 'completed'"
|
||||||
|
)
|
||||||
|
dec_count = await conn.fetchval(
|
||||||
|
"SELECT count(*) FROM decisions WHERE status = 'final'"
|
||||||
|
)
|
||||||
|
total_words = await conn.fetchval(
|
||||||
|
"SELECT sum(total_words) FROM decisions WHERE status = 'final'"
|
||||||
|
)
|
||||||
|
|
||||||
|
await close_pool()
|
||||||
|
|
||||||
|
print(f"\n{'='*50}")
|
||||||
|
print(f"✅ סה\"כ מסמכי החלטה: {doc_count}")
|
||||||
|
print(f"✅ סה\"כ החלטות סופיות: {dec_count}")
|
||||||
|
print(f"✅ סה\"כ מילים: {total_words:,}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
118
scripts/link-claims-to-discussion.py
Normal file
118
scripts/link-claims-to-discussion.py
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Link claims to discussion paragraphs using semantic similarity.
|
||||||
|
|
||||||
|
For each claim, finds the most similar paragraph in block-yod of the same decision.
|
||||||
|
Updates claims.addressed_in_paragraph with the paragraph number.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src"))
|
||||||
|
|
||||||
|
from legal_mcp.services.db import get_pool, init_schema, close_pool
|
||||||
|
from legal_mcp.services.embeddings import embed_texts
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await init_schema()
|
||||||
|
pool = await get_pool()
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
# Get all cases with both claims and discussion blocks
|
||||||
|
cases = await conn.fetch(
|
||||||
|
"""SELECT DISTINCT c.id as case_id, c.case_number
|
||||||
|
FROM cases c
|
||||||
|
JOIN claims cl ON cl.case_id = c.id
|
||||||
|
JOIN decisions d ON d.case_id = c.id
|
||||||
|
JOIN decision_blocks db ON db.decision_id = d.id AND db.block_id = 'block-yod' AND db.word_count > 0
|
||||||
|
ORDER BY c.case_number"""
|
||||||
|
)
|
||||||
|
|
||||||
|
total_linked = 0
|
||||||
|
|
||||||
|
for case in cases:
|
||||||
|
case_id = case["case_id"]
|
||||||
|
case_number = case["case_number"]
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
# Get claims for this case
|
||||||
|
claims = await conn.fetch(
|
||||||
|
"SELECT id, claim_text, party_role, claim_index FROM claims WHERE case_id = $1 ORDER BY claim_index",
|
||||||
|
case_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get discussion paragraphs (split block-yod into paragraphs)
|
||||||
|
yod_content = await conn.fetchval(
|
||||||
|
"""SELECT db.content FROM decision_blocks db
|
||||||
|
JOIN decisions d ON d.id = db.decision_id
|
||||||
|
WHERE d.case_id = $1 AND db.block_id = 'block-yod'""",
|
||||||
|
case_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not yod_content or not claims:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Split discussion into paragraphs
|
||||||
|
disc_paragraphs = [p.strip() for p in yod_content.split("\n") if p.strip() and len(p.strip()) > 30]
|
||||||
|
|
||||||
|
if not disc_paragraphs:
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"\n{case_number}: {len(claims)} טענות ← {len(disc_paragraphs)} פסקאות דיון")
|
||||||
|
|
||||||
|
# Embed all claims and discussion paragraphs
|
||||||
|
claim_texts = [c["claim_text"][:500] for c in claims]
|
||||||
|
all_texts = claim_texts + disc_paragraphs
|
||||||
|
|
||||||
|
embeddings = await embed_texts(all_texts, input_type="document")
|
||||||
|
|
||||||
|
claim_embeddings = embeddings[:len(claims)]
|
||||||
|
disc_embeddings = embeddings[len(claims):]
|
||||||
|
|
||||||
|
# For each claim, find the best matching discussion paragraph
|
||||||
|
linked = 0
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
for i, claim in enumerate(claims):
|
||||||
|
claim_emb = claim_embeddings[i]
|
||||||
|
|
||||||
|
# Cosine similarity
|
||||||
|
best_score = -1
|
||||||
|
best_para_idx = -1
|
||||||
|
for j, disc_emb in enumerate(disc_embeddings):
|
||||||
|
dot = sum(a * b for a, b in zip(claim_emb, disc_emb))
|
||||||
|
norm_a = sum(a * a for a in claim_emb) ** 0.5
|
||||||
|
norm_b = sum(b * b for b in disc_emb) ** 0.5
|
||||||
|
score = dot / (norm_a * norm_b) if norm_a > 0 and norm_b > 0 else 0
|
||||||
|
|
||||||
|
if score > best_score:
|
||||||
|
best_score = score
|
||||||
|
best_para_idx = j
|
||||||
|
|
||||||
|
if best_para_idx >= 0 and best_score > 0.3:
|
||||||
|
# paragraph_number is 1-indexed
|
||||||
|
para_num = best_para_idx + 1
|
||||||
|
await conn.execute(
|
||||||
|
"UPDATE claims SET addressed_in_paragraph = $1 WHERE id = $2",
|
||||||
|
para_num, claim["id"],
|
||||||
|
)
|
||||||
|
linked += 1
|
||||||
|
|
||||||
|
total_linked += linked
|
||||||
|
print(f" קושרו: {linked}/{len(claims)} טענות (ציון מינימלי: 0.3)")
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
total_claims = await conn.fetchval("SELECT count(*) FROM claims")
|
||||||
|
linked_claims = await conn.fetchval("SELECT count(*) FROM claims WHERE addressed_in_paragraph IS NOT NULL")
|
||||||
|
|
||||||
|
await close_pool()
|
||||||
|
|
||||||
|
print(f"\n{'='*50}")
|
||||||
|
print(f"סיכום: {linked_claims}/{total_claims} טענות קושרו לפסקאות דיון ({linked_claims/total_claims*100:.0f}%)")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
254
scripts/seed-appeals.py
Normal file
254
scripts/seed-appeals.py
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Seed appeals (cases) from legacy vault metadata."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from datetime import date
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src"))
|
||||||
|
|
||||||
|
from legal_mcp.services.db import get_pool, init_schema, close_pool
|
||||||
|
|
||||||
|
|
||||||
|
APPEALS = [
|
||||||
|
# ── Active (01_Projects) ──
|
||||||
|
{
|
||||||
|
"case_number": "1130/25",
|
||||||
|
"title": "ערר קרית יערים-1 — קובר",
|
||||||
|
"appellants": ["מרק קובר", "יצחק מטמון"],
|
||||||
|
"respondents": ["הוועדה המרחבית הראל", "ליבמן"],
|
||||||
|
"subject": "ערר על אישור תכנית להוספת קומה וזכויות בנייה",
|
||||||
|
"property_address": "רח' אבינדב 23, קריית יערים",
|
||||||
|
"status": "in_progress",
|
||||||
|
"expected_outcome": "partial",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "1194/25+1199/25",
|
||||||
|
"title": "ערר קרית יערים-2 — מטמון/קובר",
|
||||||
|
"appellants": ["יצחק מטמון", "מרק קובר"],
|
||||||
|
"respondents": ["הוועדה המקומית"],
|
||||||
|
"subject": "תוספת קומה + הגדלת זכויות בנייה",
|
||||||
|
"property_address": "חלקה 240, גוש 29536, רח' אבינדב",
|
||||||
|
"status": "new",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "8027-25",
|
||||||
|
"title": "ערר היטל השבחה תחכמוני 20",
|
||||||
|
"appellants": ["עובדיה", "מירב", "ווינשטיין ואח'"],
|
||||||
|
"respondents": ["הוועדה המקומית ירושלים"],
|
||||||
|
"subject": "היטל השבחה",
|
||||||
|
"property_address": "רח' תחכמוני, ירושלים, גוש 30069, חלקה 156",
|
||||||
|
"status": "new",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
# ── Archived — completed decisions ──
|
||||||
|
{
|
||||||
|
"case_number": "1180-1181",
|
||||||
|
"title": "ערר הכט",
|
||||||
|
"appellants": [],
|
||||||
|
"respondents": [],
|
||||||
|
"subject": "רישוי ובנייה",
|
||||||
|
"property_address": "",
|
||||||
|
"status": "final",
|
||||||
|
"expected_outcome": "rejected",
|
||||||
|
"notes": "פורסם 05.02.2026. דחייה. שימש כמודל לניתוח סגנון.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "1126/25+1141/25",
|
||||||
|
"title": "תמ\"א 38/2 בית הכרם",
|
||||||
|
"appellants": ["מרכז קהילתי זיו-מרקס", "12 תושבים"],
|
||||||
|
"respondents": ["הוועדה המקומית", "יזם"],
|
||||||
|
"subject": "תמ\"א 38/2 הריסה ובנייה מחדש",
|
||||||
|
"property_address": "רח' החלוץ 36, בית הכרם, גוש 30159/6",
|
||||||
|
"status": "final",
|
||||||
|
"expected_outcome": "partial",
|
||||||
|
"notes": "גרסה סופית טיוטה 9, מרץ 2026. קבלה חלקית. שימש כמודל לניתוח סגנון.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "8255-25",
|
||||||
|
"title": "בל\"מ אפרים אבי",
|
||||||
|
"appellants": ["אפרים אברהם"],
|
||||||
|
"respondents": ["הוועדה המקומית ירושלים"],
|
||||||
|
"subject": "היטל השבחה — בקשה להארכת מועד",
|
||||||
|
"property_address": "רח' הורקניה 4, קטמונים, ירושלים",
|
||||||
|
"status": "final",
|
||||||
|
"expected_outcome": "rejected",
|
||||||
|
"notes": "גרסה סופית מאושרת. דחייה.",
|
||||||
|
},
|
||||||
|
# ── Archived — unified decisions ──
|
||||||
|
{
|
||||||
|
"case_number": "8107-25",
|
||||||
|
"title": "אבו זאהריה",
|
||||||
|
"appellants": ["אבו זאהריה מפיד"],
|
||||||
|
"respondents": ["הוועדה המקומית ירושלים"],
|
||||||
|
"subject": "ערר על החלטת שמאי מכריע — היטל השבחה",
|
||||||
|
"property_address": "רח' אום כולתום 26, בית חנינא, גוש 30615, חלקה 69",
|
||||||
|
"status": "final",
|
||||||
|
"expected_outcome": "",
|
||||||
|
"notes": "החלטה מאחדת: ערר גפני.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "9005-24",
|
||||||
|
"title": "רמת שלמה — פיצויים ס' 197",
|
||||||
|
"appellants": ["קירמאיר אסתר ואח' (63-67 עוררים)"],
|
||||||
|
"respondents": ["הוועדה המקומית ירושלים"],
|
||||||
|
"subject": "פיצויים לפי סעיף 197",
|
||||||
|
"property_address": "רמת שלמה, ירושלים, גוש 30561, חלקות 36, 40",
|
||||||
|
"status": "final",
|
||||||
|
"expected_outcome": "",
|
||||||
|
"notes": "החלטה מאחדת: ערר ורדי 9003-23.",
|
||||||
|
},
|
||||||
|
# ── Archived — in progress ──
|
||||||
|
{
|
||||||
|
"case_number": "1113/25",
|
||||||
|
"title": "אייל מבורך לוי ואברהם עדי",
|
||||||
|
"appellants": ["אייל מבורך לוי", "אברהם עדי"],
|
||||||
|
"respondents": ["הוועדה המקומית הראל"],
|
||||||
|
"subject": "הרחבת דירות + תוספת 2 יח\"ד",
|
||||||
|
"property_address": "רח' השלום 63, מבשרת ציון, גוש 30475, חלקה 5",
|
||||||
|
"status": "in_progress",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "1128/25",
|
||||||
|
"title": "שטרית",
|
||||||
|
"appellants": [],
|
||||||
|
"respondents": [],
|
||||||
|
"subject": "",
|
||||||
|
"property_address": "",
|
||||||
|
"status": "drafted",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "1107/06/25",
|
||||||
|
"title": "בלוי נ' הוועדה המקומית",
|
||||||
|
"appellants": ["בלוי מאיר", "מזיע מאיר", "דזימיטרובסקי הדסה"],
|
||||||
|
"respondents": ["הוועדה המקומית ירושלים", "היזם"],
|
||||||
|
"subject": "תוספת בנייה וחיזוק מפני רעידות (תמ\"א 38/1)",
|
||||||
|
"property_address": "רח' הרב בלוי 16, ירושלים, גוש 30099/115",
|
||||||
|
"status": "in_progress",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "8141-23",
|
||||||
|
"title": "אזורים בנין",
|
||||||
|
"appellants": ["אזורים בנין (1965) בע\"מ"],
|
||||||
|
"respondents": ["הוועדה המקומית ירושלים"],
|
||||||
|
"subject": "היטל השבחה — תכנית 101-0611905",
|
||||||
|
"property_address": "רח' הנביאים 27, ירושלים",
|
||||||
|
"status": "drafted",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "8047-24",
|
||||||
|
"title": "משכן אליהו — היטל השבחה שמאי מכריע",
|
||||||
|
"appellants": ["עומר דרוויש"],
|
||||||
|
"respondents": ["הוועדה המקומית ירושלים"],
|
||||||
|
"subject": "ערר על שמאית מכריעה — היטל השבחה",
|
||||||
|
"property_address": "גוש 30614, חלקה 89, בית חנינא",
|
||||||
|
"status": "in_progress",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "1195-25",
|
||||||
|
"title": "וליד ג'מל",
|
||||||
|
"appellants": ["וליד ג'מל"],
|
||||||
|
"respondents": ["ועדת משנה מטה יהודה", "סמיר מוסא זעאתרה"],
|
||||||
|
"subject": "הסדרת קומה שלישית למשרדים",
|
||||||
|
"property_address": "גוש 30492, חלקה 23, כפר עין נקובא",
|
||||||
|
"status": "in_progress",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "1200/25",
|
||||||
|
"title": "קרית ענבים נופש",
|
||||||
|
"appellants": ["קרית ענבים נופש בע\"מ"],
|
||||||
|
"respondents": ["הוועדה המקומית מטה יהודה", "חברי קיבוץ קרית ענבים"],
|
||||||
|
"subject": "שימוש חורג — סופרמרקט בייעוד ספורט ונופש",
|
||||||
|
"property_address": "קיבוץ קרית ענבים, גוש 29551",
|
||||||
|
"status": "in_progress",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "1184/25",
|
||||||
|
"title": "שטוקהיים — בית נקופה",
|
||||||
|
"appellants": ["אמנון שטוקהיים", "אילנית שטוקהיים"],
|
||||||
|
"respondents": ["הוועדה המקומית מטה יהודה", "יערה טל"],
|
||||||
|
"subject": "אישור בקשה להיתר עם הקלות",
|
||||||
|
"property_address": "מגרש 51, גוש 31399, חלקה 52, בית נקופה",
|
||||||
|
"status": "in_progress",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "8070-25",
|
||||||
|
"title": "היטל השבחה — דירת גג",
|
||||||
|
"appellants": ["חיים ראם"],
|
||||||
|
"respondents": ["הוועדה המקומית ירושלים"],
|
||||||
|
"subject": "היטל השבחה — הקלה להשלמת דירת גג",
|
||||||
|
"property_address": "רח' צ.פ. חיות 2, דירה 31, נווה יעקב",
|
||||||
|
"status": "in_progress",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "8136-24",
|
||||||
|
"title": "ערר השבחה — מרפסות שירות",
|
||||||
|
"appellants": [],
|
||||||
|
"respondents": [],
|
||||||
|
"subject": "היטל השבחה — מרפסות שירות",
|
||||||
|
"property_address": "",
|
||||||
|
"status": "in_progress",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_number": "8007-24",
|
||||||
|
"title": "עומר דרוויש — שומה מכרעת",
|
||||||
|
"appellants": [],
|
||||||
|
"respondents": [],
|
||||||
|
"subject": "היטל השבחה",
|
||||||
|
"property_address": "",
|
||||||
|
"status": "in_progress",
|
||||||
|
"expected_outcome": "",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await init_schema()
|
||||||
|
pool = await get_pool()
|
||||||
|
|
||||||
|
inserted = 0
|
||||||
|
skipped = 0
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
for a in APPEALS:
|
||||||
|
existing = await conn.fetchval(
|
||||||
|
"SELECT id FROM cases WHERE case_number = $1", a["case_number"]
|
||||||
|
)
|
||||||
|
if existing:
|
||||||
|
skipped += 1
|
||||||
|
continue
|
||||||
|
await conn.execute(
|
||||||
|
"""INSERT INTO cases
|
||||||
|
(case_number, title, appellants, respondents, subject,
|
||||||
|
property_address, status, expected_outcome, notes)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)""",
|
||||||
|
a["case_number"],
|
||||||
|
a["title"],
|
||||||
|
json.dumps(a.get("appellants", [])),
|
||||||
|
json.dumps(a.get("respondents", [])),
|
||||||
|
a.get("subject", ""),
|
||||||
|
a.get("property_address", ""),
|
||||||
|
a.get("status", "new"),
|
||||||
|
a.get("expected_outcome", ""),
|
||||||
|
a.get("notes", ""),
|
||||||
|
)
|
||||||
|
inserted += 1
|
||||||
|
|
||||||
|
await close_pool()
|
||||||
|
print(f"✓ appeals: {inserted} inserted, {skipped} skipped (already exist)")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
449
scripts/seed-knowledge.py
Normal file
449
scripts/seed-knowledge.py
Normal file
@@ -0,0 +1,449 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Seed knowledge tables from legacy vault data.
|
||||||
|
|
||||||
|
Imports: lessons_learned, transition_phrases, case_law, statutory_provisions.
|
||||||
|
Sources: memory/legal-decision-lessons.md, skill-legal-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())
|
||||||
40
scripts/test-search.py
Normal file
40
scripts/test-search.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Test semantic search functions."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src"))
|
||||||
|
|
||||||
|
from legal_mcp.services.db import search_similar_paragraphs, search_similar_case_law, search_precedents, init_schema
|
||||||
|
from legal_mcp.services.embeddings import embed_query
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await init_schema()
|
||||||
|
|
||||||
|
queries = [
|
||||||
|
"טענות קנייניות רוב דרוש בעלי דירות רכוש משותף",
|
||||||
|
"חניה תנועה חניות מצוקת חניה",
|
||||||
|
"היטל השבחה שמאי מכריע התערבות",
|
||||||
|
]
|
||||||
|
|
||||||
|
for query in queries:
|
||||||
|
print(f'=== שאילתה: "{query}" ===')
|
||||||
|
emb = await embed_query(query)
|
||||||
|
results = await search_precedents(emb, limit=3)
|
||||||
|
|
||||||
|
if not results:
|
||||||
|
print(" אין תוצאות")
|
||||||
|
else:
|
||||||
|
for i, r in enumerate(results):
|
||||||
|
score = r["score"]
|
||||||
|
cn = r["case_number"]
|
||||||
|
rtype = r["type"]
|
||||||
|
content = r["content"][:120].replace("\n", " ")
|
||||||
|
print(f" {i+1}. [{rtype}] {score:.3f} | {cn} | {content}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
257
scripts/validate-decision.py
Normal file
257
scripts/validate-decision.py
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Validate a decision against block-schema rules.
|
||||||
|
|
||||||
|
Usage: python validate-decision.py <case_number>
|
||||||
|
|
||||||
|
Checks:
|
||||||
|
1. Neutral background (block-vav) — no party quotes or value words
|
||||||
|
2. Weight compliance — blocks within expected ranges
|
||||||
|
3. Structural integrity — all required blocks present
|
||||||
|
4. Claims coverage — every claim in block-zayin addressed in block-yod
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent / "mcp-server" / "src"))
|
||||||
|
|
||||||
|
from legal_mcp.services.db import get_pool, init_schema, close_pool
|
||||||
|
|
||||||
|
|
||||||
|
# Value/judgment words that shouldn't appear in neutral background
|
||||||
|
VALUE_WORDS = [
|
||||||
|
"חריג", "חטא", "בעייתי", "מזעזע", "שערורייתי", "מגוחך",
|
||||||
|
"נפשע", "פגום", "חמור", "מקומם", "בלתי סביר", "מופרז",
|
||||||
|
"מגונה", "פסול", "נלוז", "מטריד",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Party quote indicators
|
||||||
|
QUOTE_INDICATORS = [
|
||||||
|
r"לטענת\s+(העוררי|המשיב|מבקשי)",
|
||||||
|
r"לדברי\s+(העוררי|המשיב|מבקשי)",
|
||||||
|
r"העורר\s+טוען",
|
||||||
|
r"המשיבה\s+טוענת",
|
||||||
|
r"לשיטת\s+(העוררי|המשיב)",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Expected weight ranges per block type (for רישוי appeals)
|
||||||
|
WEIGHT_RANGES_LICENSING = {
|
||||||
|
"block-he": (0.5, 5),
|
||||||
|
"block-vav": (3, 40),
|
||||||
|
"block-zayin": (13, 40),
|
||||||
|
"block-chet": (0, 15),
|
||||||
|
"block-tet": (0, 15),
|
||||||
|
"block-yod": (30, 75),
|
||||||
|
"block-yod-alef": (1, 10),
|
||||||
|
"block-yod-bet": (0, 2),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Expected weight ranges for היטל השבחה
|
||||||
|
WEIGHT_RANGES_LEVY = {
|
||||||
|
"block-he": (0, 5),
|
||||||
|
"block-vav": (2, 20),
|
||||||
|
"block-zayin": (15, 40),
|
||||||
|
"block-chet": (0, 25),
|
||||||
|
"block-tet": (0, 15),
|
||||||
|
"block-yod": (25, 75),
|
||||||
|
"block-yod-alef": (1, 10),
|
||||||
|
"block-yod-bet": (0, 3),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def check_neutral_background(content: str) -> list[str]:
|
||||||
|
"""Check block-vav for neutrality violations."""
|
||||||
|
issues = []
|
||||||
|
if not content:
|
||||||
|
return issues
|
||||||
|
|
||||||
|
lines = content.split("\n")
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
# Check value words
|
||||||
|
for word in VALUE_WORDS:
|
||||||
|
if word in line:
|
||||||
|
issues.append(f"מילת שיפוט ברקע (שורה {i+1}): \"{word}\" — \"{line[:80]}...\"")
|
||||||
|
|
||||||
|
# Check party quotes
|
||||||
|
for pattern in QUOTE_INDICATORS:
|
||||||
|
if re.search(pattern, line):
|
||||||
|
match = re.search(pattern, line).group()
|
||||||
|
issues.append(f"ציטוט מצד ברקע (שורה {i+1}): \"{match}\" — \"{line[:80]}...\"")
|
||||||
|
|
||||||
|
return issues
|
||||||
|
|
||||||
|
|
||||||
|
def check_weight_compliance(blocks: list[dict], appeal_type: str) -> list[str]:
|
||||||
|
"""Check block weights are within expected ranges."""
|
||||||
|
issues = []
|
||||||
|
ranges = WEIGHT_RANGES_LEVY if appeal_type == "levy" else WEIGHT_RANGES_LICENSING
|
||||||
|
|
||||||
|
total_words = sum(b["word_count"] for b in blocks)
|
||||||
|
if total_words == 0:
|
||||||
|
return ["אין תוכן בהחלטה"]
|
||||||
|
|
||||||
|
for block in blocks:
|
||||||
|
bid = block["block_id"]
|
||||||
|
if bid in ranges and block["word_count"] > 0:
|
||||||
|
weight = block["word_count"] / total_words * 100
|
||||||
|
low, high = ranges[bid]
|
||||||
|
if weight < low:
|
||||||
|
issues.append(f"בלוק {bid} ({block['title']}): משקל {weight:.1f}% — מתחת לטווח ({low}-{high}%)")
|
||||||
|
elif weight > high:
|
||||||
|
issues.append(f"בלוק {bid} ({block['title']}): משקל {weight:.1f}% — מעל לטווח ({low}-{high}%)")
|
||||||
|
|
||||||
|
return issues
|
||||||
|
|
||||||
|
|
||||||
|
def check_structural_integrity(blocks: list[dict]) -> list[str]:
|
||||||
|
"""Check all required blocks are present."""
|
||||||
|
issues = []
|
||||||
|
required = ["block-he", "block-zayin", "block-yod"]
|
||||||
|
block_ids = {b["block_id"] for b in blocks if b["word_count"] > 0}
|
||||||
|
|
||||||
|
for req in required:
|
||||||
|
if req not in block_ids:
|
||||||
|
issues.append(f"בלוק חובה חסר: {req}")
|
||||||
|
|
||||||
|
# Check discussion is the heaviest block
|
||||||
|
yod = next((b for b in blocks if b["block_id"] == "block-yod"), None)
|
||||||
|
if yod:
|
||||||
|
max_block = max((b for b in blocks if b["block_id"] not in ("block-alef", "block-bet", "block-gimel", "block-dalet")),
|
||||||
|
key=lambda x: x["word_count"], default=None)
|
||||||
|
if max_block and max_block["block_id"] != "block-yod":
|
||||||
|
issues.append(f"בלוק הדיון (י) אינו הבלוק הגדול ביותר — {max_block['title']} ({max_block['word_count']} מילים) גדול יותר")
|
||||||
|
|
||||||
|
return issues
|
||||||
|
|
||||||
|
|
||||||
|
def check_no_duplication(vav_content: str, yod_content: str) -> list[str]:
|
||||||
|
"""Check block-yod doesn't repeat block-vav content."""
|
||||||
|
issues = []
|
||||||
|
if not vav_content or not yod_content:
|
||||||
|
return issues
|
||||||
|
|
||||||
|
# Find sentences from background that appear verbatim in discussion
|
||||||
|
vav_sentences = [s.strip() for s in re.split(r'[.!?]', vav_content) if len(s.strip()) > 30]
|
||||||
|
for sent in vav_sentences:
|
||||||
|
if sent in yod_content:
|
||||||
|
issues.append(f"כפילות: משפט מהרקע חוזר בדיון — \"{sent[:60]}...\"")
|
||||||
|
|
||||||
|
return issues
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("שימוש: python validate-decision.py <מספר_תיק>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
case_number = sys.argv[1]
|
||||||
|
await init_schema()
|
||||||
|
pool = await get_pool()
|
||||||
|
|
||||||
|
async with pool.acquire() as conn:
|
||||||
|
case = await conn.fetchrow(
|
||||||
|
"SELECT * FROM cases WHERE case_number = $1", case_number
|
||||||
|
)
|
||||||
|
if not case:
|
||||||
|
print(f"תיק {case_number} לא נמצא")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
decision = await conn.fetchrow(
|
||||||
|
"SELECT * FROM decisions WHERE case_id = $1",
|
||||||
|
case["id"],
|
||||||
|
)
|
||||||
|
if not decision:
|
||||||
|
print(f"אין החלטה לתיק {case_number}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
blocks = await conn.fetch(
|
||||||
|
"""SELECT block_id, title, content, word_count, weight_percent
|
||||||
|
FROM decision_blocks WHERE decision_id = $1
|
||||||
|
ORDER BY block_index""",
|
||||||
|
decision["id"],
|
||||||
|
)
|
||||||
|
blocks = [dict(b) for b in blocks]
|
||||||
|
|
||||||
|
claims_count = await conn.fetchval(
|
||||||
|
"SELECT count(*) FROM claims WHERE case_id = $1", case["id"]
|
||||||
|
)
|
||||||
|
|
||||||
|
await close_pool()
|
||||||
|
|
||||||
|
# Determine appeal type
|
||||||
|
num = case_number.split("/")[0].split("+")[0].split("-")[0]
|
||||||
|
if num.startswith("8"):
|
||||||
|
appeal_type = "levy"
|
||||||
|
appeal_type_heb = "היטל השבחה"
|
||||||
|
elif num.startswith("9"):
|
||||||
|
appeal_type = "compensation"
|
||||||
|
appeal_type_heb = "פיצויים"
|
||||||
|
else:
|
||||||
|
appeal_type = "licensing"
|
||||||
|
appeal_type_heb = "רישוי ובנייה"
|
||||||
|
|
||||||
|
print(f"{'='*60}")
|
||||||
|
print(f"ולידציה: {case_number} — {case['title']}")
|
||||||
|
print(f"סוג: {appeal_type_heb} | מילים: {decision['total_words']} | טענות: {claims_count}")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
|
||||||
|
all_issues = []
|
||||||
|
|
||||||
|
# 1. Neutral background
|
||||||
|
vav = next((b for b in blocks if b["block_id"] == "block-vav"), None)
|
||||||
|
issues = check_neutral_background(vav["content"] if vav else "")
|
||||||
|
if issues:
|
||||||
|
print(f"\n❌ רקע ניטרלי — {len(issues)} בעיות:")
|
||||||
|
for i in issues:
|
||||||
|
print(f" • {i}")
|
||||||
|
all_issues.extend(issues)
|
||||||
|
else:
|
||||||
|
print("\n✅ רקע ניטרלי — תקין")
|
||||||
|
|
||||||
|
# 2. Weight compliance
|
||||||
|
issues = check_weight_compliance(blocks, appeal_type)
|
||||||
|
if issues:
|
||||||
|
print(f"\n⚠ משקלות — {len(issues)} חריגות:")
|
||||||
|
for i in issues:
|
||||||
|
print(f" • {i}")
|
||||||
|
all_issues.extend(issues)
|
||||||
|
else:
|
||||||
|
print("\n✅ משקלות — בטווח")
|
||||||
|
|
||||||
|
# 3. Structural integrity
|
||||||
|
issues = check_structural_integrity(blocks)
|
||||||
|
if issues:
|
||||||
|
print(f"\n❌ מבנה — {len(issues)} בעיות:")
|
||||||
|
for i in issues:
|
||||||
|
print(f" • {i}")
|
||||||
|
all_issues.extend(issues)
|
||||||
|
else:
|
||||||
|
print("\n✅ מבנה — תקין")
|
||||||
|
|
||||||
|
# 4. No duplication
|
||||||
|
yod = next((b for b in blocks if b["block_id"] == "block-yod"), None)
|
||||||
|
issues = check_no_duplication(
|
||||||
|
vav["content"] if vav else "",
|
||||||
|
yod["content"] if yod else "",
|
||||||
|
)
|
||||||
|
if issues:
|
||||||
|
print(f"\n⚠ כפילויות — {len(issues)} נמצאו:")
|
||||||
|
for i in issues:
|
||||||
|
print(f" • {i}")
|
||||||
|
all_issues.extend(issues)
|
||||||
|
else:
|
||||||
|
print("\n✅ ללא כפילויות — תקין")
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
if all_issues:
|
||||||
|
print(f"סה\"כ: {len(all_issues)} בעיות נמצאו")
|
||||||
|
else:
|
||||||
|
print("✅ ההחלטה עומדת בכל הכללים")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
264
skill-legal-assistant/SKILL.md
Normal file
264
skill-legal-assistant/SKILL.md
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
---
|
||||||
|
name: legal-assistant
|
||||||
|
description: עוזר משפטי לניתוח וקטלוג תיקים שיפוטיים. Skill זה משמש לריכוז, ניתוח וקטלוג כרונולוגי של מסמכים משפטיים סרוקים ליצירת ציר זמן דיוני (Table of Contents). יש להשתמש ב-skill זה כאשר המשתמש מבקש לנתח מסמכים משפטיים, ליצור טבלת תוכן עניינים לתיק, או להכין תשתית לכתיבת פסק דין.
|
||||||
|
---
|
||||||
|
|
||||||
|
# עוזר משפטי לניהול וקטלוג תיק שיפוטי
|
||||||
|
|
||||||
|
## מטרת ה-Skill
|
||||||
|
|
||||||
|
ריכוז, ניתוח וקטלוג כרונולוגי של מאגר מסמכים סרוקים לצורך הכנת תשתית לכתיבת פסק דין.
|
||||||
|
התוצר הסופי הוא "ציר זמן דיוני" מפורט ומדויק בפורמט טבלה.
|
||||||
|
|
||||||
|
## מתי להשתמש ב-Skill
|
||||||
|
|
||||||
|
- כאשר המשתמש מעלה מסמכים משפטיים לניתוח
|
||||||
|
- כאשר נדרש ליצור ציר זמן דיוני או Table of Contents
|
||||||
|
- כאשר נדרש לסכם ולקטלג תיק שיפוטי
|
||||||
|
- כאשר מכינים תשתית לכתיבת פסק דין
|
||||||
|
|
||||||
|
## תהליך העבודה
|
||||||
|
|
||||||
|
### שלב א': הכנת החומר (Preprocessing)
|
||||||
|
|
||||||
|
1. **קיבוץ מסמכים**: לעבוד על קבוצות של עד 20-30 קבצים בכל פעם כדי לא להעמיס על זיכרון ההקשר.
|
||||||
|
2. **שמות קבצים**: לוודא שלקבצים יש שמות בסיסיים (למשל: `doc_001.pdf`).
|
||||||
|
3. **תמלול PDF ל-Markdown** ⚠️ **חובה**:
|
||||||
|
- **לכל קובץ PDF יש ליצור קובץ MD מקביל** באותה תיקייה
|
||||||
|
- להשתמש בכלי `mcp__gemini-vision__analyze_document` לתמלול
|
||||||
|
- לשמור את התמלול עם אותו שם קובץ וסיומת `.md`
|
||||||
|
- **דוגמה**: `כתב-ערר.pdf` → `כתב-ערר.md`
|
||||||
|
- לשמור על מבנה המסמך המקורי: כותרות, פסקאות, רשימות ממוספרות, טבלאות
|
||||||
|
|
||||||
|
### שלב ב': ניתוח המסמכים
|
||||||
|
|
||||||
|
עבור כל מסמך, לבצע את הפעולות הבאות:
|
||||||
|
|
||||||
|
1. **זיהוי תאריך קובע**:
|
||||||
|
- לחפש חותמת "נתקבל" של בית המשפט - זהו התאריך הקובע
|
||||||
|
- אם אין חותמת, לחפש את תאריך המכתב/בקשה
|
||||||
|
- **חשוב**: להבחין בין תאריך יצירת המסמך לבין תאריך הגשתו
|
||||||
|
|
||||||
|
2. **זיהוי הצד המגיש**:
|
||||||
|
- תובע / נתבע / צד ג' / בית המשפט (החלטה)
|
||||||
|
|
||||||
|
3. **סיכום המהות**:
|
||||||
|
- לסכם ב-20 מילים את מהות המסמך והסעד המבוקש
|
||||||
|
|
||||||
|
4. **הערות מיוחדות**:
|
||||||
|
- אם המסמך הוא "תגובה" המציינת תאריך של מסמך קודם - לציין זאת
|
||||||
|
- לציין חריגות: "הוגש באיחור", "חתימה חסרה" וכו'
|
||||||
|
|
||||||
|
### שלב ג': מבנה הטבלה הנדרש
|
||||||
|
|
||||||
|
הטבלה צריכה לכלול את העמודות הבאות:
|
||||||
|
|
||||||
|
| עמודה | תיאור |
|
||||||
|
|-------|-------|
|
||||||
|
| מספר סידורי | לפי סדר כרונולוגי |
|
||||||
|
| תאריך קובע | תאריך ההגשה/חותמת |
|
||||||
|
| שם המסמך | תיאור משפטי תקני |
|
||||||
|
| הצד המגיש | תובע/נתבע/צד ג'/בית המשפט |
|
||||||
|
| תמצית המהות | 2-3 משפטים על עיקרי הטענות/ההחלטה |
|
||||||
|
| הערות מיוחדות | חריגות, קישורים למסמכים קודמים |
|
||||||
|
|
||||||
|
### פורמט הפלט
|
||||||
|
|
||||||
|
להציג את התוצאה בפורמט טבלה מוכנה להעתקה ל-Excel, לדוגמה:
|
||||||
|
|
||||||
|
```
|
||||||
|
מס' | תאריך | שם המסמך | מגיש | תמצית | הערות
|
||||||
|
1 | 01/01/2024 | כתב תביעה | תובע | תביעה לפיצויים בסך 100,000 ש"ח בגין הפרת חוזה | -
|
||||||
|
2 | 15/01/2024 | כתב הגנה | נתבע | הכחשת טענות התובע, טענה לפגם בחוזה | תגובה לכתב תביעה מ-01/01/2024
|
||||||
|
```
|
||||||
|
|
||||||
|
## נקודות קריטיות לבקרת איכות
|
||||||
|
|
||||||
|
1. **פענוח חותמות**: חותמות דיו חלשות עלולות להיות קשות לקריאה - לבקש מהמשתמש לאמת במקרה של ספק.
|
||||||
|
|
||||||
|
2. **הבחנה בין סוגי מסמכים**: להקפיד לא להתבלבל בין:
|
||||||
|
- "החלטה" לבין "בקשה"
|
||||||
|
- "פסק דין" לבין "החלטה"
|
||||||
|
- "תגובה" לבין "בקשה עצמאית"
|
||||||
|
|
||||||
|
3. **הצלבת נתונים**: כאשר מסמך מתייחס למסמך קודם - לציין את הקשר בעמודת ההערות.
|
||||||
|
|
||||||
|
## דוגמה לפרומפט עבודה
|
||||||
|
|
||||||
|
כאשר המשתמש מעלה מסמכים, להגיב בצורה הבאה:
|
||||||
|
|
||||||
|
> אני מנתח את המסמכים שהעלית. עבור כל מסמך אזהה:
|
||||||
|
> - תאריך קובע (חותמת "נתקבל" או תאריך המסמך)
|
||||||
|
> - הצד המגיש
|
||||||
|
> - מהות המסמך
|
||||||
|
>
|
||||||
|
> אציג את התוצאות בטבלה מוכנה להעתקה ל-Excel.
|
||||||
|
> האם יש מסמכים נוספים לניתוח?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## טיפול בעררים/תיקים מאוחדים
|
||||||
|
|
||||||
|
כאשר מטפלים במספר עררים או תיקים שאוחדו לדיון משותף:
|
||||||
|
|
||||||
|
### מבנה תיקיות מותאם
|
||||||
|
|
||||||
|
```
|
||||||
|
[שם-פרויקט]/
|
||||||
|
├── README.md # סיכום התיק
|
||||||
|
├── קטלוג-מסמכים.md # ציר זמן דיוני
|
||||||
|
├── החלטה/ # לכתיבת ההחלטה
|
||||||
|
├── תכנון/ # טיוטות
|
||||||
|
└── חומרי-מקור/
|
||||||
|
├── [מספר-ערר-1]/ # מסמכים ייחודיים לערר 1
|
||||||
|
│ └── כתב-ערר/
|
||||||
|
├── [מספר-ערר-2]/ # מסמכים ייחודיים לערר 2
|
||||||
|
│ └── כתב-ערר/
|
||||||
|
└── משותף/ # מסמכים משותפים לכל העררים
|
||||||
|
├── כתבי-תשובה/
|
||||||
|
├── פרוטוקולי-דיון/
|
||||||
|
├── החלטות/
|
||||||
|
├── בקשות/
|
||||||
|
├── חוות-דעת/
|
||||||
|
└── מסמכים-נוספים/
|
||||||
|
```
|
||||||
|
|
||||||
|
### סיווג מסמכים
|
||||||
|
|
||||||
|
| סוג מסמך | תיקיית יעד |
|
||||||
|
|----------|------------|
|
||||||
|
| כתבי ערר ייחודיים | `[מספר-ערר]/כתב-ערר/` |
|
||||||
|
| כתבי תשובה | `משותף/כתבי-תשובה/` |
|
||||||
|
| פרוטוקולי דיון | `משותף/פרוטוקולי-דיון/` |
|
||||||
|
| החלטות ביניים/סופיות | `משותף/החלטות/` |
|
||||||
|
| בקשות (דחייה, הארכה) | `משותף/בקשות/` |
|
||||||
|
| חוות דעת מומחה | `משותף/חוות-דעת/` |
|
||||||
|
| מצגות, תשריטים, אחר | `משותף/מסמכים-נוספים/` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## שינוי שמות קבצים
|
||||||
|
|
||||||
|
### פורמט שמות
|
||||||
|
|
||||||
|
```
|
||||||
|
[YYYY-MM-DD]-[סוג-מסמך]-[מגיש]-[פרטים].pdf
|
||||||
|
```
|
||||||
|
|
||||||
|
### דוגמאות
|
||||||
|
|
||||||
|
| שם מקורי | שם חדש |
|
||||||
|
|----------|--------|
|
||||||
|
| `ערר.pdf` | `2025-02-09-כתב-ערר-רחמים-ואחרים.pdf` |
|
||||||
|
| `כתב תשובה לעררים...pdf` | `2025-06-16-כתב-תשובה-ועדה-מקומית.pdf` |
|
||||||
|
| `פרוטוקול דיון...pdf` | `2025-06-29-פרוטוקול-דיון-ראשון.pdf` |
|
||||||
|
| `בקשה דחופה...pdf` | `2025-07-16-בקשה-דחיית-דיון-יציב.pdf` |
|
||||||
|
|
||||||
|
### כללי שמות
|
||||||
|
|
||||||
|
1. **תאריך בהתחלה** - מאפשר מיון כרונולוגי אוטומטי
|
||||||
|
2. **מקפים במקום רווחים** - מונע בעיות בטרמינל
|
||||||
|
3. **עברית מותרת** - לקריאות מיטבית
|
||||||
|
4. **ללא תווים מיוחדים** - רק אותיות, מספרים, מקפים
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## זיהוי וטיפול בכפילויות
|
||||||
|
|
||||||
|
### סוגי כפילויות נפוצים
|
||||||
|
|
||||||
|
1. **signed vs unsigned**:
|
||||||
|
- לשמור רק גרסת `signed`
|
||||||
|
- לסמן unsigned כ-`-מסמך-כפול` או למחוק
|
||||||
|
|
||||||
|
2. **קבצים זהים בתיקיות שונות** (בעררים מאוחדים):
|
||||||
|
- להעביר עותק אחד ל-`משותף/`
|
||||||
|
- לא לשכפל לכל תיקיית ערר
|
||||||
|
|
||||||
|
3. **גרסאות עם מספור** (למשל `(1)`, `(2)`):
|
||||||
|
- לזהות איזו הגרסה האחרונה
|
||||||
|
- לשמור רק אותה
|
||||||
|
|
||||||
|
### תהליך זיהוי
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# השוואת שמות קבצים בין תיקיות
|
||||||
|
comm -12 <(ls תיקייה1 | sort) <(ls תיקייה2 | sort)
|
||||||
|
```
|
||||||
|
|
||||||
|
### כלל אצבע
|
||||||
|
|
||||||
|
אם קובץ מופיע ביותר מתיקייה אחת עם שם זהה - הוא כנראה משותף ויש להעבירו פעם אחת לתיקייה `משותף/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## תמלול מסמכי PDF ל-Markdown
|
||||||
|
|
||||||
|
### חובת תמלול
|
||||||
|
|
||||||
|
**כל קובץ PDF בתיק חייב להיות מתומלל לקובץ Markdown מקביל.** זה מאפשר:
|
||||||
|
- חיפוש בתוכן המסמכים
|
||||||
|
- העתקה והדבקה של ציטוטים
|
||||||
|
- עריכה ועיבוד הטקסט
|
||||||
|
- שמירה על הידע גם ללא גישה לכלי קריאת PDF
|
||||||
|
|
||||||
|
### תהליך התמלול
|
||||||
|
|
||||||
|
1. **זיהוי קבצי PDF** בתיקייה:
|
||||||
|
```bash
|
||||||
|
find . -name "*.pdf" -type f
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **תמלול כל PDF** באמצעות:
|
||||||
|
```
|
||||||
|
mcp__gemini-vision__analyze_document
|
||||||
|
- document_path: [נתיב לקובץ]
|
||||||
|
- prompt: "תמלל את המסמך במלואו בעברית. שמור על המבנה המקורי - כותרות, פסקאות, רשימות ממוספרות. אם יש טבלאות, שמור עליהן בפורמט markdown."
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **טיפול בתוצאה ארוכה** ⚠️ מסמכים משפטיים הם בדרך כלל ארוכים (20-60 עמודים). כש-`analyze_document` מחזיר תוצאה שחורגת ממגבלת הטוקנים:
|
||||||
|
- התוצאה נשמרת אוטומטית לקובץ זמני (הנתיב מופיע בהודעת השגיאה)
|
||||||
|
- **השתמש ב-Task agent** (subagent_type: general-purpose) כדי לקרוא את הקובץ הזמני בחלקים (offset/limit) ולשמור אותו כ-MD
|
||||||
|
- אל תנסה לקרוא את הקובץ הזמני ישירות - הוא בדרך כלל חורג מ-25K טוקנים
|
||||||
|
|
||||||
|
4. **שמירת התמלול** כקובץ MD:
|
||||||
|
- באותה תיקייה כמו ה-PDF
|
||||||
|
- עם אותו שם קובץ
|
||||||
|
- סיומת `.md` במקום `.pdf`
|
||||||
|
|
||||||
|
### פורמט התמלול
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# [כותרת המסמך]
|
||||||
|
|
||||||
|
**תאריך:** [תאריך המסמך]
|
||||||
|
|
||||||
|
**לכבוד:** [נמען]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. [כותרת סעיף ראשון]
|
||||||
|
|
||||||
|
1.1. [תוכן תת-סעיף]
|
||||||
|
|
||||||
|
1.2. [תוכן תת-סעיף]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## חתימות
|
||||||
|
|
||||||
|
| שם | מ.ז |
|
||||||
|
|---|---|
|
||||||
|
| [שם] | [מספר זהות] |
|
||||||
|
```
|
||||||
|
|
||||||
|
### סוגי מסמכים לתמלול
|
||||||
|
|
||||||
|
| סוג מסמך | עדיפות | הערות |
|
||||||
|
|----------|--------|-------|
|
||||||
|
| כתבי ערר | גבוהה | מכילים את טענות העוררים |
|
||||||
|
| כתבי תשובה | גבוהה | מכילים את עמדת המשיבים |
|
||||||
|
| פרוטוקולי דיון | גבוהה | מתעדים את הנאמר בדיון |
|
||||||
|
| החלטות קודמות | בינונית | לצורך הפניות ופסיקה |
|
||||||
|
| חוות דעת | בינונית | מסמכים טכניים |
|
||||||
|
| נספחים | נמוכה | לפי הצורך |
|
||||||
501
skill-legal-decision/SKILL.md
Normal file
501
skill-legal-decision/SKILL.md
Normal file
@@ -0,0 +1,501 @@
|
|||||||
|
---
|
||||||
|
name: legal-decision
|
||||||
|
description: This skill should be used when writing legal decisions (החלטות) for betterment levy appeals (היטל השבחה) and licensing appeals (רישוי). It applies low temperature for accuracy and high token output for elaborate legal analysis with citations from case law.
|
||||||
|
---
|
||||||
|
|
||||||
|
# סגנון כתיבת החלטות - דפנה תמיר
|
||||||
|
|
||||||
|
מדריך זה מלמד לכתוב החלטות של ועדת ערר לתכנון ובניה בסגנון של יו"ר הוועדה דפנה תמיר. המדריך עוסק אך ורק בסגנון הכתיבה, במבנה, בביטויים ובשיטה האנליטית. הפסיקה הרלוונטית תסופק בכל ערר בנפרד.
|
||||||
|
|
||||||
|
סוגי עררים: היטל השבחה (מספרי 8xxx), רישוי ובנייה (מספרי 1xxx), תכנון (מספרי 1xxx).
|
||||||
|
|
||||||
|
|
||||||
|
## 1. זיהוי סוג הערר והטון
|
||||||
|
|
||||||
|
מספר הערר קובע את הטון. ערר רישוי (1xxx) נכתב בטון חם יחסית עם אלמנטים אנושיים בסיום. ערר היטל השבחה (8xxx) נכתב בטון קר, יבש ומקצועי, ללא רגשות.
|
||||||
|
|
||||||
|
סוג הערר משפיע על טון הכתיבה, על פתיחת הדיון (רחבה עם הקשר תכנוני ברישוי לעומת ישירה בהיטל השבחה), על סיום ההחלטה (פסקת סיום חמה ברישוי שנדחה לעומת סיום יבש בהיטל השבחה), ועל יחסי החלקים במסמך.
|
||||||
|
|
||||||
|
|
||||||
|
## 2. מבנה המסמך
|
||||||
|
|
||||||
|
### 2.1 כותרת והרכב
|
||||||
|
|
||||||
|
המסמך נפתח בכותרת מובנית הכוללת: שם המוסד (מדינת ישראל, ועדת ערר לתכנון ובניה, מחוז ירושלים), מספר תיק, הרכב הוועדה (יו"ר וחברים), שמות הצדדים ובאי כוחם, והמילה "החלטה".
|
||||||
|
|
||||||
|
### 2.2 סדר הפרקים
|
||||||
|
|
||||||
|
הרקע העובדתי מתחיל ישירות בסעיף 1, ללא כותרת מפורשת. לאחריו באים: "תמצית טענות הצדדים" עם תת-פרקים לכל צד (טענות העוררים, עמדת הוועדה המקומית, עמדת מבקשי ההיתר), ואז "דיון והכרעה", ולבסוף "סיכום" או "סוף דבר".
|
||||||
|
|
||||||
|
כשהוועדה המקומית קיימה דיון מנומק, ייתכן פרק נפרד שמצטט את הפרוטוקול לפני הטענות. כשהדיון בפני ועדת הערר הוסיף מעבר לכתבי הטענות, ייתכן תת-פרק "הדיון בפני ועדת הערר" או "הבהרות".
|
||||||
|
|
||||||
|
כותרת הסיום: "סיכום" מועדף בעררי היטל השבחה ובדחיות. "סוף דבר" מועדף בעררי רישוי ובקבלות. לא "סיכום והכרעה".
|
||||||
|
|
||||||
|
### 2.3 כותרות משנה
|
||||||
|
|
||||||
|
כותרות משנה מופיעות רק כשיש הבחנה בין צדדים (טענות העוררים, הוועדה המקומית, מבקשי ההיתר) או בין נושאים מרכזיים שונים. בפרק הדיון וההכרעה הכלל הוא אסה רציפה אחת ללא כותרות משנה, והמעברים נעשים באמצעות ביטויי מעבר טקסטואליים. החריג: כשיש מספר נושאים נפרדים לחלוטין (למשל: "הבקשה להקלה בגובה המבנה" ואז "התייחסות לטענות נוספות שעלו בכתב הערר"), מותרת כותרת נושאית.
|
||||||
|
|
||||||
|
### 2.4 מספור סעיפים
|
||||||
|
|
||||||
|
מספרים עוקבים לאורך כל המסמך: 1, 2, 3 וכו'. אין איפוס מספור בין פרקים. המספור ממשיך ברצף מ-1 עד הסוף.
|
||||||
|
|
||||||
|
|
||||||
|
## 3. סגנון ניסוח
|
||||||
|
|
||||||
|
### 3.1 אורך סעיפים
|
||||||
|
|
||||||
|
בחלק הרקע והטענות: סעיף טענה רגיל הוא 40-60 מילים (פתיחה, טענה, פירוט, השלכה - לא פחות מ-3 משפטים). סעיף תגובה הוא 50-80 מילים (דחיית הטענה, נימוק, ראיה). סעיף עם ציטוט הוא 80-150 מילים (הקדמה, ציטוט, הסבר). סעיפי גשר בלבד הם 15-30 מילים ("נבהיר כי...", "כך גם נציין..."). הממוצע הכולל: 45-55 מילים לסעיף.
|
||||||
|
|
||||||
|
בחלק הדיון וההכרעה: הסעיפים ארוכים יותר משמעותית. סעיף ניתוח רגיל הוא 40-80 מילים. סעיף עם ציטוט מקיף מפסיקה או מהחלטה מרכזת יכול להגיע ל-200-600 מילים - ואין לפצל ציטוט כזה למספר סעיפים. הממוצע בדיון: 80-120 מילים לסעיף כולל ציטוטים.
|
||||||
|
|
||||||
|
דוגמה לסעיף טענה תקין (כ-40 מילים): "העוררים טוענים כי נפל פגם מהותי בהליך ההמצאה. לטענתם, תכניות הבנייה והבקשה להיתר לא הומצאו לידיהם כנדרש. העוררים מדגישים כי אי-ההמצאה מנעה מהם את האפשרות להתנגד במועד, ולטענתם מדובר ב'מחטף' שנועד לעקוף את זכות ההתנגדות של בעלי הזכויות בנכס."
|
||||||
|
|
||||||
|
### 3.2 יחסי הזהב - חלוקת אחוזים
|
||||||
|
|
||||||
|
ערר רישוי שנדחה (1xxx): פתיחה 0.5%, רקע 15-25%, טענות 30-40%, דיון 37-50%, סיכום 2-9%. מאפיינים: פתיחת דיון עם הקשר תכנוני רחב (5-8 פסקאות), אלמנטים אנושיים בסיום.
|
||||||
|
|
||||||
|
ערר רישוי שמתקבל (1xxx): רקע כולל ציטוט מפרוטוקול הוועדה 30-40%, טענות כולל השלמת מסמכים 20-30%, דיון עם ניתוח נימוק-נימוק 35-45%, סוף דבר 3-5%. מאפיינים: פתיחת דיון ישירה, דיון ארוך עם חזרות מכוונות, סיום עניני.
|
||||||
|
|
||||||
|
ערר רישוי שמתקבל חלקית (1xxx): רקע כולל ציטוט מפרוטוקול 25-35%, טענות כולל השלמת טיעון 25-30%, דיון 40-47%, סיכום 2-3%. מאפיינים: פתיחת דיון עם מיפוי מתחים (3-6 סעיפים), דיון ארוך עם ציטוטים נרחבים מהוראות תכנית ונספחים, סיכום מינימלי-אופרטיבי. ראה: בית הכרם 1126/25.
|
||||||
|
|
||||||
|
ערר היטל השבחה (8xxx): פתיחה 5-7%, רקע 6-18%, טענות 13-25%, דיון 32-48%, סיכום 3-4%. מאפיינים: פתיחה ישירה, הרבה ציטוטי פסיקה, סיום יבש.
|
||||||
|
|
||||||
|
### 3.3 הגדרות בשיטת "להלן"
|
||||||
|
|
||||||
|
פורמט קבוע: (להלן: "שם ההגדרה"). ההגדרה מופיעה במירכאות כפולות, בסוגריים לאחר האזכור הראשון. ניתן להגדיר שני מונחים חלופיים עם קו נטוי: (להלן: "התכנית" או "תכנית הל/435"). דוגמאות: (להלן: "הבקשה להיתר"), (להלן: "הבניין" / "המקרקעין"), (להלן: "התקנות").
|
||||||
|
|
||||||
|
### 3.4 ציטוטים ארוכים
|
||||||
|
|
||||||
|
ציטוטים ארוכים מפרוטוקולים, תכניות או פסיקה מוצגים כבלוק נפרד עם כניסה. לעיתים עם הערה "(הדגשת הח"מ)" או "(הדגשת הח.מ.)". ציטוטים ארוכים הם כלי מרכזי - דפנה מעדיפה לצטט בלוק ארוך אחד (200-500 מילים) מתוך החלטה מרכזת שכבר ריכזה את הפסיקה, במקום לצטט כל פסק דין בנפרד.
|
||||||
|
|
||||||
|
### 3.5 תמונות ונספחים
|
||||||
|
|
||||||
|
תמונות ותשריטים משולבים בטקסט עם הפניה מילולית: "להלן מתוך נספח האדריכלות והבקשה להיתר שם ניתן לראות את הדברים:", "להלן תמונת המגרשים הרלוונטיים מתוך מערכת ה-GIS של הוועדה המקומית", "להלן מתוך נספח הבינוי המצורף להוראות התכנית". העיצוב הטכני נעשה בשלב הוורד.
|
||||||
|
|
||||||
|
### 3.6 קיצורים משפטיים
|
||||||
|
|
||||||
|
עו"ד (עורך דין), ב"כ (בא כוח), עוה"ד (עורך הדין), יח"ד (יחידת דיור), מ"ר (מטר רבוע), תב"ע (תכנית בניין עיר), רמ"י (רשות מקרקעי ישראל), ר"ר / בר"ר (רשות רישוי), סה"כ (סך הכל).
|
||||||
|
|
||||||
|
### 3.7 פורמט תאריכים ומספרים
|
||||||
|
|
||||||
|
תאריכים: DD.MM.YY (לדוגמה: 12.06.25 או 17.4.2024). מספר תכנית: 102-1170893 או הל/435. מספר בקשה להיתר: 20250337. גוש וחלקה: גוש 30322 חלקה 77 מגרש 13.
|
||||||
|
|
||||||
|
### 3.8 עקרונות כלליים
|
||||||
|
|
||||||
|
הקורא צריך להבין את ההקשר המלא מקריאת ההחלטה בלבד. תן הקשר מלא ואל תניח שהקורא מכיר את התיק. ציטוט עדיף על תמצות כשיש מסמך מקור. פרט מספרים ונתונים מדויקים ("10 מתוך 14 דירות (71.4%)" ולא רק "רוב"). הסבר מונחים ("במסלול הירוק, קרי היתרים תואמי תכנית").
|
||||||
|
|
||||||
|
|
||||||
|
## 4. הצגת טענות הצדדים
|
||||||
|
|
||||||
|
### 4.1 טענות העוררים
|
||||||
|
|
||||||
|
מבנה סעיף: מספר, תיאור הטענה, פירוט, השלכות לטענת העוררים. ביטויים: "העוררים טוענים כי...", "לטענתם...", "העוררים מדגישים כי...", "עוד ציינו כי...", "לטענתם מדובר ב...", "העורר מוסיף וטוען כי...", "לחיזוק טענתו, מצביע העורר על...", "לחיזוק טענותיו...". טענות מהדיון: "בדיון הוסיפו וטענו העוררים כי...", "בדיון הוסיפה וטענה העוררת גב' [שם] כי...". הבהרות: "במסגרת הודעת העורר כי הצדדים לא הגיעו לפתרון מוסכם ביניהם צירף העורר הבהרה וטען כי...".
|
||||||
|
|
||||||
|
### 4.2 עמדת הוועדה המקומית
|
||||||
|
|
||||||
|
פתיחה: "במסגרת כתב התשובה ובדיון בפנינו הוועדה המקומית הציגה את עמדתה באופן מפורט." ביטויים: "הטענה המרכזית הינה כי...", "הוועדה המקומית הציגה נתונים מפורטים לעניין...", "הוועדה המקומית הבהירה כי...", "הוועדה הוסיפה כי...", "הוועדה המקומית טוענת כי...", "הוועדה המקומית מוסיפה כי...", "עוד טוענת הוועדה המקומית כי...", "לבסוף טוענת הוועדה המקומית כי...".
|
||||||
|
|
||||||
|
### 4.3 טענות מבקשי ההיתר
|
||||||
|
|
||||||
|
ביטויים: "מבקשי ההיתר דוחים מכל וכל את הטענה...", "לטענתם...", "מבקשי ההיתר מציינים כי...", "מבקשי ההיתר מבהירים כי...", "עוד מציינים מבקשי ההיתר כי...", "מכל מקום, מבקשי ההיתר...", "לגופו של עניין...", "לאור האמור, מבקשי ההיתר עותרים ל...".
|
||||||
|
|
||||||
|
### 4.4 כללים
|
||||||
|
|
||||||
|
הפרדה ברורה בין הצדדים - כל צד בפרק נפרד. סדר קבוע: עוררים, וועדה מקומית, מבקשי היתר. אין שילוב של טענות צדדים שונים באותו סעיף.
|
||||||
|
|
||||||
|
|
||||||
|
## 5. ביטויים ומעברים
|
||||||
|
|
||||||
|
### 5.1 ביטויים כלליים
|
||||||
|
|
||||||
|
"לפנינו" - פתיחת המסמך ("לפנינו שני עררים..."). "לענייננו" - מיקוד בנקודה רלוונטית. "נבהיר כי" - הבהרה חשובה. "כך גם נציין כי" - הוספת נקודה משלימה. "מדובר ב..." - הסבר עובדתי. "כפי ש..." - הפניה למידע קודם. "ואשר עניינם/עניינה ב..." - הגדרת נושא. "ככל ש..." - תנאי. "הרי ש..." - מסקנה. "מכל מקום" - מעבר לטענה חלופית. "לגופו של עניין" - מעבר לדיון המהותי. "אדרבא" - טענה נגדית חזקה. "קרי" - הסבר/פירוש. "כאמור" - הפניה לדבר שנאמר קודם. "בענייננו" - מעבר מכלל לפרט.
|
||||||
|
|
||||||
|
### 5.2 ביטויי מעבר בפרק הדיון
|
||||||
|
|
||||||
|
"ועל מנת לא לצאת בחסר" - פתיחת obiter dicta / נימוקים נוספים. דוגמה: "אך יחד עם זאת ועל מנת לא לצאת בחסר מצאנו להוסיף..."
|
||||||
|
|
||||||
|
"נציין כי טענות אלו נטענו בלשון רפה" - הכרה שטענות חלשות אבל נדונות. דוגמה: "...אך יחד עם זאת נדרשנו אליהם מכח הלכת שפר."
|
||||||
|
|
||||||
|
"עינינו הרואות" - סיכום ביניים לאחר ציטוט ארוך.
|
||||||
|
|
||||||
|
"נוסיף." - מעבר קצר (משפט אחד) לפני ציטוט נוסף.
|
||||||
|
|
||||||
|
"אם כן" / "אם כך" - הסקת מסקנה מציטוט או ניתוח. דוגמה: "אם כך, לעת הזו, הגישה הנוהגת היא ש..."
|
||||||
|
|
||||||
|
"למעלה מן הצורך" - דיון שאינו הכרחי להכרעה אבל נכתב מטעמים אסטרטגיים.
|
||||||
|
|
||||||
|
"ברי כי" - מסקנה מובנת מאליה.
|
||||||
|
|
||||||
|
"נפנה ל..." - פתיחת ניתוח של סעיף חוק/פסיקה.
|
||||||
|
|
||||||
|
"למיטב הבנתנו" - עמדה זהירה בסוגיה שטרם הוכרעה.
|
||||||
|
|
||||||
|
"נשלים ונציין" - תוספת אחרונה לפני הסיכום.
|
||||||
|
|
||||||
|
"מכל האמור לעיל" - מעבר לסיכום.
|
||||||
|
|
||||||
|
"נשוב על כך כי" - חזרה מכוונת על עקרון חשוב שכבר נאמר. דוגמה: "נשוב על כך כי ההחלטה לאישור הבקשה אין בה בכדי להוות כל הכרעה קניינית."
|
||||||
|
|
||||||
|
"דא עקא" - הצגת הבעיה המרכזית או מה שסותר את הטענה.
|
||||||
|
|
||||||
|
"ובמילים אחרות" - חידוד/פרפרזה של נקודה שנאמרה.
|
||||||
|
|
||||||
|
"הגענו לכלל מסקנה כי" - מסקנה מרכזית (בפתיחת דיון).
|
||||||
|
|
||||||
|
"לא נוכל לקבל" - דחיית עמדה/טענה.
|
||||||
|
|
||||||
|
"מקובלת עלינו" - קבלת עמדה.
|
||||||
|
|
||||||
|
"התרשמנו כי" - מסקנה מהדיון/ממסמכים.
|
||||||
|
|
||||||
|
"נחדד כי" - חידוד נקודה קודמת.
|
||||||
|
|
||||||
|
"סיכומם של דברים" - פתיחת סיכום מהותי לפני "סוף דבר".
|
||||||
|
|
||||||
|
"המסקנה מכל האמור היא כי" - מסקנת ביניים מקיפה.
|
||||||
|
|
||||||
|
"לעמדתנו" - עמדת הוועדה.
|
||||||
|
|
||||||
|
"בנסיבות אלה" - מעבר מעובדות למסקנה.
|
||||||
|
|
||||||
|
"נזכיר כי" - תזכורת לעקרון ידוע.
|
||||||
|
|
||||||
|
"מצאנו כי" - קביעה עובדתית.
|
||||||
|
|
||||||
|
"שוכנענו כי" - קביעה לאחר בחינה.
|
||||||
|
|
||||||
|
"על כן ולו רק מסיבה זו" - ניטרול טענה חלשה לפני ניתוח מעמיק.
|
||||||
|
|
||||||
|
"יחד עם זאת, מצאנו לנכון לדון בשאלה העקרונית" - מעבר לדיון עקרוני למרות דחייה.
|
||||||
|
|
||||||
|
"נסכם כי" - מעבר לסיכום ביניים.
|
||||||
|
|
||||||
|
"משכך" - הסקת מסקנה מהאמור.
|
||||||
|
|
||||||
|
"הדברים מתחדדים שעה ש..." - חידוד נוסף לאור נסיבות נוספות.
|
||||||
|
|
||||||
|
"נחזור על כך כי" - חזרה מודגשת על קביעה חשובה.
|
||||||
|
|
||||||
|
"זאת ועוד" - הוספת נימוק נוסף.
|
||||||
|
|
||||||
|
"יתרה מכך" - חיזוק הנימוק הקודם.
|
||||||
|
|
||||||
|
"לאור כל האמור לעיל" - פתיחת סיכום סופי.
|
||||||
|
|
||||||
|
"נפתח בכך כי" - פתיחה של הדיון (לא של המסמך).
|
||||||
|
|
||||||
|
"נפנה בעניין זה להחלטת..." - הפניה לתקדים.
|
||||||
|
|
||||||
|
"הדברים משליכים על שיקול הדעת ב..." - קישור בין ממצא למסקנה.
|
||||||
|
|
||||||
|
"רוצה לומר כי" - הסבר/פרפרזה אלטרנטיבית.
|
||||||
|
|
||||||
|
"נוצר מצב בו" - הצגת בעיה/מצב עובדתי.
|
||||||
|
|
||||||
|
"לכך נוסיף כי" - הוספת נדבך נוסף לטיעון.
|
||||||
|
|
||||||
|
"יש אולי להצר על כך ש..." - הערה ביקורתית עדינה (כלפי מוסד תכנון).
|
||||||
|
|
||||||
|
"עם ההבנה לטענה זו של העוררים, אין בידנו לקבלה" - acknowledge-reject מרוכך.
|
||||||
|
|
||||||
|
"ברי כי משאב הקרקע יקר לבעליו ולציבור" - הצדקת שימוש יעיל בקרקע.
|
||||||
|
|
||||||
|
|
||||||
|
## 6. השיטה האנליטית - "איך לחשוב" לפני "איך לכתוב"
|
||||||
|
|
||||||
|
### 6.1 שומר הסף - שאלת הסף
|
||||||
|
|
||||||
|
לפני שנוגעים בטענה לגופה, השאלה הראשונה היא: "יש לעוררים בכלל זכות ערר?" זו לא רק שאלה פרוצדורלית - זו מסגרת הניתוח כולה. **סייג חשוב:** שאלת הסף היא כלי אסטרטגי, לא חובה. בתיקים עם שאלות מהותיות חזקות (חניה, שימור, קווי בניין), דפנה עשויה לדלג על שאלת הסף ולדון ישירות בגוף העניין — במיוחד בקבלה חלקית. ראה: בית הכרם 1126/25 — דילגה על ס' 152 לחלוטין.
|
||||||
|
|
||||||
|
### 6.2 קילוף מסכות - סיווג הטענות
|
||||||
|
|
||||||
|
לוקחים כל טענה ובוחנים מה מתחת למסכה. האם טענה של "סטייה מתכנית" היא באמת סטייה, או השגה על התכנית עצמה? האם טענה קניינית לבשה כסות תכנונית? הטכניקה: לכתוב במפורש "טענות שהוצגו בכסות של טענות תכנוניות" - לחשוף את האסטרטגיה, לא רק לדחות אותה.
|
||||||
|
|
||||||
|
### 6.3 עיגולים קונצנטריים - בניית שכבות
|
||||||
|
|
||||||
|
לא לענות על כל טענה בנפרד. לבנות פירמידה של שכבות הגנה: שכבה חיצונית (אין זכות ערר כלל), "אך יחד עם זאת..." שכבה שנייה (גם אם הייתה - אין סטייה מתכנית), "למעלה מן הצורך..." שכבה שלישית (גם על המריטים - ההחלטה נכונה), "עוד נשלים..." שכבה רביעית (הטענות הקנייניות - מקומן בערכאה אחרת). ההחלטה נהיית חסינה מערעור - גם אם בית המשפט לא יקבל שכבה אחת, השכבות האחרות עומדות בפני עצמן. **הערה:** מבנה השכבות מתאים בעיקר לערר שנדחה (כמו הכט 1180-1181). בקבלה חלקית, דפנה עשויה להשתמש במבנה חלופי: הקשר → מיפוי נקודות מתח → ניתוח נושא-נושא → הוראות מעשיות. ראה: בית הכרם 1126/25.
|
||||||
|
|
||||||
|
### 6.4 הכרה-דחייה-ניתוב
|
||||||
|
|
||||||
|
לעולם לא לומר שהטענה לא לגיטימית. במקום זאת: להכיר ("אכן, לעוררים עומדת זכות להגיש התנגדות קניינית"), לדחות ("אולם הדין לא נתן בידי אותו בעל זכות גם זכות ערר"), לנתב ("מקומן של הטענות להתברר בפני המפקח על הבתים המשותפים").
|
||||||
|
|
||||||
|
### 6.5 מיפוי מצב הדין
|
||||||
|
|
||||||
|
כשיש שאלה משפטית שטרם הוכרעה, לא לבחור צד ולצטט. למפות את כל המצב: פסיקה A (דעת רוב - כיוון X), עתירה/ערעור, עמדת המדינה (כיוון Y), פסיקה B (חזרה מ-A), ערעור תלוי ועומד (טרם הוכרע), מסקנה: "לעת הזו, הגישה הנוהגת היא ש..."
|
||||||
|
|
||||||
|
### 6.6 נדיבות אסטרטגית - למעלה מן הצורך
|
||||||
|
|
||||||
|
השימוש ב"למעלה מן הצורך" הוא אסטרטגי: מראה שגם על המריטים התוצאה זהה, מונע טענה של "לא שמעו אותנו", יוצר תקדים גם בשאלות שלא היו חייבים להכריע, בונה קו פסיקתי עקבי.
|
||||||
|
|
||||||
|
### 6.7 ניטרול טענה חלשה לפני ניתוח מעמיק
|
||||||
|
|
||||||
|
כשיש טענה שאפשר לדחות מסיבה טכנית פשוטה, אבל יש גם שאלה עקרונית מעניינת מאחוריה - דפנה קודם מנטרלת את הטענה ("על כן ולו רק מסיבה זו נכון היה לדחות את הערעור ולסיים את הדיון"), ואז עוברת לדיון עקרוני ("יחד עם זאת, מצאנו לנכון לדון בשאלה העקרונית האם..."). זה מאפשר ליצור תקדים עקרוני מבלי להסתמך על הטענה החלשה.
|
||||||
|
|
||||||
|
### 6.8 טכניקת החידוד ("שארפנינג")
|
||||||
|
|
||||||
|
חזרה מכוונת על נקודות מפתח, כאשר כל חזרה מוסיפה זווית חדשה. דפנה משתמשת ב"נחדד כי...", "נשוב על כך כי...", "הדברים מתחדדים שעה ש...", "נחזור על כך כי..." - כל אחד מהביטויים האלה לא חוזר על מה שנאמר אלא מוסיף שכבה נוספת של ניתוח.
|
||||||
|
|
||||||
|
### 6.9 מנגנון פרשנות תכנית
|
||||||
|
|
||||||
|
כשצריך לפרש תכנית בניין עיר, דפנה עוברת ארבעה שלבים: ראשית, בחינת לשון התכנית (ציטוט מדויק מההוראות, בחינה האם ההוראה מחייבת או מנחה, חיפוש ניסוחים מחייבים כמו "בכל מקרה", "לא יעלה על"). שנית, בחינת תכלית התכנית (מה המטרות שהוגדרו, האם מדובר בתכנית נקודתית או כוללנית, מי היו היוזמים). שלישית, בחינת ההיסטוריה התכנונית (מה קבעו תכניות קודמות, האם התכנית החדשה החמירה או הקלה, מה המגמה). רביעית, בחינה ראייתית (היתרים שניתנו באזור, תצלומים, תשריטים, הדמיות).
|
||||||
|
|
||||||
|
### 6.10 ניתוח "בית בודד" בתמ"א 38
|
||||||
|
|
||||||
|
כשעוסקים בחיזוק/הריסה של בית בודד (להבדיל מבניין מגורים רב-קומתי), אינטרס החיזוק מפני רעידות אדמה מוחלש. דפנה מציינת זאת במפורש: "עסקינן בחיזוק בית בודד ועל כן... לא קיים באופן מלא אינטרס חיזוק כזה המצדיק את אישור מלוא הזכויות." המשמעות: שיקול דעת זהיר יותר באישור מלוא הזכויות מכוח תכנית 10038, במיוחד בנושאי קווי בניין וחניה. "הדברים משליכים על שיקול הדעת באישור הבקשה להיתר." ראה: בית הכרם ס' 41.
|
||||||
|
|
||||||
|
### 6.11 תכנית אב כ"מגן" מפני תכנון אד-הוק
|
||||||
|
|
||||||
|
כשקיימת תכנית אב/מדיניות לאזור, דפנה משתמשת בה כדי לאמת שהיתר בודד לא יוצר חריג: "קיימת תכנית אב אשר מקלה על בחינת הבקשה... החשש לאישור היתר מכח תכנית 10038 על מגרש בודד ללא ראיה כללית אינו קיים למעשה." דפוס: בדוק אם יש מדיניות → ציטוט הסעיפים הרלוונטיים → מסקנה שההיתר "משתלב עם ראיה כללית קיימת" ולא "מכתיב תכנון עתידי לסביבה". ראה: בית הכרם ס' 42.
|
||||||
|
|
||||||
|
|
||||||
|
## 7. כתיבת פרק הדיון וההכרעה
|
||||||
|
|
||||||
|
### 7.1 עקרונות כתיבה
|
||||||
|
|
||||||
|
אסה רציפה אחת - ללא כותרות משנה (חריג: נושאים נפרדים לחלוטין). מסקנה בפתיחה - הפרק נפתח עם המסקנה ואז מפרט את הנימוקים. ציטוטים ארוכים ומקיפים - העדפה לבלוק ציטוט אחד ארוך על פני פיצול. הפניה להחלטות מרכזות - במקום לצטט כל פסק דין בנפרד, הפניה להחלטה שכבר ריכזה את הפסיקה. שכבות ניתוח - מסקנה, נימוק ראשי, "אך יחד עם זאת", נימוק משני, "למעלה מן הצורך", obiter.
|
||||||
|
|
||||||
|
### 7.2 פתיחת הדיון - לפי סוג ערר ותוצאה
|
||||||
|
|
||||||
|
ערר רישוי שנדחה (פתיחה רחבה, 5-8 סעיפים): הדיון נפתח עם הקשר תכנוני רחב שמכין את הקורא. הקשר פרוצדוראלי (1-2 פסקאות) על ניסיון גישור שלא צלח. מהות דיני התכנון כעקרון (2-3 פסקאות) על יצירת פיתוח ואיכות חיים. איזונים בתכנון (1-2 פסקאות) על התחשבות בכל המעורבים. ערך ההתחשבות באחר (1-2 פסקאות). ייחוד המקרה (1 פסקה) - "בענייננו, אנו נדרשים לערוך את האיזונים הללו ולבחון האם...". רק אחרי 5-8 פסקאות אלה - צלול לעניין הספציפי עם מסקנה.
|
||||||
|
|
||||||
|
ערר רישוי שמתקבל (פתיחה ישירה, 1-2 סעיפים): "לאחר שמיעת טענות הצדדים ועיון במסמכים שהוגשו, הגענו לכלל מסקנה כי דין הערר להתקבל בכפוף למספר תיקונים בבקשה להיתר כפי שיורחב להלן." ואז הערה פרוצדורלית אם צריך.
|
||||||
|
|
||||||
|
ערר היטל השבחה (פתיחה ישירה עם מסקנה): "לאחר שבחנו את טענות הצדדים ונערך דיון בפנינו בו נשמעו בהרחבה, החלטנו בשלב ראשון כי [המסקנה]. אך יחד עם זאת ועל מנת לא לצאת בחסר ומאחר ונשמעו הצדדים בפנינו מצאנו להוסיף מספר הערות והכל כפי שיפורט להלן;"
|
||||||
|
|
||||||
|
ערר על פרשנות תכנית / סטיה ניכרת (פתיחה עם שאלה מרכזית): "כאמור השאלה המרכזית בערר הינה בחינת הבקשה ל[נושא הערר]." ואז ניטרול טענות חלשות, ומעבר לדיון עקרוני.
|
||||||
|
|
||||||
|
ערר רישוי שמתקבל חלקית (פתיחה במיפוי מתחים, 3-6 סעיפים): 1-2 פסקאות כלליות על ערך התכנון ואיזון אינטרסים. "בערר דנן עולות שאלות כיצד והאם..." → רשימה של 4-6 נקודות מתח ספציפיות בתיק (בבולטים), כל נקודה מתארת ציר מתח בין אינטרסים מנוגדים. "כל הנקודות לעיל עומדות לפנינו ולשם כך קראנו, שמענו את הצדדים..." → מעבר לניתוח. ראה: בית הכרם ס' 37-40.
|
||||||
|
|
||||||
|
### 7.3 מסלול דיון לפי סוג ערר
|
||||||
|
|
||||||
|
**ערר רישוי שנדחה - מסלול שכבות הגנה:**
|
||||||
|
פתיחה רחבה עם הקשר תכנוני (5-8 סעיפים). ניתוח זכות הערר (2-4 סעיפים). טענות קנייניות - אין זכות ערר (1-2 סעיפים ארוכים עם ציטוט מקיף מהחלטה מרכזת). דחיית טענות סטייה מתכנית (3-5 סעיפים). "למעלה מן הצורך" - היתכנות קניינית (אופציונלי). התייחסות לטענות ספציפיות (2-3 סעיפים קצרים).
|
||||||
|
|
||||||
|
**ערר רישוי שמתקבל - מסלול נימוק-נימוק:**
|
||||||
|
פתיחה ישירה עם מסקנה. הדיון מאורגן לפי נימוקי הדחייה של הוועדה המקומית. לכל נימוק: הצגת הנימוק ("באשר ל[נימוק] - הוועדה המקומית קבעה כי..."), ניתוח ("מעיון ב... / לא נוכל לקבל... / מקובלת עלינו..."), מסקנת ביניים ("משכך..." / "על כן..."). כשיש היבט קנייני - "נשוב על כך כי..." מופיע לפחות פעמיים (בדיון ובסיכום).
|
||||||
|
|
||||||
|
**ערר על פרשנות תכנית / סטיה ניכרת:**
|
||||||
|
הצגת שאלה מרכזית (1 פסקה). ניטרול טענות חלשות (1-2 פסקאות) - "על כן ולו רק מסיבה זו נכון היה לדחות". מעבר לדיון עקרוני (1 פסקה) - "יחד עם זאת, מצאנו לנכון לדון בשאלה העקרונית". ניתוח מקיף (5-15 פסקאות) באמצעות מנגנון פרשנות התכנית בארבעת שלביו: לשון, תכלית, היסטוריה תכנונית, בחינה ראייתית. ציטוטי פסיקה משולבים (2-3 פסקאות). מסקנה (1-2 פסקאות) עם "נסכם כי" או "לאור כל האמור לעיל".
|
||||||
|
|
||||||
|
**ערר היטל השבחה:**
|
||||||
|
פתיחה ישירה עם מסקנה. ניתוח ישיר - ציטוטי פסיקה מרובים. סיום יבש.
|
||||||
|
|
||||||
|
**ערר רישוי שמתקבל חלקית — מסלול מיפוי מתחים + ניתוח נושאי:**
|
||||||
|
פתיחה במיפוי מתחים (3-6 סעיפים): הקשר כללי קצר (1-2 פסקאות), רשימת נקודות מתח ספציפיות בתיק (4-6 בולטים), מעבר לניתוח. אין שימוש בשכבות/עיגולים קונצנטריים — ניתוח לפי נושאים: כל נושא מקבל טיפול מלא (הצגה → ציטוט הוראות תכנית → פסיקה → מסקנה). נושא חניה/תשתיות מקבל טיפול מעמיק במיוחד עם ציטוטים ישירים מהוראות תכנית ונספחים. טענות ספציפיות (מטרדים, עצים, בור מים) — 1-2 סעיפים תמציתיים לכל אחת. סיכום מינימלי — רק הוראות אופרטיביות (2-3 סעיפים). ראה: בית הכרם 1126/25.
|
||||||
|
|
||||||
|
### 7.4 טכניקת "ציטוט דרך החלטה מרכזת"
|
||||||
|
|
||||||
|
במקום לצטט כל פסק דין בנפרד, דפנה מפנה להחלטה שכבר ריכזה את הפסיקה: "בכל הנוגע ל[נושא], נפנה לניתוח המקיף שערכה ועדת הערר במסגרת ערר [שם] (פורסם בנבו) משם עולה כי..." ואז ציטוט בלוק ארוך (200-500 מילים) מתוך ההחלטה המרכזת שכוללת הפניות לפסיקה רלוונטית. הסיום: "אם כך, לעת הזו, הגישה הנוהגת היא ש..."
|
||||||
|
|
||||||
|
|
||||||
|
## 8. כתיבת סיכום / סוף דבר
|
||||||
|
|
||||||
|
### 8.1 ערר שנדחה
|
||||||
|
|
||||||
|
הכותרת: "סיכום". פתיחה: "לאור כל האמור לעיל, הערר נדחה." מבנה: תתי-סעיפים עם אותיות עבריות (א. ב. ג. ד. ה. ו.), כל תת-סעיף = נימוק מסכם.
|
||||||
|
|
||||||
|
בערר רישוי שנדחה בלבד - לפני "הערר נדחה", מופיעה פסקת סיום חמה ואנושית. לדוגמה: "טרם סיום נבקש לציין כי כתיבת החלטה זו לא הייתה קלה והדיון נשמע בפנינו בזמנים לא קלים. אנו מצרים כפי שציינו כי הצדדים לא הגיעו לידי הבנות והלוואי ולא היינו נדרשים לכתיבת ההחלטה. אנו תקווה כי חרף אי ההסכמות ישכילו הצדדים לייצר יחסי שכנות טובה כל אחד בדרכו ובעולמו תוך התחשבות והבנה הדדית לצרכי האחד כלפי שכנו." בערר היטל השבחה שנדחה - סיום יבש בלבד.
|
||||||
|
|
||||||
|
### 8.2 ערר שמתקבל
|
||||||
|
|
||||||
|
הכותרת: "סוף דבר". פתיחה: "לאור כל האמור לעיל, הערר מתקבל בכפוף ל..." או "אשר על כן, לאחר שמיעת הצדדים...". מבנה: סיכום רציף בפרוזה (3-5 פסקאות), כל פסקה מסכמת נימוק אחד, הוראה אופרטיבית. אין פסקה חמה. הסיום עניני: "בנסיבות העניין, אין צו להוצאות."
|
||||||
|
|
||||||
|
### 8.3 ערר שמוחזר לדיון
|
||||||
|
|
||||||
|
הכותרת: "סיכום" או "סוף דבר". מבנה: הוראות ממוספרות לוועדה המקומית ("תבחן", "תערוך", "תדון").
|
||||||
|
|
||||||
|
### 8.4 ערר שמתקבל חלקית
|
||||||
|
|
||||||
|
הכותרת: "סיכום". פתיחה: "לאור כל האמור לעיל, הערר מתקבל באופן חלקי." מבנה: 2-3 סעיפים אופרטיביים בלבד — מה מתקבל (בבולד), מה נדחה, תנאים נוספים. ללא חזרה על נימוקים (ההנמקה כבר בדיון). ייתכן ללא התייחסות להוצאות. ללא פסקת סיום חמה. ראה: בית הכרם ס' 84-86.
|
||||||
|
|
||||||
|
### 8.5 חתימה
|
||||||
|
|
||||||
|
"ניתנה פה אחד, היום [תאריך עברי], [תאריך לועזי]." חתימות יו"ר ומזכירת ועדת הערר.
|
||||||
|
|
||||||
|
### 8.6 הוצאות
|
||||||
|
|
||||||
|
"בנסיבות העניין, אין צו להוצאות." (או "יש צו להוצאות בסך...") בקבלה חלקית — ייתכן שההוצאות לא יוזכרו כלל.
|
||||||
|
|
||||||
|
|
||||||
|
## 9. דפוסים ייחודיים
|
||||||
|
|
||||||
|
### 9.1 חזרה מכוונת - "נשוב על כך כי"
|
||||||
|
|
||||||
|
בהחלטות קבלה שיש בהן היבט קנייני, דפנה חוזרת מספר פעמים על עקרון מרכזי: "נשוב על כך כי ההחלטה לאישור הבקשה אין בה בכדי להוות כל הכרעה קניינית ואין בה בכדי לגבור על כל הוראה אחרת על פי דין." כלל: בכל ערר שמתקבל ויש בו היבט קנייני, לשלב "נשוב על כך כי..." לפחות פעמיים - פעם בדיון ופעם בסיכום.
|
||||||
|
|
||||||
|
### 9.2 השלמת מסמכים
|
||||||
|
|
||||||
|
בתיקים מורכבים, לאחר הדיון ניתנת החלטה המאפשרת השלמת מסמכים. זה מתועד: "בסופו של דיון התקבלה החלטה המאפשרת השלמת מסמכים ואכן הגישו העוררים השלמת מסמכים הכוללת: [פירוט]. הוועדה המקומית השיבה וטענה כי [תשובה]." השלמת המסמכים מוצגת בסוף פרק הטענות.
|
||||||
|
|
||||||
|
### 9.3 הפניה לפרקדים של ניסיון גישור
|
||||||
|
|
||||||
|
"במסגרת הדיון בוועדת הערר הוסכם כי הצדדים ינסו לבחון דרכים להגיע לפתרון מוסכם ולבדוק דרך אפשרית לרבות קידום תוכנית נקודתית. במסגרת הודעת העורר כי הצדדים לא הגיעו לפתרון מוסכם ביניהם..."
|
||||||
|
|
||||||
|
### 9.4 עמידה על חוסר ראייתי
|
||||||
|
|
||||||
|
כשהעורר מעלה טענה בלי תימוכין: "מעבר לציון [מה שהוצג], לא הציג העורר כל תיעוד או אסמכתא להוכחת טענתו זו. בנסיבות אלה, לא עלה בידי העורר להרים את הנטל הראייתי הנדרש להוכחת טענתו בדבר [הטענה] כביכול."
|
||||||
|
|
||||||
|
### 9.5 למרות זאת - בדיקה עצמאית
|
||||||
|
|
||||||
|
גם כשהטענה לא הוכחה, דפנה בודקת בעצמה: "למרות זאת, ולמעלה מן הצורך, בחנה ועדת הערר את [מה שנבדק] והעלתה את הממצאים הבאים:..."
|
||||||
|
|
||||||
|
### 9.6 ציטוט הוראות תכנית
|
||||||
|
|
||||||
|
כשמצטטים מהוראות תכנית, דפנה מדגישה (בולד) את המילים המכריעות ומוסיפה ניתוח: "הניסוח הברור והחד-משמעי של ההוראה, בצירוף המילים 'בכל מקרה', מעיד על הכוונה ליצור מגבלה קשיחה."
|
||||||
|
|
||||||
|
### 9.7 אבחנה בין מחייב למנחה
|
||||||
|
|
||||||
|
"הנספח מבטא את נפח הבינוי המוצע והוא מנחה בלבד למעט לעניין [מה שמחייב]." הדגש המיוחד על מעמדן המחייב של הוראות מסוימות, להבדיל מיתר הוראות מנחות.
|
||||||
|
|
||||||
|
|
||||||
|
## 10. רשימת בדיקה
|
||||||
|
|
||||||
|
### רקע עובדתי
|
||||||
|
סעיף פתיחה "לפנינו..." או "עניינו בערר על החלטת...". תיאור הנכס והבקשה. הגדרות עם "להלן". ציטוט מהתכנית/פרוטוקול. תמונות רלוונטיות (מיקום מסומן). פירוט הליכים.
|
||||||
|
|
||||||
|
### טענות הצדדים
|
||||||
|
פרק "תמצית טענות הצדדים". טענות העוררים. עמדת המשיבים (הוועדה המקומית + מבקשי ההיתר). מספור רציף לאורך כל הסעיפים.
|
||||||
|
|
||||||
|
### דיון והכרעה
|
||||||
|
בדרך כלל אין כותרות משנה - הכל באסה רציפה (חריג: נושאים נפרדים). מסקנה בפתיחה. ציטוטים מקיפים מפסיקה בבלוקים ארוכים. ניטרול טענות חלשות לפני ניתוח מעמיק. מעבר לדיון עקרוני עם "יחד עם זאת, מצאנו לנכון...". שימוש בטכניקת החידוד ("נחדד כי", "נשוב על כך כי"). אם פרשנות תכנית - ארבעת השלבים (לשון, תכלית, היסטוריה, ראיות). אם קבלה עם היבט קנייני - "נשוב על כך כי..." לפחות פעמיים.
|
||||||
|
|
||||||
|
### סיכום / סוף דבר
|
||||||
|
"סיכום" (דחייה/היטל השבחה) או "סוף דבר" (קבלה/רישוי). מבנה סיכום לפי תוצאה (תתי-סעיפים בדחייה, פרוזה בקבלה, הוראות בהחזרה). ערר רישוי שנדחה: פסקת סיום חמה ואנושית. הוצאות. חתימה עם תאריך עברי ולועזי.
|
||||||
|
|
||||||
|
### סגנון כללי
|
||||||
|
שימוש ב"להלן" להגדרות. ביטויים ייחודיים לכל צד. ציטוטים ארוכים כבלוקים נפרדים. קיצורים משפטיים עקביים. אורך סעיפים מותאם (40-60 בטענות, 80-120+ בדיון). הקורא מבין את התיק רק מקריאת ההחלטה.
|
||||||
|
|
||||||
|
|
||||||
|
## 11. מבנה ההחלטה — 12 בלוקים בסדר קבוע
|
||||||
|
|
||||||
|
### 11.1 עקרון מנחה: "מבחן השופט"
|
||||||
|
|
||||||
|
כל החלטה נכתבת כאילו שופט בית משפט לעניינים מנהליים קורא אותה לראשונה במסגרת עתירה מנהלית. השופט לא מכיר את התיק, לא ביקר בשטח, ולא שמע את הצדדים. כל מה שהוא יודע — הוא מה שכתוב בהחלטה. לכן:
|
||||||
|
- הרקע מפורט ומלא (לא "כידוע" או "כמפורט בתיק")
|
||||||
|
- ציטוטים ארוכים ולא מקוצרים (השופט צריך את המקור)
|
||||||
|
- תמונות וחתכים משולבים (השופט לא היה בסיור)
|
||||||
|
- כל טענה מקבלת מענה מפורש (שלא ייאמר "הוועדה לא התייחסה")
|
||||||
|
- ההליכים מתועדים (שיהיה ברור שניתן יום בבית דין מלא)
|
||||||
|
|
||||||
|
### 11.2 סדר הבלוקים
|
||||||
|
|
||||||
|
להלן 12 הבלוקים בסדר קבוע. הסדר מחייב ואין לסטות ממנו. **להגדרות מלאות** (content model, constraints, משקלות, פרמטרי עיבוד) **ראה `references/block-schema.md`.**
|
||||||
|
|
||||||
|
| בלוק | שם | תפקיד | משקל |
|
||||||
|
|------|-----|--------|------|
|
||||||
|
| א | כותרת מוסדית | מזהה מוסד ותיק | 1% |
|
||||||
|
| ב | הרכב הוועדה | מזהה הרכב מחליט | 1% |
|
||||||
|
| ג | צדדים | מזהה עוררים ומשיבים | 1% |
|
||||||
|
| ד | "החלטה" | סימון פורמלי | 0% |
|
||||||
|
| ה | פתיחה | "לפנינו..." — מסגרת + הגדרות "להלן" | 1% |
|
||||||
|
| ו | רקע ("פתח דבר") | עובדות ניטרליות + תמונות + ציטוט מפרוטוקול | 15-35% |
|
||||||
|
| ז | טענות הצדדים | פרפרזה נאמנה — **רק כתבי טענות מקוריים** | 20-40% |
|
||||||
|
| ח | הליכים בפני ועדת הערר | דיון, סיור, השלמות טיעון (עם תוכן), החלטות ביניים | 3-15% |
|
||||||
|
| ט | תכניות חלות **(אופציונלי)** | ציטוט הוראות תכנית + ניתוח ראשוני | 0-12% |
|
||||||
|
| י | **דיון והכרעה** | **ניתוח משפטי — CREAC — ליבת ההחלטה** | **32-50%** |
|
||||||
|
| יא | סיכום / סוף דבר | תוצאה אופרטיבית בלבד | 2-9% |
|
||||||
|
| יב | חתימות | "ניתנה פה אחד" + חתימות | 1% |
|
||||||
|
|
||||||
|
**שלושה כללים מרכזיים:**
|
||||||
|
- ⚠️ **"רקע ניטרלי" (בלוק ו):** אם משפט מכיל ציטוט ישיר מצד, או מילות שיפוט ("חריג", "חטא") — הוא שייך לטענות (ז) או לדיון (י), לא לרקע. החלטות קודמות = עובדה יבשה בלבד.
|
||||||
|
- ⚠️ **"ללא כפילות" (בלוק י):** הפנה לבלוקים קודמים ("כאמור בסעיף X"), אל תחזור עליהם. חריג: "נשוב על כך כי..." (חזרה מכוונת עם שכבה חדשה).
|
||||||
|
- ⚠️ **טענות מקוריות בלבד (בלוק ז):** מכתבי ערר/תשובה. השלמות טיעון → בלוק ח עם תוכן מפורט.
|
||||||
|
|
||||||
|
### 11.3 הבדלים בין סוגי עררים
|
||||||
|
|
||||||
|
| מרכיב | ערר על היתר | ערר על תכנית | ערר היטל השבחה |
|
||||||
|
|-------|------------|-------------|---------------|
|
||||||
|
| בלוק ה (פתיחה) | "ערר על החלטת רשות הרישוי..." | "ערר על החלטת הוועדה..." | "ערר על שומת היטל השבחה..." |
|
||||||
|
| בלוק ו (מהות) | בקשה להיתר — שטחים, קומות, הריסה | תכנית — סעיפי סמכות, שטחים | שומה — תכנית משביחה, לפני/אחרי |
|
||||||
|
| בלוק ט (תכניות) | תמ"א 38, 10038, תכנית מפורטת | תכנית אב, תכנית קודמת | לא רלוונטי (בדרך כלל) |
|
||||||
|
| ציטוט מרכזי ברקע | חוו"ד מחלקת שימור / מהנדס | החלטת ועדה מחוזית / פרוטוקול | שומה + שומה נגדית |
|
||||||
|
| תמונות | תשריט היתר, הדמיות, סיור | תשריט תכנית, GIS, סיור | לרוב אין |
|
||||||
|
|
||||||
|
### 11.4 מיקומי תמונות מומלצים
|
||||||
|
|
||||||
|
| מיקום | מה להכניס | מתי |
|
||||||
|
|-------|----------|-----|
|
||||||
|
| אחרי תיאור מקרקעין (בלוק ו) | תשריט מיקום / מפת GIS עם סימון המגרש | תמיד |
|
||||||
|
| אחרי מהות הבקשה (בלוק ו) | תשריט הבקשה / נספח בינוי / תכנית מוצעת | תמיד |
|
||||||
|
| אחרי סביבת מקרקעין (בלוק ו) | צילום אוויר עם סימון המגרש והסביבה | מומלץ |
|
||||||
|
| בתוך הליכים (בלוק ח) | צילומים מהסיור | אם היה סיור |
|
||||||
|
| בתוך הליכים (בלוק ח) | הדמיות / חתכי בינוי מהשלמות טיעון | אם צורפו |
|
||||||
|
| בתוך דיון (בלוק י) | המחשה סכמטית / השוואה לפני-אחרי | לפי הצורך |
|
||||||
|
|
||||||
|
כשמכינים את טיוטת המבנה (שלב 12 להלן), בכל מקום שמתוכננת תמונה יש להכניס תיבת טקסט עם:
|
||||||
|
- "📷 תמונה:" + תיאור מה צריך להכניס
|
||||||
|
- למשל: "📷 תמונה: תשריט מיקום המגרש מתוך מערכת GIS — לסמן את חלקה 244 באדום"
|
||||||
|
|
||||||
|
|
||||||
|
### 11.5 פרמטרי עיבוד — סיכום מהיר
|
||||||
|
|
||||||
|
להגדרות מלאות של כל בלוק (content model, constraints, weight methodology, processing derivation) ראה `references/block-schema.md`. להלן טבלת סיכום בלבד:
|
||||||
|
|
||||||
|
| בלוק | Generation type | Temp | Thinking | Model |
|
||||||
|
|------|----------------|------|----------|-------|
|
||||||
|
| א-ד | template-fill | 0 | off | script |
|
||||||
|
| ה | paraphrase | 0.2 | low | sonnet |
|
||||||
|
| ו | reproduction | 0 | off | sonnet |
|
||||||
|
| ז | paraphrase | 0.1 | low | sonnet |
|
||||||
|
| ח | reproduction + paraphrase | 0 | off | sonnet |
|
||||||
|
| ט | guided-synthesis | 0.2 | medium | opus |
|
||||||
|
| **י** | **rhetorical-construction** | **0.4** | **max (16K+)** | **opus** |
|
||||||
|
| יא | paraphrase | 0.1 | low | sonnet |
|
||||||
|
| יב | template-fill | 0 | off | script |
|
||||||
|
|
||||||
|
|
||||||
|
## 12. שלב מחייב: "טיוטת מבנה — לפני דיון"
|
||||||
|
|
||||||
|
### 12.1 מהות השלב
|
||||||
|
|
||||||
|
שלב זה מתבצע **אחרי** איסוף כל החומרים, המרת מסמכים, וניתוח טיעונים — ו**לפני** כתיבת פרק הדיון וההכרעה. מייצרים קובץ DOCX מעוצב עם כל חלקי ההחלטה **עד (ולא כולל)** פרק הדיון.
|
||||||
|
|
||||||
|
**כלל מחייב:** לעולם אל תכתוב פרק דיון והכרעה לפני שקובץ המבנה קיים ואושר.
|
||||||
|
|
||||||
|
### 12.1.1 כלל "ללא כפילות"
|
||||||
|
|
||||||
|
**כלל קריטי:** ככל שהרקע, הטענות וההליכים מפורטים יותר — כך הדיון צריך להיות קצר וממוקד יותר בניתוח בלבד. אין לחזור בדיון על עובדות או טענות שכבר פורטו. הדיון מניח שהקורא קרא את הרקע.
|
||||||
|
|
||||||
|
- **ברקע (בלוקים ה-ט):** פרט את כל העובדות, הציטוטים, הטענות, ההליכים — באופן מלא ומקיף.
|
||||||
|
- **בדיון (בלוק י):** רק ניתוח, הכרעה, ומסקנות. הפנה לרקע ולטענות במקום לחזור עליהם: "כאמור בסעיף X לעיל...", "כפי שפורט...", "כפי שציינו...".
|
||||||
|
- **כלל אצבע:** אם משפט בדיון חוזר על עובדה שכבר נאמרה ברקע מילה במילה — מחק אותו והחלף בהפניה.
|
||||||
|
- **חריג:** חזרה מכוונת ("נשוב על כך כי...") היא כלי רטורי לגיטימי כשמוסיפים שכבה חדשה, לא כפילות.
|
||||||
|
|
||||||
|
### 12.2 מה כולל קובץ המבנה
|
||||||
|
|
||||||
|
הקובץ כולל את בלוקים א-ט ממולאים בתוכן, בלוק י (דיון) עם placeholder, בלוק יא (סיכום) עם placeholder, ובלוק יב (חתימות) מלא. תיבות תמונה מסומנות ב-"📷 תמונה:" במקומות הרלוונטיים.
|
||||||
|
|
||||||
|
### 12.3 סדר עבודה
|
||||||
|
|
||||||
|
```
|
||||||
|
שלב 1: איסוף חומרים ← קריאת כל המסמכים
|
||||||
|
שלב 2: המרת מסמכים ← PDF → Markdown
|
||||||
|
שלב 3: ניתוח טיעונים ← זיהוי טענות, מיון, סיווג
|
||||||
|
שלב 4: טיוטת מבנה ← ייצור DOCX עם בלוקים א-ט + placeholders ← שם הקובץ: החלטה-ערר-XXXX-מבנה.docx
|
||||||
|
שלב 5: אישור המבנה ← דפנה מעיינת ומאשרת / מתקנת
|
||||||
|
שלב 6: כתיבת דיון והכרעה ← בלוק י
|
||||||
|
שלב 7: כתיבת סיכום ← בלוק יא
|
||||||
|
שלב 8: עדכון DOCX סופי ← כל הבלוקים + תמונות אמיתיות
|
||||||
|
```
|
||||||
|
|
||||||
|
### 12.4 עיצוב קובץ ה-DOCX
|
||||||
|
|
||||||
|
**חובה לקרוא קודם** את `.claude/skills/legal-docx/SKILL.md` — כל כללי RTL, פונטים, מידות וטבלאות מוגדרים שם. הסקריפט הבסיסי נמצא ב-`.claude/skills/legal-docx/scripts/create-legal-doc.js`.
|
||||||
|
|
||||||
|
כללי RTL קריטיים (מתוך legal-docx):
|
||||||
|
- `AlignmentType.START` (לא LEFT/RIGHT) ליישור ימין
|
||||||
|
- `AlignmentType.END` ליישור שמאל
|
||||||
|
- שלוש הגדרות חובה: `bidi: true` (section), `bidirectional: true` (paragraph), `rightToLeft: true` (run)
|
||||||
|
|
||||||
|
להלן ההגדרות הייחודיות להחלטת ועדת ערר (מעבר למה שמוגדר ב-legal-docx):
|
||||||
|
|
||||||
|
| מרכיב | עיצוב | הערות |
|
||||||
|
|-------|-------|-------|
|
||||||
|
| כותרת "החלטה" | 16pt (32 half-points), bold, `AlignmentType.CENTER` | HeadingLevel.HEADING_1 |
|
||||||
|
| כותרות פרקים ("תמצית טענות הצדדים", "דיון והכרעה") | 14pt (28 half-points), bold, קו תחתון, `AlignmentType.CENTER` | HeadingLevel.HEADING_2 |
|
||||||
|
| כותרות משנה ("טענות העוררים") | 12pt (24 half-points), bold, `AlignmentType.CENTER`, ללא קו תחתון | פסקה רגילה עם bold |
|
||||||
|
| מספור סעיפים | מספר + נקודה (bold, run נפרד) + טאב + טקסט (רגיל) | `alignment: AlignmentType.START`, hanging indent |
|
||||||
|
| ציטוטים (blockquote) | הזחה 567 DXA (~1 ס"מ) משני הצדדים, פונט זהה לגוף | indent: { left: 567, right: 567 } |
|
||||||
|
| תיבות תמונה | מסגרת עם shading אפור בהיר (fill: "F0F0F0"), טקסט "📷 תמונה: [תיאור]" | ShadingType.CLEAR |
|
||||||
|
| חתימות | טבלה ללא גבולות (`visuallyRightToLeft: true`), 2 טורים | כמו בתבנית ב-create-legal-doc.js |
|
||||||
|
| כותרת מוסדית | טבלה ללא גבולות, 2 טורים: ימין=מוסד, שמאל=מספרי תיק | `visuallyRightToLeft: true` |
|
||||||
574
skill-legal-decision/references/block-schema.md
Normal file
574
skill-legal-decision/references/block-schema.md
Normal file
@@ -0,0 +1,574 @@
|
|||||||
|
# Block Schema — ארכיטקטורת מסמך החלטת ועדת ערר
|
||||||
|
|
||||||
|
מסמך זה מגדיר את המבנה הפורמלי של החלטת ועדת ערר לתכנון ובניה. הוא משמש כמקור סמכותי להגדרת בלוקים, משקלות, פרמטרי עיבוד, וכללי ולידציה.
|
||||||
|
|
||||||
|
**הפניה:** SKILL.md סעיפים 11-12 מכילים סיכום מהיר והנחיות תהליך. מסמך זה מכיל את ההגדרות המלאות.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. יסודות תיאורטיים
|
||||||
|
|
||||||
|
ארכיטקטורת המסמך מבוססת על שילוב של ארבעה frameworks מוכרים:
|
||||||
|
|
||||||
|
### CREAC — מתודולוגיית כתיבה משפטית
|
||||||
|
Conclusion → Rule → Explanation → Application → Conclusion.
|
||||||
|
מקור: Columbia Law School, Legal Writing methodology.
|
||||||
|
**מיפוי:** חל על בלוק י (דיון) ובלוק יא (סיכום). בלוק י פותח במסקנה (C), מציג כלל משפטי (R), מסביר באמצעות פסיקה (E), מיישם על העובדות (A), וחוזר למסקנה (C). בלוק יא = C אחרון בלבד.
|
||||||
|
|
||||||
|
### Federal Judicial Center — Judicial Writing Manual
|
||||||
|
מגדיר תפקוד פונקציונלי לכל חלק בהחלטה שיפוטית:
|
||||||
|
- **Orientation** (אוריינטציה) — מי, מה, איפה → בלוקים א-ה
|
||||||
|
- **Framing** (מסגור) — הקשר עובדתי ותכנוני → בלוק ו
|
||||||
|
- **Argumentation** (טיעון) — עמדות הצדדים → בלוק ז
|
||||||
|
- **Procedural record** (תיעוד הליכי) — מה עשינו → בלוק ח
|
||||||
|
- **Deliberation** (דיון) — ניתוח משפטי → בלוקים ט-י
|
||||||
|
- **Disposition** (החלטה) — תוצאה אופרטיבית → בלוק יא
|
||||||
|
|
||||||
|
### DITA — Darwin Information Typing Architecture
|
||||||
|
סטנדרט OASIS להגדרת סוגי תוכן מובנים. מספק:
|
||||||
|
- **Content model** — אילו אלמנטים מותרים בכל בלוק
|
||||||
|
- **Constraints** — מה אסור (חשוב יותר ממה שמותר)
|
||||||
|
- **Specialization** — ירושה מסוג בסיסי עם התאמות
|
||||||
|
- **Relationships** — תלויות בין בלוקים
|
||||||
|
|
||||||
|
### Akoma Ntoso / LegalDocumentML
|
||||||
|
סטנדרט OASIS בינלאומי למסמכים משפטיים מובנים (UN/DESA). מספק:
|
||||||
|
- **Semantic mapping** — כל בלוק ממופה לרכיב מוכר בסטנדרט
|
||||||
|
- **Document class** — "judgment" (פסק דין / החלטה)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. הגדרות בלוקים
|
||||||
|
|
||||||
|
### Block א: כותרת מוסדית / Institutional Header
|
||||||
|
|
||||||
|
**ID:** `block-alef`
|
||||||
|
**Akoma Ntoso:** `meta > identification`
|
||||||
|
**CREAC role:** none
|
||||||
|
**Functional purpose (JWM):** Orientation — מזהה את המוסד, התיק והגורם המחליט.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: template-field
|
||||||
|
- Elements: טבלה 2 טורים (מוסד | מספרי תיק)
|
||||||
|
- Sources: מערכת ניהול תיקים
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: שם מוסד, מספר תיק, מספר תכנית/בקשה
|
||||||
|
- MUST NOT: תוכן מהותי כלשהו
|
||||||
|
- Dependencies: none
|
||||||
|
|
||||||
|
**Weight:** 1% (קבוע, לא משתנה בין סוגי עררים)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: template-fill
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: min | Model: script
|
||||||
|
|
||||||
|
|
||||||
|
### Block ב: הרכב הוועדה / Panel Composition
|
||||||
|
|
||||||
|
**ID:** `block-bet`
|
||||||
|
**Akoma Ntoso:** `meta > references > TLCPerson`
|
||||||
|
**CREAC role:** none
|
||||||
|
**Functional purpose (JWM):** Orientation — מזהה את ההרכב המחליט. חשוב לביקורת שיפוטית (הרכב כשיר).
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: template-field
|
||||||
|
- Elements: "בפני:" + יו"ר + חברים
|
||||||
|
- Sources: מערכת ניהול
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: יו"ר + לפחות חבר אחד
|
||||||
|
- MUST NOT: תוכן מהותי
|
||||||
|
- Dependencies: none
|
||||||
|
|
||||||
|
**Weight:** 1% (קבוע)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: template-fill
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: min | Model: script
|
||||||
|
|
||||||
|
|
||||||
|
### Block ג: צדדים / Parties
|
||||||
|
|
||||||
|
**ID:** `block-gimel`
|
||||||
|
**Akoma Ntoso:** `meta > references > TLCPerson` (appellants, respondents)
|
||||||
|
**CREAC role:** none
|
||||||
|
**Functional purpose (JWM):** Orientation — מזהה את הצדדים וב"כ. מגדיר את מסגרת הדיון.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: template-field
|
||||||
|
- Elements: עוררים + "נגד" + משיבים + ב"כ
|
||||||
|
- Sources: כתב ערר, כתב תשובה
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: שם כל צד, "נגד" כמפריד
|
||||||
|
- MUST NOT: תוכן מהותי, תיאור הערר
|
||||||
|
- Dependencies: none
|
||||||
|
|
||||||
|
**Weight:** 1% (קבוע)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: template-fill
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: min | Model: script
|
||||||
|
|
||||||
|
|
||||||
|
### Block ד: כותרת "החלטה" / Decision Title
|
||||||
|
|
||||||
|
**ID:** `block-dalet`
|
||||||
|
**Akoma Ntoso:** `body > judgment > header`
|
||||||
|
**CREAC role:** none
|
||||||
|
**Functional purpose (JWM):** Orientation — סימון פורמלי של תחילת ההחלטה.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: template-field
|
||||||
|
- Elements: מילה אחת: "החלטה"
|
||||||
|
- Sources: none
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: David 16pt, bold, מרכז
|
||||||
|
- Dependencies: none
|
||||||
|
|
||||||
|
**Weight:** 0% (שורה אחת)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: template-fill
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: min | Model: script
|
||||||
|
|
||||||
|
|
||||||
|
### Block ה: פתיחה / Opening
|
||||||
|
|
||||||
|
**ID:** `block-he`
|
||||||
|
**Akoma Ntoso:** `body > judgment > introduction`
|
||||||
|
**CREAC role:** C (מסקנה ראשונית — הצגת מה לפנינו)
|
||||||
|
**Functional purpose (JWM):** Orientation — מכוון את הקורא למהות הערר במשפט אחד. מגדיר "להלן" מרכזיים.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative (1-2 סעיפים)
|
||||||
|
- Elements: numbered-para עם הגדרות "להלן"
|
||||||
|
- Sources: כתב ערר, החלטת ועדה מקומית
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: "לפנינו...", הגדרת הוועדה המקומית, הגדרת התכנית/הבקשה, הגדרת המגרש
|
||||||
|
- MUST NOT: ניתוח, ערכי שיפוט, ציטוטים מצדדים
|
||||||
|
- Dependencies: block-gimel (שמות צדדים להגדרות)
|
||||||
|
|
||||||
|
**Weight:** 1% (קבוע — 1-2 סעיפים)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: paraphrase
|
||||||
|
- Temperature: 0.2 | Thinking: low | Effort: low | Model: sonnet
|
||||||
|
|
||||||
|
|
||||||
|
### Block ו: רקע עובדתי / Factual Background ("פתח דבר")
|
||||||
|
|
||||||
|
**ID:** `block-vav`
|
||||||
|
**Akoma Ntoso:** `body > judgment > background`
|
||||||
|
**CREAC role:** none (עובדות בלבד, לא ניתוח)
|
||||||
|
**Functional purpose (JWM):** Framing — מספק את התשתית העובדתית שעליה נבנה הדיון. השופט חייב להבין את המציאות בשטח לפני שקורא טענות.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative, citation-block, image-placeholder
|
||||||
|
- Elements: numbered-para, blockquote (ציטוט מפרוטוקול), image-box
|
||||||
|
- Sources: כתבי טענות, תשריטים, פרוטוקולים, החלטות קודמות, GIS
|
||||||
|
|
||||||
|
**סדר תוכן פנימי:**
|
||||||
|
1. מקרקעין — מיקום, שטח, מאפיינים
|
||||||
|
2. סביבת מקרקעין — בנייה סמוכה, אופי
|
||||||
|
3. 📷 תמונה: מיקום GIS
|
||||||
|
4. היסטוריה תכנונית — תכניות, החלטות (עובדות יבשות בלבד)
|
||||||
|
5. מהות הבקשה/תכנית
|
||||||
|
6. 📷 תמונה: תשריט
|
||||||
|
7. ציטוט מפרוטוקול ועדה מקומית
|
||||||
|
8. החלטת הוועדה + תנאים
|
||||||
|
9. 📷 תמונה: צילום אוויר (אופציונלי)
|
||||||
|
10. הגשת הערר
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: מקרקעין, מהות הבקשה, החלטת הוועדה, הגשת הערר
|
||||||
|
- MUST: לפחות 2 תמונות (מיקום + תשריט)
|
||||||
|
- MUST: ציטוט מפרוטוקול הוועדה המקומית
|
||||||
|
- ⚠️ **MUST NOT ("רקע ניטרלי"):** ציטוטים ישירים מצדדים, מילות ערך/שיפוט ("חריג", "חטא", "בעייתי"). החלטות קודמות = עובדה יבשה ("ביום X נדחתה תכנית Y"), ללא נימוקים וציטוטים מהן.
|
||||||
|
- Dependencies: block-he (הגדרות "להלן")
|
||||||
|
|
||||||
|
**Weight:**
|
||||||
|
|
||||||
|
| סוג ערר | משקל | הערות |
|
||||||
|
|---------|------|-------|
|
||||||
|
| רישוי — דחייה | 15-25% | רקע מפורט עם הקשר תכנוני |
|
||||||
|
| רישוי — קבלה | 30-40% | כולל ציטוט מפרוטוקול |
|
||||||
|
| רישוי — קבלה חלקית | 25-35% | כולל ציטוט מפרוטוקול |
|
||||||
|
| היטל השבחה | 6-18% | רקע מצומצם |
|
||||||
|
|
||||||
|
**Weight methodology:**
|
||||||
|
- Communicative weight (40%): גבוה — מספק את "התמונה" לשופט שלא מכיר את התיק
|
||||||
|
- Reader attention (20%): בינוני-גבוה — primacy effect, הקורא קשוב בהתחלה
|
||||||
|
- Judicial review (25%): גבוה — שופט בודק שהעובדות מלאות ומדויקות
|
||||||
|
- Empirical (15%): מבוסס על מדידת החלטות דפנה (3.2 ב-SKILL.md)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: reproduction (העתקה נאמנה ממקורות)
|
||||||
|
- Cognitive complexity: lookup (ארגון, לא ניתוח)
|
||||||
|
- Accuracy: high-precision
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: low | Model: sonnet
|
||||||
|
|
||||||
|
|
||||||
|
### Block ז: טענות הצדדים / Parties' Claims
|
||||||
|
|
||||||
|
**ID:** `block-zayin`
|
||||||
|
**Akoma Ntoso:** `body > judgment > arguments`
|
||||||
|
**CREAC role:** none (הצגת טענות, לא ניתוח)
|
||||||
|
**Functional purpose (JWM):** Argumentation — מציג את עמדות הצדדים בנאמנות, כך שהקורא יבין את המחלוקת לפני שקורא את ההכרעה.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative
|
||||||
|
- Elements: section-heading ("תמצית טענות הצדדים"), sub-headings (לכל צד), numbered-para
|
||||||
|
- Sources: כתב ערר, כתב תשובה — **כתבי טענות מקוריים בלבד** (לא השלמות טיעון)
|
||||||
|
|
||||||
|
**סדר קבוע:**
|
||||||
|
1. כותרת: "תמצית טענות הצדדים"
|
||||||
|
2. "טענות העוררים" (אם כמה עוררים — תתי-כותרות לכל אחד)
|
||||||
|
3. "עמדת הוועדה המקומית"
|
||||||
|
4. "עמדת מבקשי ההיתר" / "עמדת מגישי התכנית"
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: כל טענה בסעיף נפרד, גוף שלישי ("העורר טוען כי...")
|
||||||
|
- MUST: כל צד בפרק נפרד, סדר קבוע
|
||||||
|
- MUST NOT: ניתוח, מסקנות, הערכת הוועדה ("טענה זו חלשה...")
|
||||||
|
- MUST NOT: תוכן מהשלמות טיעון (→ block-chet)
|
||||||
|
- Dependencies: block-vav (מספור רציף)
|
||||||
|
|
||||||
|
**Weight:**
|
||||||
|
|
||||||
|
| סוג ערר | משקל | הערות |
|
||||||
|
|---------|------|-------|
|
||||||
|
| רישוי — דחייה | 30-40% | טענות מפורטות |
|
||||||
|
| רישוי — קבלה | 20-30% | כולל השלמות |
|
||||||
|
| רישוי — קבלה חלקית | 25-30% | |
|
||||||
|
| היטל השבחה | 13-25% | |
|
||||||
|
|
||||||
|
**Weight methodology:**
|
||||||
|
- Communicative weight (40%): בינוני — הצגה, לא הכרעה
|
||||||
|
- Reader attention (20%): נמוך-בינוני — scanning attention, הקורא מחפש טענות ספציפיות
|
||||||
|
- Judicial review (25%): גבוה — שופט בודק ש"נשמעו כל הצדדים"
|
||||||
|
- Empirical (15%): מבוסס על מדידת החלטות דפנה
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: paraphrase (סיכום נאמן בשפה של דפנה)
|
||||||
|
- Cognitive complexity: medium-synthesis (קיבוץ וסידור טענות)
|
||||||
|
- Accuracy: high-precision (לא לפספס טענה, לא לעוות)
|
||||||
|
- Temperature: 0.1 | Thinking: low | Effort: medium | Model: sonnet
|
||||||
|
|
||||||
|
|
||||||
|
### Block ח: הליכים בפני ועדת הערר / Proceedings
|
||||||
|
|
||||||
|
**ID:** `block-chet`
|
||||||
|
**Akoma Ntoso:** `body > judgment > proceedings` (custom extension)
|
||||||
|
**CREAC role:** none (תיעוד, לא ניתוח)
|
||||||
|
**Functional purpose (JWM):** Procedural record — מתעד שהוועדה פעלה כדין ונתנה מלוא יום בבית דין. קריטי ל"מבחן השופט" — שופט בעתמ"ם בודק שהצדדים קיבלו הזדמנות הוגנת.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative, image-placeholder
|
||||||
|
- Elements: section-heading ("ההליכים בפני ועדת הערר"), numbered-para, image-box
|
||||||
|
- Sources: פרוטוקול דיון, תמונות סיור, החלטות ביניים, השלמות טיעון
|
||||||
|
|
||||||
|
**סדר כרונולוגי:**
|
||||||
|
1. דיון — תאריך, נוכחים
|
||||||
|
2. סיור — תאריך, תיאור
|
||||||
|
3. 📷 תמונה: צילומים מהסיור
|
||||||
|
4. השלמות טיעון — עם תוכן מפורט (כל השלמה = סעיף נפרד)
|
||||||
|
5. החלטות ביניים
|
||||||
|
6. תגובות לתגובות — כרונולוגי
|
||||||
|
7. 📷 תמונה: הדמיות/חתכים (אם צורפו)
|
||||||
|
8. עררים מקבילים (אם יש)
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: תאריכים מדויקים, כרונולוגיה ברורה
|
||||||
|
- MUST: תוכן השלמות טיעון מפורט — כל השלמה בסעיף נפרד עם תמצית תוכן
|
||||||
|
- MUST NOT: ניתוח או הערכה של ההשלמות ("טענה חזקה/חלשה")
|
||||||
|
- Dependencies: block-zayin (מספור רציף)
|
||||||
|
- References: block-zayin (הפניה לטענות מקוריות כשיש חפיפה)
|
||||||
|
|
||||||
|
**Weight:**
|
||||||
|
|
||||||
|
| סוג ערר | משקל | הערות |
|
||||||
|
|---------|------|-------|
|
||||||
|
| ערר פשוט (ללא השלמות) | 3-5% | דיון + סיור בלבד |
|
||||||
|
| ערר מורכב (השלמות רבות) | 8-15% | כמו אריאלי: 31 סעיפים |
|
||||||
|
| היטל השבחה | 2-4% | בדרך כלל מינימלי |
|
||||||
|
|
||||||
|
**Weight methodology:**
|
||||||
|
- Communicative weight (40%): נמוך-בינוני — תיעוד, לא הכרעה
|
||||||
|
- Reader attention (20%): נמוך — scanning, אלא אם יש ממצאים חדשים מסיור/השלמות
|
||||||
|
- Judicial review (25%): **גבוה מאוד** — שופט בודק שנתנו procedural fairness
|
||||||
|
- Empirical (15%): מגוון רחב — תלוי בכמות ההשלמות
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: reproduction + paraphrase (תאריכים מדויקים + תמצית תוכן)
|
||||||
|
- Cognitive complexity: low (סידור כרונולוגי)
|
||||||
|
- Accuracy: high-precision (תאריכים, שמות מסמכים)
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: low | Model: sonnet
|
||||||
|
|
||||||
|
|
||||||
|
### Block ט: תכניות חלות / Applicable Plans (אופציונלי)
|
||||||
|
|
||||||
|
**ID:** `block-tet`
|
||||||
|
**Akoma Ntoso:** `body > judgment > motivation > background` (extended)
|
||||||
|
**CREAC role:** R (Rule — הצגת הכללים המשפטיים/תכנוניים)
|
||||||
|
**Functional purpose (JWM):** Deliberation (preliminary) — מציג את המסגרת הנורמטיבית שלאורה ייבחנו הטענות. בלוק גשר בין עובדות לניתוח.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative, citation-block
|
||||||
|
- Elements: section-heading, numbered-para, blockquote (ציטוט מהוראות תכנית)
|
||||||
|
- Sources: הוראות תכנית (PDF), נספחי בינוי, החלטות מרכזות
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: ציטוט ישיר מהוראות תכנית עם הדגשת (bold) מילים מכריעות
|
||||||
|
- MUST NOT: ניתוח מעמיק (→ block-yod), הכרעה בין פרשנויות
|
||||||
|
- Dependencies: block-chet (מספור), block-vav (הגדרות תכניות)
|
||||||
|
- Condition: **אופציונלי** — רק כשיש מורכבות תכנונית (תכניות סותרות, תמ"א 38 + שימור, פרשנות)
|
||||||
|
|
||||||
|
**Weight:**
|
||||||
|
|
||||||
|
| מתי קיים | משקל |
|
||||||
|
|----------|------|
|
||||||
|
| תמ"א 38 + שימור | 8-12% |
|
||||||
|
| פרשנות תכנית | 5-10% |
|
||||||
|
| לא קיים | 0% |
|
||||||
|
|
||||||
|
**Weight methodology:**
|
||||||
|
- Communicative weight (40%): בינוני — הנחת תשתית נורמטיבית
|
||||||
|
- Reader attention (20%): נמוך — טכני, אלא אם פרשנות שנויה במחלוקת
|
||||||
|
- Judicial review (25%): בינוני — שופט בודק שהוועדה הבינה את הדין
|
||||||
|
- Empirical (15%): אריאלי — 14 סעיפים; בית הכרם — משולב בדיון
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: guided-synthesis (ציטוט + ניתוח ראשוני)
|
||||||
|
- Cognitive complexity: medium (פרשנות טקסט משפטי)
|
||||||
|
- Accuracy: precision + interpretation
|
||||||
|
- Temperature: 0.2 | Thinking: medium | Effort: medium | Model: opus
|
||||||
|
|
||||||
|
|
||||||
|
### Block י: דיון והכרעה / Discussion and Decision
|
||||||
|
|
||||||
|
**ID:** `block-yod`
|
||||||
|
**Akoma Ntoso:** `body > judgment > motivation`
|
||||||
|
**CREAC role:** **full-CREAC** — C (מסקנה בפתיחה) → R (כלל משפטי) → E (ציטוט פסיקה) → A (יישום על העובדות) → C (מסקנת ביניים)
|
||||||
|
**Functional purpose (JWM):** Deliberation — ליבת ההחלטה. כאן הוועדה מנתחת, מאזנת, ומכריעה. זהו ה-ratio decidendi.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative, citation-block, image-placeholder
|
||||||
|
- Elements: numbered-para (אסה רציפה ללא כותרות משנה), blockquote (ציטוטי פסיקה ותכנית), image-box
|
||||||
|
- Sources: **כל** הבלוקים הקודמים + פסיקה + skill
|
||||||
|
|
||||||
|
**מבנה פנימי (לפי סוג ערר — ראה SKILL.md סעיף 7.3):**
|
||||||
|
- דחייה: שכבות הגנה (concentric circles)
|
||||||
|
- קבלה: נימוק-נימוק
|
||||||
|
- קבלה חלקית: מיפוי מתחים + ניתוח נושאי
|
||||||
|
- היטל השבחה: פתיחה ישירה עם מסקנה
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: מסקנה בפתיחת הדיון (לא בסוף)
|
||||||
|
- MUST: מענה לכל טענה שהוצגה בבלוק ז
|
||||||
|
- MUST: ציטוט פסיקה בבלוקים ארוכים (200-600 מילים)
|
||||||
|
- ⚠️ **MUST NOT ("ללא כפילות"):** חזרה על עובדות/טענות מבלוקים קודמים. השתמש בהפניות: "כאמור בסעיף X לעיל", "כפי שפורט", "כפי שציינו"
|
||||||
|
- MUST NOT: כותרות משנה (חריג: נושאים נפרדים לחלוטין)
|
||||||
|
- Dependencies: **ALL** previous blocks (ה-ט)
|
||||||
|
|
||||||
|
**Weight:**
|
||||||
|
|
||||||
|
| סוג ערר | משקל | הערות |
|
||||||
|
|---------|------|-------|
|
||||||
|
| רישוי — דחייה | 37-50% | פתיחה רחבה + שכבות |
|
||||||
|
| רישוי — קבלה | 35-45% | נימוק-נימוק |
|
||||||
|
| רישוי — קבלה חלקית | 40-47% | מיפוי מתחים + ניתוח נושאי |
|
||||||
|
| היטל השבחה | 32-48% | ציטוטי פסיקה מרובים |
|
||||||
|
|
||||||
|
**Weight methodology:**
|
||||||
|
- Communicative weight (40%): **מקסימלי** — זהו ה-ratio decidendi, תכלית ההחלטה
|
||||||
|
- Reader attention (20%): **גבוה** — deep reading, הקורא מחפש את הנימוקים
|
||||||
|
- Judicial review (25%): **מקסימלי** — שופט בוחן סבירות, מידתיות, התייחסות לטענות
|
||||||
|
- Empirical (15%): 35-50% באופן עקבי בכל החלטות דפנה
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: **rhetorical-construction** (בניית טיעון, איזון, רטוריקה)
|
||||||
|
- Cognitive complexity: **high-reasoning** (CREAC מלא, שכבות, חידוד)
|
||||||
|
- Accuracy: **precision + creativity** (ניתוח מדויק + ביטוי אלגנטי)
|
||||||
|
- Temperature: **0.4** | Thinking: **max (budget 16K+)** | Effort: **max** | Model: **opus בלבד**
|
||||||
|
|
||||||
|
|
||||||
|
### Block יא: סיכום / סוף דבר / Summary
|
||||||
|
|
||||||
|
**ID:** `block-yod-alef`
|
||||||
|
**Akoma Ntoso:** `body > judgment > decision`
|
||||||
|
**CREAC role:** C (Conclusion אחרון — תמצית אופרטיבית)
|
||||||
|
**Functional purpose (JWM):** Disposition — ההוראה האופרטיבית שמבצעים. זה מה שהצדדים צריכים לדעת "מה עכשיו."
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: narrative
|
||||||
|
- Elements: section-heading ("סיכום"/"סוף דבר"), numbered-para, sub-items (א. ב. ג.)
|
||||||
|
- Sources: block-yod (מסקנות)
|
||||||
|
|
||||||
|
**מבנה לפי תוצאה (ראה SKILL.md סעיף 8):**
|
||||||
|
- דחייה: "הערר נדחה" + תתי-סעיפים + פסקה חמה (רישוי בלבד)
|
||||||
|
- קבלה: "הערר מתקבל בכפוף ל..." + פרוזה
|
||||||
|
- קבלה חלקית: "הערר מתקבל באופן חלקי" + 2-3 הוראות אופרטיביות
|
||||||
|
- היטל השבחה: יבש
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: תוצאה ברורה (נדחה/מתקבל/מתקבל חלקית)
|
||||||
|
- MUST NOT (בקבלה חלקית): חזרה על נימוקים — ההנמקה כבר בדיון
|
||||||
|
- Dependencies: block-yod (מסקנות)
|
||||||
|
|
||||||
|
**Weight:**
|
||||||
|
|
||||||
|
| סוג ערר | משקל |
|
||||||
|
|---------|------|
|
||||||
|
| דחייה | 2-9% |
|
||||||
|
| קבלה | 3-5% |
|
||||||
|
| קבלה חלקית | 2-3% |
|
||||||
|
| היטל השבחה | 3-4% |
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: paraphrase (עיבוד מסקנות בלוק י)
|
||||||
|
- Cognitive complexity: low
|
||||||
|
- Accuracy: high-precision (הוראות חייבות להיות חד-משמעיות)
|
||||||
|
- Temperature: 0.1 | Thinking: low | Effort: low | Model: sonnet
|
||||||
|
|
||||||
|
|
||||||
|
### Block יב: חתימות / Signatures
|
||||||
|
|
||||||
|
**ID:** `block-yod-bet`
|
||||||
|
**Akoma Ntoso:** `conclusions > signature`
|
||||||
|
**CREAC role:** none
|
||||||
|
**Functional purpose (JWM):** Authentication — אישור פורמלי של ההחלטה.
|
||||||
|
|
||||||
|
**Content model:**
|
||||||
|
- Types: template-field
|
||||||
|
- Elements: "ניתנה פה אחד" + תאריך עברי/לועזי + טבלת חתימות
|
||||||
|
- Sources: none
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- MUST: "ניתנה פה אחד", תאריך, יו"ר + מזכיר/ה
|
||||||
|
- Dependencies: none
|
||||||
|
|
||||||
|
**Weight:** 1% (קבוע)
|
||||||
|
|
||||||
|
**Processing:**
|
||||||
|
- Generation type: template-fill
|
||||||
|
- Temperature: 0 | Thinking: off | Effort: min | Model: script
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. כללי גזירת פרמטרים
|
||||||
|
|
||||||
|
פרמטרי העיבוד נגזרים ממאפייני התוכן, לא נקבעים שרירותית:
|
||||||
|
|
||||||
|
### Temperature — נגזר מסוג הייצור
|
||||||
|
|
||||||
|
| Generation type | Temperature | נימוק |
|
||||||
|
|----------------|-------------|-------|
|
||||||
|
| template-fill | 0 | אין צורך בשפה — מילוי שדות |
|
||||||
|
| reproduction | 0 | נאמנות מוחלטת למקור. אפס יצירתיות |
|
||||||
|
| paraphrase | 0.1 | מרווח מינימלי לניסוח בשפה של דפנה |
|
||||||
|
| guided-synthesis | 0.2 | גמישות בארגון וחיבור מקורות, לא בתוכן |
|
||||||
|
| analytical-reasoning | 0.3-0.4 | צריך ליצור קשרים בין עקרונות משפטיים |
|
||||||
|
| rhetorical-construction | 0.4-0.5 | טווח ביטוי רחב לכתיבה משכנעת ואלגנטית |
|
||||||
|
|
||||||
|
### Thinking budget — נגזר ממורכבות קוגניטיבית
|
||||||
|
|
||||||
|
| Cognitive task | Budget | נימוק |
|
||||||
|
|---------------|--------|-------|
|
||||||
|
| template-fill / lookup | off | אין צורך בחשיבה |
|
||||||
|
| sequential-extraction | low | חילוץ מידע חד-שלבי |
|
||||||
|
| multi-source-integration | medium | צריך להצליב מקורות |
|
||||||
|
| legal-analysis-with-CREAC | max (16K+) | חשיבה רב-שלבית: מסקנה → כלל → הסבר → יישום |
|
||||||
|
|
||||||
|
### Model — נגזר מדרישת דיוק
|
||||||
|
|
||||||
|
| Accuracy profile | Model | נימוק |
|
||||||
|
|-----------------|-------|-------|
|
||||||
|
| factual-precision | sonnet | מהיר, מדויק לחילוץ עובדות |
|
||||||
|
| precision + interpretation | opus | נדרש לפרשנות תכנית / ציטוט מובנה |
|
||||||
|
| precision + creativity | opus | נדרש לניתוח משפטי מורכב ורטוריקה |
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. מתודולוגיית משקלות
|
||||||
|
|
||||||
|
משקל כל בלוק נקבע על ידי שקלול 4 גורמים:
|
||||||
|
|
||||||
|
### 4.1 Communicative Weight (40%)
|
||||||
|
מה חלקו של הבלוק בתכלית ההחלטה? ההחלטה באה לעשות דבר אחד: להכריע במחלוקת ולנמק. בלוק י (דיון) הוא ליבת התכלית. בלוקים א-ד (כותרות) הם עטיפה.
|
||||||
|
|
||||||
|
### 4.2 Reader Attention Distribution (20%)
|
||||||
|
מבוסס על מחקרי F-pattern ו-primacy/recency:
|
||||||
|
- **פתיחה** (בלוקים ה-ו): קשב גבוה (primacy effect)
|
||||||
|
- **אמצע** (בלוקים ז-ח): scanning — הקורא מחפש טענות ספציפיות
|
||||||
|
- **דיון** (בלוק י): deep reading — הקורא מחפש נימוקים
|
||||||
|
- **סיום** (בלוק יא): קשב גבוה (recency effect)
|
||||||
|
|
||||||
|
### 4.3 Judicial Review Requirement (25%)
|
||||||
|
מה שופט בבית משפט לעניינים מנהליים יבדוק ("מבחן השופט"):
|
||||||
|
- **תשתית עובדתית** (בלוק ו): מלאה ומדויקת?
|
||||||
|
- **שמיעת צדדים** (בלוקים ז-ח): נתנו מלוא יום בבית דין?
|
||||||
|
- **סבירות ומידתיות** (בלוק י): ההכרעה מנומקת ומאוזנת?
|
||||||
|
- **התייחסות לטענות** (בלוק י): כל טענה קיבלה מענה?
|
||||||
|
|
||||||
|
### 4.4 Empirical Basis (15%)
|
||||||
|
מבוסס על מדידה מהחלטות שפורסמו:
|
||||||
|
- הכט 1180-1181 (דחייה, 02.2026)
|
||||||
|
- בית הכרם 1126/25 (קבלה חלקית, 03.2026)
|
||||||
|
- אריאלי 1078+1083 (קבלה, 03.2026)
|
||||||
|
|
||||||
|
המשקלות ב-SKILL.md סעיף 3.2 (יחסי הזהב) משמשים כבסיס אמפירי שאומת על ידי שלושת הגורמים האנליטיים.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. כללי ולידציה
|
||||||
|
|
||||||
|
### 5.1 סדר בלוקים
|
||||||
|
- בלוקים חייבים להופיע בסדר א עד יב
|
||||||
|
- בלוקים א-ה ויב נדרשים בכל החלטה
|
||||||
|
- בלוק ט אופציונלי (רק כשיש מורכבות תכנונית)
|
||||||
|
|
||||||
|
### 5.2 Content Constraints
|
||||||
|
- **רקע ניטרלי (בלוק ו):** אם סעיף מכיל ציטוט ישיר מצד או מילת שיפוט → לא שייך כאן
|
||||||
|
- **טענות מקוריות בלבד (בלוק ז):** רק מכתבי ערר/תשובה. השלמות → בלוק ח
|
||||||
|
- **ללא כפילות (בלוק י):** הפניה לבלוקים קודמים, לא חזרה. חריג: "נשוב על כך כי..." (חזרה מכוונת עם שכבה חדשה)
|
||||||
|
- **הליכים ללא הערכה (בלוק ח):** תיעוד מה הוגש, לא הערכה של חוזק הטענות
|
||||||
|
|
||||||
|
### 5.3 Weight Compliance
|
||||||
|
- משקל כל בלוק (ספירת מילים / סה"כ) צריך להיות בטווח המוגדר **±10%**
|
||||||
|
- אם בלוק י < 30% → flag: דיון לא מפותח מספיק
|
||||||
|
- אם בלוק ו > 35% → flag: רקע מנופח, בדוק שאין תוכן טענתי
|
||||||
|
|
||||||
|
### 5.4 Structural Integrity
|
||||||
|
- מספור סעיפים רציף מ-1 עד הסוף, ללא איפוס בין בלוקים
|
||||||
|
- כל הגדרת "להלן" חייבת להופיע לפני השימוש הראשון בה
|
||||||
|
- כל טענה בבלוק ז חייבת לקבל מענה בבלוק י (ישיר או "למעלה מן הצורך")
|
||||||
|
- כותרות פרקים: David 14pt, bold, קו תחתון, מרכז
|
||||||
|
- כותרות משנה: David 12pt, bold, מרכז, ללא קו תחתון
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. גרף תלויות בין בלוקים
|
||||||
|
|
||||||
|
```
|
||||||
|
א (כותרת) → עצמאי
|
||||||
|
ב (הרכב) → עצמאי
|
||||||
|
ג (צדדים) → עצמאי
|
||||||
|
ד (כותרת) → עצמאי
|
||||||
|
ה (פתיחה) → תלוי ב: ג (שמות צדדים להגדרות "להלן")
|
||||||
|
ו (רקע) → תלוי ב: ה (הגדרות). מספור ממשיך מ-ה.
|
||||||
|
ז (טענות) → תלוי ב: ו (מספור). מפנה ל: ה, ו (הגדרות)
|
||||||
|
ח (הליכים) → תלוי ב: ז (מספור). מפנה ל: ז (טענות מקוריות)
|
||||||
|
ט (תכניות) → תלוי ב: ח (מספור). אופציונלי. מפנה ל: ו (הגדרות תכניות)
|
||||||
|
י (דיון) → תלוי ב: **כל** הבלוקים ה-ט. מפנה ל: כולם.
|
||||||
|
יא (סיכום) → תלוי ב: י (מסקנות). מפנה ל: י בלבד.
|
||||||
|
יב (חתימות) → עצמאי
|
||||||
|
```
|
||||||
97
skill-legal-decision/references/decision-template.json
Normal file
97
skill-legal-decision/references/decision-template.json
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
{
|
||||||
|
"_comment": "תבנית JSON לייצור טיוטת מבנה החלטה — כל שדה עם '_comment' הוא הסבר, לא תוכן",
|
||||||
|
"_usage": "node .claude/skills/legal-decision/scripts/create-decision-structure.cjs <this-file.json> [output.docx]",
|
||||||
|
|
||||||
|
"type": "permit | plan | betterment",
|
||||||
|
|
||||||
|
"case_numbers": ["1130/25"],
|
||||||
|
"plan_number": "152-1257682",
|
||||||
|
"request_number": null,
|
||||||
|
|
||||||
|
"panel": {
|
||||||
|
"chair": "עו\"ד דפנה תמיר",
|
||||||
|
"members": [
|
||||||
|
"יעקב אנוקה, נציג מתכנן המחוז",
|
||||||
|
"יצחק ליר ליפובצקי, נציג ארגון האדריכלים"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"appellants": [
|
||||||
|
{ "name": "1. מרק קובר", "representative": null },
|
||||||
|
{ "name": "2. יצחק מטמון", "representative": null }
|
||||||
|
],
|
||||||
|
|
||||||
|
"respondents": [
|
||||||
|
{ "name": "הוועדה המרחבית לתכנון ולבניה הראל", "representative": "עו\"ד ליאורה אפרתי" },
|
||||||
|
{ "name": "אסתר שרה ליבמן", "representative": null },
|
||||||
|
{ "name": "יוסף חיים ליבמן", "representative": "עו\"ד משה ברקוביץ" }
|
||||||
|
],
|
||||||
|
|
||||||
|
"appeal_description": "ערר על החלטת הוועדה המרחבית לתכנון ולבניה הראל מיום 23.7.2025, לדחות את ההתנגדויות ולאשר את תכנית מס' 152-1257682",
|
||||||
|
|
||||||
|
"opening_paragraphs": [
|
||||||
|
"לפנינו ערר על החלטת הוועדה המרחבית לתכנון ולבניה הראל (להלן: \"הוועדה המקומית\") מיום 23.7.2025, לדחות את ההתנגדויות ולאשר את תכנית מס' 152-1257682 (להלן: \"התכנית\") ברחוב אבינדב 23, קריית יערים, גוש 29536 חלקה 244 (להלן: \"המגרש\" או \"המקרקעין\")."
|
||||||
|
],
|
||||||
|
|
||||||
|
"use_petach_davar": true,
|
||||||
|
|
||||||
|
"property_description": "המגרש מצוי ברחוב אבינדב בקריית יערים, מועצה מקומית המוגדרת בתמ\"א 35 כ\"ישוב שמור משולב\" ובתמ\"מ 30/1 כ\"ישוב פרברי\". רחוב אבינדב הינו מדרחוב צר ומפותל, מתאפיין בבנייה כפרית של וילות צמודות קרקע חד-משפחתיות, עם חניה בתוך תחום המגרשים, על פי תכנית מי/135 משנת 1972 (להלן: \"תכנית 135\").",
|
||||||
|
|
||||||
|
"planning_history": [
|
||||||
|
"בשנת 1992 אושרה תכנית מי/135/א (להלן: \"תכנית 135/א\"), אשר שינתה מהותית את ייעוד מספר מגרשים ברחוב...",
|
||||||
|
"ביום 29.6.2017 דחתה ועדת המשנה להתנגדויות של הוועדה המחוזית ירושלים את תכנית מס' 152-0137067..."
|
||||||
|
],
|
||||||
|
|
||||||
|
"request_essence": "התכנית נשוא הערר (152-1257682) עוסקת בתוספת זכויות בנייה למבנה הקיים ברחוב אבינדב 23, וכוללת: הגדלת זכויות בנייה בשיעור של 50%...",
|
||||||
|
|
||||||
|
"committee_protocol_quote": "[ציטוט מלא מתוך פרוטוקול הדיון בוועדה המקומית]",
|
||||||
|
|
||||||
|
"committee_decision": "ביום 23.7.2025 קיימה הוועדה המקומית דיון בהתנגדויות שהוגשו לתכנית. לאחר שמיעת ההתנגדויות, החליטה הוועדה המקומית פה אחד לדחות את ההתנגדויות ולאשר את התכנית כפי שהופקדה.",
|
||||||
|
|
||||||
|
"include_aerial_photo": true,
|
||||||
|
|
||||||
|
"surroundings": "[תיאור סביבת המקרקעין — מבנים סמוכים, אופי שכונתי]",
|
||||||
|
|
||||||
|
"appeal_filing": "ביום 14.8.2025 הגיש העורר את הערר שבפנינו. ביום 22.10.2025 הגיש מטמון כתב ערר/תשובה בו הצטרף לערר.",
|
||||||
|
|
||||||
|
"_comment_claims": "אפשר להשתמש ב-appellant_claims (רשימה אחת) או ב-appellant_claims_sections (כמה עוררים עם כותרות נפרדות)",
|
||||||
|
|
||||||
|
"appellant_claims_sections": [
|
||||||
|
{
|
||||||
|
"title": "טענות העורר מר קובר",
|
||||||
|
"claims": [
|
||||||
|
"העורר טוען כי לוועדה המקומית לא הייתה סמכות לאשר את התכנית...",
|
||||||
|
"עוד טוען העורר כי חישוב תוספת שטחי הבנייה שגוי..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "טענות מטמון",
|
||||||
|
"claims": [
|
||||||
|
"מטמון מדגיש את העיוות התכנוני ההיסטורי שנוצר בשנת 1992..."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"committee_position": [
|
||||||
|
"הוועדה המקומית טוענת כי לוועדה מקומית סמכות לדון בתכנית...",
|
||||||
|
"באשר להחלטת הוועדה המחוזית משנת 2017, טוענת הוועדה המקומית כי..."
|
||||||
|
],
|
||||||
|
|
||||||
|
"applicant_position": [
|
||||||
|
"מגישי התכנית טוענים כי התכנית אינה מוסיפה יחידות דיור מעבר למותר...",
|
||||||
|
"במסגרת השלמת הטיעון, הציגו מגישי התכנית תמונה תכנונית רחבה..."
|
||||||
|
],
|
||||||
|
|
||||||
|
"proceedings": [
|
||||||
|
{ "type": "text", "text": "ביום 27.10.2025 התקיים דיון בפני ועדת הערר, בו נשמעו העורר, מטמון, הוועדה המקומית ומגישי התכנית." },
|
||||||
|
{ "type": "text", "text": "ביום 30.11.2025 נערך סיור במקום." },
|
||||||
|
{ "type": "image", "description": "צילומים מהסיור ברחוב אבינדב — מבט על הבניין הקיים" },
|
||||||
|
{ "type": "text", "text": "ביום 31.12.2025 ניתנה החלטת ביניים..." },
|
||||||
|
{ "type": "text", "text": "בעקבות החלטת הביניים הוגשו השלמות טיעון מכל הצדדים..." }
|
||||||
|
],
|
||||||
|
|
||||||
|
"skip_plans_section": true,
|
||||||
|
"_comment_plans": "אם skip_plans_section=false, אפשר להוסיף applicable_plans עם פירוט תכניות",
|
||||||
|
|
||||||
|
"secretary": ""
|
||||||
|
}
|
||||||
186
skill-legal-decision/references/israeli-planning-law-basics.md
Normal file
186
skill-legal-decision/references/israeli-planning-law-basics.md
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
# יסודות דיני תכנון ובניה בישראל
|
||||||
|
## מדריך עזר למומחה הגישה השיפוטית
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## מבנה מערכת התכנון והבניה בישראל
|
||||||
|
|
||||||
|
### רמות התכנון
|
||||||
|
|
||||||
|
**1. רמה ארצית**
|
||||||
|
- המועצה הארצית לתכנון ובניה
|
||||||
|
- תכניות מתאר ארציות (תמ"א)
|
||||||
|
|
||||||
|
**2. רמה מחוזית**
|
||||||
|
- ועדות מחוזיות (6 מחוזות)
|
||||||
|
- תכניות מתאר מחוזיות (תמ"מ)
|
||||||
|
|
||||||
|
**3. רמה מקומית**
|
||||||
|
- ועדות מקומיות (לפי רשויות מקומיות)
|
||||||
|
- תכניות מפורטות
|
||||||
|
|
||||||
|
**4. ועדות ערר**
|
||||||
|
- ועדות ערר מחוזיות (מטפלות בערעורים על החלטות ועדות מקומיות)
|
||||||
|
- ועדת הערר הארצית (מטפלת בערעורים על החלטות ועדות מחוזיות)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## חוקים ותקנות מרכזיים
|
||||||
|
|
||||||
|
### 1. חוק התכנון והבניה, התשכ"ה-1965
|
||||||
|
|
||||||
|
**סעיפים חשובים:**
|
||||||
|
|
||||||
|
- **סעיף 19** - היטל השבחה
|
||||||
|
- **סעיף 62** - הוועדה המקומית
|
||||||
|
- **סעיף 149** - היתר בניה
|
||||||
|
- **סעיף 150** - תנאים למתן היתר
|
||||||
|
- **סעיף 151** - היתר בנייה בסטייה מזניחה
|
||||||
|
- **סעיף 197** - הקלות בניה
|
||||||
|
- **סעיף 204** - ועדות ערר
|
||||||
|
- **סעיף 205** - סמכויות ועדת הערר
|
||||||
|
- **סעיף 228** - עבירות בניה ללא היתר
|
||||||
|
|
||||||
|
### 2. חוק המקרקעין, התשכ"ט-1969
|
||||||
|
|
||||||
|
**סעיפים חשובים:**
|
||||||
|
- זכויות קנייניות במקרקעין
|
||||||
|
- העברת זכויות
|
||||||
|
|
||||||
|
### 3. תקנות התכנון והבניה (בקשה להיתר, תנאיו ואגרות), התש"ל-1970
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סוגי ערעורים נפוצים
|
||||||
|
|
||||||
|
### 1. ערעורים על החלטות בעניין רישוי
|
||||||
|
- דחיית בקשה להיתר בניה
|
||||||
|
- מתן היתר בתנאים
|
||||||
|
- היתר בסטייה מזניחה
|
||||||
|
- הקלות בניה
|
||||||
|
|
||||||
|
### 2. ערעורים על החלטות בעניין היטל השבחה
|
||||||
|
- חישוב היטל
|
||||||
|
- שיעור ההשבחה
|
||||||
|
- פטור מהיטל
|
||||||
|
- ערעורי שומה
|
||||||
|
|
||||||
|
### 3. ערעורים על החלטות בעניין תכניות
|
||||||
|
- אישור/דחיית תכנית
|
||||||
|
- תנאים בתכנית
|
||||||
|
- התנגדויות לתכניות
|
||||||
|
|
||||||
|
### 4. ערעורים על צווי הריסה
|
||||||
|
- צווים מנהליים
|
||||||
|
- הליכי אכיפה
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## פסקי דין חשובים בתחום
|
||||||
|
|
||||||
|
### בנושא היטל השבחה
|
||||||
|
- **ע"א 6339/97 עיריית רמת השרון נ' פנחס** - עקרונות יסוד בהיטל השבחה
|
||||||
|
- **ע"א 2892/07 בן ארי נ' הוועדה המקומית** - חישוב שיעור השבחה
|
||||||
|
|
||||||
|
### בנושא רישוי והיתרים
|
||||||
|
- **בג"ץ 5060/94 ד"ר ניימן נ' יו"ר ועדת הערר** - גבולות שיקול הדעת של ועדות
|
||||||
|
- **ע"א 1845/04 אושרי נ' הוועדה המקומית** - הקלות בניה
|
||||||
|
|
||||||
|
### בנושא שימוש חורג
|
||||||
|
- **בג"ץ 244/00 עמותת יער חמ"ד נ' ועדת הערר** - שימושים חורגים
|
||||||
|
|
||||||
|
### בנושא זכויות קנייניות מול אינטרס ציבורי
|
||||||
|
- **בג"ץ 6698/95 קעדאן נ' מינהל מקרקעי ישראל** - איזון בין זכויות
|
||||||
|
- **בג"ץ 2390/96 קרסיק נ' הממשלה** - זכות הקניין
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## מושגי יסוד
|
||||||
|
|
||||||
|
### תכנון
|
||||||
|
|
||||||
|
**תכנית מתאר** - תכנית כללית לשטח מסוים, קובעת ייעודי קרקע, צפיפות, זכויות בניה.
|
||||||
|
|
||||||
|
**תכנית מפורטת** - תכנית המפרטת פרטי בניה, קווי בניין, גבהים.
|
||||||
|
|
||||||
|
**שימוש חורג** - שימוש שונה מהייעוד בתכנית.
|
||||||
|
|
||||||
|
**הקלה** - סטייה קלה מתכנית שניתן לאשר ללא שינוי התכנית (סעיף 197).
|
||||||
|
|
||||||
|
**סטייה מזניחה** - סטייה קלה מאוד מהיתר שניתן לאשר (סעיף 151).
|
||||||
|
|
||||||
|
### רישוי
|
||||||
|
|
||||||
|
**היתר בניה** - אישור לבנות על פי תכנית.
|
||||||
|
|
||||||
|
**תנאים להיתר** - דרישות שיש לעמוד בהן לפני מתן היתר או במהלך הבניה.
|
||||||
|
|
||||||
|
**פקיעת היתר** - תום תוקף היתר אם לא הוחל בבניה.
|
||||||
|
|
||||||
|
### היטל השבחה
|
||||||
|
|
||||||
|
**השבחה** - עליית ערך מקרקעין כתוצאה מתכנית או היתר.
|
||||||
|
|
||||||
|
**היטל השבחה** - תשלום חובה בשיעור של 50% מההשבחה (בדרך כלל).
|
||||||
|
|
||||||
|
**מימוש זכויות** - התחלת בנייה או מכירה המחייבת בתשלום היטל.
|
||||||
|
|
||||||
|
**פטור מהיטל** - מקרים בהם החוק פוטר מתשלום (למשל: בניית דירת מגורים יחידה).
|
||||||
|
|
||||||
|
### הליכים
|
||||||
|
|
||||||
|
**ערר** - ערעור על החלטת ועדה מקומית לועדת ערר מחוזית.
|
||||||
|
|
||||||
|
**ערעור מינהלי** - ערעור מועדת ערר לבית משפט.
|
||||||
|
|
||||||
|
**בקשה מנהלית** - פנייה לביה"מ ללא צורך בערר קודם (במקרים מסוימים).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## סמכויות ועדת הערר (סעיף 205)
|
||||||
|
|
||||||
|
ועדת ערר רשאית:
|
||||||
|
1. לאשר את ההחלטה
|
||||||
|
2. לבטל את ההחלטה
|
||||||
|
3. להורות על שינוי בהחלטה
|
||||||
|
4. להחזיר לועדה המקומית לדיון נוסף
|
||||||
|
|
||||||
|
ועדת הערר פועלת כערכאה מינהלית וסמכויותיה דומות לאלו של בית משפט.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## עקרונות פסיקתיים נפוצים
|
||||||
|
|
||||||
|
### 1. שיקול דעת מנהלי
|
||||||
|
- לועדות תכנון יש שיקול דעת רחב
|
||||||
|
- בית המשפט (וועדת הערר) יתערב רק אם השיקול לא סביר, שרירותי, או בחוסר סמכות
|
||||||
|
|
||||||
|
### 2. האיזון בין זכויות קנייניות לאינטרס ציבורי
|
||||||
|
- יש לאזן בין זכות הקניין של הפרט לבין האינטרס הציבורי
|
||||||
|
- שני הערכים חשובים ויש לשקלם
|
||||||
|
|
||||||
|
### 3. ההסתמכות על מומחים
|
||||||
|
- חוות דעת מומחה חשובה אך לא קובעת
|
||||||
|
- הועדה רשאית לסטות מחוות דעת אם תנמק
|
||||||
|
|
||||||
|
### 4. הנמקת החלטות
|
||||||
|
- כל החלטה חייבת להיות מנומקת
|
||||||
|
- חוסר נימוק או נימוק לקוני עלול להביא לביטול ההחלטה
|
||||||
|
|
||||||
|
### 5. שימת לב להשפעות
|
||||||
|
- על הועדה לשקול השפעות על הסביבה, שכנים, תשתיות
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## טיפים למומחה הגישה השיפוטית
|
||||||
|
|
||||||
|
כשאתה מנתח החלטות בדיני תכנון ובניה, שים לב:
|
||||||
|
|
||||||
|
1. **לאיזה סעיפים בחוק מתייחסים** - אלו המקורות המשפטיים הבסיסיים
|
||||||
|
2. **אילו פסקי דין מצוטטים** - אלו המקורות הפסיקתיים שהשופט מסתמך עליהם
|
||||||
|
3. **איך מאזנים בין ערכים מנוגדים** - זכות קניין מול אינטרס ציבורי
|
||||||
|
4. **רמת ההתערבות** - האם השופט נוטה להתערב או להותיר החלטות בעינן
|
||||||
|
5. **יחס לחוות דעת מומחים** - האם סומך עליהן או ביקורתי
|
||||||
|
6. **רמת הנמקה** - האם מפורט או תמציתי
|
||||||
|
|
||||||
|
זכור - זהו תחום משפטי טכני שדורש ידע מקצועי. השופטים בועדות ערר הם לרוב עורכי דין או אנשי מקצוע בתחום התכנון.
|
||||||
635
skill-legal-decision/scripts/create-decision-structure.cjs
Normal file
635
skill-legal-decision/scripts/create-decision-structure.cjs
Normal file
@@ -0,0 +1,635 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* create-decision-structure.js — טיוטת מבנה החלטת ועדת ערר
|
||||||
|
*
|
||||||
|
* מייצר קובץ DOCX מעוצב עם כל חלקי ההחלטה (בלוקים א-יב).
|
||||||
|
* בלוקים א-ט ממולאים בתוכן, בלוק י (דיון) ויא (סיכום) = placeholders.
|
||||||
|
*
|
||||||
|
* שימוש:
|
||||||
|
* node create-decision-structure.js <input.json> [output.docx]
|
||||||
|
*
|
||||||
|
* מבוסס על create-legal-doc.js מתוך legal-docx skill.
|
||||||
|
* כללי RTL: START/END (לא LEFT/RIGHT), bidi+bidirectional+rightToLeft בכל רמה.
|
||||||
|
*
|
||||||
|
* v1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const {
|
||||||
|
Document, Packer, Paragraph, TextRun, Header, Footer,
|
||||||
|
AlignmentType, HeadingLevel, PageNumber, LevelFormat,
|
||||||
|
Table, TableRow, TableCell, WidthType, BorderStyle,
|
||||||
|
ShadingType, UnderlineType
|
||||||
|
} = require(path.join(process.cwd(), 'node_modules', 'docx'));
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
// CONFIGURATION
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
const FONT = "David";
|
||||||
|
const FONT_SIZE = 24; // 12pt
|
||||||
|
const HEADING1_SIZE = 32; // 16pt — "החלטה"
|
||||||
|
const HEADING2_SIZE = 28; // 14pt — כותרות פרקים
|
||||||
|
const MARGIN_CM = 2.5;
|
||||||
|
const MARGIN_DXA = Math.round(MARGIN_CM / 2.54 * 1440); // 1417
|
||||||
|
const PAGE_WIDTH = 11906; // A4
|
||||||
|
const PAGE_HEIGHT = 16838;
|
||||||
|
const CONTENT_WIDTH = PAGE_WIDTH - MARGIN_DXA * 2; // 9072
|
||||||
|
|
||||||
|
const noBorders = {
|
||||||
|
top: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
|
||||||
|
bottom: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
|
||||||
|
left: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
|
||||||
|
right: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
// RTL HELPERS — מבוסס על create-legal-doc.js
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
|
||||||
|
const rtlRun = (text, opts = {}) => new TextRun({
|
||||||
|
text,
|
||||||
|
font: opts.font || FONT,
|
||||||
|
size: opts.size || FONT_SIZE,
|
||||||
|
bold: opts.bold || false,
|
||||||
|
underline: opts.underline ? { type: UnderlineType.SINGLE } : undefined,
|
||||||
|
rightToLeft: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const rtlPara = (children, opts = {}) => new Paragraph({
|
||||||
|
bidirectional: true,
|
||||||
|
alignment: opts.alignment || AlignmentType.BOTH,
|
||||||
|
spacing: opts.spacing || { after: 120, line: 276 }, // 1.15 line spacing = 276 twips
|
||||||
|
indent: opts.indent,
|
||||||
|
children: Array.isArray(children) ? children : [children],
|
||||||
|
...(opts.heading ? { heading: opts.heading } : {}),
|
||||||
|
});
|
||||||
|
|
||||||
|
// כותרת ראשית — "החלטה"
|
||||||
|
const mainTitle = (text) => rtlPara(
|
||||||
|
rtlRun(text, { bold: true, size: HEADING1_SIZE }),
|
||||||
|
{ heading: HeadingLevel.HEADING_1, alignment: AlignmentType.CENTER, spacing: { before: 240, after: 240 } }
|
||||||
|
);
|
||||||
|
|
||||||
|
// כותרת פרק — "תמצית טענות הצדדים", "דיון והכרעה"
|
||||||
|
const sectionTitle = (text) => rtlPara(
|
||||||
|
rtlRun(text, { bold: true, size: HEADING2_SIZE, underline: true }),
|
||||||
|
{ heading: HeadingLevel.HEADING_2, alignment: AlignmentType.CENTER, spacing: { before: 360, after: 240 } }
|
||||||
|
);
|
||||||
|
|
||||||
|
// כותרת משנה — "טענות העוררים"
|
||||||
|
const subTitle = (text) => rtlPara(
|
||||||
|
rtlRun(text, { bold: true, size: FONT_SIZE }),
|
||||||
|
{ alignment: AlignmentType.CENTER, spacing: { before: 240, after: 160 } }
|
||||||
|
);
|
||||||
|
|
||||||
|
// סעיף ממוספר — מספר bold + טקסט רגיל
|
||||||
|
const numberedPara = (num, text) => rtlPara([
|
||||||
|
rtlRun(`${num}. `, { bold: true }),
|
||||||
|
rtlRun(text),
|
||||||
|
], { spacing: { after: 120, line: 276 } });
|
||||||
|
|
||||||
|
// ציטוט (blockquote) — הזחה משני הצדדים
|
||||||
|
const blockquote = (text) => rtlPara(
|
||||||
|
rtlRun(text),
|
||||||
|
{ indent: { left: 567, right: 567 }, spacing: { before: 120, after: 120, line: 276 } }
|
||||||
|
);
|
||||||
|
|
||||||
|
// תיבת תמונה — מסגרת אפורה עם הנחיה
|
||||||
|
const imageBox = (description) => new Paragraph({
|
||||||
|
bidirectional: true,
|
||||||
|
alignment: AlignmentType.CENTER,
|
||||||
|
spacing: { before: 200, after: 200 },
|
||||||
|
shading: { type: ShadingType.CLEAR, fill: "F0F0F0" },
|
||||||
|
children: [
|
||||||
|
new TextRun({
|
||||||
|
text: `📷 תמונה: ${description}`,
|
||||||
|
font: FONT,
|
||||||
|
size: FONT_SIZE,
|
||||||
|
rightToLeft: true,
|
||||||
|
bold: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Placeholder — טקסט אפור שמסמן מקום
|
||||||
|
const placeholder = (text) => rtlPara(
|
||||||
|
new TextRun({
|
||||||
|
text: `[${text}]`,
|
||||||
|
font: FONT,
|
||||||
|
size: FONT_SIZE,
|
||||||
|
rightToLeft: true,
|
||||||
|
italics: true,
|
||||||
|
color: "808080",
|
||||||
|
}),
|
||||||
|
{ alignment: AlignmentType.CENTER, spacing: { before: 200, after: 200 } }
|
||||||
|
);
|
||||||
|
|
||||||
|
// רווח
|
||||||
|
const spacer = (after = 200) => rtlPara(rtlRun(""), { spacing: { after, before: 0 } });
|
||||||
|
|
||||||
|
// תא בטבלה
|
||||||
|
const rtlCell = (children, width, opts = {}) => new TableCell({
|
||||||
|
borders: noBorders,
|
||||||
|
width: { size: width, type: WidthType.DXA },
|
||||||
|
children: Array.isArray(children) ? children : [children],
|
||||||
|
...(opts.verticalAlign ? { verticalAlign: opts.verticalAlign } : {}),
|
||||||
|
});
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
// BLOCK BUILDERS — בוני הבלוקים
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
|
||||||
|
// בלוק א — כותרת מוסדית (טבלה 2 טורים)
|
||||||
|
function buildInstitutionalHeader(data) {
|
||||||
|
const leftCol = CONTENT_WIDTH * 0.5;
|
||||||
|
const rightCol = CONTENT_WIDTH * 0.5;
|
||||||
|
|
||||||
|
// צד ימין — מוסד
|
||||||
|
const rightCellContent = [
|
||||||
|
rtlPara(rtlRun("מדינת ישראל", { bold: true }), { alignment: AlignmentType.START, spacing: { after: 0 } }),
|
||||||
|
rtlPara(rtlRun("ועדת ערר לתכנון ובניה"), { alignment: AlignmentType.START, spacing: { after: 0 } }),
|
||||||
|
rtlPara(rtlRun("מחוז ירושלים"), { alignment: AlignmentType.START, spacing: { after: 80 } }),
|
||||||
|
];
|
||||||
|
|
||||||
|
// צד שמאל — מספרי תיק
|
||||||
|
const leftLines = [];
|
||||||
|
if (data.case_numbers) {
|
||||||
|
data.case_numbers.forEach(cn => {
|
||||||
|
leftLines.push(rtlPara([
|
||||||
|
rtlRun("מס' תיק: "),
|
||||||
|
rtlRun(cn, { bold: true }),
|
||||||
|
], { alignment: AlignmentType.START, spacing: { after: 0 } }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (data.plan_number) {
|
||||||
|
leftLines.push(rtlPara([
|
||||||
|
rtlRun("מס' תכנית: "),
|
||||||
|
rtlRun(data.plan_number, { bold: true }),
|
||||||
|
], { alignment: AlignmentType.START, spacing: { after: 0 } }));
|
||||||
|
}
|
||||||
|
if (data.request_number) {
|
||||||
|
leftLines.push(rtlPara([
|
||||||
|
rtlRun("מס' בקשה: "),
|
||||||
|
rtlRun(data.request_number, { bold: true }),
|
||||||
|
], { alignment: AlignmentType.START, spacing: { after: 0 } }));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Table({
|
||||||
|
visuallyRightToLeft: true,
|
||||||
|
width: { size: CONTENT_WIDTH, type: WidthType.DXA },
|
||||||
|
columnWidths: [rightCol, leftCol],
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
rtlCell(rightCellContent, rightCol),
|
||||||
|
rtlCell(leftLines.length ? leftLines : [rtlPara(rtlRun(""))], leftCol),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// בלוק ב — הרכב הוועדה
|
||||||
|
function buildPanel(data) {
|
||||||
|
const lines = [];
|
||||||
|
lines.push(spacer(120));
|
||||||
|
lines.push(rtlPara([
|
||||||
|
rtlRun("בפני:", { bold: true }),
|
||||||
|
], { spacing: { after: 40 } }));
|
||||||
|
lines.push(rtlPara([
|
||||||
|
rtlRun("יו\"ר הוועדה: ", { bold: true }),
|
||||||
|
rtlRun(data.panel?.chair || "עו\"ד דפנה תמיר"),
|
||||||
|
], { spacing: { after: 40 } }));
|
||||||
|
|
||||||
|
if (data.panel?.members) {
|
||||||
|
lines.push(rtlPara([
|
||||||
|
rtlRun("חברי הוועדה: ", { bold: true }),
|
||||||
|
rtlRun(data.panel.members[0] || ""),
|
||||||
|
], { spacing: { after: 40 } }));
|
||||||
|
for (let i = 1; i < data.panel.members.length; i++) {
|
||||||
|
lines.push(rtlPara(rtlRun(data.panel.members[i]), { spacing: { after: 40 } }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
// בלוק ג — צדדים
|
||||||
|
function buildParties(data) {
|
||||||
|
const lines = [];
|
||||||
|
lines.push(spacer(120));
|
||||||
|
|
||||||
|
// עוררים
|
||||||
|
if (data.appellants) {
|
||||||
|
const label = data.appellants.length > 1 ? "העוררים:" : "העורר:";
|
||||||
|
lines.push(rtlPara(rtlRun(label, { bold: true }), { spacing: { after: 40 } }));
|
||||||
|
data.appellants.forEach(a => {
|
||||||
|
lines.push(rtlPara(rtlRun(a.name), { spacing: { after: 20 } }));
|
||||||
|
if (a.representative) {
|
||||||
|
lines.push(rtlPara(rtlRun(`ע"י ב"כ ${a.representative}`), { spacing: { after: 20 } }));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// נגד
|
||||||
|
lines.push(spacer(80));
|
||||||
|
lines.push(rtlPara(rtlRun("נגד", { bold: true }), {
|
||||||
|
alignment: AlignmentType.CENTER,
|
||||||
|
spacing: { before: 80, after: 80 }
|
||||||
|
}));
|
||||||
|
|
||||||
|
// משיבים
|
||||||
|
if (data.respondents) {
|
||||||
|
lines.push(rtlPara(rtlRun("המשיבים:", { bold: true }), { spacing: { after: 40 } }));
|
||||||
|
data.respondents.forEach((r, i) => {
|
||||||
|
lines.push(rtlPara(rtlRun(`${i + 1}. ${r.name}`), { spacing: { after: 20 } }));
|
||||||
|
if (r.representative) {
|
||||||
|
lines.push(rtlPara(rtlRun(`ע"י ב"כ ${r.representative}`), { spacing: { after: 20 } }));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
// בלוק ה — פתיחה
|
||||||
|
function buildOpening(data) {
|
||||||
|
const paras = [];
|
||||||
|
if (data.opening_paragraphs) {
|
||||||
|
data.opening_paragraphs.forEach((text, i) => {
|
||||||
|
paras.push(numberedPara(i + 1, text));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(1, `לפנינו ${data.appeal_description || "[תיאור הערר]"}.`));
|
||||||
|
}
|
||||||
|
return paras;
|
||||||
|
}
|
||||||
|
|
||||||
|
// בלוק ו — רקע עובדתי
|
||||||
|
function buildBackground(data) {
|
||||||
|
const paras = [];
|
||||||
|
let num = (data.opening_paragraphs?.length || 1) + 1;
|
||||||
|
|
||||||
|
if (data.use_petach_davar !== false) {
|
||||||
|
paras.push(sectionTitle("פתח דבר"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// מקרקעין
|
||||||
|
if (data.property_description) {
|
||||||
|
paras.push(numberedPara(num++, data.property_description));
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, "[תיאור המקרקעין — מיקום, שטח, שכונה, ייעוד, מאפיינים ייחודיים]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// היסטוריה תכנונית
|
||||||
|
if (data.planning_history) {
|
||||||
|
data.planning_history.forEach(text => {
|
||||||
|
paras.push(numberedPara(num++, text));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, "[היסטוריה תכנונית — תכניות קודמות, החלטות קודמות, היתרים]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// תמונה — מיקום
|
||||||
|
paras.push(imageBox("תשריט מיקום המגרש מתוך מערכת GIS — לסמן את המגרש"));
|
||||||
|
|
||||||
|
// מהות הבקשה
|
||||||
|
if (data.request_essence) {
|
||||||
|
if (Array.isArray(data.request_essence)) {
|
||||||
|
data.request_essence.forEach(text => {
|
||||||
|
paras.push(numberedPara(num++, text));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, data.request_essence));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, "[מהות הבקשה — פירוט מלא של מה שהתבקש]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// תמונה — תשריט
|
||||||
|
paras.push(imageBox("תשריט הבקשה / נספח בינוי / תכנית מוצעת"));
|
||||||
|
|
||||||
|
// ציטוט מפרוטוקול
|
||||||
|
if (data.committee_protocol_quote) {
|
||||||
|
paras.push(numberedPara(num++, "להלן מתוך פרוטוקול הדיון בוועדה המקומית:"));
|
||||||
|
paras.push(blockquote(data.committee_protocol_quote));
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, "[ציטוט מלא מפרוטוקול הוועדה המקומית]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// החלטת הוועדה + תנאים
|
||||||
|
if (data.committee_decision) {
|
||||||
|
paras.push(numberedPara(num++, data.committee_decision));
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, "[החלטת הוועדה המקומית — מה הוחלט, אילו תנאים נקבעו]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// תמונה אופציונלית — סביבה
|
||||||
|
if (data.include_aerial_photo !== false) {
|
||||||
|
paras.push(imageBox("צילום אוויר / מבט על הסביבה עם סימון המגרש"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// סביבת המקרקעין
|
||||||
|
if (data.surroundings) {
|
||||||
|
paras.push(numberedPara(num++, data.surroundings));
|
||||||
|
}
|
||||||
|
|
||||||
|
// הגשת הערר
|
||||||
|
if (data.appeal_filing) {
|
||||||
|
paras.push(numberedPara(num++, data.appeal_filing));
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, "[הגשת הערר — תאריך, מי הגיש, הצטרפויות]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return { paras, nextNum: num };
|
||||||
|
}
|
||||||
|
|
||||||
|
// בלוק ז — טענות הצדדים
|
||||||
|
function buildClaims(data, startNum) {
|
||||||
|
const paras = [];
|
||||||
|
let num = startNum;
|
||||||
|
|
||||||
|
paras.push(sectionTitle("תמצית טענות הצדדים"));
|
||||||
|
|
||||||
|
// טענות העוררים
|
||||||
|
if (data.appellant_claims_sections) {
|
||||||
|
// מספר עוררים עם כותרות נפרדות
|
||||||
|
data.appellant_claims_sections.forEach(section => {
|
||||||
|
paras.push(subTitle(section.title));
|
||||||
|
section.claims.forEach(text => {
|
||||||
|
paras.push(numberedPara(num++, text));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
paras.push(subTitle("טענות העוררים"));
|
||||||
|
if (data.appellant_claims) {
|
||||||
|
data.appellant_claims.forEach(text => {
|
||||||
|
paras.push(numberedPara(num++, text));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, "[טענות העוררים]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// עמדת הוועדה המקומית
|
||||||
|
paras.push(subTitle("עמדת הוועדה המקומית"));
|
||||||
|
if (data.committee_position) {
|
||||||
|
data.committee_position.forEach(text => {
|
||||||
|
paras.push(numberedPara(num++, text));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, "[עמדת הוועדה המקומית]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// עמדת מבקשי ההיתר / מגישי התכנית
|
||||||
|
const applicantTitle = data.type === "plan"
|
||||||
|
? "עמדת מגישי התכנית"
|
||||||
|
: "עמדת מבקשי ההיתר";
|
||||||
|
paras.push(subTitle(applicantTitle));
|
||||||
|
if (data.applicant_position) {
|
||||||
|
data.applicant_position.forEach(text => {
|
||||||
|
paras.push(numberedPara(num++, text));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, `[${applicantTitle}]`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return { paras, nextNum: num };
|
||||||
|
}
|
||||||
|
|
||||||
|
// בלוק ח — ההליכים בפני ועדת הערר
|
||||||
|
function buildProceedings(data, startNum) {
|
||||||
|
const paras = [];
|
||||||
|
let num = startNum;
|
||||||
|
|
||||||
|
paras.push(sectionTitle("ההליכים בפני ועדת הערר"));
|
||||||
|
|
||||||
|
if (data.proceedings) {
|
||||||
|
data.proceedings.forEach(item => {
|
||||||
|
if (item.type === "image") {
|
||||||
|
paras.push(imageBox(item.description));
|
||||||
|
} else if (item.type === "quote") {
|
||||||
|
paras.push(numberedPara(num++, item.intro || ""));
|
||||||
|
paras.push(blockquote(item.text));
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, item.text));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, "[דיון — תאריך, נוכחים, עיקרי הדברים]"));
|
||||||
|
paras.push(numberedPara(num++, "[סיור (אם היה) — תאריך, תיאור]"));
|
||||||
|
paras.push(imageBox("צילומים מהסיור"));
|
||||||
|
paras.push(numberedPara(num++, "[החלטות ביניים]"));
|
||||||
|
paras.push(numberedPara(num++, "[השלמות טיעון — כרונולוגי]"));
|
||||||
|
paras.push(numberedPara(num++, "[חוו\"ד מקצועיות שהתקבלו]"));
|
||||||
|
paras.push(imageBox("הדמיות / חתכי בינוי מהשלמות טיעון (אם יש)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return { paras, nextNum: num };
|
||||||
|
}
|
||||||
|
|
||||||
|
// בלוק ט — תכניות חלות (אופציונלי)
|
||||||
|
function buildPlans(data, startNum) {
|
||||||
|
if (data.skip_plans_section) return { paras: [], nextNum: startNum };
|
||||||
|
|
||||||
|
const paras = [];
|
||||||
|
let num = startNum;
|
||||||
|
|
||||||
|
paras.push(sectionTitle("התכניות החלות על המקרקעין"));
|
||||||
|
|
||||||
|
if (data.applicable_plans) {
|
||||||
|
data.applicable_plans.forEach(item => {
|
||||||
|
if (item.type === "quote") {
|
||||||
|
paras.push(numberedPara(num++, item.intro || ""));
|
||||||
|
paras.push(blockquote(item.text));
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, item.text));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
paras.push(numberedPara(num++, "[פירוט התכניות הרלוונטיות עם ציטוט מהוראותיהן]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return { paras, nextNum: num };
|
||||||
|
}
|
||||||
|
|
||||||
|
// בלוק יב — חתימות
|
||||||
|
function buildSignatures(data) {
|
||||||
|
const chairName = data.panel?.chair || "עו\"ד דפנה תמיר";
|
||||||
|
const secretaryName = data.secretary || "";
|
||||||
|
|
||||||
|
const halfWidth = Math.floor(CONTENT_WIDTH / 2);
|
||||||
|
|
||||||
|
return [
|
||||||
|
spacer(400),
|
||||||
|
rtlPara(rtlRun("ניתנה פה אחד, היום ______________, ______________."), {
|
||||||
|
spacing: { after: 400 }
|
||||||
|
}),
|
||||||
|
new Table({
|
||||||
|
visuallyRightToLeft: true,
|
||||||
|
width: { size: CONTENT_WIDTH, type: WidthType.DXA },
|
||||||
|
columnWidths: [halfWidth, halfWidth],
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
rtlCell([
|
||||||
|
rtlPara(rtlRun("________________________"), { alignment: AlignmentType.CENTER, spacing: { after: 40 } }),
|
||||||
|
rtlPara(rtlRun(chairName, { bold: true }), { alignment: AlignmentType.CENTER, spacing: { after: 20 } }),
|
||||||
|
rtlPara(rtlRun("יו\"ר ועדת הערר"), { alignment: AlignmentType.CENTER, spacing: { after: 20 } }),
|
||||||
|
], halfWidth),
|
||||||
|
rtlCell([
|
||||||
|
rtlPara(rtlRun("________________________"), { alignment: AlignmentType.CENTER, spacing: { after: 40 } }),
|
||||||
|
rtlPara(rtlRun(secretaryName || ""), { alignment: AlignmentType.CENTER, spacing: { after: 20 } }),
|
||||||
|
rtlPara(rtlRun("מזכירת ועדת הערר"), { alignment: AlignmentType.CENTER, spacing: { after: 20 } }),
|
||||||
|
], halfWidth),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
// MAIN — הרכבת המסמך
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
|
||||||
|
function buildDocument(data) {
|
||||||
|
const content = [];
|
||||||
|
|
||||||
|
// בלוק א — כותרת מוסדית
|
||||||
|
content.push(buildInstitutionalHeader(data));
|
||||||
|
content.push(spacer(160));
|
||||||
|
|
||||||
|
// בלוק ב — הרכב
|
||||||
|
content.push(...buildPanel(data));
|
||||||
|
content.push(spacer(80));
|
||||||
|
|
||||||
|
// בלוק ג — צדדים
|
||||||
|
content.push(...buildParties(data));
|
||||||
|
content.push(spacer(160));
|
||||||
|
|
||||||
|
// בלוק ד — כותרת "החלטה"
|
||||||
|
content.push(mainTitle("החלטה"));
|
||||||
|
|
||||||
|
// בלוק ה — פתיחה
|
||||||
|
content.push(...buildOpening(data));
|
||||||
|
|
||||||
|
// בלוק ו — רקע
|
||||||
|
const bg = buildBackground(data);
|
||||||
|
content.push(...bg.paras);
|
||||||
|
|
||||||
|
// בלוק ז — טענות
|
||||||
|
const claims = buildClaims(data, bg.nextNum);
|
||||||
|
content.push(...claims.paras);
|
||||||
|
|
||||||
|
// בלוק ח — הליכים
|
||||||
|
const proc = buildProceedings(data, claims.nextNum);
|
||||||
|
content.push(...proc.paras);
|
||||||
|
|
||||||
|
// בלוק ט — תכניות (אופציונלי)
|
||||||
|
const plans = buildPlans(data, proc.nextNum);
|
||||||
|
content.push(...plans.paras);
|
||||||
|
|
||||||
|
// בלוק י — דיון והכרעה (placeholder)
|
||||||
|
content.push(sectionTitle("דיון והכרעה"));
|
||||||
|
content.push(placeholder("כאן מתחיל פרק הדיון וההכרעה — ייכתב בשלב הבא"));
|
||||||
|
|
||||||
|
// בלוק יא — סיכום (placeholder)
|
||||||
|
content.push(sectionTitle("סיכום"));
|
||||||
|
content.push(placeholder("ייכתב לאחר השלמת פרק הדיון"));
|
||||||
|
|
||||||
|
// בלוק יב — חתימות
|
||||||
|
content.push(...buildSignatures(data));
|
||||||
|
|
||||||
|
return new Document({
|
||||||
|
styles: {
|
||||||
|
default: {
|
||||||
|
document: {
|
||||||
|
run: { font: FONT, size: FONT_SIZE, rightToLeft: true },
|
||||||
|
paragraph: { bidirectional: true, alignment: AlignmentType.BOTH }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
paragraphStyles: [
|
||||||
|
{
|
||||||
|
id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal",
|
||||||
|
quickFormat: true,
|
||||||
|
run: { size: HEADING1_SIZE, bold: true, font: FONT, rightToLeft: true },
|
||||||
|
paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0,
|
||||||
|
bidirectional: true, alignment: AlignmentType.CENTER }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal",
|
||||||
|
quickFormat: true,
|
||||||
|
run: { size: HEADING2_SIZE, bold: true, font: FONT, rightToLeft: true },
|
||||||
|
paragraph: { spacing: { before: 200, after: 200 }, outlineLevel: 1,
|
||||||
|
bidirectional: true, alignment: AlignmentType.CENTER }
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
sections: [{
|
||||||
|
properties: {
|
||||||
|
page: {
|
||||||
|
size: { width: PAGE_WIDTH, height: PAGE_HEIGHT },
|
||||||
|
margin: { top: MARGIN_DXA, right: MARGIN_DXA, bottom: MARGIN_DXA, left: MARGIN_DXA }
|
||||||
|
},
|
||||||
|
bidi: true,
|
||||||
|
},
|
||||||
|
footers: {
|
||||||
|
default: new Footer({
|
||||||
|
children: [new Paragraph({
|
||||||
|
bidirectional: true,
|
||||||
|
alignment: AlignmentType.CENTER,
|
||||||
|
children: [
|
||||||
|
rtlRun("עמוד ", { size: 18 }),
|
||||||
|
new TextRun({ children: [PageNumber.CURRENT], font: FONT, size: 18 }),
|
||||||
|
rtlRun(" מתוך ", { size: 18 }),
|
||||||
|
new TextRun({ children: [PageNumber.TOTAL_PAGES], font: FONT, size: 18 }),
|
||||||
|
]
|
||||||
|
})]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
children: content
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
// CLI
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const inputFile = process.argv[2];
|
||||||
|
|
||||||
|
if (!inputFile) {
|
||||||
|
console.error('שימוש: node create-decision-structure.js <input.json> [output.docx]');
|
||||||
|
console.error('');
|
||||||
|
console.error('קובץ ה-JSON צריך לכלול:');
|
||||||
|
console.error(' case_numbers, panel, appellants, respondents,');
|
||||||
|
console.error(' opening_paragraphs, property_description, planning_history,');
|
||||||
|
console.error(' request_essence, committee_protocol_quote, committee_decision,');
|
||||||
|
console.error(' appellant_claims, committee_position, applicant_position,');
|
||||||
|
console.error(' proceedings, applicable_plans');
|
||||||
|
console.error('');
|
||||||
|
console.error('ראה: .claude/skills/legal-decision/references/decision-template.json');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = JSON.parse(fs.readFileSync(inputFile, 'utf-8'));
|
||||||
|
const outputFile = process.argv[3] || `החלטה-ערר-${(data.case_numbers?.[0] || 'draft').replace(/\//g, '-')}-מבנה.docx`;
|
||||||
|
|
||||||
|
const doc = buildDocument(data);
|
||||||
|
const buffer = await Packer.toBuffer(doc);
|
||||||
|
fs.writeFileSync(outputFile, buffer);
|
||||||
|
|
||||||
|
console.log(`✅ ${outputFile}`);
|
||||||
|
console.log(` פונט: ${FONT} ${FONT_SIZE / 2}pt`);
|
||||||
|
console.log(` שוליים: ${MARGIN_CM} ס"מ`);
|
||||||
|
console.log(` RTL: bidi + bidirectional + rightToLeft ✓`);
|
||||||
|
console.log(` Alignment: START/END ✓`);
|
||||||
|
console.log(` גודל: ${(buffer.length / 1024).toFixed(1)} KB`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(err => {
|
||||||
|
console.error('❌ שגיאה:', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
204
skill-legal-decision/scripts/package-lock.json
generated
Normal file
204
skill-legal-decision/scripts/package-lock.json
generated
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
{
|
||||||
|
"name": "scripts",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"docx": "^9.6.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "25.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz",
|
||||||
|
"integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~7.18.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/core-util-is": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/docx": {
|
||||||
|
"version": "9.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/docx/-/docx-9.6.1.tgz",
|
||||||
|
"integrity": "sha512-ZJja9/KBUuFC109sCMzovoq2GR2wCG/AuxivjA+OHj/q0TEgJIm3S7yrlUxIy3B+bV8YDj/BiHfWyrRFmyWpDQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "^25.2.3",
|
||||||
|
"hash.js": "^1.1.7",
|
||||||
|
"jszip": "^3.10.1",
|
||||||
|
"nanoid": "^5.1.3",
|
||||||
|
"xml": "^1.0.1",
|
||||||
|
"xml-js": "^1.6.8"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/hash.js": {
|
||||||
|
"version": "1.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||||
|
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"minimalistic-assert": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/immediate": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/inherits": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/isarray": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/jszip": {
|
||||||
|
"version": "3.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
||||||
|
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
|
||||||
|
"license": "(MIT OR GPL-3.0-or-later)",
|
||||||
|
"dependencies": {
|
||||||
|
"lie": "~3.3.0",
|
||||||
|
"pako": "~1.0.2",
|
||||||
|
"readable-stream": "~2.3.6",
|
||||||
|
"setimmediate": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lie": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"immediate": "~3.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minimalistic-assert": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "5.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.7.tgz",
|
||||||
|
"integrity": "sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18 || >=20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pako": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
||||||
|
"license": "(MIT AND Zlib)"
|
||||||
|
},
|
||||||
|
"node_modules/process-nextick-args": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/readable-stream": {
|
||||||
|
"version": "2.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||||
|
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/sax": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==",
|
||||||
|
"license": "BlueOak-1.0.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/setimmediate": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "7.18.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
|
||||||
|
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/xml": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/xml-js": {
|
||||||
|
"version": "1.6.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
|
||||||
|
"integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"sax": "^1.2.4"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"xml-js": "bin/cli.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
skill-legal-decision/scripts/package.json
Normal file
5
skill-legal-decision/scripts/package.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"docx": "^9.6.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
976
skill-legal-docx/SKILL.md
Normal file
976
skill-legal-docx/SKILL.md
Normal file
@@ -0,0 +1,976 @@
|
|||||||
|
---
|
||||||
|
name: legal-docx
|
||||||
|
description: >
|
||||||
|
יצירת מסמכים משפטיים בעברית בפורמט DOCX עם תמיכה מלאה ב-RTL, עקוב אחר שינויים,
|
||||||
|
והערות. משתמש בסקיל הבסיסי docx ומוסיף התמחות בתחום המשפטי הישראלי.
|
||||||
|
|
||||||
|
טריגרים: "מסמך משפטי", "הסכם", "כתב הגנה", "כתב תביעה", "בקשה", "תצהיר",
|
||||||
|
"מכתב התראה", "חוזה", "הסכם שירותים", "ייפוי כוח", "פרוטוקול", "החלטה",
|
||||||
|
"צו", "פסק דין", "כתב טענות", בקשה ליצור מסמך DOCX בעברית, מסמך RTL,
|
||||||
|
"tracked changes בעברית", "הערות שוליים משפטיות", "עקוב אחר שינויים".
|
||||||
|
|
||||||
|
גם מתאים כאשר המשתמש מבקש מסמך Word בעברית עם פונט David/FrankRuehl/Miriam,
|
||||||
|
שוליים 2.5 ס"מ, או כל מסמך מקצועי בעברית שדורש עיצוב משפטי מדויק.
|
||||||
|
|
||||||
|
פיצ'רים: טבלאות RTL, הערות שוליים, תוכן עניינים, היפרלינקים,
|
||||||
|
לוגו/נייר פירמה, עריכת DOCX קיים, tracked changes, comments,
|
||||||
|
מרווח שורות, קו תחתי, מספר סקשנים, זיהוי אוטומטי של סוג מסמך.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Legal DOCX v3.0 — מסמכים משפטיים בעברית
|
||||||
|
|
||||||
|
סקיל זה מרחיב את סקיל docx הבסיסי עם התמחות במסמכים משפטיים ישראליים.
|
||||||
|
|
||||||
|
**תמיד לקרוא קודם** את `/mnt/skills/public/docx/SKILL.md` — הסקיל הזה מניח שאתה מכיר את תהליך העבודה הבסיסי (docx-js, unpack/pack, tracked changes, comments).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔴 קריטי: כללי RTL שחייבים לזכור
|
||||||
|
|
||||||
|
### הכלל המרכזי: START/END במקום LEFT/RIGHT
|
||||||
|
|
||||||
|
**במסמך עברי עם `bidirectional: true`, לעולם אל תשתמש ב-`AlignmentType.LEFT` או `AlignmentType.RIGHT` לפסקאות ומספור!**
|
||||||
|
|
||||||
|
| רוצה יישור ל... | ❌ לא להשתמש | ✅ להשתמש |
|
||||||
|
|-----------------|-------------|----------|
|
||||||
|
| **ימין** | `LEFT` או `RIGHT` | `AlignmentType.START` |
|
||||||
|
| **שמאל** | `LEFT` או `RIGHT` | `AlignmentType.END` |
|
||||||
|
| **מרכז** | — | `AlignmentType.CENTER` |
|
||||||
|
| **שני צדדים** | — | `AlignmentType.BOTH` |
|
||||||
|
|
||||||
|
> **למה?** כש-`bidirectional: true`, Word מתבלבל עם LEFT/RIGHT. `START` = התחלה = ימין ב-RTL, `END` = סוף = שמאל ב-RTL.
|
||||||
|
|
||||||
|
### שלוש הגדרות RTL חובה
|
||||||
|
|
||||||
|
כל מסמך עברי חייב את **שלושת** ההגדרות הבאות בכל הרמות:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 1. ברמת ה-Section
|
||||||
|
sections: [{
|
||||||
|
properties: {
|
||||||
|
bidi: true // ← חובה!
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
|
||||||
|
// 2. ברמת כל Paragraph
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true, // ← חובה!
|
||||||
|
alignment: AlignmentType.BOTH, // או START/CENTER/END
|
||||||
|
})
|
||||||
|
|
||||||
|
// 3. ברמת כל TextRun
|
||||||
|
new TextRun({
|
||||||
|
text: "טקסט בעברית",
|
||||||
|
rightToLeft: true, // ← חובה!
|
||||||
|
font: "David",
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**חוסר באחת מהן = יישור שגוי או טקסט הפוך!**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## זיהוי סוג מסמך — Document Type Detection
|
||||||
|
|
||||||
|
**לפני יצירת מסמך, זהה את סוגו.** לכל סוג יש מבנה שונה:
|
||||||
|
|
||||||
|
| סוג מסמך | דוגמאות | Header בית משפט? | מבנה מיוחד |
|
||||||
|
|----------|---------|------------------|------------|
|
||||||
|
| **כתב טענות** | תביעה, הגנה, בקשה, ערעור, תצהיר, בר"ע | ✅ כן | טבלת Header עם בית משפט + מספר תיק |
|
||||||
|
| **מכתב התראה** | התראה, דרישה, מכתב עו"ד | ❌ לא | לוגו/פרטי משרד, "הנדון:", חתימה |
|
||||||
|
| **הסכם/חוזה** | הסכם שירותים, NDA, חוזה שכירות | ❌ לא | הואילים, צדדים, חתימות בשני טורים |
|
||||||
|
| **מסמך כללי** | חוות דעת, מזכר, סיכום | ❌ לא | לפי הצורך |
|
||||||
|
|
||||||
|
### טריגרים לזיהוי
|
||||||
|
|
||||||
|
```
|
||||||
|
כתב טענות ← "בית משפט", "בית הדין", "תביעה", "הגנה", "בקשה",
|
||||||
|
"ערעור", "תצהיר", "המבקש", "המשיב", "התובע", "הנתבע", "בר\"ע"
|
||||||
|
|
||||||
|
מכתב התראה ← "התראה", "דרישה", "לכבוד", "הנדון:", "נשלח מבלי לפגוע"
|
||||||
|
|
||||||
|
הסכם/חוזה ← "הסכם", "חוזה", "בין:", "לבין:", "הואיל", "צד א'", "צד ב'",
|
||||||
|
"ולראיה באו הצדדים"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## פונטים ומידות
|
||||||
|
|
||||||
|
### פונטים משפטיים
|
||||||
|
|
||||||
|
| פונט | שימוש | size (half-points) |
|
||||||
|
|------|-------|-------------------|
|
||||||
|
| **David** | ברירת מחדל, גוף טקסט | 24 (12pt) |
|
||||||
|
| **FrankRuehl** | פורמלי/שמרני | 24 (12pt) |
|
||||||
|
| **Miriam** | מודרני יותר | 24 (12pt) |
|
||||||
|
|
||||||
|
**חשוב:** תמיד להגדיר גם `w:cs` (Complex Script) וגם `w:ascii`/`w:hAnsi`:
|
||||||
|
```javascript
|
||||||
|
new TextRun({ text: "...", font: "David", rightToLeft: true })
|
||||||
|
// docx-js מייצר: <w:rFonts w:ascii="David" w:cs="David" w:eastAsia="David" w:hAnsi="David"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### מידות ושוליים
|
||||||
|
|
||||||
|
```
|
||||||
|
2.5 ס"מ = 1417 DXA (ברירת מחדל משפטי)
|
||||||
|
3.0 ס"מ = 1701 DXA
|
||||||
|
2.0 ס"מ = 1134 DXA
|
||||||
|
1.0 אינץ' = 1440 DXA
|
||||||
|
|
||||||
|
A4 = 11906 × 16838 DXA
|
||||||
|
רוחב תוכן (A4, שוליים 2.5 ס"מ) = 9072 DXA
|
||||||
|
רוחב תוכן (A4, שוליים 2.0 ס"מ) = 9638 DXA
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## מספור סעיפים משפטיים
|
||||||
|
|
||||||
|
**⚠️ שים לב: `alignment: AlignmentType.START` — לא LEFT ולא RIGHT!**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
numbering: {
|
||||||
|
config: [{
|
||||||
|
reference: "legal-clauses",
|
||||||
|
levels: [
|
||||||
|
{
|
||||||
|
level: 0,
|
||||||
|
format: LevelFormat.DECIMAL,
|
||||||
|
text: "%1.",
|
||||||
|
alignment: AlignmentType.START, // ✅ START — לא RIGHT!
|
||||||
|
suffix: "tab",
|
||||||
|
style: { paragraph: { indent: { left: 720, hanging: 360 } } }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
level: 1,
|
||||||
|
format: LevelFormat.DECIMAL,
|
||||||
|
text: "%1.%2",
|
||||||
|
alignment: AlignmentType.START, // ✅ START — לא RIGHT!
|
||||||
|
suffix: "tab",
|
||||||
|
style: { paragraph: { indent: { left: 1440, hanging: 500 } } }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
level: 2,
|
||||||
|
format: LevelFormat.DECIMAL,
|
||||||
|
text: "%1.%2.%3",
|
||||||
|
alignment: AlignmentType.START, // ✅ START
|
||||||
|
suffix: "tab",
|
||||||
|
style: { paragraph: { indent: { left: 2160, hanging: 640 } } }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**שימוש:**
|
||||||
|
```javascript
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true,
|
||||||
|
numbering: { reference: "legal-clauses", level: 0 },
|
||||||
|
children: [new TextRun({ text: "תוכן הסעיף", font: "David", size: 24, rightToLeft: true })]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
> **הבעיה שנפתרה:** בלי `AlignmentType.START`, המספור מופיע כ-".1" במקום "1."
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## טבלאות RTL
|
||||||
|
|
||||||
|
**⚠️ קריטי: `visuallyRightToLeft: true` — בלי זה העמודות יהיו הפוכות!**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { Table, TableRow, TableCell, BorderStyle, WidthType, ShadingType } = require('docx');
|
||||||
|
|
||||||
|
const CONTENT_WIDTH = 9072; // A4 עם שוליים 2.5 ס"מ (11906 - 1417×2)
|
||||||
|
const border = { style: BorderStyle.SINGLE, size: 1, color: "999999" };
|
||||||
|
const borders = { top: border, bottom: border, left: border, right: border };
|
||||||
|
const noBorders = {
|
||||||
|
top: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
|
||||||
|
bottom: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
|
||||||
|
left: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
|
||||||
|
right: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function לתאים בעברית
|
||||||
|
const rtlCell = (text, width, opts = {}) => new TableCell({
|
||||||
|
borders: opts.noBorders ? noBorders : borders,
|
||||||
|
width: { size: width, type: WidthType.DXA },
|
||||||
|
margins: { top: 80, bottom: 80, left: 120, right: 120 },
|
||||||
|
...(opts.shading ? { shading: { fill: opts.shading, type: ShadingType.CLEAR } } : {}),
|
||||||
|
children: [new Paragraph({
|
||||||
|
bidirectional: true,
|
||||||
|
alignment: opts.alignment || AlignmentType.CENTER,
|
||||||
|
children: [new TextRun({
|
||||||
|
text, font: "David", size: 24, rightToLeft: true, bold: opts.bold
|
||||||
|
})]
|
||||||
|
})]
|
||||||
|
});
|
||||||
|
|
||||||
|
// טבלה עם גבולות
|
||||||
|
new Table({
|
||||||
|
visuallyRightToLeft: true, // ✅ קריטי! בלי זה העמודות הפוכות
|
||||||
|
width: { size: CONTENT_WIDTH, type: WidthType.DXA },
|
||||||
|
columnWidths: [4536, 2268, 2268], // חייב להסתכם ל-CONTENT_WIDTH
|
||||||
|
rows: [
|
||||||
|
new TableRow({ children: [
|
||||||
|
rtlCell("סוג שירות", 4536, { bold: true, shading: "D5E8F0" }),
|
||||||
|
rtlCell("תעריף", 2268, { bold: true, shading: "D5E8F0" }),
|
||||||
|
rtlCell("הערות", 2268, { bold: true, shading: "D5E8F0" }),
|
||||||
|
]}),
|
||||||
|
new TableRow({ children: [
|
||||||
|
rtlCell("ייעוץ משפטי", 4536),
|
||||||
|
rtlCell("850 ש״ח", 2268),
|
||||||
|
rtlCell("בתוספת מע״מ", 2268),
|
||||||
|
]}),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// טבלה ללא גבולות (לחתימות / header)
|
||||||
|
new Table({
|
||||||
|
visuallyRightToLeft: true,
|
||||||
|
width: { size: CONTENT_WIDTH, type: WidthType.DXA },
|
||||||
|
columnWidths: [CONTENT_WIDTH / 2, CONTENT_WIDTH / 2],
|
||||||
|
rows: [
|
||||||
|
new TableRow({ children: [
|
||||||
|
rtlCell("חתימה: ________", CONTENT_WIDTH / 2, { noBorders: true, alignment: AlignmentType.CENTER }),
|
||||||
|
rtlCell("חתימה: ________", CONTENT_WIDTH / 2, { noBorders: true, alignment: AlignmentType.CENTER }),
|
||||||
|
]})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**כללים:**
|
||||||
|
- **`visuallyRightToLeft: true`** — חובה! בלי זה העמודות משמאל לימין
|
||||||
|
- **`WidthType.DXA`** — לא PERCENTAGE (פחות אמין ב-RTL)
|
||||||
|
- **`columnWidths`** — סכום חייב להיות שווה ל-`CONTENT_WIDTH`
|
||||||
|
- **`bidirectional: true` + `rightToLeft: true`** — בכל תא
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tracked Changes — עקוב אחר שינויים
|
||||||
|
|
||||||
|
### שם מחבר בעברית
|
||||||
|
```xml
|
||||||
|
<w:del w:id="10" w:author="עו"ד כהן" w:date="2026-02-06T09:00:00Z">
|
||||||
|
```
|
||||||
|
|
||||||
|
### שינוי ערך (סכום, תאריך, תקופה)
|
||||||
|
פצל את הטקסט ועטוף רק את הערך שמשתנה:
|
||||||
|
```xml
|
||||||
|
<w:r><w:rPr>...RTL PROPS...</w:rPr>
|
||||||
|
<w:t xml:space="preserve">שכר הטרחה יעמוד על סך של </w:t></w:r>
|
||||||
|
<w:del w:id="10" w:author="עו"ד כהן" w:date="...">
|
||||||
|
<w:r><w:rPr>...RTL PROPS...</w:rPr><w:delText>750</w:delText></w:r>
|
||||||
|
</w:del>
|
||||||
|
<w:ins w:id="11" w:author="עו"ד כהן" w:date="...">
|
||||||
|
<w:r><w:rPr>...RTL PROPS...</w:rPr><w:t>850</w:t></w:r>
|
||||||
|
</w:ins>
|
||||||
|
<w:r><w:rPr>...RTL PROPS...</w:rPr>
|
||||||
|
<w:t xml:space="preserve"> ש״ח לשעת עבודה</w:t></w:r>
|
||||||
|
```
|
||||||
|
|
||||||
|
### מחיקת סעיף שלם
|
||||||
|
סמן גם את ה-paragraph mark כ-deleted:
|
||||||
|
```xml
|
||||||
|
<w:p>
|
||||||
|
<w:pPr>
|
||||||
|
<w:bidi/>
|
||||||
|
<w:jc w:val="both"/>
|
||||||
|
<w:rPr>
|
||||||
|
<w:del w:id="20" w:author="עו"ד כהן" w:date="..."/>
|
||||||
|
</w:rPr>
|
||||||
|
</w:pPr>
|
||||||
|
<w:del w:id="21" w:author="עו"ד כהן" w:date="...">
|
||||||
|
<w:r><w:rPr>...RTL PROPS...</w:rPr>
|
||||||
|
<w:delText>הסעיף שנמחק</w:delText></w:r>
|
||||||
|
</w:del>
|
||||||
|
</w:p>
|
||||||
|
```
|
||||||
|
|
||||||
|
### RTL PROPS — בלוק rPr מלא לכל run
|
||||||
|
```xml
|
||||||
|
<w:rPr>
|
||||||
|
<w:rFonts w:ascii="David" w:cs="David" w:eastAsia="David" w:hAnsi="David"/>
|
||||||
|
<w:sz w:val="24"/>
|
||||||
|
<w:szCs w:val="24"/>
|
||||||
|
<w:rtl/>
|
||||||
|
</w:rPr>
|
||||||
|
```
|
||||||
|
|
||||||
|
### קבלה/דחייה של שינויים
|
||||||
|
|
||||||
|
**קבלת Insertion:**
|
||||||
|
```
|
||||||
|
לפני: <w:ins w:id="5" w:author="..."><w:r>...<w:t>טקסט חדש</w:t></w:r></w:ins>
|
||||||
|
אחרי: <w:r>...<w:t>טקסט חדש</w:t></w:r>
|
||||||
|
→ הסר את תגית <w:ins> ושמור את התוכן הפנימי.
|
||||||
|
```
|
||||||
|
|
||||||
|
**דחיית Insertion:**
|
||||||
|
```
|
||||||
|
לפני: <w:ins w:id="5" w:author="..."><w:r>...<w:t>טקסט חדש</w:t></w:r></w:ins>
|
||||||
|
אחרי: (הסר לחלוטין)
|
||||||
|
→ מחק את כל בלוק ה-<w:ins> כולל תוכנו.
|
||||||
|
```
|
||||||
|
|
||||||
|
**קבלת מחיקה:**
|
||||||
|
```
|
||||||
|
לפני: <w:del w:id="10" w:author="..."><w:r>...<w:delText>טקסט שנמחק</w:delText></w:r></w:del>
|
||||||
|
אחרי: (הסר לחלוטין)
|
||||||
|
→ מחק את כל בלוק ה-<w:del> כולל תוכנו — המחיקה מתקבלת.
|
||||||
|
```
|
||||||
|
|
||||||
|
**שחזור טקסט מקורי (דחיית מחיקה):**
|
||||||
|
```
|
||||||
|
לפני: <w:del w:id="10" w:author="..."><w:r>...<w:delText>טקסט מקורי</w:delText></w:r></w:del>
|
||||||
|
אחרי: <w:r>...<w:t>טקסט מקורי</w:t></w:r>
|
||||||
|
→ הסר <w:del>, החלף <w:delText> ב-<w:t>, הסר <w:del> מ-rPr אם קיים.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## הערות (Comments)
|
||||||
|
|
||||||
|
הערות משמשות בסקירה משפטית להסביר *למה* בוצע שינוי:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python /mnt/skills/public/docx/scripts/comment.py unpacked/ 0 "הערה בעברית" --author "עו״ד כהן"
|
||||||
|
```
|
||||||
|
|
||||||
|
שימושים נפוצים:
|
||||||
|
- הסבר לשינוי סכום או תאריך
|
||||||
|
- דגל על סעיף בעייתי
|
||||||
|
- הפניה לפסיקה או חקיקה
|
||||||
|
- שאלה ללקוח / לצד השני
|
||||||
|
|
||||||
|
> **הערה:** `comment.py` מטפל אוטומטית ב-Content_Types ו-relationships.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## עריכת DOCX קיים (Unpack → Edit → Pack)
|
||||||
|
|
||||||
|
### תהליך מאומת
|
||||||
|
```bash
|
||||||
|
# 1. פתיחת הקובץ
|
||||||
|
python /mnt/skills/public/docx/scripts/unpack.py input.docx unpacked/
|
||||||
|
|
||||||
|
# 2. עריכת word/document.xml (או קבצי XML אחרים)
|
||||||
|
|
||||||
|
# 3. ארגון מחדש
|
||||||
|
python /mnt/skills/public/docx/scripts/pack.py unpacked/ output.docx --original input.docx
|
||||||
|
```
|
||||||
|
|
||||||
|
### מיקום הוספת תוכן — כלל קריטי
|
||||||
|
```
|
||||||
|
⚠️ פסקאות חדשות חייבות להיכנס *לפני* <w:sectPr> האחרון בגוף המסמך.
|
||||||
|
הוספה *אחרי* sectPr תיכשל בוולידציה.
|
||||||
|
|
||||||
|
מבנה תקין:
|
||||||
|
<w:body>
|
||||||
|
<w:p>...</w:p> ← פסקאות קיימות
|
||||||
|
<w:p>...</w:p> ← פסקה חדשה כאן ✅
|
||||||
|
<w:sectPr>...</w:sectPr> ← תמיד אחרון
|
||||||
|
</w:body>
|
||||||
|
```
|
||||||
|
|
||||||
|
### דוגמה — הוספת פסקה בעברית
|
||||||
|
```xml
|
||||||
|
<w:p>
|
||||||
|
<w:pPr>
|
||||||
|
<w:bidi/>
|
||||||
|
<w:jc w:val="both"/>
|
||||||
|
</w:pPr>
|
||||||
|
<w:r>
|
||||||
|
<w:rPr>
|
||||||
|
<w:rFonts w:ascii="David" w:cs="David" w:eastAsia="David" w:hAnsi="David"/>
|
||||||
|
<w:sz w:val="24"/>
|
||||||
|
<w:szCs w:val="24"/>
|
||||||
|
<w:rtl/>
|
||||||
|
</w:rPr>
|
||||||
|
<w:t>הטקסט החדש</w:t>
|
||||||
|
</w:r>
|
||||||
|
</w:p>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## הערות שוליים (Footnotes)
|
||||||
|
|
||||||
|
**השימוש המרכזי:** הפניות לחקיקה ופסיקה.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { FootnoteReferenceRun } = require('docx');
|
||||||
|
|
||||||
|
// 1. הגדרה ב-Document:
|
||||||
|
const doc = new Document({
|
||||||
|
footnotes: {
|
||||||
|
1: { children: [new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.START, // ✅ START
|
||||||
|
children: [new TextRun({
|
||||||
|
text: "חוק החוזים (חלק כללי), התשל״ג-1973, סעיף 12.",
|
||||||
|
font: "David", size: 20, rightToLeft: true // 10pt להערות שוליים
|
||||||
|
})]
|
||||||
|
})] },
|
||||||
|
2: { children: [new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.START,
|
||||||
|
children: [new TextRun({
|
||||||
|
text: "ע״א 1234/20 כהן נ׳ לוי, פסקה 15 (פורסם בנבו, 1.1.2024).",
|
||||||
|
font: "David", size: 20, rightToLeft: true
|
||||||
|
})]
|
||||||
|
})] },
|
||||||
|
},
|
||||||
|
// ...sections
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. הפניה בגוף הטקסט:
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.BOTH,
|
||||||
|
children: [
|
||||||
|
new TextRun({ text: "חובת תום הלב", font: "David", size: 24, rightToLeft: true }),
|
||||||
|
new FootnoteReferenceRun(1),
|
||||||
|
new TextRun({ text: " חלה על כל שלבי המשא ומתן", font: "David", size: 24, rightToLeft: true }),
|
||||||
|
new FootnoteReferenceRun(2),
|
||||||
|
new TextRun({ text: ".", font: "David", size: 24, rightToLeft: true }),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### תיקון RTL בהערות שוליים (post-unpack)
|
||||||
|
docx-js לא מגדיר RTL מלא בהערות שוליים. אחרי unpack, צריך לתקן ב-`word/footnotes.xml`:
|
||||||
|
```xml
|
||||||
|
<!-- 1. הוסף pStyle + bidi לכל הערת שוליים: -->
|
||||||
|
<w:footnote w:id="1">
|
||||||
|
<w:p>
|
||||||
|
<w:pPr>
|
||||||
|
<w:pStyle w:val="FootnoteText"/>
|
||||||
|
<w:bidi/>
|
||||||
|
<w:jc w:val="start"/>
|
||||||
|
</w:pPr>
|
||||||
|
...
|
||||||
|
|
||||||
|
<!-- 2. הוסף rtl ל-footnoteRef run: -->
|
||||||
|
<w:r>
|
||||||
|
<w:rPr>
|
||||||
|
<w:rStyle w:val="FootnoteReference"/>
|
||||||
|
<w:rtl/>
|
||||||
|
</w:rPr>
|
||||||
|
<w:footnoteRef/>
|
||||||
|
</w:r>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## מרווח שורות (Line Spacing)
|
||||||
|
|
||||||
|
**דרישת בתי המשפט:** בדרך כלל 1.5 שורות.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { LineRuleType } = require('docx');
|
||||||
|
|
||||||
|
// LineRuleType.AUTO — הערך הוא ב-1/240 שורה
|
||||||
|
spacing: { line: 240, lineRule: LineRuleType.AUTO } // 1.0 — צפוף
|
||||||
|
spacing: { line: 276, lineRule: LineRuleType.AUTO } // 1.15 — ברירת מחדל Word
|
||||||
|
spacing: { line: 360, lineRule: LineRuleType.AUTO } // 1.5 — נדרש בבתי משפט
|
||||||
|
spacing: { line: 480, lineRule: LineRuleType.AUTO } // 2.0 — כפול
|
||||||
|
|
||||||
|
// שילוב עם before/after:
|
||||||
|
spacing: { line: 360, lineRule: LineRuleType.AUTO, before: 120, after: 120 }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## תוכן עניינים (TOC)
|
||||||
|
|
||||||
|
**⚠️ חובה: TOC ידני (לא TableOfContents).**
|
||||||
|
`TableOfContents` של docx-js מייצר שדה שוורד מעדכן ב-F9 ומאבד הגדרות RTL.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { Tab, TabStopType, LeaderType, PageBreak } = require('docx');
|
||||||
|
|
||||||
|
// שורת TOC ידנית
|
||||||
|
const tocEntry = (text, pageNum, opts = {}) => new Paragraph({
|
||||||
|
bidirectional: true,
|
||||||
|
spacing: { after: 60, line: 276, lineRule: LineRuleType.AUTO },
|
||||||
|
...(opts.indent ? { indent: { right: opts.indent } } : {}),
|
||||||
|
tabStops: [{ type: TabStopType.RIGHT, position: 9026, leader: LeaderType.DOT }],
|
||||||
|
children: [
|
||||||
|
new TextRun({
|
||||||
|
text, font: "David", size: 24, rightToLeft: true,
|
||||||
|
bold: opts.bold || false,
|
||||||
|
}),
|
||||||
|
new TextRun({ children: [new Tab()], font: "David", rightToLeft: true }),
|
||||||
|
new TextRun({
|
||||||
|
text: String(pageNum), font: "David", size: 24, rightToLeft: true,
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// שימוש:
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||||
|
spacing: { after: 200 },
|
||||||
|
children: [new TextRun({
|
||||||
|
text: "תוכן עניינים", font: "David", size: 32, bold: true, rightToLeft: true
|
||||||
|
})]
|
||||||
|
}),
|
||||||
|
tocEntry("פרק א׳ — הגדרות כלליות", 2, { bold: true }),
|
||||||
|
tocEntry("1. הגדרות יסוד", 2, { indent: 400 }),
|
||||||
|
tocEntry("פרק ב׳ — השירותים", 3, { bold: true }),
|
||||||
|
new Paragraph({ children: [new PageBreak()] }),
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## קו תחתי (Underline)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { UnderlineType } = require('docx');
|
||||||
|
|
||||||
|
// קו תחתי רגיל:
|
||||||
|
new TextRun({
|
||||||
|
text: "נושא: הסכם שירותים",
|
||||||
|
font: "David", size: 24, rightToLeft: true,
|
||||||
|
underline: { type: UnderlineType.SINGLE }
|
||||||
|
})
|
||||||
|
|
||||||
|
// קו תחתי כפול (לכותרות חשובות):
|
||||||
|
underline: { type: UnderlineType.DOUBLE }
|
||||||
|
|
||||||
|
// סוגים שימושיים: SINGLE, DOUBLE, THICK, DOTTED, DASH, WAVE
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## מספר סקשנים (Multiple Sections)
|
||||||
|
|
||||||
|
**שימוש:** כותרות שונות לנספחים, עמוד לרוחב לטבלאות, שוליים שונים.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const doc = new Document({
|
||||||
|
sections: [
|
||||||
|
// סקשן 1 — גוף ההסכם
|
||||||
|
{
|
||||||
|
properties: {
|
||||||
|
page: { size: { width: 11906, height: 16838 },
|
||||||
|
margin: { top: 1417, right: 1417, bottom: 1417, left: 1417 } },
|
||||||
|
bidi: true,
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
default: new Header({ children: [new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||||
|
children: [new TextRun({ text: "הסכם שירותים", font: "David", size: 20, bold: true, rightToLeft: true })]
|
||||||
|
})] })
|
||||||
|
},
|
||||||
|
children: [ /* ... */ ]
|
||||||
|
},
|
||||||
|
// סקשן 2 — נספח עם כותרת שונה
|
||||||
|
{
|
||||||
|
properties: {
|
||||||
|
page: { size: { width: 11906, height: 16838 },
|
||||||
|
margin: { top: 1417, right: 1417, bottom: 1417, left: 1417 } },
|
||||||
|
bidi: true,
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
default: new Header({ children: [new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.START, // ✅ START
|
||||||
|
children: [new TextRun({ text: "נספח א׳ — לוח תעריפים", font: "David", size: 20, bold: true, rightToLeft: true })]
|
||||||
|
})] })
|
||||||
|
},
|
||||||
|
children: [ /* ... */ ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## לוגו/תמונה בכותרת (Letterhead)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { ImageRun } = require('docx');
|
||||||
|
|
||||||
|
const logoBuffer = fs.readFileSync('/path/to/logo.png');
|
||||||
|
|
||||||
|
headers: {
|
||||||
|
default: new Header({
|
||||||
|
children: [
|
||||||
|
new Paragraph({
|
||||||
|
alignment: AlignmentType.CENTER,
|
||||||
|
children: [
|
||||||
|
new ImageRun({
|
||||||
|
data: logoBuffer,
|
||||||
|
transformation: { width: 200, height: 60 }, // pixels
|
||||||
|
type: "png",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||||
|
children: [new TextRun({
|
||||||
|
text: "משרד עורכי דין ישראלי ושות׳",
|
||||||
|
font: "David", size: 20, bold: true, rightToLeft: true
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**הערה:** תמונה חייבת להיות קובץ אמיתי — לבקש מהמשתמש אם אין.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## היפרלינקים
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { ExternalHyperlink, UnderlineType } = require('docx');
|
||||||
|
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true,
|
||||||
|
children: [
|
||||||
|
new TextRun({ text: "ראה: ", font: "David", size: 24, rightToLeft: true }),
|
||||||
|
new ExternalHyperlink({
|
||||||
|
link: "https://www.nevo.co.il/law_html/law01/073_002.htm",
|
||||||
|
children: [new TextRun({
|
||||||
|
text: "חוק החוזים באתר נבו",
|
||||||
|
font: "David", size: 24, rightToLeft: true,
|
||||||
|
color: "0563C1",
|
||||||
|
underline: { type: UnderlineType.SINGLE },
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**⚠️ אזהרות:**
|
||||||
|
- **לא להשתמש ב-`style: "Hyperlink"`** — מפריע ל-RTL!
|
||||||
|
- **לא להוסיף `alignment: AlignmentType.RIGHT`** — `bidirectional: true` מספיק
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## תבניות מסמכים — Document Templates
|
||||||
|
|
||||||
|
### תבנית 1: כתב טענות (בקשה, תביעה, הגנה, ערעור)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
|
||||||
|
AlignmentType, LevelFormat, BorderStyle, WidthType } = require('docx');
|
||||||
|
|
||||||
|
const PAGE_WIDTH = 11906;
|
||||||
|
const MARGINS = { top: 1134, right: 1134, bottom: 1134, left: 1134 };
|
||||||
|
const CONTENT_WIDTH = PAGE_WIDTH - MARGINS.left - MARGINS.right;
|
||||||
|
|
||||||
|
const noBorder = { style: BorderStyle.NONE, size: 0, color: "FFFFFF" };
|
||||||
|
const noBorders = { top: noBorder, bottom: noBorder, left: noBorder, right: noBorder };
|
||||||
|
|
||||||
|
// Header בית משפט — טבלה עם שם בית המשפט (ימין) ומספר תיק (שמאל)
|
||||||
|
function courtHeader(courtName, caseNumber) {
|
||||||
|
return new Table({
|
||||||
|
width: { size: CONTENT_WIDTH, type: WidthType.DXA },
|
||||||
|
columnWidths: [CONTENT_WIDTH / 2, CONTENT_WIDTH / 2],
|
||||||
|
visuallyRightToLeft: true,
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
width: { size: CONTENT_WIDTH / 2, type: WidthType.DXA },
|
||||||
|
borders: noBorders,
|
||||||
|
children: [new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.START,
|
||||||
|
children: [new TextRun({ text: courtName, bold: true, font: "David", size: 26, rightToLeft: true })]
|
||||||
|
})]
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
width: { size: CONTENT_WIDTH / 2, type: WidthType.DXA },
|
||||||
|
borders: noBorders,
|
||||||
|
children: [new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.END,
|
||||||
|
children: [new TextRun({ text: caseNumber, bold: true, font: "David", size: 26, rightToLeft: true })]
|
||||||
|
})]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// כותרת ראשית ממורכזת עם קו תחתון
|
||||||
|
function mainTitle(text) {
|
||||||
|
return new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||||
|
spacing: { before: 300, after: 300 },
|
||||||
|
children: [new TextRun({ text, bold: true, font: "David", size: 28, rightToLeft: true, underline: {} })]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// כותרת משנה מיושרת לימין עם קו תחתון
|
||||||
|
function subHeading(text) {
|
||||||
|
return new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.START,
|
||||||
|
spacing: { before: 240, after: 120 },
|
||||||
|
children: [new TextRun({ text, bold: true, font: "David", size: 24, rightToLeft: true, underline: {} })]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// שימוש:
|
||||||
|
const doc = new Document({
|
||||||
|
numbering: {
|
||||||
|
config: [{
|
||||||
|
reference: "legal-clauses",
|
||||||
|
levels: [{
|
||||||
|
level: 0, format: LevelFormat.DECIMAL, text: "%1.",
|
||||||
|
alignment: AlignmentType.START, suffix: "tab",
|
||||||
|
style: { paragraph: { indent: { left: 360, hanging: 360 } } }
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
sections: [{
|
||||||
|
properties: {
|
||||||
|
page: { size: { width: PAGE_WIDTH, height: 16838 }, margin: MARGINS },
|
||||||
|
bidi: true
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
courtHeader("בית המשפט המחוזי בתל אביב", "ת\"א 12345-01-26"),
|
||||||
|
mainTitle("כתב תביעה"),
|
||||||
|
// ... פרטי צדדים, סעיפים, חתימה
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### תבנית 2: מכתב התראה
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// מכתב התראה — ללא header בית משפט, עם פרטי משרד
|
||||||
|
|
||||||
|
function letterHeader(firmName, address, phone, email) {
|
||||||
|
return [
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.START,
|
||||||
|
children: [new TextRun({ text: firmName, bold: true, font: "David", size: 28, rightToLeft: true })]
|
||||||
|
}),
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.START,
|
||||||
|
children: [new TextRun({ text: address, font: "David", size: 22, rightToLeft: true })]
|
||||||
|
}),
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.START,
|
||||||
|
spacing: { after: 300 },
|
||||||
|
children: [new TextRun({ text: `טל': ${phone} | ${email}`, font: "David", size: 22, rightToLeft: true })]
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function subjectLine(text) {
|
||||||
|
return new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||||
|
spacing: { before: 200, after: 200 },
|
||||||
|
children: [
|
||||||
|
new TextRun({ text: "הנדון: ", bold: true, font: "David", size: 24, rightToLeft: true }),
|
||||||
|
new TextRun({ text, bold: true, font: "David", size: 24, rightToLeft: true, underline: {} })
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// שימוש:
|
||||||
|
sections: [{
|
||||||
|
properties: { page: { ... }, bidi: true },
|
||||||
|
children: [
|
||||||
|
...letterHeader("משרד עו\"ד כהן ושות'", "רח' הרצל 1, תל אביב", "03-1234567", "office@cohen-law.co.il"),
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.START,
|
||||||
|
children: [new TextRun({ text: "תאריך: 10.2.2026", font: "David", size: 24, rightToLeft: true })]
|
||||||
|
}),
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.START,
|
||||||
|
spacing: { before: 200 },
|
||||||
|
children: [new TextRun({ text: "לכבוד: [שם הנמען]", font: "David", size: 24, rightToLeft: true })]
|
||||||
|
}),
|
||||||
|
subjectLine("התראה בטרם נקיטת הליכים משפטיים"),
|
||||||
|
// ... גוף המכתב
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
### תבנית 3: הסכם/חוזה
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// הסכם — הואילים, צדדים, חתימות בשני טורים
|
||||||
|
|
||||||
|
function contractTitle(text) {
|
||||||
|
return new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||||
|
spacing: { after: 300 },
|
||||||
|
children: [new TextRun({ text, bold: true, font: "David", size: 32, rightToLeft: true })]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function partyClause(label, name, id, address, alias) {
|
||||||
|
return new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.BOTH,
|
||||||
|
spacing: { after: 120 },
|
||||||
|
children: [
|
||||||
|
new TextRun({ text: `${label}: `, bold: true, font: "David", size: 24, rightToLeft: true }),
|
||||||
|
new TextRun({ text: `${name}, ח.פ./ת.ז. ${id}, מ${address} (להלן: "`, font: "David", size: 24, rightToLeft: true }),
|
||||||
|
new TextRun({ text: alias, bold: true, font: "David", size: 24, rightToLeft: true }),
|
||||||
|
new TextRun({ text: '")', font: "David", size: 24, rightToLeft: true }),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function signatureTable() {
|
||||||
|
return new Table({
|
||||||
|
width: { size: CONTENT_WIDTH, type: WidthType.DXA },
|
||||||
|
columnWidths: [CONTENT_WIDTH / 2, CONTENT_WIDTH / 2],
|
||||||
|
visuallyRightToLeft: true,
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
borders: noBorders,
|
||||||
|
children: [
|
||||||
|
new Paragraph({ bidirectional: true, alignment: AlignmentType.CENTER,
|
||||||
|
children: [new TextRun({ text: "_________________", font: "David", size: 24, rightToLeft: true })] }),
|
||||||
|
new Paragraph({ bidirectional: true, alignment: AlignmentType.CENTER,
|
||||||
|
children: [new TextRun({ text: "צד א'", font: "David", size: 24, rightToLeft: true })] })
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
borders: noBorders,
|
||||||
|
children: [
|
||||||
|
new Paragraph({ bidirectional: true, alignment: AlignmentType.CENTER,
|
||||||
|
children: [new TextRun({ text: "_________________", font: "David", size: 24, rightToLeft: true })] }),
|
||||||
|
new Paragraph({ bidirectional: true, alignment: AlignmentType.CENTER,
|
||||||
|
children: [new TextRun({ text: "צד ב'", font: "David", size: 24, rightToLeft: true })] })
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// שימוש:
|
||||||
|
sections: [{
|
||||||
|
properties: { page: { ... }, bidi: true },
|
||||||
|
children: [
|
||||||
|
contractTitle("הסכם שירותים"),
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||||
|
children: [new TextRun({ text: "נערך ונחתם בתל אביב ביום __________", font: "David", size: 24, rightToLeft: true })]
|
||||||
|
}),
|
||||||
|
partyClause("מצד אחד", "[שם]", "[מספר]", "[כתובת]", "המזמין"),
|
||||||
|
partyClause("מצד שני", "[שם]", "[מספר]", "[כתובת]", "הספק"),
|
||||||
|
// הואילים...
|
||||||
|
// סעיפים...
|
||||||
|
new Paragraph({
|
||||||
|
bidirectional: true, alignment: AlignmentType.CENTER,
|
||||||
|
spacing: { before: 400, after: 300 },
|
||||||
|
children: [new TextRun({ text: "ולראיה באו הצדדים על החתום:", bold: true, font: "David", size: 24, rightToLeft: true })]
|
||||||
|
}),
|
||||||
|
signatureTable()
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference — טבלת עזר מהיר
|
||||||
|
|
||||||
|
### יישור
|
||||||
|
|
||||||
|
| רוצה | השתמש ב... | ❌ לא להשתמש |
|
||||||
|
|------|-----------|-------------|
|
||||||
|
| ימין | `AlignmentType.START` | `LEFT`, `RIGHT` |
|
||||||
|
| שמאל | `AlignmentType.END` | `LEFT`, `RIGHT` |
|
||||||
|
| מרכז | `AlignmentType.CENTER` | — |
|
||||||
|
| שני צדדים | `AlignmentType.BOTH` | `JUSTIFIED` |
|
||||||
|
|
||||||
|
### גדלי טקסט (half-points)
|
||||||
|
|
||||||
|
| שימוש | size | נקודות |
|
||||||
|
|-------|------|--------|
|
||||||
|
| גוף טקסט | 24 | 12pt |
|
||||||
|
| כותרת משנה | 26 | 13pt |
|
||||||
|
| כותרת ראשית | 28-32 | 14-16pt |
|
||||||
|
| הערות שוליים | 20 | 10pt |
|
||||||
|
| Header/Footer | 18-20 | 9-10pt |
|
||||||
|
|
||||||
|
### מרווחי שורות
|
||||||
|
|
||||||
|
| רווח | line value |
|
||||||
|
|------|-----------|
|
||||||
|
| 1.0 | 240 |
|
||||||
|
| 1.15 | 276 |
|
||||||
|
| 1.5 | 360 |
|
||||||
|
| 2.0 | 480 |
|
||||||
|
|
||||||
|
### Checklist — הגדרות חובה
|
||||||
|
|
||||||
|
```
|
||||||
|
☐ Section: bidi: true
|
||||||
|
☐ Paragraph: bidirectional: true
|
||||||
|
☐ TextRun: rightToLeft: true
|
||||||
|
☐ Numbering: alignment: AlignmentType.START
|
||||||
|
☐ Table: visuallyRightToLeft: true
|
||||||
|
☐ Footnotes: alignment: AlignmentType.START
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Troubleshooting
|
||||||
|
|
||||||
|
**מספור מופיע הפוך (.1 במקום 1.):**
|
||||||
|
→ וודא `alignment: AlignmentType.START` במספור (לא RIGHT!)
|
||||||
|
|
||||||
|
**טקסט מופיע משמאל לימין:**
|
||||||
|
→ וודא את שלושת ההגדרות: Section `bidi`, Paragraph `bidirectional`, TextRun `rightToLeft`
|
||||||
|
|
||||||
|
**עמודות טבלה הפוכות:**
|
||||||
|
→ הוסף `visuallyRightToLeft: true` לטבלה
|
||||||
|
|
||||||
|
**columnWidths לא מסתכם:**
|
||||||
|
→ וודא שסכום כל הרוחבים = CONTENT_WIDTH (9072 לשוליים 2.5 ס"מ, חישוב: 11906 - 1417×2)
|
||||||
|
|
||||||
|
**המסמך לא נפתח / שגיאה ב-Word:**
|
||||||
|
→ בדוק שלא הוספת פסקה אחרי `<w:sectPr>` (חייב להיות אחרון ב-body)
|
||||||
|
→ וודא `npm list docx` >= 8.0.0
|
||||||
|
|
||||||
|
**הערות שוליים לא ב-RTL:**
|
||||||
|
→ אחרי unpack, תקן ידנית ב-word/footnotes.xml (ראה סעיף הערות שוליים)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## טעויות נפוצות — Common Pitfalls
|
||||||
|
|
||||||
|
| ❌ טעות | ✅ תיקון |
|
||||||
|
|--------|---------|
|
||||||
|
| `AlignmentType.RIGHT` במספור | `AlignmentType.START` |
|
||||||
|
| `AlignmentType.LEFT` ליישור שמאלי | `AlignmentType.END` |
|
||||||
|
| טבלה בלי `visuallyRightToLeft` | הוסף `visuallyRightToLeft: true` |
|
||||||
|
| שכחת `bidirectional: true` בפסקה | הוסף לכל פסקה |
|
||||||
|
| שכחת `rightToLeft: true` ב-TextRun | הוסף לכל TextRun |
|
||||||
|
| שכחת `bidi: true` ב-Section | הוסף ל-properties |
|
||||||
|
| הוספת פסקה אחרי `sectPr` | הוסף לפני `sectPr` |
|
||||||
|
| שימוש ב-`style: "Hyperlink"` | הגדר ידנית `color` + `underline` |
|
||||||
|
| `columnWidths` לא מסתכם נכון | וודא שהסכום = `CONTENT_WIDTH` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## קבצי עזר
|
||||||
|
|
||||||
|
- **`references/document-types.md`** — מבנים מפורטים ל-9 סוגי מסמכים משפטיים
|
||||||
|
- **`scripts/create-legal-doc.js`** — סקריפט בסיסי עם כל הגדרות ה-RTL המתוקנות
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install docx
|
||||||
|
```
|
||||||
|
|
||||||
|
**גרסה מומלצת:** docx >= 8.0.0
|
||||||
271
skill-legal-docx/references/document-types.md
Normal file
271
skill-legal-docx/references/document-types.md
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
# סוגי מסמכים משפטיים — מבנים ותבניות
|
||||||
|
|
||||||
|
## תוכן עניינים
|
||||||
|
1. [הסכם / חוזה](#הסכם--חוזה)
|
||||||
|
2. [מכתב התראה](#מכתב-התראה)
|
||||||
|
3. [כתב תביעה](#כתב-תביעה)
|
||||||
|
4. [כתב הגנה](#כתב-הגנה)
|
||||||
|
5. [בקשה לבית משפט](#בקשה-לבית-משפט)
|
||||||
|
6. [תצהיר](#תצהיר)
|
||||||
|
7. [ייפוי כוח](#ייפוי-כוח)
|
||||||
|
8. [פרוטוקול ישיבה](#פרוטוקול-ישיבה)
|
||||||
|
9. [חוות דעת משפטית](#חוות-דעת-משפטית)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## הסכם / חוזה
|
||||||
|
|
||||||
|
### מבנה
|
||||||
|
```
|
||||||
|
כותרת: "הסכם [סוג]" (מרכז, bold, 16pt)
|
||||||
|
תאריך ומקום: "נערך ונחתם ב[עיר] ביום [תאריך]"
|
||||||
|
צדדים:
|
||||||
|
"מצד אחד: [שם], ח.פ./ת.ז. [מספר], מ[כתובת] (להלן: "[כינוי]")"
|
||||||
|
"מצד שני: [שם], ח.פ./ת.ז. [מספר], מ[כתובת] (להלן: "[כינוי]")"
|
||||||
|
הואילים (מוספרים):
|
||||||
|
"1. והואיל ו[תנאי ראשון];"
|
||||||
|
"2. והואיל ו[תנאי שני];"
|
||||||
|
מעבר: "לפיכך הוסכם, הותנה והוצהר בין הצדדים כדלקמן:" (מרכז, bold)
|
||||||
|
סעיפים ממוספרים: 1., 1.1, 1.2, 2., 2.1...
|
||||||
|
חתימות: "ולראיה באו הצדדים על החתום:" + שורות חתימה
|
||||||
|
```
|
||||||
|
|
||||||
|
### סעיפים נפוצים
|
||||||
|
- היקף השירותים / הגדרות
|
||||||
|
- תמורה ותשלום
|
||||||
|
- תקופת ההסכם
|
||||||
|
- סודיות
|
||||||
|
- קניין רוחני
|
||||||
|
- אחריות ושיפוי
|
||||||
|
- סיום ההתקשרות
|
||||||
|
- שונות (דין חל, סמכות שיפוט, כתובות)
|
||||||
|
|
||||||
|
### כותרות heading
|
||||||
|
- כותרת ראשית: Heading1, center, 16pt
|
||||||
|
- "בין הצדדים", "הואיל:": Heading2, center, 14pt
|
||||||
|
- כותרות סעיפים ("1. היקף השירותים"): Heading2, right/justified, 14pt
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## מכתב התראה
|
||||||
|
|
||||||
|
### מבנה
|
||||||
|
```
|
||||||
|
Header: לוגו/שם משרד, כתובת, טלפון, פקס, דוא"ל
|
||||||
|
תאריך: "ב[עיר], [תאריך]"
|
||||||
|
סימוכין: "סימוכין: [מספר תיק]"
|
||||||
|
נמען: "לכבוד [שם]\n[כתובת]"
|
||||||
|
שורת נדון: "הנדון: [נושא]" (bold, underline)
|
||||||
|
סיווג: "מכתב זה נשלח מבלי לפגוע בזכויות מרשי/תי" (bold)
|
||||||
|
גוף: פסקאות ללא מספור — תיאור עובדות, עילה, דרישה
|
||||||
|
סיום: "בכבוד רב," + חתימה
|
||||||
|
העתק: "העתק: [נמענים]"
|
||||||
|
```
|
||||||
|
|
||||||
|
### טון
|
||||||
|
- פורמלי ותקיף
|
||||||
|
- עובדתי ומדויק
|
||||||
|
- מציין מועד אחרון לתגובה
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## כתב תביעה
|
||||||
|
|
||||||
|
### מבנה
|
||||||
|
```
|
||||||
|
Header: "בבית המשפט [סוג] ב[עיר]"
|
||||||
|
מספר תיק: "ת"א [מספר]"
|
||||||
|
צדדים:
|
||||||
|
"התובע: [שם], ת.ז. [מספר]"
|
||||||
|
"ע"י ב"כ עו"ד [שם], [כתובת]"
|
||||||
|
"-נגד-"
|
||||||
|
"הנתבע: [שם], ת.ז. [מספר]"
|
||||||
|
כותרת: "כתב תביעה" (מרכז, bold, 16pt)
|
||||||
|
מבוא / הצדדים
|
||||||
|
עילות (סעיפים ממוספרים):
|
||||||
|
1. עובדות (בפסקאות ממוספרות)
|
||||||
|
2. הנזק
|
||||||
|
3. העילות המשפטיות
|
||||||
|
הסעדים המבוקשים
|
||||||
|
חתימה
|
||||||
|
אימות (תצהיר מצורף)
|
||||||
|
```
|
||||||
|
|
||||||
|
### דגשים
|
||||||
|
- כל עובדה בסעיף נפרד
|
||||||
|
- הפניות לסעיפי חוק
|
||||||
|
- סכום התביעה בסוף
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## כתב הגנה
|
||||||
|
|
||||||
|
### מבנה
|
||||||
|
```
|
||||||
|
Header: "בבית המשפט [סוג] ב[עיר]"
|
||||||
|
מספר תיק: "ת"א [מספר]"
|
||||||
|
צדדים: (כמו בכתב התביעה, עם "הנתבע/הנתבעת")
|
||||||
|
כותרת: "כתב הגנה" (מרכז, bold, 16pt)
|
||||||
|
מבוא
|
||||||
|
תשובה לכתב התביעה:
|
||||||
|
- התייחסות סעיף-סעיף ("לסעיף X — מוכחש/מאושר/אין ידיעה")
|
||||||
|
- טענות הגנה
|
||||||
|
- טענות מקדמיות (התיישנות, חוסר סמכות, חוסר עילה)
|
||||||
|
סיכום
|
||||||
|
חתימה
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## בקשה לבית משפט
|
||||||
|
|
||||||
|
### מבנה
|
||||||
|
```
|
||||||
|
Header: "בבית המשפט [סוג] ב[עיר]"
|
||||||
|
מספר תיק
|
||||||
|
צדדים
|
||||||
|
כותרת: "בקשה ל[סוג הבקשה]" (מרכז, bold, 16pt)
|
||||||
|
לדוגמה: "בקשה למתן צו מניעה זמני"
|
||||||
|
מבוא
|
||||||
|
הרקע העובדתי (ממוספר)
|
||||||
|
הנימוקים המשפטיים (ממוספר)
|
||||||
|
הסעד המבוקש
|
||||||
|
חתימה
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## תצהיר
|
||||||
|
|
||||||
|
### מבנה
|
||||||
|
```
|
||||||
|
Header: "בבית המשפט [סוג] ב[עיר]" (אם מוגש לבימ"ש)
|
||||||
|
כותרת: "תצהיר" / "תצהיר עדות ראשית" (מרכז, bold, 16pt)
|
||||||
|
פתיחה: "אני, [שם], ת.ז. [מספר], לאחר שהוזהרתי כי עלי לומר את
|
||||||
|
האמת וכי אהיה צפוי/ה לעונשים הקבועים בחוק אם לא אעשה כן,
|
||||||
|
מצהיר/ה בזה כדלקמן:"
|
||||||
|
גוף: סעיפים ממוספרים (עובדות בגוף ראשון)
|
||||||
|
נספחים: "מצ"ב מסמך... מסומן כנספח [א']"
|
||||||
|
סיום: "[שם המצהיר/ה]"
|
||||||
|
אימות: "אישור עורך דין"
|
||||||
|
"אני, עו"ד [שם], מאשר/ת בזה כי ביום [תאריך] התייצב/ה בפני
|
||||||
|
[שם], שזיהה/תה עצמו/ה באמצעות ת.ז. [מספר], ולאחר שהזהרתיו/ה
|
||||||
|
כי עליו/ה להצהיר אמת וכי יהיה/תהיה צפוי/ה לעונשים הקבועים בחוק
|
||||||
|
אם לא יעשה/תעשה כן, אישר/ה את נכונות הצהרתו/ה וחתם/ה עליה
|
||||||
|
בפני."
|
||||||
|
חתימת עו"ד
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ייפוי כוח
|
||||||
|
|
||||||
|
### מבנה
|
||||||
|
```
|
||||||
|
כותרת: "ייפוי כוח" / "ייפוי כוח כללי" / "ייפוי כוח מיוחד"
|
||||||
|
מייפה הכוח: "[שם], ת.ז. [מספר], מ[כתובת]"
|
||||||
|
מיופה הכוח: "עו"ד [שם], רישיון [מספר]"
|
||||||
|
ההרשאה: פירוט הפעולות המורשות
|
||||||
|
- ייפוי כוח כללי: "לייצגני בכל עניין ולפעול בשמי..."
|
||||||
|
- ייפוי כוח מיוחד: פירוט ספציפי של הפעולה
|
||||||
|
תוקף: תאריך תחילה וסיום (אם רלוונטי)
|
||||||
|
חתימה + אימות נוטריוני (אם נדרש)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## פרוטוקול ישיבה
|
||||||
|
|
||||||
|
### מבנה
|
||||||
|
```
|
||||||
|
כותרת: "פרוטוקול ישיבת [סוג] מס' [מספר]"
|
||||||
|
פרטים:
|
||||||
|
"תאריך: [תאריך]"
|
||||||
|
"שעה: [שעה]"
|
||||||
|
"מקום: [מקום]"
|
||||||
|
"נוכחים: [רשימה]"
|
||||||
|
"חסרים: [רשימה]"
|
||||||
|
"מנהל הישיבה: [שם]"
|
||||||
|
"מזכיר: [שם]"
|
||||||
|
סדר יום (ממוספר)
|
||||||
|
דיון (לפי סעיפי סדר היום)
|
||||||
|
החלטות (ממוספרות, bold)
|
||||||
|
חתימה: מנהל הישיבה + מזכיר
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## חוות דעת משפטית
|
||||||
|
|
||||||
|
### מבנה
|
||||||
|
```
|
||||||
|
כותרת: "חוות דעת משפטית" (מרכז, bold, 16pt)
|
||||||
|
"לכבוד: [שם הלקוח]"
|
||||||
|
"הנדון: [נושא]"
|
||||||
|
"סימוכין: [מספר תיק]"
|
||||||
|
תקציר מנהלים (אופציונלי)
|
||||||
|
רקע עובדתי
|
||||||
|
השאלה המשפטית
|
||||||
|
הדין החל
|
||||||
|
ניתוח משפטי
|
||||||
|
מסקנות והמלצות
|
||||||
|
הסתייגויות: "חוות דעת זו מבוססת על העובדות שנמסרו לי..."
|
||||||
|
חתימה
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## החלטת ועדת ערר לתכנון ובניה
|
||||||
|
|
||||||
|
### מבנה
|
||||||
|
```
|
||||||
|
כותרת מוסדית: טבלה ללא גבולות, 2 טורים
|
||||||
|
ימין: "מדינת ישראל" (bold), "ועדת ערר לתכנון ובניה", "מחוז ירושלים"
|
||||||
|
שמאל: "מס' תיק:" + מספרים (bold), מספרנו, "מס' בקשה:"/"מס' תכנית:"
|
||||||
|
הרכב: "בפני:" (bold), יו"ר + חברים
|
||||||
|
צדדים: "העורר/ים:" + שמות + ב"כ, "-נגד-" (מרכז, bold), "המשיבים:" + שמות + ב"כ
|
||||||
|
כותרת: "החלטה" (16pt, bold, מרכז)
|
||||||
|
פתיחה: 1-2 סעיפים ללא כותרת ("לפנינו...")
|
||||||
|
פתח דבר / רקע: מקרקעין, היסטוריה תכנונית, מהות הבקשה, ציטוט מפרוטוקול, תמונות
|
||||||
|
תמצית טענות הצדדים: (14pt, bold, קו תחתון, מרכז)
|
||||||
|
טענות העוררים (12pt, bold, מרכז)
|
||||||
|
עמדת הוועדה המקומית (12pt, bold, מרכז)
|
||||||
|
עמדת מבקשי ההיתר / מגישי התכנית (12pt, bold, מרכז)
|
||||||
|
ההליכים בפני ועדת הערר: (14pt, bold, קו תחתון, מרכז) — דיון, סיור, השלמות טיעון
|
||||||
|
התכניות החלות על המקרקעין: (אופציונלי, 14pt, bold, קו תחתון, מרכז)
|
||||||
|
דיון והכרעה: (14pt, bold, קו תחתון, מרכז) — אסה רציפה ללא כותרות משנה
|
||||||
|
סיכום / סוף דבר: (14pt, bold, קו תחתון, מרכז)
|
||||||
|
חתימות: טבלה ללא גבולות, 2 טורים (יו"ר + מזכירה)
|
||||||
|
```
|
||||||
|
|
||||||
|
### דגשים
|
||||||
|
- מספור סעיפים רציף לאורך כל המסמך (לא מתאפס בין חלקים)
|
||||||
|
- מספר הסעיף bold (run נפרד), הטקסט רגיל
|
||||||
|
- ציטוטים בהזחה משני הצדדים (~1 ס"מ), פונט זהה לגוף
|
||||||
|
- תמונות ותשריטים משולבים בטקסט עם הפניה מילולית לפניהם
|
||||||
|
- "ניתנה פה אחד, [תאריך עברי], [תאריך לועזי]." לפני חתימות
|
||||||
|
- מספור עמודים: "עמוד X מתוך Y" תחתון מרכזי
|
||||||
|
- **ראה** `.claude/skills/legal-decision/SKILL.md` סעיפים 11-12 למבנה מלא ותהליך עבודה
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## עקרונות עיצוב משותפים
|
||||||
|
|
||||||
|
### כל מסמך משפטי
|
||||||
|
- **פונט**: David 12pt (ברירת מחדל), FrankRuehl לפורמלי
|
||||||
|
- **שוליים**: 2.5 ס"מ (1417 DXA) מכל הצדדים
|
||||||
|
- **יישור**: Justified (משני צדדים)
|
||||||
|
- **מרווח שורות**: 1.15 או 1.5 (לפי בית המשפט)
|
||||||
|
- **מספור עמודים**: תחתון מרכזי
|
||||||
|
- **כיוון**: RTL מלא (bidi בכל הרמות)
|
||||||
|
|
||||||
|
### כתבי בית דין (תביעה, הגנה, בקשה)
|
||||||
|
- Header עם שם בית המשפט ומספר תיק
|
||||||
|
- צדדים בפורמט סטנדרטי עם "-נגד-"
|
||||||
|
- מספור סעיפים רציף (לא מתאפס בכל חלק)
|
||||||
|
- Footer עם מספר עמוד
|
||||||
|
|
||||||
|
### הסכמים חוזיים
|
||||||
|
- "הואילים" לפני הסעיפים
|
||||||
|
- "ולראיה באו הצדדים על החתום" לפני חתימות
|
||||||
|
- חתימות בשני טורים
|
||||||
261
skill-legal-docx/scripts/create-legal-doc.js
Normal file
261
skill-legal-docx/scripts/create-legal-doc.js
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* create-legal-doc.js — תבנית בסיסית למסמך משפטי בעברית
|
||||||
|
*
|
||||||
|
* שימוש: העתק לתיקיית העבודה, ערוך את CONTENT, הרץ עם node.
|
||||||
|
*
|
||||||
|
* הסקריפט כולל את כל הגדרות ה-RTL הנדרשות ב-5 רמות:
|
||||||
|
* 1. Document defaults (styles)
|
||||||
|
* 2. Section properties (bidi: true)
|
||||||
|
* 3. Per-paragraph (bidirectional + alignment)
|
||||||
|
* 4. Per-run (rightToLeft + font)
|
||||||
|
* 5. Numbering (alignment: START, not RIGHT!)
|
||||||
|
*
|
||||||
|
* שינוי פונט: החלף "David" ב-"FrankRuehl" או "Miriam"
|
||||||
|
* שינוי שוליים: שנה MARGIN_CM
|
||||||
|
*
|
||||||
|
* v3.0 — תיקון באג: AlignmentType.START במקום RIGHT במספור
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const { Document, Packer, Paragraph, TextRun, Header, Footer,
|
||||||
|
AlignmentType, HeadingLevel, PageNumber, LevelFormat,
|
||||||
|
Table, TableRow, TableCell, WidthType, BorderStyle,
|
||||||
|
LineRuleType } = require('docx');
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
// CONFIGURATION — שנה כאן
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
const FONT = "David";
|
||||||
|
const FONT_SIZE = 24; // half-points (24 = 12pt)
|
||||||
|
const HEADING1_SIZE = 32; // 16pt
|
||||||
|
const HEADING2_SIZE = 28; // 14pt
|
||||||
|
const MARGIN_CM = 2.5;
|
||||||
|
const MARGIN_DXA = Math.round(MARGIN_CM / 2.54 * 1440);
|
||||||
|
const OUTPUT_FILE = "legal-document.docx";
|
||||||
|
|
||||||
|
const HEADER_TEXT = ""; // שם המשרד — השאר ריק אם לא צריך
|
||||||
|
const FOOTER_CONFIDENTIAL = "";
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
// HELPERS — פונקציות עזר
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
|
||||||
|
// TextRun עם RTL
|
||||||
|
const rtlRun = (text, opts = {}) => new TextRun({
|
||||||
|
text,
|
||||||
|
...opts,
|
||||||
|
font: opts.font || FONT,
|
||||||
|
size: opts.size || FONT_SIZE,
|
||||||
|
rightToLeft: true, // ← חובה! תמיד אחרון — לא ניתן לדריסה
|
||||||
|
});
|
||||||
|
|
||||||
|
// Paragraph עם RTL
|
||||||
|
const rtlPara = (children, opts = {}) => new Paragraph({
|
||||||
|
bidirectional: true, // ← חובה!
|
||||||
|
alignment: opts.alignment || AlignmentType.BOTH, // ✅ BOTH, לא JUSTIFIED
|
||||||
|
spacing: opts.spacing,
|
||||||
|
children: Array.isArray(children) ? children : [children],
|
||||||
|
...(opts.heading ? { heading: opts.heading } : {}),
|
||||||
|
...(opts.numbering ? { numbering: opts.numbering } : {}),
|
||||||
|
});
|
||||||
|
|
||||||
|
// כותרת ראשית
|
||||||
|
const heading1 = (text) => rtlPara(
|
||||||
|
rtlRun(text, { bold: true, size: HEADING1_SIZE }),
|
||||||
|
{ heading: HeadingLevel.HEADING_1, alignment: AlignmentType.CENTER }
|
||||||
|
);
|
||||||
|
|
||||||
|
// כותרת משנה
|
||||||
|
const heading2 = (text) => rtlPara(
|
||||||
|
rtlRun(text, { bold: true, size: HEADING2_SIZE }),
|
||||||
|
{ heading: HeadingLevel.HEADING_2, alignment: AlignmentType.START } // ✅ START
|
||||||
|
);
|
||||||
|
|
||||||
|
// רווח
|
||||||
|
const spacer = (after = 200) => rtlPara(rtlRun(""), { spacing: { after } });
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
// CONTENT — ערוך כאן את תוכן המסמך
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
|
||||||
|
const CONTENT = [
|
||||||
|
// כותרת
|
||||||
|
heading1("הסכם שירותים משפטיים"),
|
||||||
|
|
||||||
|
// תאריך
|
||||||
|
rtlPara(rtlRun("נערך ונחתם בתל אביב ביום ___________"), { spacing: { after: 200 } }),
|
||||||
|
|
||||||
|
// צדדים
|
||||||
|
heading2("בין הצדדים"),
|
||||||
|
|
||||||
|
rtlPara([
|
||||||
|
rtlRun("מצד אחד: ", { bold: true }),
|
||||||
|
rtlRun('[שם], ח.פ./ת.ז. [מספר], מ[כתובת] (להלן: "'),
|
||||||
|
rtlRun("המזמין", { bold: true }),
|
||||||
|
rtlRun('")'),
|
||||||
|
], { spacing: { after: 120 } }),
|
||||||
|
|
||||||
|
rtlPara([
|
||||||
|
rtlRun("מצד שני: ", { bold: true }),
|
||||||
|
rtlRun('[שם], ח.פ./ת.ז. [מספר], מ[כתובת] (להלן: "'),
|
||||||
|
rtlRun("הספק", { bold: true }),
|
||||||
|
rtlRun('")'),
|
||||||
|
], { spacing: { after: 200 } }),
|
||||||
|
|
||||||
|
// הואילים
|
||||||
|
heading2("הואיל:"),
|
||||||
|
rtlPara(rtlRun("1. והואיל ו[תנאי ראשון];"), { spacing: { after: 120 } }),
|
||||||
|
rtlPara(rtlRun("2. והואיל ו[תנאי שני];"), { spacing: { after: 120 } }),
|
||||||
|
rtlPara(rtlRun("3. והואיל והצדדים מעוניינים להסדיר את תנאי ההתקשרות ביניהם;"),
|
||||||
|
{ spacing: { after: 200 } }),
|
||||||
|
|
||||||
|
// מעבר
|
||||||
|
rtlPara(rtlRun("לפיכך הוסכם, הותנה והוצהר בין הצדדים כדלקמן:", { bold: true }),
|
||||||
|
{ alignment: AlignmentType.CENTER, spacing: { before: 200, after: 200 } }),
|
||||||
|
|
||||||
|
// סעיפים
|
||||||
|
heading2("1. היקף השירותים"),
|
||||||
|
rtlPara(rtlRun("1.1 [תוכן הסעיף]"), { spacing: { after: 120 } }),
|
||||||
|
rtlPara(rtlRun("1.2 [תוכן הסעיף]"), { spacing: { after: 120 } }),
|
||||||
|
|
||||||
|
heading2("2. התמורה"),
|
||||||
|
rtlPara(rtlRun("2.1 [תוכן הסעיף]"), { spacing: { after: 120 } }),
|
||||||
|
|
||||||
|
// חתימות
|
||||||
|
rtlPara(rtlRun("ולראיה באו הצדדים על החתום:", { bold: true }),
|
||||||
|
{ alignment: AlignmentType.CENTER, spacing: { before: 600, after: 400 } }),
|
||||||
|
|
||||||
|
// טבלת חתימות
|
||||||
|
new Table({
|
||||||
|
visuallyRightToLeft: true, // ✅ קריטי!
|
||||||
|
width: { size: 9072, type: WidthType.DXA },
|
||||||
|
columnWidths: [4536, 4536],
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
borders: {
|
||||||
|
top: { style: BorderStyle.NONE },
|
||||||
|
bottom: { style: BorderStyle.NONE },
|
||||||
|
left: { style: BorderStyle.NONE },
|
||||||
|
right: { style: BorderStyle.NONE }
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
rtlPara(rtlRun("________________________"), { alignment: AlignmentType.CENTER }),
|
||||||
|
rtlPara(rtlRun("המזמין"), { alignment: AlignmentType.CENTER })
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
borders: {
|
||||||
|
top: { style: BorderStyle.NONE },
|
||||||
|
bottom: { style: BorderStyle.NONE },
|
||||||
|
left: { style: BorderStyle.NONE },
|
||||||
|
right: { style: BorderStyle.NONE }
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
rtlPara(rtlRun("________________________"), { alignment: AlignmentType.CENTER }),
|
||||||
|
rtlPara(rtlRun("הספק"), { alignment: AlignmentType.CENTER })
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
// DOCUMENT GENERATION — לא לשנות (אלא אם יודע מה עושים)
|
||||||
|
// ═══════════════════════════════════════════════
|
||||||
|
|
||||||
|
const doc = new Document({
|
||||||
|
// רמה 1: Document defaults
|
||||||
|
styles: {
|
||||||
|
default: {
|
||||||
|
document: {
|
||||||
|
run: { font: FONT, size: FONT_SIZE, rightToLeft: true },
|
||||||
|
paragraph: { bidirectional: true, alignment: AlignmentType.BOTH }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
paragraphStyles: [
|
||||||
|
{
|
||||||
|
id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal",
|
||||||
|
quickFormat: true,
|
||||||
|
run: { size: HEADING1_SIZE, bold: true, font: FONT, rightToLeft: true },
|
||||||
|
paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0,
|
||||||
|
bidirectional: true, alignment: AlignmentType.CENTER }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal",
|
||||||
|
quickFormat: true,
|
||||||
|
run: { size: HEADING2_SIZE, bold: true, font: FONT, rightToLeft: true },
|
||||||
|
paragraph: { spacing: { before: 200, after: 200 }, outlineLevel: 1,
|
||||||
|
bidirectional: true, alignment: AlignmentType.START } // ✅ START
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// מספור סעיפים
|
||||||
|
numbering: {
|
||||||
|
config: [{
|
||||||
|
reference: "legal-clauses",
|
||||||
|
levels: [
|
||||||
|
{
|
||||||
|
level: 0,
|
||||||
|
format: LevelFormat.DECIMAL,
|
||||||
|
text: "%1.",
|
||||||
|
alignment: AlignmentType.START, // ✅ START — לא RIGHT!
|
||||||
|
suffix: "tab",
|
||||||
|
style: { paragraph: { indent: { left: 720, hanging: 360 } } }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
level: 1,
|
||||||
|
format: LevelFormat.DECIMAL,
|
||||||
|
text: "%1.%2",
|
||||||
|
alignment: AlignmentType.START, // ✅ START — לא RIGHT!
|
||||||
|
suffix: "tab",
|
||||||
|
style: { paragraph: { indent: { left: 1440, hanging: 500 } } }
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
sections: [{
|
||||||
|
// רמה 2: Section properties
|
||||||
|
properties: {
|
||||||
|
page: {
|
||||||
|
size: { width: 11906, height: 16838 }, // A4
|
||||||
|
margin: { top: MARGIN_DXA, right: MARGIN_DXA, bottom: MARGIN_DXA, left: MARGIN_DXA }
|
||||||
|
},
|
||||||
|
bidi: true, // ← חובה!
|
||||||
|
},
|
||||||
|
headers: HEADER_TEXT ? {
|
||||||
|
default: new Header({
|
||||||
|
children: [rtlPara(rtlRun(HEADER_TEXT, { bold: true, size: 20 }),
|
||||||
|
{ alignment: AlignmentType.CENTER })]
|
||||||
|
})
|
||||||
|
} : undefined,
|
||||||
|
footers: {
|
||||||
|
default: new Footer({
|
||||||
|
children: [new Paragraph({
|
||||||
|
bidirectional: true,
|
||||||
|
alignment: AlignmentType.CENTER,
|
||||||
|
children: [
|
||||||
|
rtlRun("עמוד ", { size: 18 }),
|
||||||
|
new TextRun({ children: [PageNumber.CURRENT], font: FONT, size: 18 }),
|
||||||
|
...(FOOTER_CONFIDENTIAL ? [rtlRun(` | ${FOOTER_CONFIDENTIAL}`, { size: 18 })] : []),
|
||||||
|
]
|
||||||
|
})]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
children: CONTENT
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
Packer.toBuffer(doc).then(buffer => {
|
||||||
|
fs.writeFileSync(OUTPUT_FILE, buffer);
|
||||||
|
console.log(`✅ ${OUTPUT_FILE} created successfully`);
|
||||||
|
console.log(` Font: ${FONT} ${FONT_SIZE/2}pt`);
|
||||||
|
console.log(` Margins: ${MARGIN_CM}cm (${MARGIN_DXA} DXA)`);
|
||||||
|
console.log(` Size: ${(buffer.length / 1024).toFixed(1)} KB`);
|
||||||
|
console.log(` RTL: bidi + bidirectional + rightToLeft ✓`);
|
||||||
|
console.log(` Alignment: START/END (not LEFT/RIGHT) ✓`);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user