{ "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" }, { "id": 83, "title": "Phase 1 — Project setup (legal-ai UI rewrite)", "description": "הקמת scaffold של Next.js עם TypeScript + Tailwind v4 + App Router ב-web-ui/. התקנת כל התלויות: @tanstack/react-query, @tanstack/react-table, react-hook-form, @hookform/resolvers, zod, lucide-react, react-dropzone, openapi-typescript. העברת design-system.css tokens (navy/gold/parchment, Heebo) ל-Tailwind theme דרך @theme ו-CSS variables. הגדרת RTL עברית עם Heebo via next/font/google. בניית AppShell עם navy header + gold rule + nav.", "status": "done", "dependencies": [], "priority": "high", "details": "**השלמות (2026-04-11):**\n\n✅ **Scaffold:** Next.js 16.2.3 (חדש יותר מ-v15 שתוכנן), React 19.2.4, Tailwind v4, Turbopack.\n\n✅ **תלויות מותקנות** (`web-ui/package.json:11-21`):\n- @tanstack/react-query ^5.97.0\n- @tanstack/react-table ^8.21.3\n- react-hook-form ^7.72.1 + @hookform/resolvers ^5.2.2\n- zod ^4.3.6\n- lucide-react ^1.8.0\n- react-dropzone ^15.0.0\n- openapi-typescript ^7.13.0 (devDep)\n\n✅ **Design tokens** (`web-ui/src/app/globals.css:10-107`): Tailwind v4 @theme עם כל הצבעים (navy, cream, parchment, gold, ink, status colors), radii, shadows, fonts, dark mode preserved.\n\n✅ **RTL Hebrew** (`web-ui/src/app/layout.tsx:5-10, 23`): Heebo עם hebrew+latin subsets, `lang=\"he\" dir=\"rtl\"` on html.\n\n✅ **AppShell** (`web-ui/src/components/app-shell.tsx:29-70`): Navy header עם gold border-b-3, RTL nav, parchment body.\n\n✅ **Home page placeholder** (`web-ui/src/app/page.tsx`).\n\n✅ **Build:** `npm run build` עובר ב-3.8s, 0 errors, static.\n\n**נותר:** אישור ויזואלי של המשתמש עם `npm run dev`.\n\n**תוכנית מלאה:** `~/.claude/plans/joyful-marinating-sutton.md`", "testStrategy": "1. `cd web-ui && npm run dev` — פתיחה ב-http://localhost:3000\n2. וידוא ויזואלי: Header navy עם gold rule, RTL rendering, פונט Heebo טעון\n3. השוואה ל-legal-ai.nautilus.marcusgroup.org — אותו מראה header\n4. בדיקת dark mode (toggle class על html)\n5. אישור סופי מהמשתמש", "subtasks": [ { "id": 1, "title": "יצירת Next.js 16 scaffold עם TypeScript + Tailwind v4 + App Router", "description": "הרצת create-next-app ב-web-ui/ עם App Router, TypeScript, Tailwind v4, ESLint", "dependencies": [], "details": "Next.js 16.2.3 (חדש יותר מ-v15), React 19.2.4, Tailwind v4, Turbopack. קבצים: web-ui/package.json, tsconfig.json, next.config.ts", "status": "done", "testStrategy": "npm run build succeeds", "parentId": "undefined" }, { "id": 2, "title": "התקנת כל התלויות הנדרשות", "description": "npm install של @tanstack/react-query, @tanstack/react-table, react-hook-form, @hookform/resolvers, zod, lucide-react, react-dropzone, openapi-typescript", "dependencies": [ 1 ], "details": "ראה web-ui/package.json:11-21 לגרסאות המותקנות. כולל openapi-typescript כ-devDep לשלב 2.", "status": "done", "testStrategy": "npm ls shows all packages", "parentId": "undefined" }, { "id": 3, "title": "העברת design tokens ל-Tailwind v4 @theme", "description": "פורט מלא של design-system.css ל-globals.css עם Tailwind v4 @theme syntax", "dependencies": [ 1 ], "details": "web-ui/src/app/globals.css:10-107 כולל כל הצבעים (navy, cream, parchment, gold, ink), status colors, radii, shadows, fonts, dark mode. CSS variables עובדים עם Tailwind classes.", "status": "done", "testStrategy": "Tailwind classes like bg-navy, text-gold work correctly", "parentId": "undefined" }, { "id": 4, "title": "הגדרת RTL Hebrew עם Heebo font", "description": "next/font/google Heebo עם hebrew+latin, lang=he dir=rtl על html", "dependencies": [ 1 ], "details": "web-ui/src/app/layout.tsx:5-10 — Heebo עם weights 300-900, display swap. שורה 23: html lang=he dir=rtl.", "status": "done", "testStrategy": "Page renders RTL, Heebo font loaded", "parentId": "undefined" }, { "id": 5, "title": "בניית AppShell component עם navy header + gold rule", "description": "רכיב shell עם header navy, gold border, RTL nav, parchment body", "dependencies": [ 3, 4 ], "details": "web-ui/src/components/app-shell.tsx:29-70 — Header עם bg-navy, border-b-3 border-gold, nav links (בית, העלאת מסמכים, אימון סגנון, מיומנויות, אבחון), main content area עם max-w-1400px.", "status": "done", "testStrategy": "Visual match to current header", "parentId": "undefined" }, { "id": 6, "title": "יצירת דף בית placeholder", "description": "דף page.tsx עם AppShell ו-placeholder content", "dependencies": [ 5 ], "details": "web-ui/src/app/page.tsx:1-27 — דף בית עם כותרת 'עוזר משפטי', תיאור המערכת, gold gradient divider, כרטיס סטטוס.", "status": "done", "testStrategy": "npm run build succeeds (done: 3.8s, 0 errors)", "parentId": "undefined" }, { "id": 7, "title": "אישור ויזואלי מהמשתמש — npm run dev", "description": "הרצת dev server ואישור סופי שה-UI תואם לציפיות — header, RTL, fonts, colors", "dependencies": [ 6 ], "details": "המשתמש צריך להריץ 'cd web-ui && npm run dev' ולאשר שהכל נראה כמו legal-ai.nautilus.marcusgroup.org. בדיקת dark mode אופציונלית.", "status": "pending", "testStrategy": "User confirms visual parity with current site, RTL works, Heebo font loads", "parentId": "undefined" } ], "updatedAt": "2026-04-11T13:50:47.941Z" }, { "id": 84, "title": "Phase 2 — API client + generated TypeScript types", "description": "Add npm run api:types script that runs openapi-typescript against FastAPI's /openapi.json -> src/lib/api/types.ts. Build lib/api/client.ts (typed fetch wrapper + TanStack Query client with default retry/staleTime). Create one lib/api/.ts per endpoint category (cases, upload, compose, training, system), each exporting typed useQuery/useMutation hooks. Build lib/sse.ts as EventSource -> Query cache adapter. Plan: ~/.claude/plans/joyful-marinating-sutton.md.", "details": "See full plan at ~/.claude/plans/joyful-marinating-sutton.md for architecture, critical files, risks, and open questions. This task is phase 2 of 7 in the legal-ai UI rewrite from vanilla HTML to Next.js 15 + shadcn/ui.", "testStrategy": "useCases() hook returns typed array from live FastAPI. TypeScript errors if backend endpoint changes without frontend update.", "status": "done", "dependencies": [ "83" ], "priority": "high", "subtasks": [], "updatedAt": "2026-04-11T15:51:34.020Z" }, { "id": 85, "title": "Phase 3 — Core read views (home, case detail, compose)", "description": "Port the 3 highest-value screens. Use the frontend-design Claude Code skill to generate layout + composition, passing design tokens (navy/gold/parchment, Heebo), editorial voice, and typed API hooks. Use shadcn Card/Badge/Tabs/Sheet/ScrollArea as primitives. Port the custom donut chart into component. TanStack Query staleTime:5000 for case detail replaces manual 5s polling. Plan: ~/.claude/plans/joyful-marinating-sutton.md.", "details": "See full plan at ~/.claude/plans/joyful-marinating-sutton.md for architecture, critical files, risks, and open questions. This task is phase 3 of 7 in the legal-ai UI rewrite from vanilla HTML to Next.js 15 + shadcn/ui.", "testStrategy": "Users can browse case list, open a case detail, and view the compose screen with live data from FastAPI. All 3 screens visually match the existing legal-ai identity.", "status": "done", "dependencies": [ "84" ], "priority": "high", "subtasks": [], "updatedAt": "2026-04-11T16:09:18.006Z" }, { "id": 86, "title": "Phase 4 — Forms and wizards (new case, upload, inline edits)", "description": "Port new case wizard, bulk upload, inline forms on case detail. Use react-hook-form + zod with schemas in lib/schemas/.ts. Build shared from shadcn Card + Progress + Tabs. Build (react-dropzone + shadcn). Integrate SSE for upload progress via lib/sse.ts. Plan: ~/.claude/plans/joyful-marinating-sutton.md.", "details": "See full plan at ~/.claude/plans/joyful-marinating-sutton.md for architecture, critical files, risks, and open questions. This task is phase 4 of 7 in the legal-ai UI rewrite from vanilla HTML to Next.js 15 + shadcn/ui.", "testStrategy": "Users can create a new case via the multi-step wizard (case appears in Gitea + Paperclip), upload documents with live SSE progress, and edit case fields inline.", "status": "done", "dependencies": [ "85" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-04-11T16:25:55.569Z" }, { "id": 87, "title": "Phase 5 — Secondary screens (compare, training, style report, skills, diagnostics)", "description": "Port the remaining 5 views. Use TanStack Table for training corpus and diagnostics lists. Port any charts/visualizations from current index.html. Plan: ~/.claude/plans/joyful-marinating-sutton.md.", "details": "See full plan at ~/.claude/plans/joyful-marinating-sutton.md for architecture, critical files, risks, and open questions. This task is phase 5 of 7 in the legal-ai UI rewrite from vanilla HTML to Next.js 15 + shadcn/ui.", "testStrategy": "Feature parity with old legal-ai/web/static/index.html across all 10 views.", "status": "done", "dependencies": [ "86" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-04-11T17:33:42.976Z" }, { "id": 88, "title": "Phase 6 — Polish & testing", "description": "Accessibility pass (keyboard nav, aria-label on RTL icons, focus trap in modals). Error boundaries + toast notifications for failed mutations. Loading states for every query. Cross-browser smoke test (Chrome, Firefox, Safari) + mobile device test. Document E2E smoke test script in web-ui/README.md. Plan: ~/.claude/plans/joyful-marinating-sutton.md.", "details": "See full plan at ~/.claude/plans/joyful-marinating-sutton.md for architecture, critical files, risks, and open questions. This task is phase 6 of 7 in the legal-ai UI rewrite from vanilla HTML to Next.js 15 + shadcn/ui.", "testStrategy": "Lighthouse a11y score > 90, all loading states visible, errors show toasts, README has documented smoke test steps.", "status": "done", "dependencies": [ "87" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-04-11T17:44:08.337Z" }, { "id": 89, "title": "Phase 7 — Deployment & cutover", "description": "Add multi-stage Dockerfile for web-ui/ (Node 20 build -> nginx serve of out/). Add web-ui as new app in Coolify project pointing to staging subdomain legal-ai-next.nautilus.marcusgroup.org. Run full smoke test against staging. Cutover: DNS flip legal-ai.nautilus.marcusgroup.org to new app, keep old on rollback subdomain for 1 week. Follow-up PR removes legal-ai/web/static/index.html + design-system.css once stable. Plan: ~/.claude/plans/joyful-marinating-sutton.md.", "details": "See full plan at ~/.claude/plans/joyful-marinating-sutton.md for architecture, critical files, risks, and open questions. This task is phase 7 of 7 in the legal-ai UI rewrite from vanilla HTML to Next.js 15 + shadcn/ui.", "testStrategy": "legal-ai.nautilus.marcusgroup.org serves the new Next.js UI in production. Old UI accessible on rollback subdomain for 7 days. SSE streams working through Coolify proxy.", "status": "pending", "dependencies": [ "88" ], "priority": "medium", "subtasks": [] }, { "id": 90, "title": "Phase 4.5 — Practice area integration", "description": "Add practice_area + appeal_subtype to the wizard, types, schema, case header, and cases table. Gap identified after backend commit 26d09d6 (multi-tenant axis) — new Next.js UI has zero integration while vanilla UI is fully wired. Plan: ~/.claude/plans/woolly-cooking-graham.md", "details": "", "testStrategy": "", "status": "done", "dependencies": [ "86" ], "priority": "high", "subtasks": [], "updatedAt": "2026-04-11T17:15:57.831Z" }, { "id": 91, "title": "Precedent attachment in compose screen", "description": "Add case_precedents table + FastAPI endpoints + MCP tools + Next.js compose UI for attaching legal precedents (quote + citation + optional archived PDF) to threshold_claims/issues and to the case as a whole. Plan: ~/.claude/plans/woolly-cooking-graham.md", "details": "", "testStrategy": "", "status": "done", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-04-11T19:20:56.040Z" }, { "id": 92, "title": "הסרת אפליקציית Flask הישנה מ-Coolify", "description": "ארכיון והסרה של אפליקציית Flask הישנה מ-Coolify, וכיוון DNS כך ש-legal-ai.nautilus.marcusgroup.org יצביע על אפליקציית Next.js", "details": "## פסאודו-קוד:\n```\n1. גיבוי הגדרות Flask מ-Coolify לפני מחיקה\n2. ב-Coolify dashboard:\n - מצא את הקונטיינר legal-ai-flask (או שם דומה)\n - עצור את הקונטיינר\n - צור snapshot או ארכיון של ההגדרות\n - מחק את הקונטיינר והסרוויס\n3. ב-DNS (Cloudflare/Coolify proxy):\n - שנה את legal-ai.nautilus.marcusgroup.org\n - הפנה ל-IP/service של legal-ai-next (Next.js app)\n4. ב-Next.js app (Coolify):\n - הוסף domain alias: legal-ai.nautilus.marcusgroup.org\n - עדכן SSL certificate\n```\n\n## קבצים מושפעים:\n- Coolify dashboard settings\n- DNS records (Cloudflare או ספק אחר)\n- Coolify proxy/Traefik configuration\n\n## הערות:\n- **אין שינויים בקוד** - רק הגדרות תשתית\n- ודא שה-Next.js app עובד עם שני הדומיינים במקביל לפני הסרת Flask\n- שמור לוגים מ-Flask לפני מחיקה למקרה של rollback", "testStrategy": "## בדיקות:\n1. **לפני הסרה**: ודא ש-legal-ai-next.nautilus.marcusgroup.org עובד תקין\n2. **אחרי שינוי DNS**: \n - `curl -I https://legal-ai.nautilus.marcusgroup.org` - צריך להחזיר 200\n - בדוק SSL certificate תקין\n3. **בדיקת UI**: \n - פתח את legal-ai.nautilus.marcusgroup.org בדפדפן\n - ודא שזה אותו UI כמו legal-ai-next\n4. **בדיקת API**: \n - `curl https://legal-ai.nautilus.marcusgroup.org/api/cases`\n - ודא שמחזיר נתונים", "priority": "high", "dependencies": [], "status": "pending", "subtasks": [] }, { "id": 93, "title": "עדכון סטטוסים ב-WorkflowTimeline וב-status-badge", "description": "עדכון רשימת הסטטוסים בממשק לפי ה-pipeline החדש: new → proofread → documents_ready → analyst_verified → research_complete → outcome_set → direction_approved → drafted → qa_passed → exported, כולל qa_failed ו-blocked", "details": "## קבצים לעדכון:\n1. `web-ui/src/lib/api/cases.ts` - עדכון type CaseStatus\n2. `web-ui/src/components/cases/status-badge.tsx` - תוויות ועיצוב\n3. `web-ui/src/components/cases/workflow-timeline.tsx` - שלבי pipeline\n\n## פסאודו-קוד:\n\n### 1. cases.ts - עדכון הטיפוס:\n```typescript\nexport type CaseStatus =\n | \"new\"\n | \"proofread\"\n | \"documents_ready\"\n | \"analyst_verified\"\n | \"research_complete\"\n | \"outcome_set\"\n | \"direction_approved\"\n | \"drafted\"\n | \"qa_passed\"\n | \"exported\"\n | \"qa_failed\"\n | \"blocked\";\n```\n\n### 2. status-badge.tsx - תוויות עבריות וצבעים:\n```typescript\nconst STATUS_LABELS: Record = {\n new: \"חדש\",\n proofread: \"הוגה\",\n documents_ready: \"מסמכים מוכנים\",\n analyst_verified: \"אומת ע״י אנליסט\",\n research_complete: \"מחקר הושלם\",\n outcome_set: \"תוצאה נקבעה\",\n direction_approved: \"כיוון אושר\",\n drafted: \"טיוטה\",\n qa_passed: \"עבר QA\",\n exported: \"יוצא\",\n qa_failed: \"נכשל QA\",\n blocked: \"חסום\",\n};\n\nconst STATUS_TONE: Record = {\n new: \"bg-rule-soft text-ink-muted border-rule\",\n proofread: \"bg-info-bg text-info border-info/30\",\n documents_ready: \"bg-info-bg text-info border-info/40\",\n analyst_verified: \"bg-info-bg text-info border-info/50\",\n research_complete: \"bg-gold-wash text-gold-deep border-gold/40\",\n outcome_set: \"bg-gold-wash text-gold-deep border-gold/50\",\n direction_approved: \"bg-gold-wash text-gold-deep border-gold/60\",\n drafted: \"bg-warn-bg text-warn border-warn/40\",\n qa_passed: \"bg-success-bg text-success border-success/40\",\n exported: \"bg-success-bg text-success border-success/60\",\n qa_failed: \"bg-danger-bg text-danger border-danger/40\",\n blocked: \"bg-danger-bg text-danger border-danger/50\",\n};\n```\n\n### 3. workflow-timeline.tsx - קבוצות שלבים חדשות:\n```typescript\nconst PHASES: Phase[] = [\n { key: \"intake\", label: \"קליטה ועיבוד\", statuses: [\"new\", \"proofread\", \"documents_ready\"] },\n { key: \"analysis\", label: \"ניתוח\", statuses: [\"analyst_verified\", \"research_complete\"] },\n { key: \"direction\", label: \"קביעת כיוון\", statuses: [\"outcome_set\", \"direction_approved\"] },\n { key: \"writing\", label: \"כתיבה וביקורת\", statuses: [\"drafted\", \"qa_passed\"] },\n { key: \"done\", label: \"סגירה\", statuses: [\"exported\"] },\n];\n\n// טיפול בסטטוסי שגיאה (qa_failed, blocked) - הצגה מיוחדת\nif (status === \"qa_failed\" || status === \"blocked\") {\n // הצג באדום עם אייקון אזהרה\n}\n```", "testStrategy": "## בדיקות:\n1. **Unit Tests** (אם קיימים):\n - ודא שכל הסטטוסים מופו נכון\n - בדוק שאין סטטוס חסר ב-STATUS_LABELS ו-STATUS_TONE\n\n2. **Visual Testing**:\n - צור/ערוך תיק ידנית ב-DB לכל סטטוס\n - ודא שהתווית מוצגת בעברית נכונה\n - ודא שהצבע מתאים (כחול לעיבוד, זהב לניתוח, ירוק להצלחה, אדום לשגיאה)\n\n3. **WorkflowTimeline**:\n - ודא שהשלב הנוכחי מודגש בצהוב\n - ודא ששלבים שהושלמו מסומנים בירוק\n - ודא שסטטוסי שגיאה (qa_failed, blocked) מוצגים עם אינדיקציה ויזואלית מיוחדת", "priority": "high", "dependencies": [], "status": "pending", "subtasks": [] }, { "id": 94, "title": "דף/קומפוננטה להצגת כל הסטטוסים עם הסברים", "description": "יצירת דף /statuses או מודל עזרה שמסביר את כל הסטטוסים האפשריים - מה כל סטטוס אומר, איזה agent קובע אותו, ומה קורה אחר כך", "details": "## אפשרויות מימוש:\n\n### אפשרות A: Popover tooltip בתוך WorkflowTimeline (מומלץ)\n```typescript\n// web-ui/src/components/cases/workflow-timeline.tsx\n// הוסף אייקון (?) ליד הכותרת שפותח popover\n\nconst STATUS_INFO: Record = {\n new: {\n description: \"תיק נוצר, ממתין להעלאת מסמכים\",\n agent: \"משתמש\",\n nextStep: \"העלאת מסמכים → proofread\"\n },\n proofread: {\n description: \"מסמכים הועלו, עוברים הגהה אוטומטית\",\n agent: \"Proofread Agent\",\n nextStep: \"הגהה הושלמה → documents_ready\"\n },\n documents_ready: {\n description: \"מסמכים מוכנים לניתוח\",\n agent: \"Document Processor\",\n nextStep: \"בדיקת אנליסט → analyst_verified\"\n },\n analyst_verified: {\n description: \"אנליסט אימת את חילוץ הטענות\",\n agent: \"Analyst Agent\",\n nextStep: \"מחקר → research_complete\"\n },\n research_complete: {\n description: \"מחקר משפטי הושלם, פסיקה זוהתה\",\n agent: \"Research Agent\",\n nextStep: \"קביעת תוצאה → outcome_set\"\n },\n outcome_set: {\n description: \"דפנה קבעה את התוצאה (דחייה/קבלה)\",\n agent: \"משתמש (דפנה)\",\n nextStep: \"אישור כיוון → direction_approved\"\n },\n direction_approved: {\n description: \"כיוון ההחלטה אושר, מוכן לכתיבה\",\n agent: \"משתמש\",\n nextStep: \"כתיבה → drafted\"\n },\n drafted: {\n description: \"טיוטת החלטה נכתבה\",\n agent: \"Writing Agent\",\n nextStep: \"בדיקת QA → qa_passed\"\n },\n qa_passed: {\n description: \"טיוטה עברה בדיקת איכות\",\n agent: \"QA Agent\",\n nextStep: \"ייצוא → exported\"\n },\n exported: {\n description: \"ההחלטה יוצאה כ-DOCX\",\n agent: \"Export Service\",\n nextStep: \"הושלם\"\n },\n qa_failed: {\n description: \"טיוטה נכשלה בבדיקת QA\",\n agent: \"QA Agent\",\n nextStep: \"חזרה לכתיבה → drafted\"\n },\n blocked: {\n description: \"תיק חסום - דורש התערבות ידנית\",\n agent: \"מערכת\",\n nextStep: \"טיפול ידני\"\n },\n};\n```\n\n### אפשרות B: דף /statuses נפרד\n```typescript\n// web-ui/src/app/statuses/page.tsx\n// דף עצמאי עם טבלה של כל הסטטוסים\n```\n\n## המלצה: אפשרות A - פשוטה יותר ומשתלבת ב-UX הקיים", "testStrategy": "## בדיקות:\n1. **UI Testing**:\n - לחיצה על אייקון העזרה פותחת popover/tooltip\n - כל סטטוס מציג: תיאור, agent, שלב הבא\n - סגירת ה-popover עובדת (לחיצה מחוץ/Escape)\n\n2. **Accessibility**:\n - ה-popover נגיש למקלדת (Tab, Enter, Escape)\n - aria-label מתאים\n - RTL מוצג נכון\n\n3. **Content Review**:\n - כל ההסברים בעברית תקנית\n - הזרימה בין סטטוסים מובנת", "priority": "medium", "dependencies": [ 93 ], "status": "pending", "subtasks": [] }, { "id": 95, "title": "עריכה ידנית של סטטוס בדף התיק", "description": "הוספת dropdown או מודל בדף התיק לשינוי סטטוס ידני, לטיפול במקרים שבהם ה-pipeline נתקע או צריך reset", "details": "## מיקום: בתוך הכרטיס של WorkflowTimeline (בצד ימין של דף התיק)\n\n## פסאודו-קוד:\n\n### 1. קומפוננטת StatusEditor:\n```typescript\n// web-ui/src/components/cases/status-editor.tsx\n\nimport { Select } from \"@/components/ui/select\";\nimport { Button } from \"@/components/ui/button\";\nimport { useUpdateCase } from \"@/lib/api/cases\";\nimport { toast } from \"sonner\";\n\nexport function StatusEditor({ caseNumber, currentStatus }: Props) {\n const [selectedStatus, setSelectedStatus] = useState(currentStatus);\n const updateCase = useUpdateCase(caseNumber);\n\n const handleSave = async () => {\n if (selectedStatus === currentStatus) return;\n \n try {\n await updateCase.mutateAsync({ status: selectedStatus });\n toast.success(\"סטטוס עודכן בהצלחה\");\n } catch (error) {\n toast.error(\"שגיאה בעדכון הסטטוס\");\n }\n };\n\n return (\n
\n \n \n
\n );\n}\n```\n\n### 2. שילוב בדף התיק:\n```typescript\n// web-ui/src/app/cases/[caseNumber]/page.tsx\n// בתוך הכרטיס של WorkflowTimeline\n\n\n \n

שלב בתהליך

\n \n {data && }\n
\n
\n```\n\n### 3. עדכון ה-API (אם נדרש):\nה-`useUpdateCase` כבר תומך ב-status field לפי `caseUpdateSchema`.", "testStrategy": "## בדיקות:\n1. **Functionality**:\n - בחירת סטטוס חדש מה-dropdown\n - לחיצה על \"עדכן\" שולחת PUT request ל-API\n - הסטטוס מתעדכן ב-UI אחרי הצלחה\n - toast הודעה מוצגת\n\n2. **Edge Cases**:\n - לחיצה על \"עדכן\" כשהסטטוס לא השתנה - כפתור disabled\n - טיפול בשגיאת API - הודעת שגיאה\n - כפתור disabled בזמן loading\n\n3. **Integration**:\n - ה-WorkflowTimeline מתעדכן מיד אחרי שינוי סטטוס\n - ה-StatusBadge בכותרת מתעדכן\n - הנתונים מסונכרנים עם ה-DB", "priority": "medium", "dependencies": [ 93 ], "status": "pending", "subtasks": [] }, { "id": 96, "title": "מיזוג כפתורי פעולות לכרטיס הסקירה הראשי", "description": "העברת הכפתורים 'פתח בעורך ההחלטה' ו'עריכת פרטי תיק' מהלשונית 'פעולות' לכרטיס הכותרת העליון, והסרת הלשונית המיותרת", "details": "## קבצים לעדכון:\n- `web-ui/src/app/cases/[caseNumber]/page.tsx`\n- `web-ui/src/components/cases/case-header.tsx`\n\n## פסאודו-קוד:\n\n### 1. עדכון CaseHeader להוספת כפתורי פעולה:\n```typescript\n// web-ui/src/components/cases/case-header.tsx\n\nimport Link from \"next/link\";\nimport { Button } from \"@/components/ui/button\";\nimport { CaseEditDialog } from \"@/components/cases/case-edit-dialog\";\n\nexport function CaseHeader({ data }: { data?: CaseDetail }) {\n return (\n \n \n {/* ... breadcrumb קיים ... */}\n \n
\n
\n {/* ... כותרת וסטטוס קיימים ... */}\n
\n\n {/* כפתורי פעולה - חדש */}\n
\n \n {data && }\n
\n
\n\n {/* ... תאריכים קיימים ... */}\n
\n
\n );\n}\n```\n\n### 2. הסרת לשונית \"פעולות\" מדף התיק:\n```typescript\n// web-ui/src/app/cases/[caseNumber]/page.tsx\n\n// הסר את TabsTrigger value=\"actions\"\n\n סקירה\n מסמכים (...)\n {/* הוסר: פעולות */}\n\n\n// הסר את TabsContent value=\"actions\"\n// הקוד הבא נמחק:\n// \n//
\n// \n// {data && }\n//
\n//
\n```\n\n### 3. עדכון CaseHeader props:\n```typescript\n// צריך להעביר caseNumber ל-CaseHeader אם עדיין לא קיים\n\n```", "testStrategy": "## בדיקות:\n1. **Visual**:\n - כפתורי הפעולה מופיעים בכרטיס העליון\n - הכפתורים מיושרים ימינה (RTL)\n - responsive - נגלשים נכון במסכים קטנים\n\n2. **Functionality**:\n - \"פתח בעורך ההחלטה\" מנווט ל-/cases/{caseNumber}/compose\n - \"עריכת פרטי תיק\" פותח את ה-CaseEditDialog\n - ה-dialog עובד כרגיל\n\n3. **Removal**:\n - לשונית \"פעולות\" לא מופיעה יותר ב-Tabs\n - אין שגיאות קונסול\n - ניווט ל-#actions לא עובד (ולא אמור)\n\n4. **Regression**:\n - לשוניות \"סקירה\" ו\"מסמכים\" עובדות כרגיל\n - שאר הדף לא נפגע", "priority": "low", "dependencies": [], "status": "pending", "subtasks": [] } ], "metadata": { "created": "2026-04-13T14:20:54.888Z", "updated": "2026-04-13T14:20:54.888Z", "description": "Tasks for master context" } }, "legal-ai": { "tasks": [ { "id": "1", "title": "V7 schema: precedent library + halachot tables", "description": "Add SCHEMA_V7_SQL to db.py: extend case_law with source_kind/document_id/extraction_status/halacha_extraction_status/practice_area (CHECK constraint for 3 areas)/appeal_subtype/headnote. Create precedent_chunks table with vector(1024). Create halachot table with vector(1024), review_status, practice_areas array. Add IVFFlat indexes. Register V7 in init_schema().", "details": "", "testStrategy": "", "status": "done", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-05-03T08:17:59.928Z" }, { "id": "2", "title": "Chunker: add court ruling section patterns", "description": "Extend services/chunker.py SECTION_PATTERNS with 4 patterns for external court rulings: פסק דין→ruling, נימוקים→legal_analysis, סוף דבר→conclusion, העובדות הצריכות לעניין→facts", "details": "", "testStrategy": "", "status": "done", "dependencies": [ "1" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-03T08:18:33.239Z" }, { "id": "3", "title": "Service: halacha_extractor.py", "description": "New service that runs claude_session.query_json() over chunks where section_type IN (legal_analysis, ruling, conclusion). Concurrency=3, retry=1. Validates supporting_quote with substring check after Hebrew normalization. All halachot inserted with review_status=pending_review (no auto-publish). Embeds rule_statement+reasoning_summary via Voyage. Uses Hebrew prompt from plan appendix א. Idempotent on case_law_id.", "details": "", "testStrategy": "", "status": "done", "dependencies": [ "1", "2" ], "priority": "high", "subtasks": [], "updatedAt": "2026-05-03T08:22:12.392Z" }, { "id": "4", "title": "Service: precedent_library.py orchestrator", "description": "New service with ingest_precedent(file_path, citation, court, decision_date, source_type, precedent_level, practice_area, appeal_subtype, subject_tags, case_name, task_id) that orchestrates: extract_text → proofread → INSERT case_law (source_kind=external_upload) → chunk → embed → store precedent_chunks → halacha_extractor.extract → embed halachot → publish progress. Plus delete_precedent (cascading), list_precedents(filters), get_precedent(id), search_library(query, filters, limit) merging chunks+approved-halachot ranked.", "details": "", "testStrategy": "", "status": "done", "dependencies": [ "1", "2", "3" ], "priority": "high", "subtasks": [], "updatedAt": "2026-05-03T08:23:33.235Z" }, { "id": "5", "title": "MCP tools: precedent_library + halacha_review", "description": "Create mcp-server/src/legal_mcp/tools/precedent_library.py with tools: precedent_library_upload, precedent_library_list, precedent_library_get, precedent_library_delete, precedent_extract_halachot, search_precedent_library (semantic, returns merged halachot+chunks), halacha_review (approve/reject). Register all in server.py. Do NOT modify existing precedent_search_library or search_decisions.", "details": "", "testStrategy": "", "status": "done", "dependencies": [ "4" ], "priority": "high", "subtasks": [], "updatedAt": "2026-05-03T08:25:07.439Z" }, { "id": "6", "title": "FastAPI endpoints under /api/precedent-library", "description": "Add to web/app.py: POST /api/precedent-library/upload (multipart), GET /api/precedent-library (filters), GET /api/precedent-library/{id}, PATCH /api/precedent-library/{id}, DELETE /api/precedent-library/{id}, POST /api/precedent-library/{id}/extract-halachot, GET /api/precedent-library/search, GET /api/halachot?status=pending_review, PATCH /api/halachot/{id}, GET /api/precedent-library/stats. Reuse existing /api/progress/{task_id} SSE.", "details": "", "testStrategy": "", "status": "done", "dependencies": [ "5" ], "priority": "high", "subtasks": [], "updatedAt": "2026-05-03T08:26:21.860Z" }, { "id": "7", "title": "UI: /precedents page with 4 tabs", "description": "New web-ui/src/app/precedents/page.tsx with tabs: Library (table+filters+upload), Semantic Search, Pending Review (PRIMARY - bulk approval UX with J/K nav, A/R/E shortcuts, side-by-side rule_statement vs supporting_quote, badge count), Stats. New components in web-ui/src/components/precedents/: precedent-upload-sheet, precedent-list-table, precedent-search-panel, precedent-detail-panel, halacha-review-card. New hooks in web-ui/src/lib/api/precedent-library.ts. Add nav link in app-shell.tsx.", "details": "", "testStrategy": "", "status": "done", "dependencies": [ "6" ], "priority": "high", "subtasks": [], "updatedAt": "2026-05-03T08:34:00.548Z" }, { "id": "8", "title": "Agent integration: legal-writer + 3 others", "description": "Update .claude/agents/legal-writer.md (PRIMARY) — add mcp__legal-ai__search_precedent_library to tools and prompt section explaining when to use it for CREAC rule+explanation in block י. Update legal-researcher.md, legal-analyst.md, legal-ceo.md, legal-qa.md to add the tool. Update skills/decision/SKILL.md with section explaining the 3 corpora (style_corpus, case_precedents, precedent_library).", "details": "", "testStrategy": "", "status": "done", "dependencies": [ "5" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-03T08:36:24.711Z" }, { "id": "9", "title": "Service: precedent_metadata_extractor.py", "description": "LLM-based extractor that auto-fills empty metadata fields after upload: short case_name (e.g. 'אהרון ברק' from long citation), summary (2-3 sentences), headnote, key_quote, subject_tags array, appeal_subtype. Reuses claude_session.query_json. Returns dict; caller decides which empty fields to merge (never overrides user values).", "details": "", "testStrategy": "", "status": "done", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-05-03T10:19:15.105Z" }, { "id": "10", "title": "Halacha extractor: dual mode (binding vs persuasive)", "description": "Update halacha_extractor.py prompt to branch on is_binding: binding=true → strict halacha extraction (current). binding=false → extract reasoning principles, applications of established halachot, persuasive conclusions. New rule_types: 'application' (applying known rule to facts), 'persuasive' (committee's reasoning citable as authority). Schema unchanged (rule_type already TEXT).", "details": "", "testStrategy": "", "status": "done", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-05-03T10:19:15.117Z" }, { "id": "11", "title": "Ingest pipeline: add metadata extraction stage", "description": "In services/precedent_library.py:ingest_precedent, after halacha extraction, run metadata_extractor and PATCH the case_law row with auto-filled fields (only those left empty by user). Publish progress 'extracting_metadata'.", "details": "", "testStrategy": "", "status": "done", "dependencies": [ "9" ], "priority": "high", "subtasks": [], "updatedAt": "2026-05-03T10:19:15.128Z" }, { "id": "12", "title": "UI: precedent edit sheet", "description": "Add edit button to library-list-panel rows that opens a Sheet with all editable fields (case_name, citation, court, date, practice_area, appeal_subtype, subject_tags, summary, headnote, key_quote, source_type, precedent_level, is_binding). Pre-populated from current values. Submit calls PATCH /api/precedent-library/{id} via useUpdatePrecedent. After save, invalidate library list query.", "details": "", "testStrategy": "", "status": "done", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-05-03T10:19:15.134Z" }, { "id": "13", "title": "Test on 403-17: fix metadata + re-extract", "description": "After deploy: PATCH 403-17 to set case_name='ערר 403/17', then trigger precedent_extract_halachot to test the dual-mode extraction on a non-binding committee decision.", "details": "", "testStrategy": "", "status": "done", "dependencies": [ "9", "10", "11", "12" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-26T10:38:07.071897Z" }, { "id": "14", "title": "Upgrade: speed up halacha+metadata extraction", "description": "Halacha extraction on long rulings is slow (5-15 min for typical court ruling, 30-50 min for a 207-chunk appeals committee decision). Root cause: each chunk spawns a separate `claude -p` subprocess (5-10 sec startup overhead each), Hebrew prompts on cold cache run 30-90 sec, and there's no prompt-cache sharing between chunks. Acceleration options to evaluate later when speed becomes a real blocker.\n\nOptions (each can be combined):\n\n1. Concurrency 3 -> 6 in halacha_extractor.CHUNK_CONCURRENCY. ~2x faster wall-clock. Cost: 6x ~300MB RSS = 1.8GB peak — verify on Nautilus headroom.\n\n2. Larger chunks 12K -> 18-25K chars (CHUNK_TARGET_CHARS in claims_extractor.py / halacha_extractor.py). Fewer waves. Risk: timeout on cold cache (currently 1800s ceiling), and may degrade extraction precision for very long sections.\n\n3. Anthropic SDK direct with 5-min ephemeral prompt caching on the static instruction prefix (already wired the parameter as system= in claude_session.query). Estimated 5-10x faster because cache reads are ~10% of cold cost. Costs ~$0.30-2 per long ruling on Sonnet 4.6. Chair previously rejected this path for ALL traffic ('we work only with claude session'). Compromise: SDK only for the precedent-library corpus build (static, one-time), claude session for live decision drafting (interactive, frequent).\n\n4. Two-tier prompt: a short 'classification' pass with claude -p deciding which chunks contain halachot, then deep extraction only on positive chunks. Could cut total LLM time by 40-60% on rulings with lots of factual chapters.\n\n5. Already implemented (Apr 3, 2026): skip non-extractable sections — only run on chunks where section_type IN (legal_analysis, ruling, conclusion); fallback to all chunks when chunker labels nothing. So that win is already banked.\n\nRe-evaluate when: a chair drops a 200K+ char ruling into the queue and the wait becomes painful, OR when the precedent-library has 50+ pending entries and bulk processing matters.", "details": "נסקר 2026-06-03 — אין blocker נוכחי. הרצתי reindex ל-73 תקדימים + חילוצים מרובים בלי שמהירות הייתה כאב. YAGNI: לא מבצעים אופטימיזציה מוקדמת. נשאר deferred עם trigger ברור: פסק-דין 200K+ תווים שתוקע את התור, או 50+ פריטים ממתינים. ה-win הזול (concurrency 3→6) דורש אימות headroom של 1.8GB RSS ב-Nautilus לפני — לא עכשיו.", "testStrategy": "", "status": "deferred", "dependencies": [], "priority": "low", "subtasks": [], "updatedAt": "2026-06-03T00:00:00.000Z" }, { "id": "15", "title": "Multimodal — כיוונון MULTIMODAL_TEXT_WEIGHT (A/B) + הכרעה על backfill", "description": "נסגר 2026-06-03 לאחר A/B אובייקטיבי על gold-set (86 שאילתות, eval_retrieval.py). הנחת היסוד התיישנה: multimodal כבר ברירת-מחדל בייצור (110 מסמכים מוטמעים אוטומטית בהעלאה), לא רק 2 תיקי A/B. ממצא: ה-weight 0.5 (ברירת-מחדל) היה mis-tuned — צד-התמונה כבד מדי וחתך recall של precedent_library (0.971→0.885). sweep 0.5→0.75: במשקל 0.65 multimodal מנצח את text-only בכל מדד ובכל corpus (R@5 0.994 מול 0.989; nDCG@5 0.960 מול 0.944; MRR 0.954 מול 0.936; precedent_library R@5 0.983, internal_decisions nDCG 0.978). כיסוי: 28/79 מסמכי gold-set מוטמעים multimodal (35% — אות אמיתי). דפנה אישרה.", "details": "בוצע: MULTIMODAL_TEXT_WEIGHT=0.65 הוגדר ב-Coolify env של legal-ai (runtime) + redeploy; baseline (data/eval/baseline.json) עודכן לקונפיג 0.65. ה-backfill היקר ל-140 התיקים ה-legacy *לא* בוצע — אין הצדקת-אחזור לשאלות טקסט, וערך ה-image-answer לא נבדק. מומר ל-#80 (מותנה). ראיות: data/eval/eval-report-20260603T08*.md, project_multimodal_stage_c.", "testStrategy": "", "status": "done", "dependencies": [], "priority": "medium", "subtasks": [], "updatedAt": "2026-06-03T00:00:00.000Z" }, { "id": "16", "title": "[Paperclip Gap 1] runtime_config ריק — חסרים graceSec/cooldownSec/maxConcurrentRuns", "description": "runtime_config = '{}' לכל 14 הסוכנים. מסתבר שעיקר ההגדרות החשובות (timeoutSec=3600, maxTurnsPerRun=500) יושבות ב-adapter_config ולא ב-runtime_config — אז המצב פחות חמור. אבל graceSec/cooldownSec/maxConcurrentRuns עדיין חסרים.", "details": "תיקון לניתוח המקורי שגוי בעקבות בדיקה ב-DB:\n\nמה שכן יש לנו (ב-adapter_config, לא runtime_config):\n- timeoutSec: 3600 (לכל הסוכנים)\n- maxTurnsPerRun: 500 (לכל הסוכנים)\n- model + effort=high (לכל הסוכנים)\n- paperclipSkillSync.desiredSkills (5/7 סוכנים — חסר אצל הגהת מסמכים ומנתח משפטי)\n\nמה שבאמת חסר ב-runtime_config:\n- heartbeat.graceSec — זמן grace לפני SIGKILL אחרי timeout. מהקוד: Math.max(1, graceSec)*1000. אם לא מוגדר → 1ms grace. בעיה אם הסוכן נחתך באמצע commit ל-DB.\n- heartbeat.cooldownSec — default ביצירה חדשה: 10. אצלנו לא מוגדר.\n- heartbeat.maxConcurrentRuns — default מ-AGENT_DEFAULT_MAX_CONCURRENT_RUNS (כנראה 1).\n- heartbeat.wakeOnDemand — default=true בקוד. אצלנו לא מוגדר אבל בפועל true.\n- heartbeat.enabled — default=false (timer off). זה הרצוי אצלנו.\n\nפעולה (Phase 1):\n1. עדכון runtime_config של כל סוכן: { heartbeat: { graceSec: 60, cooldownSec: 10, maxConcurrentRuns: 1, wakeOnDemand: true } }\n2. בעיקר graceSec — בלעדיו commit באמצע יכול להיכשל\n3. cooldownSec=10 (זהה לdefault ב-UI ליצירת agent חדש)\n\nהשפעה: minimal — רוב המקרים עובדים עם defaults. graceSec הוא העיקר.", "testStrategy": "1. SELECT name, runtime_config->'heartbeat' FROM agents → לראות שכל סוכן מקבל graceSec/cooldownSec/maxConcurrentRuns/wakeOnDemand.\n2. בדיקה: סוכן ארוך נחתך ב-timeout — לבדוק שהיתה הזדמנות לציין graceful shutdown ב-30-60 שניות", "status": "done", "dependencies": [], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-04T07:47:02.008Z" }, { "id": "17", "title": "[Paperclip Gap 2] תקציבים = 0 לכל הסוכנים — אין budget enforcement", "description": "budget_monthly_cents = 0 ו-spent_monthly_cents = 0 לכל 14 הסוכנים. Paperclip מציע cost control מובנה — אנחנו מתעלמים.", "details": "ממצא: SELECT name, budget_monthly_cents, spent_monthly_cents FROM agents → הכל אפס.\n\nסיכון: לולאה חבויה יכולה לשרוף מאות $. אין auto-pause ב-80% spend (דפוס ש-CEO HEARTBEAT הרשמי מצפה לו).\n\nפעולה (Phase 3):\n1. מדידה: כמה כל סוכן באמת מוציא בחודש כיום (דרך לוגי claude-code, או Anthropic dashboard).\n2. הגדרת budget_monthly_cents סביר לכל סוכן (כותב Opus ≫ מנתח Sonnet).\n3. בדיקה שהמנגנון מפסיק כשמגיעים ל-100%.\n\nשאלה לחיים לפני ביצוע: באיזו רזולוציה למדוד? לפי Anthropic invoice, או לפי טוקנים בלוגים של claude_session?", "testStrategy": "בדיקה ידנית: להגדיר budget קטן לסוכן ניסוי (1 cent), לעורר אותו על משימה, לוודא שמתעורר ונחסם. לעקוב ב-spent_monthly_cents.", "status": "done", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-05-04T10:18:08.046Z" }, { "id": "18", "title": "[Paperclip Gap 3] חסר X-Paperclip-Run-Id header בקריאות API", "description": "ה-skill הרשמי קובע: 'You MUST include -H X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID on ALL API requests that modify issues'. ב-HEARTBEAT.md שלנו אין זכר לכך.", "details": "ממצא: grep -n 'X-Paperclip-Run-Id' .claude/agents/ → 0 hits. כל curl ב-checkout/comments/PATCH issues — בלי הheader.\n\nסיכון: audit trail שבור. שאלה 'איזו ריצה שינתה את ה-issue X?' אין לה תשובה ב-DB.\n\nפעולה (Phase 1):\n1. עדכון .claude/agents/HEARTBEAT.md — דוגמאות ה-curl יכללו את הheader\n2. עדכון 6 קבצי הסוכנים (legal-ceo.md, legal-analyst.md, legal-researcher.md, legal-writer.md, legal-qa.md, legal-exporter.md) — כל מקום שיש curl POST/PATCH\n3. בדיקה שיש env var $PAPERCLIP_RUN_ID זמין בכל heartbeat", "testStrategy": "בלוגי Paperclip (heartbeat_runs טבלה) לראות שהפעולות שלנו מקושרות ל-run_id. SELECT * FROM activity_log WHERE run_id IS NOT NULL ORDER BY created_at DESC LIMIT 10.", "status": "done", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-05-04T08:49:44.646Z" }, { "id": "19", "title": "[Paperclip Gap 4] לא משתמשים ב-/api/issues/{id}/interactions לאישורים", "description": "Paperclip מציע API מובנה לאישור/שאלות (request_confirmation, ask_user_questions, suggest_tasks) עם idempotency keys ו-auto-wake. אנחנו עדיין כותבים 'חיים, מה לעשות?' כ-comment חופשי.", "details": "סוגי interaction:\n- ask_user_questions — שאלות מובנות\n- request_confirmation — yes/no עם idempotency key (confirmation:{issueId}:plan:{revisionId})\n- suggest_tasks — הצעת עץ משימות\n- continuationPolicy: wake_assignee — wake אוטומטי על מענה\n- supersedeOnUserComment: true — בטל אם חיים עונה\n\nסיכון: אין UI מובנה לחיים (כפתורים), רק טקסט. אם הסוכן מתעורר פעמיים — שתי שאלות זהות.\n\nפעולה (Phase 2):\n1. בlegal-ceo.md — להחליף 'אם חיים לא הגדיר outcome: שאל בcomment' ב-request_confirmation\n2. בbrainstorm_directions — suggest_tasks במקום רשימת bullet\n3. בlegal-qa.md — request_confirmation לאישור export\n\nשאלה לחיים: האם תרצה לראות UI חדש או להישאר ב-Markdown comments?", "testStrategy": "יצירת request_confirmation מסוכן ניסוי, בדיקה ב-UI שמופיעים כפתורי אישור/דחייה, בדיקה שהסוכן מתעורר אוטומטית עם PAPERCLIP_APPROVAL_ID env.", "status": "done", "dependencies": [ "16", "17", "18" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-04T11:18:59.050Z" }, { "id": "20", "title": "[Paperclip Gap 5] לא משתמשים ב-PAPERCLIP_WAKE_PAYLOAD_JSON fast-path", "description": "בwake שמכוון ל-issue ספציפי, ה-env var מכיל כבר issue summary + comments חדשים דחוסים. ה-skill הרשמי אומר 'skip Steps 1-4 entirely'. שלנו תמיד fetcher גם ה-API.", "details": "ממצא: HEARTBEAT.md סעיפים 2-2c תמיד פונים ל-API גם אם ה-payload כבר מכיל את הכל.\n\nתועלת: חיסכון 3-4 קריאות API לכל ריצה. בwakeups תכופים (CEO על comments) — חיסכון ניכר.\n\nפעולה (Phase 2):\n1. הוספה ל-HEARTBEAT.md בראש הסעיפים: 'אם $PAPERCLIP_WAKE_PAYLOAD_JSON קיים — קרא אותו ראשון. רק אם fallbackFetchNeeded:true או חסר הקשר רחב — fetch'.\n2. דוגמה לפענוח JSON: jq עם key paths\n3. בדיקה איזה wake reasons בכלל מקבלים payload (כנראה comment-driven בלבד)", "testStrategy": "בWakeup דרך API עם payload, לבדוק בלוגי הסוכן שאין fetch לcomments. timeit על מספר ריצות לפני/אחרי.", "status": "done", "dependencies": [ "18" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-04T09:15:46.339Z" }, { "id": "21", "title": "[Paperclip Gap 6] שאילתות psql ישירות ל-issue_attachments — שובר אבסטרקציה", "description": "HEARTBEAT.md סעיף 2c משתמש ב-psql ישיר ל-issue_attachments + assets. אם schema ישתנה (כפי שצפוי בעדכוני Paperclip) — כל הסוכנים נשברים.", "details": "ממצא: 6 קבצי סוכן + HEARTBEAT.md מכילים PGPASSWORD=paperclip psql ... FROM issue_attachments ia JOIN assets a.\n\nסיכון: breakage בעדכון Paperclip. כפילות לוגיקה (copy-paste בכל סוכן).\n\nפעולה (Phase 2):\n1. בדיקה אם קיים endpoint רשמי /api/issues/{id}/attachments (curl + grep ב-server/src/routes)\n2. אם כן — להחליף את כל ה-psql\n3. אם לא — להעביר את ה-psql למקום יחיד: helper ב-mcp-server (mcp__legal-ai__list_issue_attachments tool)\n4. אופציה ג: לפתוח issue ב-paperclipai/paperclip לבקש endpoint\n\nתלוי במחקר API.", "testStrategy": "אחרי החלפה: grep -rn 'issue_attachments' .claude/agents/ → 0 hits. בדיקה שסוכן עדיין רואה attachments בריצה.", "status": "done", "dependencies": [ "20" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-04T09:28:18.058Z" }, { "id": "22", "title": "[Paperclip Gap 7] לא משתמשים ב-/api/issues/{id}/heartbeat-context", "description": "Endpoint רשמי שמחזיר issue + ancestors + goal/project + comment cursor בקריאה אחת. אנחנו עושים 3 קריאות נפרדות.", "details": "ה-skill הרשמי: 'Prefer GET /api/issues/{issueId}/heartbeat-context first. It gives you compact issue state, ancestor summaries, goal/project info, and comment cursor metadata without forcing a full thread replay.'\n\nשלנו: HEARTBEAT.md סעיפים 2 + 2b → שלוש קריאות (inbox-lite, issue, comments).\n\nפעולה (Phase 2):\n1. הוספת endpoint כצעד 6 ב-HEARTBEAT.md לפני 'Do the work'\n2. הסרת קריאות מיותרות שכבר ב-context\n3. שמירת comment cursor (after={last-seen-id}) לקריאות עוקבות", "testStrategy": "בדיקה שהendpoint מחזיר את כל המידע הדרוש. ספירת קריאות API לפני/אחרי בריצה אמיתית.", "status": "done", "dependencies": [ "20" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-04T09:28:14.247Z" }, { "id": "23", "title": "[Paperclip Gap 8+11] HEARTBEAT.md ארוך + אין שימוש ב-skills של Paperclip", "description": "HEARTBEAT.md שלנו 220 שורות (vs upstream 85). Paperclip מציע 8 skills מוכנים (paperclip, paperclip-create-agent, וכו') שאנחנו לא משתמשים באף אחד.", "details": "תיקון לניתוח: מסתבר ש-CEO + 4 סוכנים אחרים כן משתמשים ב-paperclipSkillSync עם 4 paperclip skills (paperclip, paperclip-create-agent, paperclip-create-plugin, para-memory-files). חסר אצל: הגהת מסמכים ומנתח משפטי (skills_count=0).\n\nממצא: ls skills/ ב-paperclip repo → 8 skills. שלנו: 0 skills של Paperclip בשימוש.\n\nרלוונטיים לנו:\n- paperclip — API patterns + heartbeat checklist (יכול להחליף חלק מ-HEARTBEAT.md)\n- paperclip-create-agent — אם נוסיף סוכן\n- paperclip-create-plugin — לעדכוני plugin-legal-ai\n- paperclip-converting-plans-to-tasks — יכול להחליף brainstorm_directions\n- diagnose-why-work-stopped — לתחזוקה\n\nפעולה (Phase 3):\n1. קריאת skills/paperclip/SKILL.md מלא\n2. הזרקת skill לסביבת הסוכנים (כנראה דרך CLI: paperclipai agent local-cli)\n3. שכתוב HEARTBEAT.md לפי הדפוס: project-specific only, delegation לskill הרשמי לכלל ה-API\n4. יעד: ~120 שורות ב-HEARTBEAT.md שלנו\n\nשאלה לחיים: האם להזריק skills כסימלינקים ל-symlinks קיימים, או דרך paperclipai CLI?", "testStrategy": "אחרי שכתוב: סוכן ניסוי קורא את HEARTBEAT.md + paperclip skill, מבצע heartbeat מלא בלי שגיאות. השוואת אורך לפני/אחרי.", "status": "done", "dependencies": [ "16", "17", "18", "19", "20", "21", "22" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-04T16:44:27.553Z" }, { "id": "24", "title": "[Paperclip Gap 9] לבדוק bootstrapPromptTemplate deprecated באף סוכן", "description": "מ-docs/agents-runtime.md: 'bootstrapPromptTemplate is deprecated... should be migrated to the managed instructions bundle system.' לבדוק האם adapter_config שלנו משתמש בזה.", "details": "פעולה (Phase 1):\n1. SELECT name, adapter_config->'promptTemplate' as pt, adapter_config->'bootstrapPromptTemplate' as bpt FROM agents WHERE adapter_type = 'claude_local';\n2. אם בשימוש אצל סוכן כלשהו — מיגרציה למבנה החדש\n3. ייעוד: לבדוק תיעוד managed instructions bundle ב-paperclip docs\n\nהערה: זה כנראה לא ישפיע אצלנו (אנחנו משתמשים ב-symlinks ל-AGENTS.md/HEARTBEAT.md ישירות) — אבל חובה לוודא.", "testStrategy": "SELECT הנ\"ל. אם 0 שורות מחזירות bpt לא-NULL — סגור את המשימה.", "status": "done", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-05-04T08:19:27.766Z" }, { "id": "25", "title": "[Paperclip Gap 10] סוכנים מוכפלים בין 2 חברות — אין סנכרון", "description": "14 שורות = 7 סוכנים × 2 חברות (1xxx, 8xxx). כל שינוי בהגדרות הסוכן צריך להיעשות פעמיים. אין מנגנון סנכרון או הורשה.", "details": "ממצא: SELECT name, COUNT(*) FROM agents GROUP BY name → 2 לכל אחד.\n\nסיכון: drift בין החברות. שינוי runtime_config ל-CEO של 1xxx יכול לפספס את CEO של 8xxx.\n\nפעולה (Phase 3):\n1. בדיקה: האם Paperclip תומך ב-shared agents או chainOfCommand? (לקרוא docs/companies/)\n2. אם כן — מיגרציה למבנה משותף\n3. אם לא — סקריפט סנכרון: scripts/sync_agents_across_companies.py שמעתיק כל שינוי מחברה לחברה\n\nשאלה לחיים: בעתיד אם יהיו עוד סוגי ערר (10xxx?) — להוסיף עוד חברה או להשאיר 2?", "testStrategy": "אם סקריפט: dry-run שמראה הבדלים בין 2 ה-CEOs. ואז apply ולוודא runtime_config זהה.", "status": "done", "dependencies": [ "16" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-04T09:52:14.263Z" }, { "id": "26", "title": "[Paperclip Gap 12] עדכון @paperclipai/plugin-sdk + capabilities חדשות", "description": "ה-plugin שלנו: @paperclipai/plugin-sdk@^2026.325.0, apiVersion: 1, minimumHostVersion: 2026.325.0. ה-host: 2026.428.0. ייתכן capabilities חדשות (issue.interactions.create, וכו').", "details": "פעולה (Phase 4 — אחרי שדרוג Paperclip stable):\n1. cd /home/chaim/plugin-legal-ai && npm view @paperclipai/plugin-sdk version\n2. אם חדשה: npm install @paperclipai/plugin-sdk@latest\n3. קריאת adapter-plugin.md המעודכן ב-paperclip repo\n4. בדיקה אם apiVersion: 2 קיים\n5. הוספת capabilities חדשות אם רלוונטי (בעיקר issue.interactions.create אחרי gap #4)\n6. npm run build && reinstall plugin\n\nתלוי בgap #19 (interactions API) — אם אנחנו רוצים שהplugin יוכל ליצור interactions, חייב capability חדש.", "testStrategy": "אחרי npm install: בדיקה ש-plugin עולה ב-Paperclip בלי last_error. SELECT status, last_error FROM plugins WHERE plugin_key='marcusgroup.legal-ai'.", "status": "done", "dependencies": [ "27", "19" ], "priority": "low", "subtasks": [], "updatedAt": "2026-05-26T12:19:16.180163Z" }, { "id": "27", "title": "[Paperclip Phase 4] שדרוג Paperclip לגרסה stable הבאה (לא 2026.428.0)", "description": "כרגע אנחנו על 2026.428.0 — הגרסה היציבה האחרונה. כשיופיע stable חדש (כנראה 2026.5xx.x), לבצע שדרוג מבוקר.", "details": "טריגר: npm view paperclipai dist-tags.latest מחזיר משהו ≠ 2026.428.0.\n\nפעולה:\n1. קריאת releases/v2026.5xx.x.md ב-GitHub\n2. בדיקת שינויים שעלולים להשפיע (CUSTOMIZATIONS.md סעיפים: hebrew, RTL, plugin driver, heartbeat)\n3. גיבוי: pg_dump של paperclip DB + cp -r ~/.npm/_npx/43414d9b790239bb /tmp/\n4. pm2 stop paperclip\n5. rm -rf ~/.npm/_npx/43414d9b790239bb\n6. npx paperclipai@latest run (יוריד גרסה חדשה)\n7. הרצה מחדש: ~/.paperclip/hebrew/apply-hebrew.sh && ~/.paperclip/issue-link-fix/apply-issue-link-fix.sh\n8. pm2 restart paperclip\n9. בדיקה ב-pc.nautilus.marcusgroup.org: עברית + plugin פעיל + סוכן מתעורר על comment\n\nתלוי בלי dependencies (יכול להיות מבוצע בכל עת אחרי שיש stable חדש).", "testStrategy": "אחרי שדרוג: cat ~/.npm/_npx/43414d9b790239bb/node_modules/paperclipai/package.json | grep version → גרסה חדשה. UI עברית. test wakeup על issue.", "status": "done", "dependencies": [], "priority": "low", "subtasks": [], "updatedAt": "2026-05-26T12:19:16.180163Z" }, { "id": "28", "title": "[Paperclip Auxiliary] להפעיל skill-sync ל-2 סוכנים שפיספסו", "description": "הגהת מסמכים ומנתח משפטי לא קיבלו אף פעם revision מסוג skill-sync (לעומת 5 האחרים שכן). לבצע sync.", "details": "ממצא: בדיקה ב-agent_config_revisions:\n- עוזר משפטי: 3 skill-sync revisions (יש 7 skills)\n- חוקר תקדימים: 3 (יש 5)\n- מייצא טיוטה: 5 (יש 5)\n- בודק איכות: 1 (יש 5)\n- כותב החלטה: 1 (יש 5)\n- הגהת מסמכים: 0 (יש 0) ❌\n- מנתח משפטי: 0 (יש 0) ❌\n\nאופציות:\n1. UI: agent settings → 'sync skills'\n2. API: POST /api/agents/{id}/skills-sync (לאתר)\n3. CLI: paperclipai agent skill-sync (לבדוק אם קיים)\n4. SQL ידני (לא מומלץ — דורף revision tracking)\n\nSkills להעתקה (לפי בודק איכות):\n- paperclipai/paperclip/paperclip\n- paperclipai/paperclip/paperclip-create-agent\n- paperclipai/paperclip/paperclip-create-plugin\n- paperclipai/paperclip/para-memory-files\n- (אופציונלי) local/eba6210d5a/legal-decision", "testStrategy": "SELECT name, jsonb_array_length(adapter_config->'paperclipSkillSync'->'desiredSkills') FROM agents WHERE name IN ('הגהת מסמכים', 'מנתח משפטי') → 4-5. revision חדש ב-agent_config_revisions עם source='skill-sync'.", "status": "done", "dependencies": [], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-04T09:46:32.092Z" }, { "id": "29", "title": "[legal-ai UI] מסך הגדרות סוכנים — הצגה + עריכה + שמירה", "description": "מסך אדמין ב-legal-ai UI שמציג את כל הגדרות הסוכנים (model, timeout, runtime_config, skills, budget) ומאפשר עריכה ושמירה. מונע SQL ישיר.", "details": "מטרה: ממשק אדמין מרכזי במקום שעריכה תהיה רק ב-UI של Paperclip + SQL ישיר + CUSTOMIZATIONS.md.\n\nשדות (לכל סוכן × 2 חברות):\n1. adapter_config: model, effort, timeoutSec, maxTurnsPerRun, extraArgs[], paperclipSkillSync.desiredSkills[]\n2. runtime_config.heartbeat: graceSec, cooldownSec, wakeOnDemand, maxConcurrentRuns, enabled, intervalSec\n3. budget_monthly_cents (לקראת gap #2)\n4. status / pause_reason (קריאה + כפתור pause/resume)\n\nאופציות מימוש:\nA. עמוד חדש ב-legal-ai/web-ui (Next.js 16) — קורא Paperclip DB דרך FastAPI endpoint חדש (/api/admin/paperclip-agents)\nB. קריאה ל-Paperclip API (/api/companies/{id}/agents) — REST טהור, פחות שדות זמינים\nC. iframe ל-Paperclip UI — שטחי\n\nהמלצה: A. שולט מלא + ולידציה משפטית (timeoutSec >= 1800 כי OCR).\n\nתלוי ב: gap #25 (סוכנים מוכפלים) — אם נעבור לshared, המסך יתאים.\n\nשאלות פתוחות לחיים:\n- auth: מי יכול לגשת? (כיום אין auth ב-legal-ai)\n- bulk edit ל-2 חברות יחד או נפרד?\n- חשיפת skill marketplace (להוסיף/להוריד skills) או רק קריאה?", "testStrategy": "1. עמוד עולה ב-/admin/agents בlegal-ai UI. 2. עריכת timeoutSec ושמירה → SELECT ב-DB מאמת. 3. revision חדש ב-agent_config_revisions עם source מתאים.", "status": "done", "dependencies": [ "16", "17", "25" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-04T17:29:25.686Z" }, { "id": "30", "title": "תיקון 3 baגים בקטלוג (practice_area + source_kind + upload route)", "description": "CRITICAL: 3 sub-bugs. (א) יצירת תיקים מתייגת practice_area='appeals_committee' במקום rishuy_uvniya/betterment_levy/compensation_197 לפי קידומת מספר התיק (1xxx/8xxx/9xxx) — audit + migration לכל התיקים הקיימים + תיקון נתיב היצירה. (ב) כל החלטה של ועדת ערר שהועלתה ל-case_law מסומנת כ-source_kind='external_upload' במקום 'internal_committee' — audit ל-case_law עם case_number שמתחיל ב'ערר' → reclassify + מילוי chair_name + district רטרואקטיבית. (ג) POST /api/precedent-library/upload לא מבחין — תיקון: ניתוב לפי תחילית הציטוט (ערר/ועדות ערר → internal_committee, אחרת → external_upload).", "details": "ראה תוכנית /home/chaim/.claude/plans/3-glimmering-oasis.md חלק א משימה #1. Pre-requirement: השתמש במחיקה+rerun של halachot אחרי שינוי source_kind. השתמש בpattern של internal_decisions.py (dry_run+log_action).", "testStrategy": "", "status": "done", "dependencies": [], "priority": "high", "subtasks": [ { "id": 1, "title": "Audit + migration practice_area (1xxx→rishuy_uvniya, 8xxx→betterment_levy, 9xxx→compensation_197)", "status": "done", "parentId": "undefined" }, { "id": 2, "title": "Audit + reclassify case_law source_kind external_upload → internal_committee עבור 'ערר' prefix", "status": "done", "parentId": "undefined" }, { "id": 3, "title": "Delete + re-extract halachot עבור רשומות שעברו reclassification", "status": "done", "parentId": "undefined" }, { "id": 4, "title": "תיקון נתיב יצירת תיק לתיוג practice_area נכון מההתחלה", "status": "done", "parentId": "undefined" }, { "id": 5, "title": "תיקון /api/precedent-library/upload לניתוב לפי תחילית הציטוט", "status": "done", "parentId": "undefined" }, { "id": 6, "title": "מבחני רגרסיה לכל 3 הbaגים", "status": "done", "parentId": "undefined" }, { "id": 7, "title": "תיקון MCP `case_update` + API `PUT /api/cases/{case_number}` לתמוך בעדכון practice_area + appeal_subtype", "status": "done", "details": "התגלה ב-26/05/2026: MCP tool case_update והAPI לא מקבלים את השדה practice_area, ולכן אי-אפשר לתקן תיוג שגוי דרך הממשק. נאלצתי לעדכן ידנית ב-SQL. צריך להוסיף את השדות ל-CaseUpdateRequest ב-web/app.py וב-cases_tools.case_update בmcp-server.", "parentId": "undefined" }, { "id": 8, "title": "[prevention] DB CHECK constraints: source_kind='internal_committee' ⇒ chair_name NOT NULL; cases.practice_area enum", "status": "done", "description": "מיגרציה: ALTER TABLE case_law ADD CONSTRAINT chair_required_for_internal CHECK (source_kind <> 'internal_committee' OR (chair_name IS NOT NULL AND chair_name <> '')); וכן CHECK על cases.practice_area לערכים תקינים. חייב לרוץ אחרי subtask #2 (backfill) אחרת constraint creation ייכשל.", "parentId": "undefined" }, { "id": 9, "title": "[prevention] Unify practice_area taxonomy — מיפוי או מחיקה של appeals_committee מ-practice_area.py", "status": "done", "description": "ב-mcp-server/src/legal_mcp/services/practice_area.py:21 יש PRACTICE_AREAS={appeals_committee,national_insurance,labor_law} שסותר את ה-DB constraint של case_law (rishuy_uvniya/betterment_levy/compensation_197). grep מקיף לכל caller של 'appeals_committee'; להחליף במיפוי מפורש או למחוק.", "parentId": "undefined" } ], "updatedAt": "2026-05-26T08:35:22.762800Z" }, { "id": "31", "title": "מיצוי chair_name + district בהעלאת ועדת ערר", "description": "תוספת לטופס + חילוץ אוטומטי מהציטוט/text הפסיקה. רטרואקטיבי לכל הרשומות הקיימות עם source_kind='internal_committee' שהשדות בהן ריקים.", "details": "ראה תוכנית /home/chaim/.claude/plans/3-glimmering-oasis.md חלק א משימה #2. תלוי במשימה #30 (sub-bug ב).", "testStrategy": "", "status": "done", "dependencies": [ "30" ], "priority": "high", "subtasks": [ { "id": 1, "title": "Backfill chair_name + district לכל 7 הרשומות החסרות (LLM extraction)", "status": "done", "description": "psql query: SELECT id, case_number FROM case_law WHERE source_kind='internal_committee' AND (chair_name IS NULL OR chair_name=''); לכל אחת — חילוץ ע\"י precedent_metadata_extractor.extract_and_apply.", "parentId": "undefined" }, { "id": 2, "title": "[prevention] Validation: chair_name+district required ב-internal_decisions_upload (API+MCP)", "status": "done", "description": "ב-web/app.py:4607-4680 כיום chair_name/district = Form(\"\") (default ריק). שנה ל-required עם validation שדוחה ריק כשsource_kind='internal_committee'. הוסף enum של 6 ערכי district (ירושלים/מרכז/תל אביב/צפון/דרום/ארצי).", "parentId": "undefined" }, { "id": 3, "title": "[prevention] UI dropdown ל-district בטופס העלאת החלטות ועדה (web-ui)", "status": "done", "description": "במקום free-text — Select של 6 הערכים. גם בטופס חיפוש (search_internal_decisions).", "parentId": "undefined" } ], "updatedAt": "2026-05-26T08:35:22.762800Z" }, { "id": "32", "title": "UI — דף עריכת פסיקה ייפתח רחב-במרכז (לא צר-בצד)", "description": "חוסר נוחות בעריכה. שינוי ה-Dialog/Sheet ל-Modal רחב מרכזי. רלוונטי גם להוספת שדות chair_name + district מהמשימה #31.", "details": "ראה תוכנית /home/chaim/.claude/plans/3-glimmering-oasis.md חלק א משימה #3.", "testStrategy": "", "status": "done", "dependencies": [], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-26T10:38:07.071897Z" }, { "id": "33", "title": "UI — הסתרת עמודת 'שם' (case_name) בדף רשימת פסיקה", "description": "רוב הערכים זהים למספר התיק. להסתיר את העמודה ב-UI, לשמור עמודה ב-DB לשימוש עתידי.", "details": "ראה תוכנית /home/chaim/.claude/plans/3-glimmering-oasis.md חלק א משימה #4.", "testStrategy": "", "status": "done", "dependencies": [], "priority": "low", "subtasks": [], "updatedAt": "2026-05-26T11:27:09.039154Z" }, { "id": "34", "title": "חילוץ ציטוטי-פנים מהחלטות דפנה (internal_committee + ירושלים)", "description": "פאטרן: 'ונפנה להחלטות של ועדת ערר זו...', 'כפי שקבעתי בערר X', 'בדומה לעמדתי בהחלטה Y'. חילוץ אוטומטי + שמירה ב-precedent_internal_citations table שיאפשר ל-search_internal_decisions להחזיר גם את הפסיקה המוזכרת.", "details": "ראה תוכנית /home/chaim/.claude/plans/3-glimmering-oasis.md חלק א משימה #5. תלוי במשימה #30 (sub-bug ב) ובמשימה #31.", "testStrategy": "", "status": "done", "dependencies": [ "30", "31" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-26T10:38:07.071897Z" }, { "id": "35", "title": "דף/דוח 'פסיקה חסרה בקורפוס' — פיצ'ר מלא", "description": "טבלת DB missing_precedents (id, citation, case_name, cited_in_case_id, cited_in_document_id, cited_by_party, legal_topic, legal_issue, claim_quote, status, linked_case_law_id, closed_at, created_at), API endpoints (POST/GET/upload/PATCH), MCP tools (missing_precedent_create/list/close), דף Next.js /missing-precedents, הוק אוטומטי במחקר ע\"י legal-researcher.", "details": "ראה תוכנית /home/chaim/.claude/plans/3-glimmering-oasis.md חלק א משימה #6.", "testStrategy": "", "status": "done", "dependencies": [], "priority": "high", "subtasks": [ { "id": 1, "title": "Migration + model missing_precedents", "status": "done", "parentId": "undefined" }, { "id": 2, "title": "API endpoints POST/GET/upload/PATCH /api/missing-precedents", "status": "done", "parentId": "undefined" }, { "id": 3, "title": "MCP tools missing_precedent_create/list/close", "status": "done", "parentId": "undefined" }, { "id": 4, "title": "Next.js page /missing-precedents עם list + detail + upload form", "status": "done", "parentId": "undefined" }, { "id": 5, "title": "Auto-creation hook במחקר (legal-researcher יוצר רשומה כשמזהה ציטוט חסר)", "status": "done", "parentId": "undefined" }, { "id": 6, "title": "Webhook עדכון לפלאגין Paperclip + Comment לחיים", "status": "done", "parentId": "undefined" } ], "updatedAt": "2026-05-26T08:35:22.762800Z" }, { "id": "36", "title": "כינוס פרופוזיציות לטיעונים משפטיים אמיתיים (de-dup/aggregation)", "description": "extract_claims מחזיר ~60 פרופוזיציות לתיק, צריך לאגד ל-~10 טיעונים משפטיים אמיתיים. טבלה חדשה legal_arguments + טבלת קישור legal_argument_propositions (M:M ל-case_claims). LLM aggregation job (Hermes/DeepSeek). API + MCP + UI display שמציג 'X טיעונים משפטיים' במקום 'Y טענות'.", "details": "ראה תוכנית /home/chaim/.claude/plans/3-glimmering-oasis.md חלק א משימה #7.", "testStrategy": "", "status": "done", "dependencies": [], "priority": "high", "subtasks": [ { "id": 1, "title": "Migration + models legal_arguments + legal_argument_propositions", "status": "done", "parentId": "undefined" }, { "id": 2, "title": "LLM aggregation job (Hermes/DeepSeek profile)", "status": "done", "parentId": "undefined" }, { "id": 3, "title": "API + MCP tool aggregate_claims_to_arguments", "status": "done", "parentId": "undefined" }, { "id": 4, "title": "UI display update — case detail page מציג טיעונים אמיתיים", "status": "done", "parentId": "undefined" }, { "id": 5, "title": "Backfill לכל התיקים הקיימים", "status": "done", "parentId": "undefined" } ], "updatedAt": "2026-05-26T08:35:22.762800Z" }, { "id": "37", "title": "הפרדת תתי-סוגי בל\"מ לפי practice_area", "description": "3 ערכי appeal_subtype חדשים: extension_request_building_permit (1xxx, ס'152 - 30 ימים), extension_request_betterment_levy (8xxx, ס'14 לתוספת ג' - 45 ימים), extension_request_compensation (9xxx, ס'198(ד) - 30 ימים). 3 templates מתודולוגיים נפרדים. אוטו-זיהוי מהsubject. UI badge + filter.", "details": "ראה תוכנית /home/chaim/.claude/plans/3-glimmering-oasis.md חלק א משימה #8. Pre-requirement: עדכון mcp-server/src/legal_mcp/services/practice_area.py APPEALS_COMMITTEE_SUBTYPES + עדכון web/paperclip_client.py mapping appeal_subtype → company.", "testStrategy": "", "status": "done", "dependencies": [], "priority": "high", "subtasks": [ { "id": 1, "title": "הוספת 3 ערכי enum ל-practice_area.py APPEALS_COMMITTEE_SUBTYPES", "status": "done", "parentId": "undefined" }, { "id": 2, "title": "כתיבת 3 templates מתודולוגיים ב-docs/methodology/extension-request-{type}.md", "status": "done", "parentId": "undefined" }, { "id": 3, "title": "אוטו-זיהוי בקוד יצירת תיק (subject='בקשה להארכת מועד' → קביעת subtype לפי practice_area)", "status": "done", "parentId": "undefined" }, { "id": 4, "title": "UI badge + filter ייעודי לבל\"מ", "status": "done", "parentId": "undefined" }, { "id": 5, "title": "עדכון web/paperclip_client.py mapping ל-company עבור 3 הערכים החדשים", "status": "done", "parentId": "undefined" } ], "updatedAt": "2026-05-26T08:35:22.762800Z" }, { "id": "38", "title": "שדרוג סוכני Paperclip להכרת השינויים מ-#30-#37", "description": "עדכון 7 הגדרות סוכן (CEO/analyst/researcher/writer/QA/proofreader/exporter) + HEARTBEAT.md לזיהוי המבנים החדשים. בלי זה כל הפיצ'רים נשארים זמינים אבל הסוכנים לא יודעים להשתמש בהם. כולל הוספת research_complete כ-valid case_status.", "details": "ראה תוכנית /home/chaim/.claude/plans/3-glimmering-oasis.md חלק א משימה #9. תלוי במשימות #30-#37.", "testStrategy": "", "status": "done", "dependencies": [ "30", "31", "34", "35", "36", "37" ], "priority": "high", "subtasks": [ { "id": 1, "title": "עדכון .claude/agents/legal-ceo.md — routing + statuses + wake reasons", "status": "done", "parentId": "undefined" }, { "id": 2, "title": "עדכון .claude/agents/legal-analyst.md — practice_area, legal_arguments, בל\"מ detection", "status": "done", "parentId": "undefined" }, { "id": 3, "title": "עדכון .claude/agents/legal-researcher.md — 2 layers, missing_precedents, citations, בל\"מ templates", "status": "done", "parentId": "undefined" }, { "id": 4, "title": "עדכון .claude/agents/legal-writer.md — legal_arguments view, בל\"מ templates", "status": "done", "parentId": "undefined" }, { "id": 5, "title": "עדכון .claude/agents/legal-qa.md — בל\"מ-aware validation", "status": "done", "parentId": "undefined" }, { "id": 6, "title": "עדכון .claude/agents/HEARTBEAT.md — כללי routing משותפים + research_complete status", "status": "done", "parentId": "undefined" }, { "id": 7, "title": "סנכרון לכל החברות CMPA mirror — sync_agents_across_companies.py", "status": "done", "parentId": "undefined" }, { "id": 8, "title": "[alignment] researcher docs: דרישה מפורשת שכל 'ערר' → internal_decision_upload, לעולם לא precedent_library_upload", "status": "done", "description": "בלגל-researcher.md: דוגמת קוד מפורשת + flowchart החלטה: לפי תחילית הציטוט. הסבר על השלילה של precedent_library_upload כשמדובר ב-ערר. תלוי במשימה #39 (MCP tool חדש).", "parentId": "undefined" }, { "id": 9, "title": "[alignment] analyst docs: הסבר על 2 taxonomies של practice_area + מתי משתמשים בכל אחת", "status": "done", "description": "בלגל-analyst.md: טבלה ברורה — practice_area (case_law) vs practice_area (cases). מתי להעביר rishuy_uvniya ומתי appeals_committee. אחרי משימה #30.9 (taxonomy unification) — סביר שזה ייפשט.", "parentId": "undefined" }, { "id": 10, "title": "[alignment] writer docs: הבחנה בין source_kind בציטוט (binding vs persuasive)", "status": "done", "description": "בלגל-writer.md: 'החלטת ועדת ערר אחרת ⇒ עקביות אופקית, לא הלכה מחייבת'. 'פס\"ד עליון/מנהלי ⇒ סמכותי בינדינג'. דוגמאות פרזיולוגיה מ-skills/decision/SKILL.md.", "parentId": "undefined" } ], "updatedAt": "2026-05-26T07:41:47.880478Z" }, { "id": "39", "title": "[ROOT CAUSE] MCP tool חדש: internal_decision_upload", "description": "הוספת @mcp.tool() עם chair_name+district חובה ו-source_kind='internal_committee' אוטומטי. סוגר את ה-root cause של Bug (ב) ב-#30. בלעדיו 44 רשומות חדשות יחזרו כ-external_upload תוך חודש.", "details": "מיקום: mcp-server/src/legal_mcp/tools/internal_decisions.py (אם לא קיים — ליצור). רישום ב-server.py סביב שורה 169 (ליד precedent_library_upload). הקריאה מנותבת ל-int_decisions_service.ingest_internal_decision (קיים ב-internal_decisions.py).", "testStrategy": "1. שלח tool call ללא chair_name → JSON error. 2. שלח עם chair+district → רשומה נוצרת עם source_kind='internal_committee'. 3. precedent_chunks נוצרים עם source_kind ירש.", "status": "done", "dependencies": [ "30" ], "priority": "high", "subtasks": [], "updatedAt": "2026-05-26T07:41:37.260868Z" }, { "id": "40", "title": "[שלב B - ROI מיידי] הפעלת VOYAGE_RERANK_ENABLED=true ב-Coolify", "description": "Cross-encoder rerank-2 ממומש ב-mcp-server/src/legal_mcp/services/rerank.py אבל כבוי בייצור (default=false). POC הוכיח +4.5% mean@3 ו-+11.6% practical queries (latency +702ms acceptable לזרימה האסינכרונית). 5 דקות עבודה — env change ב-Coolify.", "details": "mcp__coolify__env_vars set VOYAGE_RERANK_ENABLED=true. ראה web/mcp_env_catalog.py:71-72 לdescription. אופציה: rampup רק על search_precedent_library (לא על find_similar_cases — latency-sensitive).", "testStrategy": "search_precedent_library('היקף הסמכות') לפני/אחרי — לראות שינוי ב-ordering. בדוק שלא יותר מ-1000ms latency.", "status": "done", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-05-26T08:08:27.953285Z" }, { "id": "41", "title": "[שלב B] BM25/tsvector hybrid retrieval על precedent_chunks + halachot", "description": "כיום כל החיפוש הוא 100% dense (cosine). ציטוטים מספריים ('עע\"מ 1461/20') נכשלים כי semantic לא מצליח בהם. הוספת tsvector GIN + RRF merge dense+lexical = +15-25% recall על ציטוטים — קריטי לאימות פסיקה ב-3-glimmering-oasis שלב 3.", "details": "ALTER TABLE precedent_chunks ADD COLUMN content_tsv tsvector GENERATED ALWAYS AS (to_tsvector('simple', content)) STORED; CREATE INDEX ... USING gin (content_tsv). באותו אופן על halachot.rule_statement. ב-db.py:2357 (search_precedent_library_semantic) — להוסיף שאילתה מקבילה של websearch_to_tsquery → RRF merge עם cosine. אזהרה: postgres אינו תומך ב-'hebrew' config — simple config יעבוד אבל בלי stemming.", "testStrategy": "שאילתה 'עע\"מ 1461/20' לפני/אחרי. לפני: 0 hits. אחרי: 1 hit מדויק על הציטוט. וגם — שאילתות סמנטיות לא מאבדות recall.", "status": "done", "dependencies": [ "40" ], "priority": "high", "subtasks": [], "updatedAt": "2026-05-26T08:08:27.953285Z" }, { "id": "42", "title": "[שלב B] Query expansion via Claude Haiku — 2-3 variants per query", "description": "שאילתות עם abbreviations משפטיות ('בל\"מ'/'בקשה להארכת מועד') חוטפות recall. LLM expansion: שאילתה → 2-3 variants → union retrieval. +10-15% recall.", "details": "בוטל 2026-06-03 — obviated. BM25_HYBRID_ENABLED=true כבר פעיל ותופס קיצורים לקסיקלית (בל\"מ כ-token). ב-gold-set (86 שאילתות) 0 שאילתות-קיצורים, ו-recall כללי ≈0.99 — אין gap נמדד. Query-expansion דרך LLM מוסיף latency+עלות לכל שאילתה ללא צורך מוכח (YAGNI). re-open trigger: אם eval ייעודי על שאילתות-קיצורים יראה recall<0.9.", "testStrategy": "Eval על 20 שאילתות עם abbreviations: לפני/אחרי recall@10. צפוי +10-15%.", "status": "cancelled", "dependencies": [ "41" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-06-03T00:00:00.000Z" }, { "id": "43", "title": "[שלב B] MMR / diversity penalty — limit 2 chunks per case_law_id", "description": "תוצאות חיפוש דומות מאוד זו לזו (אותה פסיקה, chunks סמוכים) — פסיקות חוזרות תופסות slots → diversity@10 נמוך. הוספת cap per case_law_id (2-3 max) או MMR אמיתי.", "details": "פתרון קל: SQL DISTINCT ON (case_law_id) + 2 בpost-processing. פתרון איכותי: MMR — לכל candidate, score = λ*relevance - (1-λ)*max_similarity_to_selected. λ=0.7 דיפולט.", "testStrategy": "כל שאילתה ב-top-10: <= 2 chunks per case_law_id. diversity score עולה.", "status": "done", "dependencies": [ "40" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-26T08:08:27.953285Z" }, { "id": "44", "title": "[שלב B] HNSW migration (or lists=68 IVFFlat) + REINDEX", "description": "IVFFlat lists=50 עם 4,595 vectors — sub-optimal. sqrt(4595)≈68. HNSW עדיף ל-recall (אבל יותר זיכרון). שיפור +3-5% recall@10.", "details": "אופציה 1: REINDEX עם lists=68 (פשוט, idempotent). אופציה 2: DROP+CREATE עם HNSW (m=16, ef_construction=64) — דורש pgvector ≥0.5 ובדיקת זמן build. בדוק SELECT extversion FROM pg_extension WHERE extname='vector'.", "testStrategy": "EXPLAIN ANALYZE לפני/אחרי על 5 שאילתות מייצגות. בנצ'מרק recall@10 על blind set.", "status": "done", "dependencies": [], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-26T08:08:27.953285Z" }, { "id": "45", "title": "[שלב B] Halacha auto-approve sweep — בדיקת 219 pending + הורדת סף ל-0.78", "description": "219 halachot pending review (17%) חסומות מ-search. אם dafna לא מסקר ידנית — הם מתבזבזים. dashboard batch + הורדת auto-approve threshold.", "details": "1. בדוק 20 דגימות אקראיות של pending — אם רובן ראויות לאישור, הורד HALACHA_AUTO_APPROVE_THRESHOLD מ-0.80 ל-0.78. 2. הוסף UI batch approval ב-/halachot עם filter pending+confidence>0.75. 3. one-shot SQL לאישור 200 halachot שעמדו בקריטריונים החדשים.", "testStrategy": "אחרי sweep: halachot approved יעלה מ-1,064 ל-~1,260. search_precedent_library יחזיר יותר rule-level results.", "status": "done", "dependencies": [], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-26T08:08:27.953285Z" }, { "id": "46", "title": "[שלב B] Dynamic halacha boost — לפי query-rule similarity", "description": "כיום halacha boost = +0.05 קבוע. דינמי לפי query similarity ירוץ דייקנות (5% precision על שאילתות ספציפיות).", "details": "ב-db.py:2479 — score = float(d['score']) + 0.05. החלף ב-boost = 0.10 * d['score'] (proportional). או — אם rerank ON, השתמש בrerank score כbaseline (אין צורך ב-boost כלל).", "testStrategy": "A/B test על 10 שאילתות: precision@5 לפני/אחרי.", "status": "done", "dependencies": [ "40" ], "priority": "low", "subtasks": [], "updatedAt": "2026-05-26T08:08:27.953285Z" }, { "id": "47", "title": "[שלב C - prevention] Audit script periodic: detect new external_upload עם case_number של ערר", "description": "Drift detection: שגיאה דומה ל-Bug (ב) יכולה לחזור בעתיד. periodic check (יומי?) + alert ל-Slack/comment.", "details": "scripts/audit_corpus_consistency.py — בודק: 1. case_law WHERE source_kind='external_upload' AND case_number ~ '^ערר|^ARAR'. 2. case_law WHERE source_kind='internal_committee' AND chair_name IS NULL. הרצה דרך cron או scheduled task ב-Paperclip.", "testStrategy": "להריץ אחרי כל העלאה חדשה (וגם פעם ביום). אם מוצא drift — comment ב-Paperclip ל-CEO.", "status": "done", "dependencies": [ "30", "39" ], "priority": "low", "subtasks": [], "updatedAt": "2026-05-26T11:27:09.039154Z" }, { "id": "48", "title": "[שלב C] Parent-doc retrieval (child=300, parent=1500 tokens)", "description": "chunk_size=600 חותך חלק מהלכות ארוכות. parent-doc: חיפוש על child קטן (300 tokens), החזרת parent גדול (1500 tokens) ל-LLM context.", "details": "מיגרציה DB: precedent_chunks.parent_chunk_id (FK self). chunking pipeline משתנה ל-2 רמות. retrieval: SELECT distinct parent_chunk WHERE child_chunk matches.", "testStrategy": "Eval: writer מקבל context מלא יותר, לא חתוך באמצע משפט/ציטוט.", "status": "done", "dependencies": [ "41" ], "priority": "low", "subtasks": [], "updatedAt": "2026-05-26T11:27:09.039154Z" }, { "id": "49", "title": "[שלב C] Multimodal backfill ל-77 רשומות שנותרו", "description": "כיום 40/117 precedent_image_embeddings (34%). 77 רשומות נותרו ללא image embeddings. ערך נמוך כשהמסמכים digital-native, אבל קריטי לscanned PDFs.", "details": "scripts/multimodal_backfill.py כבר קיים. להריץ עם batch size 10 כדי לא לדפוק את Voyage rate limits. אומדן: 77×~10K tokens = ~770K tokens ($10-15).", "testStrategy": "אחרי backfill: COUNT(*) FROM precedent_image_embeddings ≥ 117 (מותר יותר אם יש כמה pages per pdf).", "status": "done", "dependencies": [], "priority": "low", "subtasks": [], "updatedAt": "2026-05-26T11:27:09.039154Z" }, { "id": "50", "title": "[שלב C] Closed-loop retrieval feedback + ndcg dashboard", "description": "אין tracking של 'what was retrieved → what writer cited'. בלי זה — אי אפשר לעדכן את ה-RAG בצורה מדודה לאורך זמן.", "details": "טבלה חדשה retrieval_feedback (query, candidates_retrieved JSONB, cited_in_final_decision UUID[], created_at). hooks ב-writer לדווח. dashboard חודשי עם ndcg@10.", "testStrategy": "אחרי 3 החלטות סופיות: SELECT count FROM retrieval_feedback ≥ 3. dashboard מציג ndcg trend.", "status": "done", "dependencies": [], "priority": "low", "subtasks": [], "updatedAt": "2026-05-26T11:27:09.039154Z" }, { "id": "51", "title": "[שלב C] Halacha quality monitoring — confidence drift, alert", "description": "אם prompt או model משתנה — confidence distribution יכול לזוז. בלי monitoring — דרדור איכות עובר תחת הראדר.", "details": "scheduled job: weekly mean confidence per practice_area. אם זז ביותר מ-0.05 — alert. dashboard ב-/halachot עם histogram.", "testStrategy": "אחרי 4 שבועות — לבדוק שיש 4 datapoints + alert עובד על נתון synthetic.", "status": "done", "dependencies": [], "priority": "low", "subtasks": [], "updatedAt": "2026-05-26T11:27:09.039154Z" }, { "id": "52", "title": "[Retrieval RC-A] הוספת case_name + case_number ל-tsvector הלקסיקלי", "description": "השורש האמיתי לכך שסוכן לא מאתר החלטה לפי שם (אגסי). ה-tsvector הלקסיקלי (SCHEMA_V12_SQL ב-db.py) בנוי רק מ-precedent_chunks.content ומ-halachot rule/quote/reasoning — לא משם התיק/הצד או ממספר התיק. לכן שאילתת-שם מחזירה את מי שמצטט את ההחלטה, לא את ההחלטה עצמה. לשלב את case_law.case_name + case_number באינדקס הלקסיקלי (tsvector ייעודי על case_law או setweight) כך שחיפוש לפי שם יפגע ברשומה עצמה.", "status": "done", "priority": "high", "dependencies": [], "details": "קבצים: mcp-server/src/legal_mcp/services/db.py (SCHEMA_V12_SQL ~שורה 774, search_precedent_library_lexical), hybrid_search.py (_merge_sem_lex). דורש ALTER TABLE + migration על Postgres (localhost:5433) + restart MCP server. בדיקה: search_internal_decisions('אגסי') ו-search_precedent_library('אגסי') חייבים להחזיר את אגסי (1a87efe5) בעמוד הראשון.", "testStrategy": "reproduction test: query='אגסי' → expect case_law_id 1a87efe5 in top-3. regression: substantive query עדיין מחזיר 0.6+ score.", "subtasks": [], "updatedAt": "2026-05-30T11:05:36.307Z" }, { "id": "53", "title": "[Retrieval RC-B] חיפוש/רשימה מאוחדים — לא לחתוך internal_committee", "description": "החלטות ערר/בל\"מ שמועלות נשמרות source_kind='internal_committee'. precedent_library_list ברירת מחדל external_upload ומסתיר אותן; כלי ה-MCP precedent_library_list אפילו לא חושף פרמטר source_kind, כך שסוכן לעולם לא יכול לדפדף בהן. לחשוף source_kind/all_committees בכלי ה-MCP ובמידת הצורך לאחד את שכבת ה-list/search.", "status": "done", "priority": "high", "dependencies": [ "52" ], "details": "קבצים: web/app.py (precedent_library_list ~5194, all_committees expansion ב-db.list_external_case_law ~2708), mcp-server tool def ל-precedent_library_list. בדיקה: precedent_library_list יכול להחזיר את אגסי כשמבקשים committees; חיפוש סמנטי כבר מאוחד (אומת).", "testStrategy": "precedent_library_list(source_kind='all_committees', practice_area='betterment_levy') כולל את אגסי+וינפלד. regression: ברירת מחדל external_upload עדיין מחזירה 14 ולא שוברת UI.", "subtasks": [], "updatedAt": "2026-05-30T11:09:44.511Z" }, { "id": "54", "title": "[Retrieval RC-3] הנחיית סוכנים — איתור לפי שם + שני קורפוסים", "description": "לעדכן הנחיות legal-analyst/researcher/writer: לאיתור החלטה ספציפית לפי שם להוסיף מונחי תוכן או מספר תיק, ולחפש בשני הקורפוסים (search_internal_decisions + search_precedent_library) לפני שמסיקים 'לא קיים בקורפוס'. כולל יצירת missing_precedent רק אחרי חיפוש כפול.", "status": "done", "priority": "medium", "dependencies": [ "53" ], "details": "קבצים: .claude/agents/legal-analyst.md, legal-researcher.md, legal-writer.md. אחרי שינוי skills/agent config — להריץ sync_agents_across_companies.py.", "testStrategy": "קריאת ההנחיות מאשרת fallback ברור; (אם אפשר) הרצת סוכן על שאילתת-שם מחזירה את ההחלטה.", "subtasks": [], "updatedAt": "2026-05-30T11:12:44.727Z" }, { "id": "55", "title": "[Retrieval RC-4] תיקון chunking — פרגמנטים זעירים", "description": "בתוצאות החיפוש מופיעים chunks של מילה-שתיים ('דיון','דיון וב','סיכום ו') כתוצאות מובילות. מציפים תוצאות ומורידים דירוג תוכן אמיתי. לחקור את chunker.py (פיצול לפי כותרת-סעיף שיוצר chunks ריקים) ולתקן: מינימום אורך chunk / מיזוג כותרת לגוף.", "status": "done", "priority": "medium", "dependencies": [ "54" ], "details": "קבצים: mcp-server/src/legal_mcp/services/chunker.py (SECTION_PATTERNS). דורש שיקול re-chunk לרשומות קיימות — לבדוק עלות מול feedback_no_reocr_retrofit (להשתמש בטקסט שמור, לא re-OCR).", "testStrategy": "אין chunks < N תווים בקורפוס אחרי תיקון; search_internal_decisions('אגסי') לא מציג פרגמנטי 'דיון'.", "subtasks": [], "updatedAt": "2026-05-30T11:19:23.923Z" }, { "id": "56", "title": "[Retrieval finding] halacha_filters לא מסננים source_kind — דליפה חוצת-קורפוסים", "description": "התגלה תוך כדי משימה 53. ב-search_precedent_library_semantic וב-search_precedent_library_lexical (db.py): chunk_filters כוללים cl.source_kind=$sk אבל halacha_filters כוללים רק review_status. תוצאה: search_precedent_library(external) מחזיר גם הלכות internal_committee, ו-search_internal_decisions(internal) מחזיר גם הלכות external. אי-עקביות: chunks מסוננים, halachot לא. כרגע זה דווקא מסייע למציאוּת (לכן לא רגרסיה), אבל לא עקבי. דורש החלטת מדיניות: או לסנן halachot גם לפי source_kind (עקבי, אך 'מסתיר' שכבות), או להשאיר מאוחד במכוון + לתעד. אם משאירים מאוחד — לעדכן docstrings של שני הכלים שזה לא 'corpus נפרד'.", "status": "cancelled", "priority": "low", "dependencies": [], "details": "db.py: search_precedent_library_semantic (~שורה הקודמת ל-3311), search_precedent_library_lexical (3346). שתי הפונקציות: halacha_filters=['h.review_status IN ...'] — חסר cl.source_kind. נמצא בעת בדיקת רגרסיה למשימה 53.\n\n[SUPERSEDED 2026-05-30] נבלע ב-FU-4 / תת-משימה 62.1 (GAP-10). נסגר כדי למנוע כפילות-tracker.", "testStrategy": "לאחר החלטה: אם מסננים — search_precedent_library('...substantive...', external) לא מחזיר case_law_id internal; אם משאירים — docstring מעודכן + טסט מאשר התנהגות מכוונת.", "subtasks": [], "updatedAt": "2026-05-30T11:09:30.257989+00:00" }, { "id": "57", "title": "[Retrieval #55 follow-up] re-chunk+re-embed של פסיקה שהוטמעה לפני תיקון ה-chunker", "description": "משימה 55 תיקנה את ה-chunker (עיגון כותרות + מיזוג) ומסננת את 484 הפרגמנטים בזמן query. הרמדיאציה המלאה: re-chunk מ-full_text השמור (ללא re-OCR — תואם feedback_no_reocr_retrofit) + re-embed, כדי שהתוכן יהיה נכון ולא רק מוסתר. נדחה כי זו מיגרציית-נתונים עם עלות Voyage API על ~13+ תיקים — דורש אישור עלות מ-chaim לפני הרצה. לבדוק כמה תיקים מושפעים (יש להם chunk<50) ולהריץ בקבוצות.", "status": "done", "priority": "low", "dependencies": [ "55" ], "details": "מקור: case_law.full_text קיים. נתיב: chunker.chunk_document(_hierarchical) → embeddings → החלפת precedent_chunks לתיק. למחוק chunks ישנים של התיק לפני הוספה. אחרי הרצה — ניתן להסיר את פילטר ה->=50 query (אופציונלי). תיקים מושפעים: SELECT DISTINCT case_law_id WHERE length(trim(content))<50.\n\n[קישור 2026-05-30] קשור ל-FU-3 (task 61, GAP-09 re-index). #57 = מיגרציה חד-פעמית של העבר (re-chunk legacy); FU-3 = ה-invariant הקדמי. נשמרים בנפרד במכוון.", "testStrategy": "אחרי re-chunk לתיק לדוגמה: 0 chunks<50 לאותו case_law_id; search_internal_decisions עדיין מחזיר את התיק; ספירת chunks סבירה.", "subtasks": [], "updatedAt": "2026-06-03T07:56:21.688Z" }, { "id": "58", "title": "[Case access] get_case_by_number שביר לפורמט — סוכן 'עיוור' למסמכי תיק", "description": "דווח ע\"י chaim: סוכן כתב שחסרים מסמכי תיק כי document_list החזיר ריק, אך המסמכים קיימים. שורש: get_case_by_number (db.py) עושה 'WHERE case_number=$1' התאמה מדויקת בלבד. אומת — 8137-24 מחזיר 9 מסמכים, אבל 8137/24 / 'ערר 8137-24' / רווחים / zero-pad → 'תיק לא נמצא'. הסוכן מקבל את המספר בפורמט שונה (כותרת issue, לוכסן, תחילית ערר/בל\"מ) → התאמה נכשלת → 'אין מסמכים'. משפיע על כל הכלים מבוססי case_number (document_list, extract_references, search_case_documents, get_claims, draft, וכו'). תיקון: נורמליזציה (strip prefix לתחילת ספרה, trim, '/'→'-') + fallback בשאילתה. תיקון נקודה-אחת מתקן את כל הכלים.", "status": "done", "priority": "high", "dependencies": [], "details": "db.py: get_case_by_number (~שורה לאחר get_case). להוסיף _normalize_case_number + שאילתה עם OR על replace(trim(case_number),'/','-')=norm, ORDER BY exact-first. בדיקה: כל הווריאציות של 8137-24 מחזירות 9 מסמכים.", "testStrategy": "document_list על 7 וריאציות פורמט של תיק קיים → כולן מחזירות את אותם מסמכים; תיק לא-קיים אמיתי עדיין מחזיר 'לא נמצא'.", "subtasks": [], "updatedAt": "2026-05-30T11:54:34.291Z" }, { "id": "59", "title": "[FU-1] איחוד מסלול ה-ingest למסלול קנוני אחד", "description": "מאחד את ingest_precedent ו-ingest_internal_decision למסלול קנוני יחיד; מבטל את האסימטריות.", "details": "מכסה GAP-01,02,04,05. מספק INV-ING1/ING3/G2/G4. severity: Critical. סוג: קוד. יסוד — FU-2/FU-3/FU-7 תלויים בו. מקור: docs/spec/gap-audit.md + 01-ingest.md.", "testStrategy": "", "status": "done", "dependencies": [], "priority": "high", "subtasks": [ { "id": 1, "title": "[GAP-01] מסלול ingest קנוני יחיד", "description": "ביטול שני המסלולים המקבילים (precedent_library.py:88 vs internal_decisions.py:73); כל סוג = פרמטרים, לא פונקציה נפרדת.", "dependencies": [], "details": "INV-ING1/G2", "status": "done", "testStrategy": "", "parentId": "59" }, { "id": 2, "title": "[GAP-02] תזמון חילוץ metadata לכל סוג", "description": "קריאה ל-request_metadata_extraction גם במסלול הפנימי (היום רק halacha, internal_decisions.py:208).", "dependencies": [], "details": "INV-ING3/DM1", "status": "done", "testStrategy": "", "parentId": "59" }, { "id": 3, "title": "[GAP-04] ולידציית enums אחידה", "description": "הוספת ולידציית practice_area/source_type למסלול הפנימי (כמו precedent_library.py:131-134).", "dependencies": [], "details": "INV-G4", "status": "done", "testStrategy": "", "parentId": "59" }, { "id": 4, "title": "[GAP-05] איחוד staging/derivation/citation-guard/multimodal/fallback", "description": "שאר 6 האסימטריות → פרמטרים של המסלול הקנוני (01-ingest §4).", "dependencies": [], "details": "INV-ING1", "status": "done", "testStrategy": "", "parentId": "59" } ], "updatedAt": "2026-05-30T17:37:34.741136+00:00" }, { "id": "60", "title": "[FU-2a] ingest idempotent + נרמול-בכתיבה + searchable (pure-code)", "description": "upsert ON CONFLICT על מפתח קנוני + נרמול case_number בכתיבה (type-aware) + דגל searchable מפורש. אפס מיגרציית-נתונים.", "details": "מכסה GAP-03,06,13. מספק INV-ING2/G3/G1/ID1/DM1. severity: Critical. סוג: pure-code (schema-additive). תלוי ב-FU-1 (#59). FU-2b (#67) מטפל ב-GAP-07/08 בנפרד.", "testStrategy": "", "status": "done", "dependencies": [ "59" ], "priority": "high", "subtasks": [ { "id": 1, "title": "[GAP-03] קליטה idempotent (upsert על מפתח קנוני)", "description": "קליטה חוזרת = עדכון, לא כפילות.", "dependencies": [], "details": "INV-ING2/G3", "status": "done", "testStrategy": "", "parentId": "60" }, { "id": 2, "title": "[GAP-06] נרמול case_number בכתיבה", "description": "היום רק תיקון-קריאה (_normalize_case_number, db.py:1196-1211).", "dependencies": [], "details": "INV-G1/ID1", "status": "done", "testStrategy": "", "parentId": "60" }, { "id": 5, "title": "[GAP-13] שדה searchable מפורש", "description": "דגל 'עבר חוזה-שלמות' מובחן מ-extraction_status.", "dependencies": [], "details": "INV-DM1", "status": "done", "testStrategy": "", "parentId": "60" } ], "updatedAt": "2026-05-30T17:37:34.741136+00:00" }, { "id": "61", "title": "[FU-3] re-index בשינוי תוכן", "description": "embedding מתעדכן אוטומטית בשינוי תוכן (כיום trigger-dependent, לא GENERATED).", "details": "מכסה GAP-09. מספק INV-DM3/G6. severity: High. סוג: קוד + מיגרציה (re-embed). תלוי ב-FU-1.", "testStrategy": "", "status": "done", "dependencies": [ "59" ], "priority": "medium", "subtasks": [ { "id": 1, "title": "[GAP-09] re-index/re-embed בשינוי תוכן", "description": "embedding לא GENERATED בניגוד ל-tsvectors; נקודת-drift.", "dependencies": [], "details": "INV-DM3/G6", "status": "done", "testStrategy": "", "parentId": "61" }, { "id": 2, "title": "[backfill] multimodal page-images ל-42 החלטות-ועדה קיימות", "description": "42/56 רשומות source_kind='internal_committee' נקלטו במסלול הישן בלי multimodal page-images (FU-1 מתקן רק קדימה). אחרי שמנגנון ה-re-index של FU-3 קיים — להריץ re-embed של עמודי-תמונה עליהן. ⚠️ קודם לכמת כמה מה-42 הן PDF-backed (לרשומות שנקלטו מ-text בלבד אין קובץ → אי-אפשר להטמיע עמודים). רק PDF-backed רלוונטיות.", "dependencies": [ 1 ], "details": "מקור: בדיקת DB 2026-05-30 (precedent_image_embeddings JOIN case_law). internal_committee: 14/56 עם page-images, 42 בלי. נגזר מ-GAP-02/FU-1 boundary discussion. לא פער-תקינות — שיפור multimodal coverage. | CLOSED not-applicable 2026-05-30: כל 42 הרשומות document_id=NULL + אין PDF בדיסק; multimodal דורש רינדור PDF → בלתי-אפשרי לרשומות-טקסט. אם יועלה PDF — ingest רגיל מטפל.", "status": "cancelled", "testStrategy": "", "parentId": "61" } ], "updatedAt": "2026-05-30T17:37:34.741136+00:00" }, { "id": "62", "title": "[FU-4] בידוד-קורפוס בכל מסלול query", "description": "אכיפת source_kind בכל פילטר (כולל halacha_filters); חסימת חיפוש ללא תחום.", "details": "מכסה GAP-10,12. מספק INV-RET1/G5. severity: Critical. סוג: קוד. ללא תלות — דחוף (דליפה פעילה).", "testStrategy": "", "status": "done", "dependencies": [], "priority": "high", "subtasks": [ { "id": 1, "title": "[GAP-10] סינון source_kind ב-halacha_filters (#56)", "description": "db.py:3168/3401 — halacha_filters בלי source_kind בעוד chunk_filters עם.", "dependencies": [], "details": "INV-RET1/G5", "status": "done", "testStrategy": "", "parentId": "62", "updatedAt": "2026-05-30T18:30:11.496Z" }, { "id": 2, "title": "[GAP-12] חסימת חיפוש ללא practice_area", "description": "search_decisions מזהיר אך לא חוסם (search.py:45-49).", "dependencies": [], "details": "INV-RET/G5", "status": "done", "testStrategy": "", "parentId": "62", "updatedAt": "2026-05-30T18:30:11.503Z" } ], "updatedAt": "2026-05-30T18:30:11.503Z" }, { "id": "63", "title": "[FU-5] eval-harness + נראות backlog", "description": "מדידת precision/recall על gold-set + חשיפת backlog הלכות בבדיקת-בריאות.", "details": "מכסה GAP-11,14. מספק INV-RET4/G8/QA1/G10. severity: High. סוג: קוד + החלטת-יו\"ר (בניית gold-set). תלוי ב-FU-2. | DONE 2026-05-31: Unit B (GAP-14) — halacha_backlog נחשף ב-metrics.get_dashboard + /api/system/diagnostics (גילה 178 pending_review מתוך 1552, הישן 3.5.26). Unit A (GAP-11) — scripts/eval_gold_bootstrap.py (citations+known_item) + scripts/eval_retrieval.py (P/R/MRR/nDCG@5,10, self-test, baseline+config). gold-set=77 known-item queries (citation-source ריק: 0 ציטוטים בהחלטות). baseline בייצור: R@10=0.987 MRR=0.837; ממצא: MULTIMODAL=true מוריד known-item recall קלות (relevant ל-#15). gold-set=provisional עד סקירת דפנה (chair-gate; הדומיין). spec: docs/superpowers/specs/2026-05-31-fu5-eval-harness-design.md", "testStrategy": "", "status": "done", "dependencies": [ "60" ], "priority": "medium", "subtasks": [ { "id": 1, "title": "[GAP-11] eval-harness precision+recall + gold-set", "description": "כיום רק telemetry.log_search_bg; איכות-אחזור לא נמדדת.", "dependencies": [], "details": "INV-RET4/G8", "status": "done", "testStrategy": "", "parentId": "63", "updatedAt": "2026-05-31T14:55:38.289Z" }, { "id": 2, "title": "[GAP-14] נראות backlog הלכות", "description": "ספירת pending_review בבדיקת-בריאות (10/19 התגלה במקרה).", "dependencies": [], "details": "INV-QA1/G10", "status": "done", "testStrategy": "", "parentId": "63", "updatedAt": "2026-05-31T14:55:38.295Z" } ], "updatedAt": "2026-05-31T14:55:38.295Z" }, { "id": "64", "title": "[FU-6] שערי-QA נאכפים בקוד", "description": "export חוסם בקוד על כשל-QA קריטי; תיקון neutral_background critical-but-passes.", "details": "מכסה GAP-15,16. מספק INV-QA3/EX3/G10. severity: Critical. סוג: קוד. ללא תלות — מהיר.", "testStrategy": "", "status": "done", "dependencies": [], "priority": "high", "subtasks": [ { "id": 1, "title": "[GAP-15] export חוסם QA קריטי בקוד", "description": "export_docx (drafting.py:384) לא קורא ל-validate_decision — ניתן לעקיפה.", "dependencies": [], "details": "INV-QA3/EX3", "status": "done", "testStrategy": "", "parentId": "64", "updatedAt": "2026-05-30T18:30:11.515Z" }, { "id": 2, "title": "[GAP-16] תיקון neutral_background critical-but-passes", "description": "fallback בלוק-ו ריק מסומן critical אך passed=True (qa_validator.py:70).", "dependencies": [], "details": "QA-gate", "status": "done", "testStrategy": "", "parentId": "64", "updatedAt": "2026-05-30T18:30:11.521Z" } ], "updatedAt": "2026-05-30T18:30:11.521Z" }, { "id": "65", "title": "[FU-7] audit-trail + provenance", "description": "כתיבת audit_log בכל פעולה; קישור בלוק→קטעי-מקור; סנכרון DB אחרי עריכה; אימות citation→corpus.", "details": "מכסה GAP-17,18,19,20. מספק INV-AUD1/2/3/EX1/G9. severity: High. סוג: קוד + backfill קל. תלוי ב-FU-1. (זרע לתת-פרויקט 3/audit-provenance.)", "testStrategy": "", "status": "done", "dependencies": [ "59" ], "priority": "medium", "subtasks": [ { "id": 1, "title": "[GAP-17] סנכרון בלוקי-DB אחרי עריכת draft", "description": "active_draft_path הופך ל'מקור-אמת', בלוקים לא מסונכרנים (db.py:189).", "dependencies": [], "details": "INV-EX1/AUD2", "status": "done", "testStrategy": "", "parentId": "65" }, { "id": 2, "title": "[GAP-18] כתיבת audit_log בכל פעולה מהותית", "description": "הטבלה קיימת אך נכתבת כמעט רק ב-case_subtype_override (cases.py:203).", "dependencies": [], "details": "INV-AUD1", "status": "done", "testStrategy": "", "parentId": "65" }, { "id": 3, "title": "[GAP-19] קישור בלוק→קטעי-מקור", "description": "decision_blocks שומר model_used אך לא אילו chunks/precedents הזינו.", "dependencies": [], "details": "INV-AUD1", "status": "done", "testStrategy": "", "parentId": "65" }, { "id": 4, "title": "[GAP-20] אימות citation→corpus", "description": "decision_paragraphs.citations ללא ולידציה שכל ציטוט מתאים.", "dependencies": [], "details": "INV-AUD3", "status": "done", "testStrategy": "", "parentId": "65" } ], "updatedAt": "2026-05-30T17:37:34.741136+00:00" }, { "id": "66", "title": "[FU-8a] מחסומי-תהליך→קוד: enforce sync + Paperclip-access guard (pure-code)", "description": "אכיפת cross-company sync (--verify יוצא non-zero על drift; adapter_type mismatch = drift לא silent skip) + fitness-function שחוסם גישת-Paperclip לא-מאושרת (raw http / INSERT agent_wakeup_requests).", "details": "מכסה GAP-21,22. מספק INV-MC1/INT1/INT3. severity: High. סוג: pure-code. GAP-23 (חיווט ספ→סוכנים) הופרד ל-#69 (משנה התנהגות-ייצור). | DONE 2026-05-31 PR#16: --verify drift-gate (exit≠0) + Paperclip-access fitness function. GAP-23→#69.", "testStrategy": "", "status": "done", "dependencies": [], "priority": "medium", "subtasks": [ { "id": 1, "title": "[GAP-21] אכיפת sync חוצה-חברות", "description": "sync ידני ולא-נאכף; adapter_type-mismatch מדולג בשקט (sync...py:387-389).", "dependencies": [], "details": "INV-MC1", "status": "done", "testStrategy": "", "parentId": "66" }, { "id": 2, "title": "[GAP-22] מחסומי-קוד ל-wakeup/API", "description": "אין אילוץ-schema נגד INSERT ישיר ל-agent_wakeup_requests; אין linter נגד httpx/curl גולמי.", "dependencies": [], "details": "INV-INT1/INT3", "status": "done", "testStrategy": "", "parentId": "66" } ], "updatedAt": "2026-05-30T17:37:34.741136+00:00" }, { "id": "67", "title": "[FU-2b] תיאום מזהים קנוניים + ניקוי ציטוט-כמזהה (data-migration, chair)", "description": "מיגרציה חד-פעמית של ~52+ רשומות case_law עם ציטוט-מלא ב-case_number → מספר-בסיס מנורמל; dedup (למשל 8047-23 כפול); הכרעת צורה קנונית per-record.", "details": "מכסה GAP-07,08. מספק INV-ID1/ID2/DM2. severity: High. סוג: DATA-MIGRATION + chair-decision (מספר רשמי per-record, with-month canonical). דורש: גיבוי, dry-run, סקירת-יו\"ר, reversibility. תלוי ב-FU-2a (#60, לצורך פונקציית הנרמול). מקור: בדיקת DB 2026-05-30 — internal_committee ~52/56 ציטוט-מלא, ≥1 dup (8047-23), 1 בלתי-פתיר (ערר אדלר/cited_only). | APPLIED 2026-05-31: 55 internal rows normalized to bare case_number; corrupted 8047 dup (מטודלה) deleted; חלוואני 1028-20 proc→בל\"מ. Backups in data/audit/fu2b-*. external→#68.", "testStrategy": "", "status": "done", "dependencies": [ "60" ], "priority": "high", "subtasks": [ { "id": 1, "title": "[GAP-07] תיאום מספרי-תיק מעורבים (with-month canonical)", "description": "מיגרציה חד-פעמית; הצורה עם-חודש קנונית (החלטת-יו\"ר).", "dependencies": [], "details": "INV-ID1", "status": "done", "testStrategy": "", "parentId": "67" }, { "id": 2, "title": "[GAP-08] הסרת ציטוט-מלא כ-case_number", "description": "רשומות עם ציטוט מלא כמזהה (legacy).", "dependencies": [], "details": "INV-DM2/ID2", "status": "done", "testStrategy": "", "parentId": "67" } ] }, { "id": "68", "title": "[FU-2c] תיאום מזהי external_upload (case_number↔citation_formatted)", "description": "פסיקה חיצונית: case_number מחזיק ציטוט מלא; citation_formatted לא תמיד תואם (נמצאה סתירה 25226-04-25 מול 1975/24). דורש קודם תיקון סתירות citation_formatted↔case_number, ואז הכרעה אם docket מחולץ הופך ל-case_number או שהציטוט נשאר המזהה.", "details": "מקור: בדיקת DB 2026-05-31 (FU-2b scoping). 22/24 external עם ציטוט ב-case_number; citation_formatted נוצר בנפרד (LLM) ולא אמין כ-ground truth. שונה מ-internal (שם 0 סתירות). דורש סקירת-יו\"ר פר-רשומה. severity: Medium. סוג: data-migration + chair. תלוי בהחלטה: האם זהות external = ציטוט (FU-1) או docket מנורמל (INV-ID2). מופרד מ-FU-2b לפי החלטת chaim 2026-05-31. | APPLIED 2026-05-31: chair decision Option A (designator+docket, '/' kept). 21 external_upload case_number normalized + 3 citation_formatted fixed (D=לויתן/קלמנוביץ consolidated→25226-04-25; 2×C empty-citation composed). אהוד שפר עע\"מ 317/10 deferred (cross-source dup w/ cited_only → #70). collision-guard: 0. Backups data/audit/fu2c-backup-20260531T140943Z.csv. cited_only(49)→#70.", "testStrategy": "", "status": "done", "dependencies": [ "67" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-31T14:11:37.689Z" }, { "id": "69", "title": "[FU-8b] חיווט הספ לסוכני-Paperclip (GAP-23)", "description": "HEARTBEAT/agent docs דורשים קריאת 00-constitution + ספ-תחום רלוונטי לפני פעולה. משנה התנהגות-סוכן בייצור; prereq לתת-פרויקט 5.", "details": "מכסה GAP-23. מספק INV-AG1. severity: High. סוג: docs+chair-decision. דורש ספ יציב (קיים) + החלטה על שילוב בזרימת-הסוכנים. הופרד מ-FU-8a לפי החלטת chaim 2026-05-31 (GAP-21/22 = pure-code עכשיו).", "testStrategy": "", "status": "done", "dependencies": [ "66" ], "priority": "medium", "subtasks": [ { "id": 1, "title": "[GAP-23] חיווט הספ לסוכנים", "description": "HEARTBEAT/agent docs דורשים קריאת 00-constitution + ספ-תחום (prereq לתת-פרויקט 5).", "dependencies": [], "details": "INV-AG1\n\nהושלם 2026-05-31 (FU-8b/GAP-23 → INV-AG1). חיווט הספ לסוכנים:\n\n1. **HEARTBEAT.md:** נוסף סעיף עליון \"קריאת-ספ — קודם החוקה (00), אז ספ-התחום — לפני פעולה מהותית (INV-AG1)\" לפני §0–§8 התפעוליים, כולל טבלת תפקיד→ספ (8 שורות: ceo→00+כל-הספ, proofreader→01, researcher→03+01, analyst→02+03+04, writer→04+05, qa→05, exporter→06, hermes-curator→07).\n\n2. **8 קבצי-סוכן:** legal-ceo, legal-proofreader, legal-researcher, legal-analyst, legal-writer, legal-qa, legal-exporter, hermes-curator — כל אחד קיבל סעיף \"קרא לפני פעולה (INV-AG1)\" בראש גוף-הקובץ עם קריאת 00-constitution.md תחילה ואז ספ-התחום לפי הטבלה ב-X4 §2.\n\n3. **X4-agents.md:** שדה \"אכיפה\" של INV-AG1 עודכן ל\"מחוּוט (FU-8b, 2026-05-31): פרוצדורלי, לא שער-קוד\". סעיף §5 (בוצע) מתעד את הפעולות שבוצעו.\n\n**אופי האכיפה:** פרוצדורלית בכוונה — invariant פרויקטלי-תפעולי (מי קורא מה לפני שהוא פועל), אין שער-קוד שמכריח את הקריאה — זה גלום בטבע ה-invariant (מבוצע ע\"י הסוכן, לא ע\"י מערכת חיצונית).\n", "status": "done", "testStrategy": "", "parentId": "69", "updatedAt": "2026-05-31T16:01:42.032Z" } ], "updatedAt": "2026-05-31T16:01:42.032Z" }, { "id": "70", "title": "[FU-2c-b] תיאום + dedup של cited_only (49 רשומות) + אהוד שפר cross-source", "description": "המשך ל-FU-2c (#68). ה-dry-run של תיאום-המזהים החיצוני חשף 49 רשומות source_kind='cited_only' (הפניות-ציטוט שחולצו מהחלטות) שלא היו בהיקף #68. דורשות נרמול נפרד: צורות-ועדה כמו 'ערר 1093-19' (NNNN-NN) שה-extractor הנוכחי לא תופס (NO_DOCKET), 'בש\"א 2487-14', dups, ו-'ערר אדלר' בלתי-פתיר (ללא מספר). בנוסף: dedup חוצה-source של אהוד שפר — external_upload 'עע\"מ 317/10 אהוד שפר' מול cited_only קיים 'עע\"מ 317/10' (אותו תיק; ה-collision-guard מנע התנגשות ב-uq_case_law_external_number, ה-external_upload נשאר עם case_number מנופח עד הכרעה).", "details": "[2026-06-03] נרמול מבוסס-מחקר (4 מקורות: ECLI work-level id, Akoma Ntoso FRBR Work/Manifestation, ELI canonical+alias, OpenCitations OMID + Christen data-matching). מדיניות: צורה קנונית אחת + alias; cited_only stub = אותו Work כמו ה-doc → merge על התאמה-מדויקת בלבד; un-resolvable = display+flag, לא למחוק; merge = re-point edges + dedup, שמרני (false-merge בגרף-ציטוט יקר). בוצע: 46 רשומות cited_only סווגו; 3 תיקונים מכניים-דטרמיניסטיים הוחלו (ערר \\n316/10→ערר 316/10; עע\"מ65/13→עע\"מ 65/13; עע\"מ9057/09→עע\"מ 9057/09). 0 malformed (whitespace/no-space) נותרו. **נותר לשיקול יו\"ר (לא ננחש, לפי המשמר)**: (1) 2 garbled — 'ערר 1078/0724' (4a38c202), 'ערר 1083/0724' (6682f9cb); (2) 'ערר אדלר' (863a7bf8) ללא docket → keep+flag; (3) combined 'ערר (ירושלים) 1078+1083/24' (e7f6fd06) → פיצול ל-1078/24+1083/24 מתנגש עם stub קיים 'ערר 1083/24' → entity-resolution ידני. תוספת קוד עתידית: טיפול '+' ב-citation_extractor. הדדאפ הקודם (shafer + stub cleanup) כבר הושלם. אלה chair-domain — לא הכרעת-מהנדס. [2026-06-03 סגירה]: בדיקת-קשתות חשפה ש-4 ה'דו-משמעיים' (+11 נוספים) הם stubs **יתומים מתים** — 0 קשתות בכל 5 מנגנוני-הציטוט, 0 full_text, 0 הלכות, 0 chunks/embeddings. כלומר ניקוי טכני, לא שיפוט-יו\"ר (OpenCitations שומר ישות חסרת-מזהה רק אם מצוטטת — אלה לא). נמחקו 15 יתומים (cited_only 46→31), גיבוי data/audit/fu2b-orphan-stub-cleanup-20260603T093741Z.json. 0 malformed/יתומים נותרו; כל 31 הנותרים מצוטטים. forward-edge ידוע (לא חוסם, ללא משימה): טיפול '+' בציטוט-משולב ב-citation_extractor אם יחזור בחילוץ עתידי. #70 done.", "testStrategy": "אחרי תיקון: 0 NO_DOCKET ב-cited_only (פרט ל-ערר אדלר המתועד); אין case_number כפול בין external_upload ל-cited_only; אהוד שפר עע\"מ 317/10 = רשומה אחת.", "status": "done", "dependencies": [ "68" ], "priority": "medium", "subtasks": [], "updatedAt": "2026-06-03T00:00:00.000Z" }, { "id": "71", "title": "[FU-5 follow-up] כוונון עומק-אחזור/rerank — recall רב-תקדימי לסוגיות רחבות", "description": "נפתר ע\"י תיקון ה-weight של #15 (multimodal 0.5→0.65). מדידה 2026-06-03: כל 11 השאילתות הרב-תקדים/יו\"ר מחזירות את כל התקדימים הרלוונטיים ב-top-10 (רובם top-6; גרוע ביותר rank 9). השאילתות החלשות מהבייסליין (S2 הבית-שמעוני@16, S4 ב.דייניש@15, S7@15, S8) כולן תוקנו. recall@10≈1.0.", "details": "החלטה מבוססת-מדידה+מחקר (6 מקורות: Cormack RRF, Drowning-in-Documents 2411.11767, ReFIT, MMR, Elastic, Pinecone). המחקר המליץ להפעיל rerank (fetch_k=50,return_k=10); בדקתי אמפירית — VOYAGE_RERANK_ENABLED=true דווקא הזיק: nDCG@5 0.879 מול 0.960, MRR 0.867 מול 0.954, R@5 0.966 מול 0.994 (כל המדדים שליליים). הסיבה: recall כבר רווי, וה-cross-encoder הכללי מוריד את ההתאמה המדויקת ב-known-item. **המדידה גוברת על התיאוריה — לא מפעילים rerank, לא מעלים limit, RRF_K=60 נשאר.** אין שינוי-קוד נדרש.", "testStrategy": "לפני/אחרי כל שינוי: eval_retrieval.py באותו retrieval_config; הוכחה ש-R@10 הרב-תקדימי עולה בלי ירידה ב-MRR/known-item recall.", "status": "done", "dependencies": [ "63" ], "priority": "low", "subtasks": [], "updatedAt": "2026-06-03T00:00:00.000Z" }, { "id": "72", "title": "[ops] MCP 'No such tool' תחת עומס חילוץ opus-4-8@xhigh — timeout ב-handshake", "description": "בריצת CMPA-71 (חילוץ הלכות 9002-24, סוכן עוזר משפטי) שרת ה-legal-ai MCP לא נטען — כל קריאות mcp__legal-ai__* החזירו 'No such tool available' אחרי 3 ניסיונות+המתנות; הסוכן עשה fallback ל-.venv ישיר (לפי legal-ceo.md) והחילוץ הצליח על claude-opus-4-8@xhigh.", "status": "done", "priority": "medium", "dependencies": [], "details": "שורש (אובחן 2026-05-31 ~20:02): ה-.mcp.json של ה-workspace תקין (command/cwd/env נכונים), ו-import של legal_mcp.server מהיר (~2s, 110MB) — לא config שבור ולא רגרסיית Paperclip 529. הגורם: עומס-מכונה קיצוני (load avg 30.0, 10 תהליכי 'claude -p --effort xhigh' במקביל) → ה-MCP handshake לא ייצב בתוך ה-timeout של claude → 'No such tool'. תופעת-לוואי של מעבר חילוץ-הלכות ל-opus-4-8@xhigh (PR #26) שהוא CPU/token-כבד; ראינו 10 תהליכים למרות CHUNK_CONCURRENCY=3 (לבדוק אם רצו כמה חילוצים/heartbeats במקביל). מקלות: (1) להקטין CHUNK_CONCURRENCY ל-xhigh, או effort נמוך-יותר לחילוץ-bulk; (2) להאריך MCP startup timeout לסוכנים; (3) להגביל חילוצים מקבילים. ה-fallback ב-legal-ceo.md עבד — עמידוּת טובה. ראה run-log: instances/default/data/run-logs/8639e837.../cdbfa8bc-.../ [נסגר 2026-05-31] שלוש הקשחות מוזגו: נעילה גלובלית (PR #30, חילוץ אחד בכל רגע), חילוץ מצטבר crash-safe+resume (PR #31), ו-effort קל-יותר ל-bulk (PR #32, config.HALACHA_BULK_EXTRACT_EFFORT=high). שורש ה-freeze מטופל בכל הצירים.", "testStrategy": "לשחזר: להריץ חילוץ xhigh כבד ובמקביל להעיר סוכן — לוודא שה-MCP נטען (אין 'No such tool'). אחרי מקלה (concurrency/timeout): load < ~עומס-ליבות, ו-handshake מצליח.", "subtasks": [] }, { "id": "73", "title": "החלטת ועדת ערר: ברירת מחדל is_binding=false (יישור דוקטרינרי)", "description": "כשמעלים החלטת ועדת ערר דרך מסך העלאת הפסיקה (precedent-upload-sheet, isCommittee=true), הצ'קבוקס 'הלכה מחייבת' (is_binding) כברירת מחדל הוא true — כך שההלכות שמחולצות מהחלטה לא-מחייבת מתויגות rule_type='binding'. זה סותר את ההגדרה הדוקטרינרית שלנו (ועדת ערר = persuasive בלבד, לא binding כמו עליון/מנהלי). התיקון: כש-isCommittee=true ב-precedent-upload-sheet.tsx, להפוך את is_binding ל-false כברירת מחדל (או לנעול/להסתיר את הצ'קבוקס ולתייג אוטומטית persuasive). הערה חשובה: זהו תיקון יישור-דוקטרינרי בלבד — אין השפעה downstream על ranking/injection (rule_type הוא תווית תצוגה; השער הפונקציונלי האמיתי הוא review_status שדפנה שולטת בו ידנית). קבצים: web-ui/src/components/precedents/precedent-upload-sheet.tsx (useState isBinding שורה 47, isCommittee שורה 53); guard clause קיים ב-mcp-server/src/legal_mcp/services/halacha_extractor.py:229-235 שמוריד binding→persuasive רק כאשר is_binding=false.", "details": "", "testStrategy": "", "status": "done", "dependencies": [], "priority": "medium", "subtasks": [], "updatedAt": "2026-05-31T20:41:04.160Z" }, { "id": "74", "title": "ניקוי רטרואקטיבי: rule_type binding→persuasive להלכות ממקור ועדת ערר", "description": "המשך משימה #73 (PR #29 מנע binding חדש לועדת ערר מכאן והלאה). יש 82 הלכות קיימות ב-DB עם rule_type='binding' שמקורן (case_law) בהחלטת ועדת ערר — בסתירה לדוקטרינה (ועדת ערר = persuasive). פילוח: 75 approved + 7 pending_review. גישה #2 (שמרנית): לתקן רק את ה-binding ל-persuasive, ולהשאיר interpretive/procedural/application/obiter כמות שהם (תקינים גם לועדת ערר). הגדרת 'מקור ועדת ערר': case_law WHERE source_type='appeals_committee' OR precedent_level LIKE 'ועדת%' OR court LIKE '%ועדת%ערר%' OR court LIKE '%ועדות ערר%'. שאילתה: UPDATE halachot SET rule_type='persuasive' WHERE rule_type='binding' AND case_law_id IN (). הערה: rule_type הוא תווית תצוגה בלבד — אין השפעה על ranking/injection (השער הפונקציונלי הוא review_status). DB: legal_ai על Postgres pgvector קונטיינר t84kegpjm5qrttd6nw7bgoxe (פורט 5433). ביצוע דרך docker exec עם trust מקומי. לגבות/לספור לפני ואחרי לאימות (צפוי: 82 שורות מושפעות, 0 binding ממקור ועדת ערר אחרי).", "details": "", "testStrategy": "", "status": "done", "dependencies": [ "73" ], "priority": "low", "subtasks": [], "updatedAt": "2026-05-31T20:49:28.894Z" }, { "id": "75", "title": "[X11 Phase 2] חיווט אוטו-אישור מבוסס-ציטוט + backfill", "description": "Phase 2 של citation-corroboration (X11). Phase 1 (האות) מוזג ב-PR #27. דפנה אימתה את האות ואישרה הפעלה (2026-06-01). Phase 2: (1) חיווט אוטו-אישור — הלכה corroborated (≥2 ציטוטים חיוביים בלתי-תלויים, 0 שליליים) עוברת ל-review_status='approved' עם reviewer='corroborated (…judicial citations)' (INV-COR4/G10); (2) הדחת overruled — הלכה approved שקיבלה טיפול overruled בציטוט מאוחר חוזרת לשער-היו\"ר (INV-COR2); (3) backfill על 12 התקדימים (halachot+ציטוטים-נכנסים); (4) כלי-MCP write להרצת rebuild.", "details": "דגל: HALACHA_CORROBORATION_AUTO_APPROVE (default true, env-tunable). פונקציית-הכרעה טהורה approval_action(agg, has_overruled)→'approve'/'demote'/None (unit-tested, INV-COR2/COR4). DB: approve_halacha_by_corroboration (רק על pending_review), demote_halacha_overruled (רק על approved→pending_review), list_corroboration_grouped, precedents_with_halachot_and_incoming_citations. שירות: reconcile_approvals מופעל בסוף build_for_precedent; build_all driver. backfill target=12 תקדימים (אומת 2026-06-01). נדחה ל-backlog (proposal-only, מסוכן-תוכן): enrichment של rule_statement, treatment-backfill ל-case_law_citations.citation_type. תוכנית: docs/superpowers/plans/2026-06-01-x11-citation-corroboration-phase2.md. spec: docs/spec/X11-citation-corroboration.md §4-6.", "testStrategy": "unit: approval_action — overruled→demote, corroborated→approve, יחיד/שלילי→None. integration: build_for_precedent על שפר מחזיר approved/flagged; backfill על 12 תקדימים ללא exception. DB: רק pending_review→approved (לא נוגע ב-published/rejected); overruled מדיח רק approved.", "status": "done", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-06-01T04:43:40.474Z" }, { "id": "76", "title": "תיקון כפתור \"צור משימה\" ב-Paperclip — מאופשר אך submit חוזר בשקט", "description": "בוטל 2026-06-03 — באג upstream של Paperclip, לא ניתן לתיקון בטוח אצלנו (ee=companyId; הכפתור מאופשר לפי כותרת בלבד אך submit דורש חברה שלא אותחלה). אומת ע\"י chaim שעובד מהקשרי-חברה רגילים. Workaround: לבחור חברה במודאל / לפתוח מתוך לוח. מסלול אמין: pc.sh POST /companies/{id}/issues. תיקון יסודי = upstream. #78 מסיר את הצורך בזרימת הפסיקה.", "details": "אבחנה סופית מתוך הבאנדל (index-BWGhimVr.js): ה-submit הוא `function xi(){const je=m.current.trim();if(!ee||!je||He.isPending)return;...He.mutate({...companyId:ee...})}`. `je`=כותרת (קיים), `He`=mutation. ה-guard שנכשל הוא **`ee`**, ש-`ee` משמש כ-`projects.list(ee)` וכ-`companyId:ee` במוטציה — כלומר **`ee` = מזהה החברה**. השורש: הכפתור מאופשר לפי הכותרת בלבד (`disabled:!b`, b=כותרת), אבל ה-submit דורש גם חברה (`!ee`). כשהמודאל נפתח בהקשר שבו החברה לא אותחלה, המשתמש לוחץ כפתור 'מאופשר' וה-handler חוזר בשקט — בלי POST, בלי שגיאה. בחירת הסוכן (callback Ro) לא מגדירה את החברה — היא נקבעת רק דרך בורר חברה נפרד (pr/oe). ההזרקה שלנו (translate-he.js) זוכתה: reverseComments נוגע רק ב-[id^='comment-'], לא במודאל; isUserContent מדלג על contentEditable. **לא ניתן לתקן בבטחה דרך injection**: אי-אפשר לכתוב ל-state של React מבחוץ; shim שמגרד DOM ויוצר issue דרך API הוא שביר (צריך IDs מה-DOM) ועלול ליצור משימות פגומות — גרוע מהבאג. **Workaround**: לוודא שהחברה נבחרה במודאל (בורר החברה) לפני לחיצה על 'צור משימה'; או לפתוח 'משימה חדשה' מתוך הקשר חברה/לוח. מסלול אמין תמיד: API ישיר `pc.sh POST /companies/{id}/issues`. **תיקון יסודי = upstream Paperclip** (הכפתור צריך להיות disabled כשאין חברה, או החברה צריכה להיגזר מהלוח/סוכן הנבחר). הערה: #78 (חילוץ פסיקה אוטומטי) מסיר את הצורך במודאל הזה בזרימת חילוץ-הפסיקה; הזרימה הרגילה מניעה סוכנים דרך תגובות (CEO מנתב).", "testStrategy": "לאחר ה-shim: לפתוח \"משימה חדשה\", להקליד כותרת עברית, ללחוץ \"צור משימה\" → לוודא POST /issues ב-access-log + ה-issue מופיע בלוח. לבדוק גם בלוח רגיל (לא תור חילוץ) ובשתי החברות.", "status": "cancelled", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-06-03T00:00:00.000Z" }, { "id": "77", "title": "תיקון מיפוי שדות בהעלאת פסיקת ועדת-ערר — מראה-מקום נדחס ל-case_number; case_number לא ניתן לעריכה", "description": "בטופס העלאת פסיקה (precedent-upload-sheet), עבור החלטות ועדת-ערר ה-frontend ממפה את שדה \"מראה המקום\" אל case_number (`case_number: citation.trim()`), כך שהמזהה הייחודי מקבל את המראה-מקום הארוך במקום מספר תיק נקי (למשל '8027-25'). בנוסף case_number כלל לא קיים ב-PrecedentUpdateRequest — אז מסך העריכה לא יכול לתקן אותו בדיעבד. citation_formatted נשאר ריק בהעלאה (מתמלא רק בחילוץ מטא). תוצאה ב-8027-25: case_number=מראה-מקום, case_name=מראה-מקום, מראה-מקום ריק עד החילוץ.", "details": "קבצים: web-ui/src/components/precedents/precedent-upload-sheet.tsx:121-123 (committee path ממפה citation→case_number); web/app.py:5147-5163 (PrecedentUpdateRequest חסר case_number); mcp-server/.../internal_decisions.py (id_field=case_number, display_name_fallback=case_number); precedent_metadata_extractor.py:247-253 (guard: case_name מתוקן רק אם ריק או ==case_number, לכן לא תיקן). תיקון מוצע: (1) בטופס committee — שדה נפרד \"מספר תיק (מזהה ייחודי)\" שממפה ל-case_number, ולמפות \"מראה המקום\" ל-citation (→citation_formatted), במקום לדחוס הכל ל-case_number; (2) להוסיף case_number ל-PrecedentUpdateRequest כדי שהעריכה תוכל לתקן בדיעבד (update_case_law כבר מתיר אותו); (3) להריץ `npm run api:types`. ראה כללי השם שהוגדרו: מזהה ייחודי = שם הקובץ/מספר תיק; מראה-מקום בשדה שלו; שם קצר = שם הצד.", "testStrategy": "להעלות פסיקת ועדת-ערר עם מספר תיק + מראה-מקום נפרדים → לוודא case_number=מספר התיק, citation_formatted=מראה-מקום, case_name=שם קצר. לפתוח עריכה ולוודא שניתן לתקן case_number.", "status": "done", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-06-02T12:17:44.302Z" }, { "id": "78", "title": "כשל שקט ב-wakeup לחילוץ פסיקה — חילוץ אוטומטי לא רץ והתיק נתקע ב-pending", "description": "אחרי העלאת פסיקה, הבקאנד מסמן metadata+halacha כ-pending וקורא ל-pc_wake_for_precedent_extraction להעיר את ה-CEO. הקריאה נבלעת בשקט (try/except 'non-fatal') — אם PAPERCLIP_BOARD_API_KEY חסר מחזיר {ok:false,skipped:no_api_key}, או שה-wakeup API נכשל — והתוצאה: ה-CEO לא מתעורר, לא רץ חילוץ מטא ולא חילוץ הלכות, וה-UI מציג 'ממתין לחילוץ' לנצח. קרה ב-8027-25 (תוקן ידנית עם precedent_process_pending). זה גם הסיבה ששדות המטא (תקציר/headnote/תגיות/citation) היו ריקים.", "details": "קבצים: web/app.py:5250-5262 (wakeup best-effort, exception נבלעת); web/paperclip_client.py:816-820 (skip שקט כש-no api key) ו-~905-907 (כשל API נבלע). תיקון מוצע: (1) להציף את הכשל למשתמש — סטטוס מובחן (extraction_wakeup_failed / 'ממתין-לעיבוד-ידני') ב-UI במקום 'pending' אילם; (2) fallback אוטומטי — אם ה-wakeup נכשל, או job מתוזמן (כמו sync-case-status) שמנקז את התור עם precedent_process_pending, או retry; (3) לאמת אם PAPERCLIP_BOARD_API_KEY מוגדר בקונטיינר (Coolify env) — אם לא, להוסיף. עיין reference: project_precedent_auto_extraction. לא לבלוע exceptions בשקט (feedback_silent_swallow).", "testStrategy": "להעלות פסיקה חדשה ולוודא שחילוץ מטא+הלכות רץ אוטומטית (CEO מתעורר), או שבכשל wakeup מופיע סטטוס שגיאה ברור + מסלול ניקוז אוטומטי. לבדוק שאין 'pending' אילם.", "status": "done", "dependencies": [], "priority": "high", "subtasks": [], "updatedAt": "2026-06-02T12:07:22.194Z" }, { "id": "79", "title": "[#55 follow-up] chunker — כותרות-סעיף מבודדות נשארות chunks זעירים (<50)", "description": "ה-chunker ההיררכי הנוכחי (אחרי תיקון #55) עדיין פולט מדי פעם chunk זעיר שהוא כותרת-סעיף בודדת שלא מוזגה קדימה לתוכן שאחריה. התגלה בסגירת #57 (re-chunk legacy): מתוך 73 תקדימים שעברו reindex, נשארו 4 chunks זעירים — כולם כותרות מבודדות: 'דיון' (ע\"א 5138/04, len=4), 'טענות המשיבים' (בג\"ץ 6525/15, len=13), 'העובדות וההליכים' (בר\"מ 2340/02, len=16), ושבר-ציטוט 'כלל התושבים\". (ע' 13 להחלטה)' (403-17, len=32). לא שאריות legacy — אלה פלט דטרמיניסטי של ה-chunker הנוכחי.", "details": "השפעה: נמוכה — chunks אלה כבר מסוננים ב-query-time (פילטר length>=50 שנוסף ב-#55), אז החיפוש לא מושפע; זו בעיית-איכות-chunking ולא בעיית-אחזור. מיקום: chunker ההיררכי ב-mcp-server (chunk_document_hierarchical / מדיניות מיזוג הכותרות שב-#55). התיקון הצפוי: כשכותרת/heading קצרה (<50, או section_type שמתחיל סעיף) נותרת כ-chunk עצמאי ללא גוף — למזג אותה קדימה אל ה-chunk הבא (anchor-forward), או אחורה אם אין הבא. לשים לב ל-section boundaries: 'דיון'/'טענות המשיבים' הן תחילת סעיף — המיזוג צריך לצרף את הכותרת לראש הסעיף שאחריה, לא לזנב הקודם. אימות: להריץ scripts/rechunk_legacy_precedents.py אחרי התיקון — אמור להגיע ל-0 chunks<50 (או רק שברי-ציטוט לגיטימיים נדירים). תלוי ב-#55. ראה גם feedback_no_reocr_retrofit (re-chunk מ-full_text בלבד).", "testStrategy": "אחרי תיקון ה-chunker: reindex של 4 התיקים (ע\"א 5138/04, בג\"ץ 6525/15, בר\"מ 2340/02, 403-17) → 0 chunks<50 בהם; SELECT count(*) FROM precedent_chunks WHERE length(trim(content))<50 → 0 (או רק שברי-ציטוט). ללא רגרסיה: search_precedent_library עדיין מחזיר את התיקים.", "status": "done", "dependencies": [ "55" ], "priority": "low", "subtasks": [], "updatedAt": "2026-06-03T08:10:57.844Z" }, { "id": "80", "title": "[#15 follow-up] בדיקת ערך image-answer ל-multimodal → הכרעה על backfill 140 legacy", "description": "נסגר 2026-06-03 — ההנחה התבררה שגויה בכל מרכיב (full check). לא '140 מסמכים / 17,700 עמ' / שעתיים / אישור-עלות chaim + תיוג דפנה', אלא: מתוך 140 חסרי-image רק 65 PDF (השאר MD/DOCX — ה-pipeline מרנדר PDF בלבד), ובסך 704 עמ'. תיקי-השמאות (כל ערך ה-multimodal) כבר היו 8/12 מוטמעים — הפער היחיד היה תיק 8070-25 (4 מסמכי שמאות).", "details": "בוצע: backfill מקומי (multimodal_backfill.py 8070-25, voyage-multimodal-3, ~30 שניות) → כל 14 מסמכי 8070-25 הוטמעו. **כיסוי שמאות עכשיו 12/12 (100%)**. נותרו 51 PDF/649 עמ' ללא multimodal — כולם טקסטואליים (reference/response/appeal), ו-#15 הוכיח ש-multimodal לא עוזר (אף מדלל) על מסמכים טקסטואליים → **מושארים בכוונה** text-only; זו לא חוסר-עקביות אלא הקונפיג הנכון. אין צורך ב-gold-set/דפנה/אישור-עלות — העלות הייתה סנטים והערך הוכח ב-#15 לתיקי ועדה/שמאות. #80 done (טכני, לא human-gated).", "testStrategy": "eval על ה-image-answer gold-set: multimodal ON מאחזר ≥1 מסמך/קטע ש-OFF מפספס (R@k גבוה יותר על שאלות-טבלה).", "status": "done", "dependencies": [ "15" ], "priority": "low", "subtasks": [], "updatedAt": "2026-06-03T00:00:00.000Z" }, { "id": "81", "title": "איכות חילוץ הלכות — לוודא שמה שמחולץ הוא הלכה אמיתית ולא ציטוט/אמרת-אגב", "description": "מנוע חילוץ ההלכות מפיק כיום פריטים שאינם 'הלכות' במובן המהותי: אמרות-אגב שהערכאה לא הכריעה בהן, יישומים ספציפיים-לתיק (rule_type=application), ציטוטים חתוכים, ופירוק-יתר (עד 351 'הלכות' מפסק אחד). המשימה: לחדד את ה-prompt ולהוסיף ולידטורים אוטומטיים כך שרק עיקרון משפטי בר-הכללה ובר-הסתמכות ייכנס למאגר. מבוססת מחקר מקצועי (ratio decidendi מול obiter dictum, holding-extraction בספרות legal-NLP, קריטריונים לאיכות rule_statement). תתי-המשימות יוגדרו לאחר המחקר.", "details": "רקע מבצעי (ניקוי 2026-06-03): נמחקו 196 רשומות מתוך 1650 (165 כפילויות תוכן + 31 Tier B/C). גיבוי: data/audit/halacha-cleanup-backup-20260603T101747Z.sql ; מניפסט: data/audit/halacha-cleanup-manifest-20260603T101747Z.csv . קוד רלוונטי: mcp-server/src/legal_mcp/services/halacha_extractor.py (prompts BINDING/PERSUASIVE, _coerce_halacha, אימות ציטוט). תחומי בדיקה ידועים: (א) חסימת quote_verified=false מהתור; (ב) הוצאת rule_type=application מהגדרת 'הלכה'; (ג) שמירה על דחיית dicta שלא הוכרעו; (ד) תקרת כמות/גרנולריות לפסק; (ה) הגנה מפני ציטוט חתוך (truncation guard). מפרט מאומת: docs/halacha-strict-rubric.md (הרובריקה האגרסיבית שהנחיתה ניקוי קורפוס 1454→534 ב-2026-06-03, שפר 51→22). להטמיע אותה במחלץ + dedup-on-insert (#82).", "testStrategy": "Gold-set ידני של ~30 פריטים מתויגים הלכה/לא-הלכה ע\"י דפנה/חיים; מדידת precision/recall של המחלץ המעודכן מולו. בדיקת רגרסיה: הרצת המחלץ החדש על 3-5 פסקים שכבר נוקו והשוואת הפריטים.", "status": "in-progress", "dependencies": [], "priority": "high", "subtasks": [ { "id": 1, "title": "מבחן ההיפוך (Wambaugh) + גלאי אי-הכרעה בפרומפט", "description": "הטמעת מבחן ההיפוך של Wambaugh ולקסיקון ביטויי אי-הכרעה עבריים בשני וריאנטי הפרומפט; ניסוח עיקרון, שלילתו, ובדיקה אם תוצאת הוועדה הייתה משתנה — אם לא → obiter.", "details": "מקור: Wambaugh inversion test; Goodhart material-facts. לקסיקון: 'אין צורך להכריע','מבלי לקבוע מסמרות','ניתן להניח','לכאורה','למעלה מן הצורך','אגב אורחא' → מאלצים rule_type=obiter ו-confidence<0.80. קוד: halacha_extractor.py prompts BINDING/PERSUASIVE.", "status": "done", "dependencies": [], "testStrategy": "על מדגם 30 רשומות obiter שזוהו ידנית באודיט, ≥90% מסווגות obiter ולא מאושרות אוטומטית.", "parentId": "81", "updatedAt": "2026-06-03T12:32:01.304Z" }, { "id": 2, "title": "ולידטור שלמות ציטוט (truncation guard, V1)", "description": "בדיקה ש-supporting_quote מתחיל בגבול משפט ומסתיים בפיסוק סופי (./?/:/מרכאה סוגרת) ואינו קטוע באמצע משפט; דגלון לציטוט קטוע.", "details": "מקור: span-completeness / grounding-score. כיום הבדיקה מאמתת נוכחות verbatim אך לא שלמות. דוגמת אודיט: ציטוט '...ראוי כי תהיה השפעה על ה' (חתוך).", "status": "done", "dependencies": [], "testStrategy": "על 50 ציטוטים קטועים ידועים ≥95% מסומנים; false-positive <5% על ציטוטים תקינים.", "parentId": "81", "updatedAt": "2026-06-03T12:32:01.318Z" }, { "id": 3, "title": "ולידטור entailment (NLI) בין rule ל-quote (V2)", "description": "מודל NLI מאמת ש-rule_statement נובע (entailed) מ-supporting_quote; neutral/contradiction → מתחת לסף אישור אוטומטי.", "details": "מקור: NLI-faithfulness (DeBERTa-NLI / atomic-fact verification). בודק שהכלל אכן נתמך בציטוט ולא הוזה/הורחב מעבר למקור.", "status": "pending", "dependencies": [], "testStrategy": "על gold-set מתויג, NLI-reject מתאם עם פסילה אנושית ב-AUC ≥0.80.", "parentId": "81" }, { "id": 4, "title": "ולידטור הפשטה + סיווג application (V3)", "description": "פסילת restatement דק (token-overlap גבוה מול הציטוט) וסיווג כללים תלויי-עובדות/סכומים/צדדים-ספציפיים כ-application (מוחרג מאישור binding).", "details": "מקור: rule-synthesis (Mangan) — broad holding מפשיט עובדות ספציפיות. כיום application סותם את התור (16/55 pending נמחקו באודיט).", "status": "in-progress", "dependencies": [], "testStrategy": "על מדגם 40 פריטי application מהאודיט, ≥85% מזוהים ולא מאושרים כ-binding/interpretive.", "parentId": "81", "updatedAt": "2026-06-03T12:32:19.701Z" }, { "id": 5, "title": "בקרת over-extraction: clustering + תקרה (V5)", "description": "embedding+clustering של ה-rule_statements בתוך פסק-דין, נציג אחד לאשכול, ותקרה לכמות לפי מספר מקטעי reasoning/decision (לא לפי מספר משפטים).", "details": "מקור: SemDeDup + claim-clustering (MultiClaimNet). דוגמה: פסק 403-17 ייצר 351 'הלכות' — over-decomposition.", "status": "pending", "dependencies": [], "testStrategy": "פסק עם 351 פריטים יורד ל-≤ מספר מקטעי ההנמקה; ירידה כוללת ≥40% בכפילויות.", "parentId": "81" }, { "id": 6, "title": "סינון לפי תפקיד רטורי (rhetorical-role pre-filter)", "description": "רק מקטעי Reasoning/Decision מועמדים לחילוץ; Facts/Arguments מוחרגים מראש.", "details": "מקור: LegalSeg / rhetorical-role labeling (Bhattacharya). בלבול Facts↔Reasoning הוא מחלקת השגיאה הדומיננטית — סינון מקדים מעלה precision.", "status": "pending", "dependencies": [], "testStrategy": "precision של מועמדים שעוברים סינון עולה ≥10 נק' מול baseline על gold-set.", "parentId": "81" }, { "id": 7, "title": "בניית gold-set + מבחן אנונימיזציית ציטוטים", "description": "תיוג ידני של ~150 רשומות (binding/interpretive/obiter/application + שלמות-ציטוט) ע\"י חיים/דפנה, ומבחן אנונימיזציה (שמות-תיק בדויים) לזיהוי שינון מול הנמקה אמיתית.", "details": "מקור: CaseHOLD/RegLab (macro-F1≈0.72-0.74 לזיהוי holdings — לא 'פתור') + מבחן anonymization (arXiv:2505.02172). בסיס למדידת כל הוולידטורים.", "status": "pending", "dependencies": [], "testStrategy": "gold-set מתויג עם κ≥0.6 בין שני מתייגים; pipeline מודד P/R/F1 מולו.", "parentId": "81" }, { "id": 8, "title": "כיול מחדש של סף האישור האוטומטי", "description": "אחרי V1-V5, כיול סף ה-0.80; שקילת החלפת confidence עצמי בציון משולב (confidence × validators).", "details": "מקור: CaseHOLD מראה ש-self-confidence 0.80 אופטימי מדי בלי אימות חיצוני. תלוי ב-gold-set (81.7).", "status": "pending", "dependencies": [ 7 ], "testStrategy": "precision של פריטים מאושרים-אוטומטית ≥0.90 על gold-set, עם recall מתועד ל-trade-off.", "parentId": "81" } ], "updatedAt": "2026-06-03T12:32:19.701Z" }, { "id": "82", "title": "Dedup בזמן הכנסה — מניעת הלכות כמעט-זהות בכתיבה (semantic dedup on insert)", "description": "store_halachot_for_chunk מבצע INSERT עיוור ללא בדיקת כפילות, ולכן נצברו עשרות הלכות 'אותו עיקרון במילים אחרות'. המשימה: לפני שמירה, לבדוק דמיון סמנטי (embedding) מול הלכות קיימות באותו פסק ולדלג/למזג near-duplicates, וכן לזהות ציטוט-תומך זהה. מבוססת מחקר (ספי near-duplicate ב-embedding-IR, MinHash/LSH מול cosine, בחירת צורה קנונית, merge מול skip). תתי-המשימות יוגדרו לאחר המחקר.", "details": "ממצא מהניקוי: סף cosine ≥0.90 תוך-פסק זיהה כפילויות אמיתיות בוודאות גבוהה (הרצועה 0.90-0.95 הייתה כמעט כולה 'אותו עיקרון בניסוח שונה'); ≥0.95 = ודאי. ציטוט-תומך זהה = איתות ודאי. להחליט: סף מבצעי, התנהגות (skip/merge/flag-for-review), ובחירת השורד (approved>pending, ביטחון גבוה, quote_verified). קוד: db.store_halachot_for_chunk; קיים idx_halachot_vec (pgvector).", "testStrategy": "הרצה חוזרת של חילוץ על פסק שכבר חולץ — אפס כפילויות חדשות. בדיקת יחידה: הזנת שתי הלכות מנוסחות-שונה של אותו עיקרון → רק אחת נשמרת. בדיקה שלילית: שתי הלכות שונות ≥0.85 אך מובחנות → שתיהן נשמרות.", "status": "in-progress", "dependencies": [], "priority": "high", "subtasks": [ { "id": 1, "title": "כיול ספים מתוך ה-audit (calibration harness)", "description": "בניית set מתויג מזוגות האודיט שכבר נבדקו ידנית; sweep של cosine × (Jaccard/Levenshtein) ודיווח precision/recall לבחירת נקודת עבודה.", "details": "מקור: SemDeDup tunes ε ע\"י דגימת ~10% ואינטרפולציה ליעד — לכייל, לא לנחש. הנתונים קיימים במניפסט הניקוי data/audit/halacha-cleanup-manifest-*.csv.", "status": "pending", "dependencies": [], "testStrategy": "הסקריפט מפיק (cosine_hi, band_lo, lexical_lo, jaccard_τ, levenshtein_δ) עם ≥0.95 precision נגד מיזוג-שווא של כללים מובחנים.", "parentId": "82" }, { "id": 2, "title": "שכבת בדיקה אקזקטית בתוך precedent (exact-cosine probe)", "description": "בהכנסה: שאילתת halachot קיימות מסוננת ב-precedent_id עם cosine מדויק (לא ANN) + התאמת supporting_quote מנורמל.", "details": "מקור: pgvector ANN (HNSW/IVFFlat) מאבד recall → false-negative בדדופ. מועמדים בתוך פסק בודד = set קטן → exact scan בטוח. שמירה על HNSW לנתיב הקריאה.", "status": "done", "dependencies": [], "testStrategy": "בדיקת יחידה: dup מנוסח-שונה (cosine 0.92) + dup ציטוט-verbatim שניהם מזוהים; כלל מובחן (0.7) לא; EXPLAIN מראה filtered scan ולא ANN.", "parentId": "82", "updatedAt": "2026-06-03T12:32:01.334Z" }, { "id": 3, "title": "זנב מתחת ל-0.90 — אות לקסיקלי משני", "description": "הוספת Jaccard-on-shingles + Levenshtein מנורמל על rule_statement; שער לרצועה 0.83-0.90 (cosine נמוך אך חפיפה לקסיקלית גבוהה → flag).", "details": "מקור: hybrid lexical+semantic עדיף על כל אחד לבד (arXiv:1805.11611, WED arXiv:1810.10752). תופס את הזנב שדמיון-וקטורי לבד מפספס בלי להוריד סף גלובלי.", "status": "pending", "dependencies": [], "testStrategy": "זוג מנוסח-שונה ב-cosine~0.87 עם חפיפה גבוהה → flag; זוג בחפיפה נמוכה ב-0.87 → נשמר כחדש.", "parentId": "82" }, { "id": 4, "title": "התנהגות בהתאמה: skip/merge/flag + מיזוג provenance", "description": "מימוש החלטה מדורגת (ציטוט-זהה/≥0.95→skip+merge; 0.90-0.95→merge; 0.83-0.90+לקסיקלי→flag). במיזוג: איחוד citations/corroboration/source-refs; בחירת קנוני לפי provenance עשיר ביותר, שובר-שוויון ציטוט verbatim ארוך.", "details": "מקור: entity-resolution — לכללים יקרי-ערך flag+merge-with-provenance, לא drop עיוור (ThingSolver/ScrapingAnt). בחירת נציג לפי כלל-תוכן (SemDeDup: גאומטריה שולית).", "status": "in-progress", "dependencies": [], "testStrategy": "מיזוג שתי שורות → שורה אחת עם איחוד קישורי citation/corroboration; שורות flag נוחתות בטבלת תור-ביקורת, לא נמחקות ולא ממוזגות אוטומטית.", "parentId": "82", "updatedAt": "2026-06-03T12:32:19.710Z" }, { "id": 5, "title": "אידמפוטנטיות ומפתח ייחוד", "description": "אילוץ UNIQUE על (precedent_id, normalized supporting_quote) + נתיב ON CONFLICT כך שהרצת חילוץ חוזרת אינרטית.", "details": "מקור: 'dedup=suppression, idempotency=identity' — שער fuzzy חייב מפתח-זהות מדויק לצדו. מתואם עם #83.", "status": "in-progress", "dependencies": [], "testStrategy": "הרצת store_halachot_for_chunk פעמיים על אותו chunk → אפס שורות נטו חדשות.", "parentId": "82", "updatedAt": "2026-06-03T12:32:19.721Z" }, { "id": 6, "title": "הגנה מפני over-merge טרנזיטיבי", "description": "מיזוג בהכנסה רק pairwise מול שורות קנוניות קיימות; ללא connected-components closure בהכנסה — קריסות רב-שורתיות נדחות לתור-ביקורת.", "details": "מקור: over-merge דרך CC הוא הסיכון המרכזי (A~B~C קורס גם כש-A,C מובחנים) — בכלל משפטי = אובדן תקדים.", "status": "pending", "dependencies": [], "testStrategy": "שרשרת סינתטית A~B~C כש-A,C מתחת לסף זה-לזה אינה קורסת לשורה אחת בהכנסה; לכל היותר מיזוג pairwise + flag.", "parentId": "82" }, { "id": 7, "title": "(אופציונלי) batch reconciliation חוצה-פסקים", "description": "job offline שמרני (סף ≥0.95) לדדופ חוצה-פסקים, נפרד מנתיב ההכנסה, כותב לאותו תור-ביקורת.", "details": "מקור: cross-precedent שמרני יותר מ-within-precedent (האודיט הראה ש-≥0.90 אמין רק תוך-פסק). תחת scripts/ + עדכון SCRIPTS.md.", "status": "pending", "dependencies": [ 1 ], "testStrategy": "dry-run מפיק דוח מועמדים חוצי-פסקים עם cosine+lexical; כלום לא מוחל בלי flag.", "parentId": "82" } ], "updatedAt": "2026-06-03T12:32:19.721Z" }, { "id": "83", "title": "חוסן pipeline החילוץ — re-run אידמפוטנטי + אינדוקס תקין (תיקון באגים)", "description": "התגלו שני באגים: (1) halacha_index מוקצה per-chunk ולכן אינו ייחודי לפסק — שני עקרונות שונים מקבלים אותו מספר (לא כפילות, אך שובר dedup/מיון מבוסס-אינדקס); (2) חילוץ רץ פי-2/3 על אותו פסק (למשל 85026-17 שלוש ריצות תוך דקתיים) ומוסיף append במקום להחליף — ה-advisory lock לא מנע. המשימה: אינדוקס ייחודי לפסק, force=True שמוחק לפני re-extract, וחיזוק ה-lock/אידמפוטנטיות. מחקר קצר: דפוסי idempotency/exactly-once ב-pipelines.", "details": "קוד: halacha_extractor.py (global advisory lock, per-chunk checkpoints ב-precedent_chunks.halacha_extracted_at, force flag), db.store_halachot_for_chunk (הקצאת halacha_index). לשקול unique constraint (case_law_id, halacha_index) אחרי תיקון ההקצאה.", "testStrategy": "הרצת חילוץ פעמיים ברצף על אותו פסק → ספירה זהה, אפס אינדקסים כפולים. הרצת force=True → המאגר מוחלף ולא מצטבר. בדיקת מרוץ: שתי הרצות במקביל → רק אחת מבצעת (lock).", "status": "done", "dependencies": [], "priority": "medium", "subtasks": [ { "id": 1, "title": "נעילה גלובלית אמינה (advisory lock על חיבור ייעודי)", "description": "העברת ה-pg_advisory_lock מחיבור pooled לחיבור ייעודי שאינו ממוחזר לאורך כל ה-job (או pg_advisory_xact_lock בדפוס מתאים), עם finally שמשחרר תמיד; תיעוד איסור transaction-pooler לפני החיבור.", "details": "מקור: PG docs — session advisory lock לא בטוח תחת transaction-pooling (PgBouncer ממליץ נגדו). השורש האמיתי של 3 ריצות תוך 2 דקות: הנעילה לא החזיקה. קוד: halacha_extractor.py:372-394.", "status": "done", "dependencies": [], "testStrategy": "שתי הרצות extract במקביל על אותו precedent — השנייה מחזירה busy ולא רצה (נבדק עם 2 תהליכים נפרדים).", "parentId": "83", "updatedAt": "2026-06-03T13:08:00.800Z" }, { "id": 2, "title": "אילוץ UNIQUE (case_law_id, halacha_index)", "description": "migration ל-halachot עם UNIQUE (case_law_id, halacha_index) כרשת ביטחון נגד התנגשויות מספור.", "details": "מקור: FireHydrant/OneUptime — per-scope ordinal דורש UNIQUE(scope,number) כערובת התקינות; הנעילה היא אופטימיזציה. כיום ההקצאה MAX+1 מוגנת רק ב-asyncio.Lock תוך-תהליכי. db.py:645-669.", "status": "done", "dependencies": [], "testStrategy": "INSERT ידני של index כפול לאותו precedent נכשל ב-DB; query GROUP BY case_law_id,halacha_index HAVING count>1 מחזיר 0 בקורפוס.", "parentId": "83", "updatedAt": "2026-06-03T13:08:00.811Z" }, { "id": 3, "title": "דה-דופ לפי תוכן (content_hash + ON CONFLICT DO NOTHING)", "description": "עמודת content_hash (md5 של rule_statement+supporting_quote) + UNIQUE(case_law_id, content_hash); שינוי ה-INSERT ל-ON CONFLICT DO NOTHING.", "details": "מקור: upsert/replace הם פרימיטיב האידמפוטנטיות. משלים את שער ה-fuzzy של #82 במפתח-זהות מדויק. db.py:3325-3374.", "status": "cancelled", "dependencies": [], "testStrategy": "הרצת extract(force=False) פעמיים ברצף על precedent שהושלם → מספר ה-halachot לא גדל.", "parentId": "83", "updatedAt": "2026-06-03T13:08:06.185Z" }, { "id": 4, "title": "מספור עמיד למרוץ ב-store_halachot_for_chunk", "description": "retry-on-unique-violation סביב read-MAX→insert (או חישוב index מ-sequence עם RETURNING) — ללא הסתמכות על asyncio.Lock בלבד לבטיחות חוצת-תהליכים.", "details": "מקור: race condition handling ב-PG. כיום MAX+1 מוגן רק תוך-תהליכית. db.py:3341-3344.", "status": "done", "dependencies": [ 2 ], "testStrategy": "בדיקה שמדמה שני קוראי-MAX מקבילים — שניהם נשמרים עם indexים שונים רצופים, אפס DuplicateKey לא-מטופל.", "parentId": "83", "updatedAt": "2026-06-03T13:08:00.826Z" }, { "id": 5, "title": "semantics של force = replace אטומי + עמידות לקריסה", "description": "ודאות ש-force=True מבצע delete+checkpoint-clear בטרנזקציה אחת (קיים ב-reset_halacha_extraction), וש-resume אחרי קריסה אמצע re-extract לא מכפיל (הודות לאילוצי 83.2/83.3).", "details": "מקור: delete-before-insert atomic / replace-partition. per-chunk commits נשמרים ל-resumability. db.py:3299-3304.", "status": "done", "dependencies": [ 2, 3 ], "testStrategy": "הזרקת קריסה אחרי חלק מהצ'אנקים → resume משלים ללא כפילויות; count(halachot) תואם הרצה נקייה.", "parentId": "83", "updatedAt": "2026-06-03T13:08:00.834Z" }, { "id": 6, "title": "ניקוי נתונים היסטוריים לפני החלת אילוצים", "description": "סקריפט חד-פעמי (scripts/ + SCRIPTS.md) שמזהה precedents עם indexים מתנגשים, ממספר מחדש רציף, ומכין את הקורפוס להחלת UNIQUE של 83.2/83.3.", "details": "הניקוי של 2026-06-03 טיפל בכפילויות תוכן אך לא במספור; אילוצי UNIQUE ייכשלו אם יש index כפול שריר. גיבוי קיים: data/audit/halacha-cleanup-backup-*.sql.", "status": "done", "dependencies": [ 2 ], "testStrategy": "אחרי הרצה, אילוצי 83.2/83.3 נוצרים ללא שגיאה; דוח CSV ב-data/audit/ מפרט כמה תוקנו לכל precedent.", "parentId": "83", "updatedAt": "2026-06-03T13:08:00.841Z" } ], "updatedAt": "2026-06-03T13:08:10.793Z" }, { "id": "84", "title": "טריאז' תור אישור ההלכות — אישור יעיל ולא מתיש", "description": "אישור ההלכות ידני ומתיש: קריאת עקרונות כמעט-זהים שוב ושוב, ללא תיעדוף או קיבוץ. המשימה: לייעל את חוויית האישור — מיון לפי ביטחון/corroboration, קיבוץ near-duplicates יחד, auto-defer/הסתרה של פריטים באיכות נמוכה, ופעולות batch (אישור/דחייה מרובים). מבוססת מחקר (human-in-the-loop review UX, active-learning prioritization, triage queues). תתי-המשימות לאחר המחקר.", "details": "הקשר: הדחייה כמעט לא בשימוש (1/1650) — התור הוא 'אשר-או-השאר-תלוי'. כלים קיימים: halachot_pending, halacha_review (MCP), דף ביקורת ב-UI. לשלב עם פלט #81 (איכות) ו-#82 (dedup) כדי שהתור יציג רק מועמדים אמיתיים ומקובצים.", "testStrategy": "מדידת זמן/קליקים לאישור N הלכות לפני/אחרי. בדיקה: פריטים כמעט-זהים מוצגים כקבוצה אחת; פריטי איכות-נמוכה אינם מופיעים כברירת-מחדל בתור.", "status": "in-progress", "dependencies": [ "81", "82" ], "priority": "medium", "subtasks": [ { "id": 1, "title": "סינון מועמדים אמיתיים בלבד בתור (quality gating מ-#81)", "description": "הסתרת פריטים שסומנו low-quality (quote_verified=false, rule_type=application, truncated) מתצוגת ברירת-המחדל של halachot_pending; ניתובם ל-bucket 'דורש תיקון-חילוץ'.", "details": "מקור: default-defer/auto-archive של איכות-נמוכה (Prodigy/content-moderation). צורך פלט #81. כלי: halachot_pending.", "status": "in-progress", "dependencies": [], "testStrategy": "תור ברירת-מחדל מחזיר 0 פריטים עם דגלי low-quality; פרמטר include_low_quality=true עדיין חושף אותם.", "parentId": "84", "updatedAt": "2026-06-03T13:43:18.478Z" }, { "id": 2, "title": "קיבוץ near-duplicates לכרטיס ביקורת אחד (מ-#82)", "description": "halachot_pending מחזיר near-duplicates (cosine ≥0.90) מקובצים בכרטיס אחד: נציג קנוני + מונה וריאנטים + רשימת וריאנטים.", "details": "מקור: similarity-clustering + review-by-cluster (Labelbox/Label Studio). צורך פלט #82.", "status": "pending", "dependencies": [], "testStrategy": "קבוצת כפילויות ידועה (מהניקוי 2026-06-03) חוזרת ככרטיס מקובץ אחד ולא N שורות; הוריאנטים ניתנים למנייה.", "parentId": "84" }, { "id": 3, "title": "תיעדוף התור לפי ציון משוקלל (uncertainty + impact)", "description": "החלפת FIFO בציון עדיפות משולב: ביטחון באזור-אפור קודם, מוגבר ע\"י corroboration של ציטוט-בודד ותחומי-עיסוק בכיסוי דליל; דיכוי כפילויות של פריט-הראש.", "details": "מקור: active learning — least-confidence first + diversity/impact weighting (Encord/Label Studio/greip). uncertainty לבד מדגים יתר-על-המידה near-dups.", "status": "in-progress", "dependencies": [], "testStrategy": "בהינתן set מתוכנן, ראש התור הוא הפריט בעל הציון המשולב הגבוה; שתי כפילויות לא מופיעות יחד ב-top-5.", "parentId": "84", "updatedAt": "2026-06-03T13:43:18.488Z" }, { "id": 4, "title": "פעולות batch: אישור/דחייה לכל הקבוצה", "description": "הרחבת halacha_review לקבלת מזהה-קבוצה והחלת approve/reject על כל הוריאנטים בקריאה אחת, עם אפשרות override ידני של וריאנט לפני commit.", "details": "מקור: propagate-one-decision-to-group + checkpoint אנושי על bulk (Labelbox). סיכון: bulk-apply עיוור מפיץ שגיאה — חובה הצגת וריאנטים לפני אישור.", "status": "done", "dependencies": [], "testStrategy": "אישור קבוצת 5 וריאנטים מסמן את כולם approved בפעולה אחת; דחייה מסמנת את כולם rejected; override של וריאנט בודד אפשרי.", "parentId": "84", "updatedAt": "2026-06-03T13:43:13.227Z" }, { "id": 5, "title": "דחייה/השהיה זולה + סמנטיקת reject נכונה", "description": "הוספת outcomes מפורשים reject ו-defer ל-halacha_review; reject שומר אות שלילי מתמשך (מזין חזרה ל-#81), defer משאיר pending ומחזיר לסוף התור.", "details": "מקור: Prodigy accept/reject/ignore — הבחנה סמנטית היא הפתרון ל-1/1650. כיום אין פועל 'זבל' זול ולכן זבל מצטבר כ-pending.", "status": "done", "dependencies": [], "testStrategy": "reject קובע status rejected מתמשך + סיבה (queryable למשוב מחלץ); defer משאיר pending אך מוריד עדיפות.", "parentId": "84", "updatedAt": "2026-06-03T13:43:13.239Z" }, { "id": 6, "title": "UI: ביקורת keyboard-first עם 4 מקשים (a/r/space/e)", "description": "עיצוב-מחדש של דף הביקורת ב-Next.js לכרטיס-בכל-פעם, מונע-מקלדת (Approve a / Reject r / Defer space / Edit e), עם הקשר-קבוצה וציטוט-מקור inline.", "details": "מקור: keyboard-first מעלה throughput 20-30% בלי פגיעה באיכות (CleverX); one-card-at-a-time מפחית עומס קוגניטיבי (Hick's law). דף: web-ui /feedback או דף ביקורת ייעודי.", "status": "done", "dependencies": [ 4, 5 ], "testStrategy": "מבקר יכול approve/reject/defer/edit-then-approve כולו במקלדת בלי עכבר; הכרטיס מציג מונה-וריאנטים וציטוט-מקור.", "parentId": "84", "updatedAt": "2026-06-03T13:43:13.253Z" }, { "id": 7, "title": "מדדי תור: throughput + איכות", "description": "אינסטרומנטציה וחשיפה: time-per-item, decisions-per-session, יחס approve/reject/defer/edit, pending-count + גיל-הישן-ביותר, ומדגם spot-check post-hoc של פריטים מאושרים.", "details": "מקור: Prodigy metrics + IAA (Krippendorff α / Gwet AC2). מבקר-יחיד לא נמדד ב-IAA → spot-check error rate חיוני.", "status": "pending", "dependencies": [ 5 ], "testStrategy": "endpoint/דף מדדים מדווח את הנ\"ל; נמדד before/after של קליקים-וזמן לביקורת N=20 הלכות.", "parentId": "84" } ], "updatedAt": "2026-06-03T13:43:18.488Z" }, { "id": "85", "title": "CEO MCP instance: nested claude -p exits 1 in write_interim_draft", "description": "write_interim_draft נכשל לכל 5 הבלוקים מתוך session ה-CEO עם 'Claude CLI failed (exit 1): unknown error'. אומת: claude CLI תקין מ-bash (exit 0), PATH+HOME של תהליך ה-MCP תקינים (/home/chaim/.local/bin/claude), אין ANTHROPIC_API_KEY ב-.env, הבלוקים נכתבים סדרתית (לא concurrency). סוכני משנה (proofreader/analyst CMPA-73..76) הריצו claude -p בהצלחה באותו יום. ⇒ כשל ספציפי ל-MCP server instance של ה-CEO. עוקף: האצלה ל-writer agent. דרוש: לבדוק מדוע nested claude -p נכשל מ-instance זה (אולי session lock / env stale); שקול restart ל-CEO agent session.", "details": "", "testStrategy": "", "status": "pending", "dependencies": [], "priority": "high", "subtasks": [] }, { "id": "86", "title": "טיפול ב-preamble/רציו של נבו — anti-contamination + gold-set מהרציו", "description": "התגלה (2026-06-03) ש-`strip_nevo_preamble` קיים ומחווט ל-ingest, אבל ה-regex `_DECISION_START` מזהה רק פתיחות של ועדת ערר (בפנינו/הערר שבנדון/ועדת הערר לתכנון/רקע עובדתי/עסקינן) — ולא פסקי-דין שנפתחים ב'פסק-דין' (כמו בג\"ץ 1764/05). לכן בפסקי-דין מנבו — בדיוק אלה שיש להם מיני-רציו — ה-preamble/רציו **אינו נחתך**, דולף לצ'אנקים, ועלול לזהם את חילוץ ההלכות (המחלץ קורא את התשובון של נבו) ואת הקורפוס. במקביל — הרציו של נבו הוא gold-set אנושי-מקצועי חינמי לאמידת איכות החילוץ.", "details": "קוד: mcp-server/src/legal_mcp/services/extractor.py — `strip_nevo_preamble` (~367), `_NEVO_MARKERS` (ספרות:/חקיקה שאוזכרה:/מיני-רציו:/...), `_DECISION_START` (~361). מחווט ב-ingest.py:161 ו-documents.py:152. הוכחה: ב-1764/05 המיני-רציו שרד כ-chunk מסוג intro (לא נחתך) ורק במזל לא חולץ (intro לא ב-EXTRACTABLE_SECTIONS). השוואת benchmark שבוצעה ידנית על 1764/05: 14 הלכות שלנו כיסו 100% מ-4 הלכות-הרציו של נבו + 2 נוספות, בגרנולריות פי ~3.5 (קשור ל-#81.5).", "testStrategy": "strip_nevo_preamble על טקסט 1764/05 מסיר את בלוק המיני-רציו ומתחיל מ'פסק-דין'; regression: פתיחות ועדת-ערר ממשיכות להיחתך נכון. benchmark מפיק recall/precision/granularity.", "status": "pending", "dependencies": [], "priority": "high", "subtasks": [ { "id": 1, "title": "הרחבת _DECISION_START לפסקי-דין (anti-contamination)", "description": "הוספת פתיחות פסק-דין ל-`_DECISION_START` (פסק-דין / פסק דין / 'השופט'/'כב' השופט'/'לפני:') כך ש-strip_nevo_preamble חותך את ה-preamble/רציו גם בפסקי-דין מנבו.", "details": "קוד: extractor.py `_DECISION_START`. שמירה על תאימות לאחור לפתיחות ועדת-ערר הקיימות.", "status": "pending", "dependencies": [], "testStrategy": "unit: strip_nevo_preamble(טקסט 1764/05) מסיר את המיני-רציו ומתחיל מ'פסק-דין'; טקסט ועדת-ערר עם בפנינו עדיין נחתך נכון; טקסט ללא preamble חוזר ללא שינוי.", "parentId": "86" }, { "id": 2, "title": "backfill — זיהוי וטיהור פסקי-דין שהרציו דלף אליהם", "description": "סקריפט לזיהוי פסקי-דין בקורפוס שה-preamble/רציו של נבו דלף לצ'אנקים (intro/legal_analysis) או להלכות שחולצו; re-ingest/strip + בדיקת זיהום בהלכות הקיימות.", "details": "להריץ אחרי 85.1. גיבוי לפני re-ingest. לבדוק האם הלכות קיימות הן העתק של רציו.", "status": "pending", "dependencies": [ 1 ], "testStrategy": "דוח (CSV ב-data/audit/) של פסקים מושפעים; אחרי טיהור — אף chunk לא מכיל בלוק מיני-רציו; re-extraction נקי.", "parentId": "86" }, { "id": 3, "title": "Nevo-ratio gold-set benchmark (מזין #81.7)", "description": "חילוץ בלוק המיני-רציו החתוך כ-ground-truth לכל פסק-דין מנבו; harness שמשווה הלכות-שלנו מול הרציו ומפיק recall (כיסוי הלכות-הרציו) / precision / יחס-גרנולריות.", "details": "מקור ground-truth חינמי ואיכותי. ה-benchmark על 1764/05 כבר הודגם ידנית (recall=100%). לשמור את הרציו בשדה ייעודי (למשל case_law.headnote) במקום למחוק.", "status": "pending", "dependencies": [ 1 ], "testStrategy": "על 1764/05: recall=100%, מדווח granularity ratio; ניתן להריץ batch על כל פסקי-נבו ולהפיק טבלת איכות.", "parentId": "86" } ], "updatedAt": "2026-06-03T00:00:00.000Z" } ], "metadata": { "version": "1.0.0", "lastModified": "2026-06-03T13:43:18.488Z", "taskCount": 85, "completedCount": 77, "tags": [ "legal-ai" ] } } }