Commit Graph

800 Commits

Author SHA1 Message Date
e7d8b24d7c feat(pipeline): durable execution for final_halacha via LangGraph (P0, X16/INV-DUR1, #114)
scripts/_pipeline_runtime.py — runtime עמידות משותף: עוטף רשימת-צעדים async ב-LangGraph
StateGraph ליניארי עם AsyncSqliteSaver (checkpoint לכל צעד). קריסה/OOM ממשיכה מהצעד
שנכשל במקום להריץ הכל מחדש. degradation חיננית: ללא langgraph → ריצה ליניארית כמו קודם
(הכפתור לא נשבר). מימוש אחד לשני הפייפליינים (G2).

final_halacha_pipeline.py — 4 הצעדים ([0]extract [1]citations [2]corroboration [3]panel)
רצים דרך ה-runtime. CLI זהה + --fresh (ברירת-מחדל auto-resume). thread יציב לכל תיק;
dry-run = preview נפרד (תמיד fresh). קריסה בפאנל [3] → resume מ-[3] (steps 0-2 שמורים).

pyproject: extra "durable" (langgraph + langgraph-checkpoint-sqlite) — host-only,
optional. data/checkpoints/ ב-.gitignore.

גבול (X16 §1): LangGraph רק כמנוע-פנימי של הסקריפט — לא orchestrator (לא מסלול מקביל
ל-Paperclip; G2/G12). #108 (atomic extract) קדם לזה כתנאי.

אימות: test_pipeline_runtime.py — עם langgraph (venv-זמני): 3 passed (resume מדלג צעדים
שהושלמו · fresh מריץ-מחדש · linear). בלי langgraph (venv משותף): 1 passed + 2 skipped
(degradation). final_halacha מתקמפל ומיובא נקי בשני המצבים. הרצה end-to-end על הפייפליין
החי (DB+LLM) — לאחר `pip install -e ".[durable]"` בעץ הראשי.

Invariants: INV-DUR1 (עמידות), G2 (runtime יחיד), G3 (idempotency מחוזק).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 09:52:35 +00:00
20781398ee Merge pull request 'refactor(web-ui): פירוק התנגשות-שם של Paperclip agent DTO + גבול-פלטפורמה מוצהר (R3, G12, #112)' (#176) from worktree-web-ui-platform-types into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 44s
2026-06-10 09:34:11 +00:00
e5168fe79d refactor(web-ui): disambiguate Paperclip agent DTO; document platform-presentation boundary (R3, G12, #112)
ממצא: התוכנית המקורית (namespace ל-paperclip.* ב-types.ts) בלתי-ישימה — types.ts
נוצר-אוטומטית מ-OpenAPI ("Do not make direct changes"); הפניות-Paperclip שם רק משקפות
את ה-API של ה-backend, ונשלטות ע"י מודלי-ה-Pydantic, לא ע"י הפרונט. הפרונט אינו
שכבת-אינטליגנציה — הפניות-Paperclip בו הן הצגת-נתוני-פלטפורמה (activity feed, קישור
לדאשבורד, סטטוס-ארכוב) או UI-ניהול מוצהר (paperclip-tab/agents-tab) — כולן shell-adjacent
לגיטימי תחת G12.

הבעיה האמיתית-והישימה: התנגשות-שם — `PaperclipAgent` הוגדר פעמיים עם shapes שונים
(config ב-paperclip-agents.ts מול activity ב-agents.ts). פוצל: ה-activity-DTO →
`PaperclipAgentStatus`; ה-config שומר `PaperclipAgent`. + הערת-כותרת שמסמנת את agents.ts
כמודול הצגת-פלטפורמה מוצהר.

מזין את R4 (#113): leak-guard חייב להחריג קבצים-נוצרים (types.ts) ולא לכלול את הפרונט
בהיקף שכבת-האינטליגנציה המוגנת.

אימות: tsc --noEmit נקי; eslint נקי על הקבצים ששונו.

Invariants: G12 (גבול-פלטפורמה מוצהר בפרונט), G2 (הסרת שם-טיפוס כפול-משמעות).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 09:33:44 +00:00
8a2ae9921a Merge pull request 'feat(web): Agent Platform Port — Paperclip מאחורי seam-import יחיד (R2, G12, #111)' (#175) from worktree-agent-platform-port into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 10s
2026-06-10 09:28:46 +00:00
d4514e608d feat(web): Agent Platform Port — Paperclip behind a single import seam (R2, G12, #111)
יוצר web/agent_platform_port.py כמודול היחיד שמייבא web.paperclip_client/paperclip_api.
app.py מייבא כעת אך-ורק מה-Port — 0 imports ישירים של paperclip_* (היפוך-תלות פנימה,
Ports & Adapters / Dependency Rule). החלפת-הפלטפורמה = מימוש-מחדש של מודול אחד.

שתי שכבות ב-Port: (א) side-effects של מחזור-חיים נחשפים גם בשם-דומיין
(archive_case_project/restore/create/notify_case_status — אירועי-הדומיין המומלצים
לקוד חדש); (ב) פעולות issue/interaction/comment/agent — re-export בשם pc_* (קריאות
API, לא אירועים). מעבר מלא לפעלי-דומיין = follow-up; ה-import seam (החלק הניתן-לאכיפה
ב-G12) מוחזק בכל מקרה.

שינוי import-only באתרי-הקריאה — אפס שינוי-התנהגות, regression מינימלי.

אימות: app.py 0 imports ישירים; py_compile OK; כל 23 הסמלים נפתרים מה-Port;
domain-aliases identity-wired; test_paperclip_access_guard 5 passed.

Invariants: G12 (שער-הפלטפורמה — seam יחיד), G2 (מקור-אמת יחיד למגע-פלטפורמה).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 09:28:19 +00:00
b4f141df84 Merge pull request 'docs(agents): ריכוז פרוטוקול-הדיווח ל-HEARTBEAT §4 (R1, G12, #110)' (#174) from worktree-centralize-agent-protocol-heartbeat into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 9s
2026-06-10 09:22:52 +00:00
1c182edb29 docs(agents): centralize completion/wakeup protocol to HEARTBEAT §4 (R1, G12, #110)
6 סוכני-העובד (writer/exporter/proofreader/qa/researcher/analyst) שכפלו inline את
בלוק-הדיווח-וההשכמה הזהה (PATCH done/blocked + CEO_ID if-block + wakeup JSON +
אזהרת agent_wakeup_requests) — שהוא כבר המקור הקנוני ב-HEARTBEAT.md §4ב/§4ג.

הוחלף בכל קובץ במצביע קומפקטי ל-HEARTBEAT §4ב/§4ג, תוך שימור: ה-rationale
(auto-retry), reason ספציפי-לתפקיד, ומלכודות ספציפיות (UUID של analyst, QA gate
של writer). כפילות הפרוטוקול הקשיח: 288→83 hits (היתרה: orchestration לגיטימי של
CEO + מצביעי-HEARTBEAT). סוכני gemini נשארו (וריאנט מצומצם מכוון, ללא CEO).

Invariants: G12 (פרומפטים מצביעים ל-HEARTBEAT, לא משכפלים פרוטוקול) · G2 (מקור יחיד).

הפצה לסוכנים-רצים: לאחר מיזוג — git pull בעץ הראשי + sync_agents_across_companies.py
(הפרומפטים נטענים מ-cwd המשותף). אומת מבנית: code-fences מאוזנים, מצביעי §4 מדויקים.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 09:22:20 +00:00
8b69adc7bd Merge pull request 'docs(spec): רישום G12 (שער-הפלטפורמה) בחוקה + תבנית-PR + CLAUDE (R0b, #109)' (#173) from worktree-register-g12-platform-port into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 9s
2026-06-10 09:14:13 +00:00
2b6e95c484 docs(spec): register G12 (Platform Port) in constitution + PR template + CLAUDE (R0b, #109)
- 00-constitution.md §5א: INV-G12 (שער-הפלטפורמה) — Paperclip מאחורי Port יחיד;
  מקורות Cockburn Ports&Adapters + Martin Dependency Rule + Evans ACL, verified.
  עדכון תיאור-הבמה ל-"G1–G10, G12 הנדסיים"; אינדקס §7 השלים X14/X15/X16 + G1–G12.
- PULL_REQUEST_TEMPLATE.md: שורת-צ'קליסט G12 + דוגמה בהצהרת-invariants.
- CLAUDE.md: מצביע ל-X15 ב-§Paperclip ו-§פרוטוקול-כתיבת-קוד; G1–G12.
- X15 §2: סומן ש-R0b הושלם (G12 רשום בחוקה).

תיעוד בלבד. Invariants: G12 (מוגדר/נרשם), G2 (מיישם).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 09:13:48 +00:00
c903770fb3 Merge pull request 'fix(halacha): חילוץ-מחדש משמר הלכות מאושרות (INV-G10, #108)' (#172) from worktree-fix-halacha-reextract-dataloss into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m30s
2026-06-10 09:08:47 +00:00
26e0219219 fix(halacha): re-extraction preserves chair-approved halachot (INV-G10, #108)
תיקון data-loss: reset_halacha_extraction ביצע DELETE ללא-תנאי לפני חילוץ-מחדש;
קריסה בין המחיקה לאחסון הראשון מחקה את כל אישורי-היו"ר והשאירה את הרשומה תקועה
status='processing' עם 0 שורות (תקרית עמיאל 8126-03-25, 2026-06-08).

עכשיו המחיקה מחריגה review_status IN ('approved','published') — אישור אנושי לא
נמחק בשקט (INV-G10). ה-dedup-on-insert של store_halachot_for_chunk מדלג על חילוץ
טרי שמשכפל מאושרת שנשמרה, כך שאין כפילות. reset מחזיר {deleted, preserved},
וה-extractor מתעד כמה מאושרות נשמרו (provenance, G9).

עמידות מלאה מול מוות-תהליך (OOM) נשארת ל-X16/#114 (durable resume) — זה תנאי-מקדים.

בדיקה: test_halacha_reextract_preserves_approved.py (offline SQL-capture) מאמת
שה-DELETE מחריג approved/published; 64 בדיקות-הלכה קיימות עוברות.

Invariants: G10 (שער-יו"ר — אישור לא נמחק), G1 (תיקון במקור), G9 (provenance).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 09:08:16 +00:00
81171983e4 Merge pull request 'feat(agents): שער anti-hallucination משותף מעוגן-מקור (INV-AH) + ידע CEO על שטן-מליץ' (#171) from worktree-anti-hallucination-gate into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 11s
2026-06-09 17:05:56 +00:00
d156bcfaf1 feat(agents): שער anti-hallucination משותף מעוגן-מקור (INV-AH) לכל הסוכנים
מחלץ את דיסציפלינת מניעת-ההזיות לבלוק קנוני אחד (docs/anti-hallucination-gate.md)
ומחיל אותו אחיד על כל הסוכנים — במקום שכל סוכן ימציא אותה מחדש ad-hoc (G2: בלי מסלולים מקבילים).

5 טכניקות, כל אחת מעוגנת במקור מקצועי:
- AH-1 עיגון-מקור (אפס ציטוט מהזיכרון) — Stanford RegLab/Magesh JELS 2025 (כלי-RAG משפטיים הוזים 17-33%)
- AH-2 quote-or-retract + AH-3 abstention — Anthropic Reduce-hallucinations
- AH-4 תיוג-ודאות — NIST AI RMF GenAI Profile + RAGAS
- AH-5 Chain-of-Verification — Dhuliawala et al. arXiv:2309.11495

הפצה DRY: הפניה ב-HEARTBEAT.md (נקרא ע"י כל סוכני Paperclip) + שורה אחידה בבלוק
'קרא לפני פעולה' של כל 8 הסוכנים, עם הערת-יישום לכל תפקיד (writer=read-only, qa=אוכף,
proofreader=אל תתקן לכיוון מונח משפטי, exporter=אפס מהות חדשה).

בנוסף: legal-ceo.md מקבל ידע על 'שטן מליץ (Gemini)' עם מדיניות on-demand טהורה —
לא בפייפליין, מופעל רק לבקשת חיים/דפנה, הפלט=לידים ליו"ר (לא לכותב, human-in-the-loop).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 17:05:33 +00:00
33d8faf74a Merge pull request 'docs(spec): X15 שער-הפלטפורמה (G12) + X16 עמידות-פייפליין' (#170) from worktree-platform-port-durability-spec into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8s
2026-06-09 16:27:39 +00:00
cb822c4900 docs(spec): X15 שער-הפלטפורמה (G12) + X16 עמידות-פייפליין
X15 — Agent Platform Port: Paperclip כמעטפת ניתנת-להחלפה מאחורי Port יחיד.
מגדיר INV-PORT1/G12 (Ports&Adapters + Dependency Rule + Anti-Corruption Layer),
מצאי-דליפה baseline (mcp-server נקי; דליפה ב-app.py + 10 פרומפטים + web-ui),
מפת-תיקון R0–R4, ומנגנון-אכיפה נגד דליפה-עתידית (leak-guard + תבנית-PR).

X16 — Durable Pipeline Execution: LangGraph כספרייה בתוך הסקריפט (לא תחליף-פלטפורמה)
ל-final_halacha/final_learning. מגדיר INV-DUR1 (checkpointing+replay, מימוש משותף),
SqliteSaver תחת data/checkpoints, גרעיניות מדורגת P0–P3, שימור-חוזה-CLI.

מיישם/מחזק: G2 (X15), G3 (X16). תכנון בלבד — ללא שינוי-קוד.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 16:26:57 +00:00
f1d6f5dafc Merge pull request 'feat(agents): שטן מליץ (Gemini) — red-team מוגבל עם שער anti-hallucination' (#169) from worktree-gemini-critique into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 10s
2026-06-09 16:16:13 +00:00
1a50aa7709 feat(agents): שטן מליץ (Gemini) — red-team מוגבל עם שער anti-hallucination
ממסד את סוכן-Gemini מחדש כשכבת דעה-שנייה (devil's advocate) שרצה אחרי Opus
ומפיקה מזכר-לידים לא-סמכותי ליו"ר — לא ניתוח מתחרה. read-only (critique-gemini.md בלבד).

9 אילוצי anti-hallucination קשיחים, מעוגנים במקורות מקצועיים:
- Stanford RegLab/Magesh JELS 2025 (כלי-RAG משפטיים הוזים 17-33%) → עיגון-קורפוס מוחלט
- Anthropic Reduce-hallucinations → quote-or-retract + abstention
- Chain-of-Verification (Dhuliawala 2023, arXiv:2309.11495) → מעבר-אימות חובה
- RAGAS faithfulness → atomic-claim grounding
- NIST AI RMF GenAI Profile 2024 → human-in-the-loop, לידים-לא-הכרעות

מתחיל בכותרת # (לא ---) למניעת כשל yargs ב-gemini --prompt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 16:15:53 +00:00
405167269f Merge pull request 'fix(agents): הסר frontmatter מ-legal-analyst-gemini (שובר את gemini --prompt)' (#168) from worktree-gemini-analyst-fix into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 10s
2026-06-09 15:30:41 +00:00
7f573c0db3 fix(agents): הסר YAML frontmatter מ-legal-analyst-gemini.md
adapter gemini_local מעביר את תוכן הקובץ כ-arg ל-`gemini --prompt <content>`.
כש-content מתחיל ב-`---` (frontmatter), yargs מפרש זאת כדגל ולא כערך →
'Not enough arguments following: prompt' וה-run נכשל ב-adapter_failed תוך 2ש'.
הפיכת הראש לכותרת # פותרת. (claude_local לא נתקל בזה — הוא מעביר --append-system-prompt-file <path>.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 15:30:18 +00:00
aa0fde2724 Merge pull request 'feat(agents): מנתח משפטי וריאנט Gemini (read-only benchmark)' (#167) from worktree-gemini-analyst into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 9s
2026-06-09 15:13:42 +00:00
e57730f375 feat(agents): מנתח משפטי וריאנט Gemini (read-only benchmark)
עותק של legal-analyst שרץ תחת gemini_local (Gemini CLI, gemini-3.1-pro-preview)
לצורך השוואת איכות-ניתוח מול Opus. מצב read-only: שלבי extract/aggregate/case_update
מוחלפים בקריאה בלבד, והפלט נכתב ל-analysis-and-research.GEMINI.md בלבד — כדי לא לדרוס
את ניתוח-Opus הקנוני. אכיפת read-only גם ברמת MCP (excludeTools ב-~/.gemini/settings.json).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 15:13:08 +00:00
6299998267 Merge pull request 'feat(arguments): פופאפ פרופוזיציות גולמיות בלחיצה על "מסתמך על N"' (#166) from worktree-argument-claims-popover into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m28s
2026-06-09 06:51:51 +00:00
d4d2ab4d68 feat(arguments): פופאפ פרופוזיציות גולמיות בלחיצה על "מסתמך על N"
הקישור טיעון↔פרופוזיציות כבר נשמר ב-DB (legal_argument_propositions),
אך ה-UI הציג רק את המספר. מעשיר את get_legal_arguments באותו round-trip
(JOIN ל-claims) להחזיר supporting_propositions = {id, text, source_document},
ועוטף את שורת "מסתמך על N פרופוזיציות" ב-Popover שמציג את הטענות הגולמיות
verbatim עם מקור. שקיפות ועקיבוּת מהטיעון המאוגד חזרה לטענות-המקור.

- supporting_claims נשאר id-only (תאימות לאחור: מונה, צרכני MCP)
- supporting_propositions שדה חדש אופציונלי; fallback לטקסט סטטי כשחסר
- אין מסלול מקביל (G2) — העשרה של אותו endpoint; נרמול-במקור (G1)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 06:51:09 +00:00
c0af8c7cda Merge pull request 'feat(learning): מטא-דאטה מלא להחלטות-פנימיות בקליטה + חילוץ-הלכות אוטומטי' (#165) from worktree-internal-decision-metadata into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 11s
2026-06-08 15:19:34 +00:00
2f43960353 feat(learning): מטא-דאטה מלא להחלטות-פנימיות בקליטה + חילוץ-הלכות אוטומטי
סוגר את הפער שעלה על בל"מ 8126: החלטה שנכנסה לספריית-הפסיקה הופיעה ללא
מטא-דאטה (summary/citation/date ריקים, proceeding_type שגוי) כי מחלץ-ה-Gemini
מיועד לפסיקה חיצונית ומחזיר no_metadata לפנימיות, והחילוץ-הלכות נשאר pending.

web/app.py — `_enroll_final_in_library` עכשיו ממלא **דטרמיניסטית** מהתיק (בלי LLM):
- proceeding_type (מהתיק — בל"מ/ערר, גם idempotency key נכון מהקליטה הראשונה),
  decision_date (fallback ל-hearing_date), subject_tags, summary (=subject).
- `citation_formatted` נבנה דטרמיניסטית (`_build_internal_citation`):
  'ועדת ערר ... בל"מ <num> <עורר> נ' <משיב> (יו"ר עו"ד <chair>)'.

scripts/final_halacha_pipeline.py — שלב [0] חדש: `precedent_extract_halachot`
על ההחלטה עצמה (idempotent — מדלג כש-completed/dry-run), כך שהלכות-ההחלטה
לא נשארות pending.

אומת: py_compile ✓ · ה-pipeline רץ dry-run נקי (4 שלבים). 8126 כבר תוקן ידנית;
מכאן זה אוטומטי לכל החלטה. Invariants: INV-LRN4/X11 · G1 (נרמול-במקור) ·
DM7 · feedback_silent_swallow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 15:19:14 +00:00
de777c2b13 Merge pull request 'feat(cases): תצוגת "פסיקה שצוטטה בהחלטה" בעמוד-התיק + שחזור חיווט-הרמס' (#164) from worktree-case-citations-ui into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 41s
2026-06-08 11:59:45 +00:00
98c5feff25 feat(cases): תצוגת "פסיקה שצוטטה בהחלטה" בעמוד-התיק + שחזור חיווט-הרמס
UI שביקש חיים: בכניסה להחלטה רואים את הפסיקה שצוטטה בתוכה — מקושרת לספרייה
(קליק → /precedents/[id]) מול חסרה (סומנה אוטומטית להעלאה).

- web/app.py: GET /api/cases/{case}/citations — מהשורה internal_committee של
  ההחלטה ב-case_law → precedent_internal_citations: linked (join case_law) +
  missing (unresolved + האם flagged ב-missing_precedents).
- web-ui: lib/api/citations.ts (hook) + CitationsSection ב-drafts-panel
  (מוצג כשההחלטה בספרייה). מקושרת=ירוק/קליק, חסרה=ענבר "סומנה להעלאה".
- scripts/curator_apply_pipeline_branch.py: מקור-אמת לחיווט-הכפתורים של הרמס
  (ה-prompt חי רק ב-Paperclip DB). מקדים branch שמריץ את pipeline-ה-final
  ל-wake reason final_learning_*/final_halacha_* (HOME/DOTENV/DATA_DIR מוחלטים
  → מפתחות DeepSeek+Gemini + DATA_DIR נפתרים נכון). idempotent, שני הסוכנים.
  כבר הוחל ב-DB; הסקריפט לשחזור אחרי reset.

אומת: py_compile ✓ · tsc ✓ · החיווט אומת חי על 8126 (deepseek+gemini, dedup,
✓ pipeline הושלם). G2 (יכולת חסרה) · INV-LRN1/G10 נשמרים.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 11:59:21 +00:00
2c4287fd3d Merge pull request 'feat(learning): כל החלטה שלנו תמיד בספריית-הפסיקה + בדיקת-ציטוטים וסימון-חסרים אוטומטי' (#163) from worktree-final-into-library into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 40s
2026-06-08 11:28:16 +00:00
55362bf5a1 feat(learning): כל החלטה שלנו נכנסת תמיד לספריית-הפסיקה + בדיקת-ציטוטים אוטומטית
סוגר את הפער שלולאת-צמיחת-הקורפוס (07-learning §1.3) הוגדרה אך לא חווטה: מסלול
/final/upload הכניס רק לקורפוס-הסגנון, וההכנסה ל-case_law הייתה best-effort
שקטה שנכשלה כש-chair_name ריק.

web/app.py — /api/cases/{case}/final/upload עכשיו, סינכרונית:
- קובע chair_name דטרמיניסטית (תיק → ברירת-מחדל-ועדה לפי prefix; לעולם לא ריק →
  אילוץ case_law_internal_chair_check תמיד מסופק). לא נשען על חילוץ-LLM —
  להחלטות שלנו היו"ר ידוע.
- מכניס את ההחלטה ל-case_law כ-internal_committee (תמיד, לא best-effort) →
  ברת-ציטוט בהחלטות עתידיות. מטה-דאטה נוסף מועשר אסינכרונית (Gemini).
- מחלץ את הציטוטים שההחלטה מצטטת (extract_internal_citations), ו**מסמן
  אוטומטית** כל ציטוט שאינו בספרייה כ-missing_precedent (open) — dedup מול קיימים.
- התוצאה מוחזרת ב-response (enrolled/linked/missing_flagged) — לא נבלעת בשקט.

הציטוטים-המקושרים מזינים את לולאת-ה-corroboration (X11) — תוקן הניתוק שבו
החלטות שלנו לא היו ב-case_law ולכן לא חיזקו הלכות.

web-ui — toast מציג "נוספה לספרייה · N ציטוטים · M חסרים סומנו".
ספ: 07-learning §0.6 עודכן. אומת ידנית על בל"מ 8126-03-25 (15 קושרו / 6 סומנו).

Invariants: INV-LRN4, X11; G2 (יכולת חסרה, לא מקבילה); feedback_silent_swallow
(כשל-הכנסה צף, לא נבלע); DM7 (סמכות נגזרת).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 11:27:55 +00:00
7ebd4187a9 Merge pull request 'fix(style-panel): idempotency + dedup — הרצה חוזרת לא משכפלת לקחים' (#162) from worktree-style-panel-dedup into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8s
2026-06-08 10:58:16 +00:00
c8344342a8 fix(style-panel): idempotency + dedup — re-running --apply never duplicates lessons
style_lesson_panel.py: before writing 2/2-keep lessons, skip any whose normalized
lesson_text already exists on the corpus (any source), and collapse duplicates within
a run. Makes the run-learning button safe to click repeatedly (the curator may re-run
the pipeline) — it converges instead of piling up duplicate decision_lessons.

Verified on בל"מ 8126-03-25: re-running --apply with 7 existing lessons wrote 0
("1 כפילויות דולגו"), count stayed 7.

Invariants: INV-LRN1/G10 unchanged (proposals only, manual fold).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 10:57:57 +00:00
02f411f4dc Merge pull request 'feat(learning): חיווט אוטונומי לכפתורי מסלול-הסופי (סקריפט-תזמור אחד לכל שלב)' (#161) from worktree-autonomous-final-pipeline into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 14s
2026-06-08 10:22:00 +00:00
0f0656ecca feat(learning): חיווט אוטונומי לכפתורי מסלול-הסופי — סקריפט-תזמור אחד לכל שלב
הכפתורים "הרץ למידת-קול"/"הרץ אימות-הלכות" מעירים את הרמס, ובמקום שהסוכן
(DeepSeek) ירכיב כמה קריאות-כלי (שביר), הוא מריץ עכשיו פקודה דטרמיניסטית אחת.

חדש:
- scripts/final_learning_pipeline.py — (1) ingest_final_version עם נתיב-הסופי
  (מדלג אם הזוג כבר analyzed; --force לחידוש), (2) רישום לקורפוס-הסגנון
  (idempotent — סוגר את הפער שפאנל-הסגנון דרש corpus_id), (3) style_lesson_panel
  --apply. --dry-run להרצה בטוחה.
- scripts/final_halacha_pipeline.py — extract_internal_citations →
  corroboration.build_all → halacha_panel_approve --apply. --dry-run / --limit.

briefs הרמס (web/paperclip_client._curator_task_brief) פושטו לפקודה-אחת לכל
task — חסין מול הרצת-סוכן. תוקנו שני הפערים שזוהו: ingest דרש file_path,
ופאנל-הסגנון דרש style_corpus.

נלווה: תיקון help מיושן של halacha_panel_approve (--apply מחווט). SCRIPTS.md.

אומת: שני ה-pipelines רצו dry-run על בל"מ 8126-03-25 (skip-ingest, קורפוס,
פאנלים) בהצלחה. Invariants: INV-LRN1/LRN5/G10 (הפיך, שער-יו"ר ידני נשמר),
INV-DM7. G2 — תזמור של יכולות קיימות, לא מסלול-מקביל.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 10:21:39 +00:00
c028328175 Merge pull request 'docs(claude-md): לרזות CLAUDE.md מ-11.3k ל-~7k טוקן (TaskMaster #107.1)' (#160) from worktree-claude-md-trim into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 10s
2026-06-08 09:15:45 +00:00
471cd37fc8 docs(claude-md): לרזות CLAUDE.md מ-11.3k ל-~7k טוקן (TaskMaster #107.1)
מעביר עומק תפעולי ל-docs/operations-runbook.md חדש כדי לצמצם את ההקשר
שנטען אוטומטית בכל סשן. CLAUDE.md נשאר אינדקס דק עם כל הכללים הקריטיים.

הועבר ל-runbook: טבלת Nautilus, פירוט Deploy (Coolify/pm2/legal-chat-service),
עץ-תיקיות מלא, Paperclip deep-ops (wakeup payload, cross-company sync,
webhook flow, scheduled jobs, deepseek_local + hermes curator adapters),
Chair-Feedback, TaskMaster מפורט.

נשמר inline (קריטי): spec-first protocol, worktree isolation, יעד-העל
Style-Acquisition, טבלת מסמכי-ייחוס, עקרונות-כתיבה G11, וכללי-Paperclip
הקריטיים בתמצית (wakeup-via-API, helper-not-curl, comment routing).

344→159 שורות; ~4.3k טוקן/סשן נחסכים. כל התוכן נשאר ב-repo ונגיש דרך קישור.

Invariants: G2 (אין מסלול מקביל — תוכן הועבר, לא שוכפל), G11 (עקרונות-כתיבה
נשמרו inline). תיעוד בלבד, אין נגיעה בקוד.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 09:14:52 +00:00
9f358db353 Merge pull request 'fix(ops): self-restart/stop של גשר-המארח מחזיר 200 (detached)' (#159) from worktree-ops-selfrestart into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m33s
2026-06-08 09:09:30 +00:00
d23f854c25 fix(ops): self-restart/stop of the host bridge returns 200 (detached)
Restarting/stopping legal-court-fetch-service from its own /pm2/control kills
the process before it can reply — the client got a misleading 502 even though
pm2 performed the restart. Detach the self-action (sleep 1; pm2 ...) so the HTTP
response flushes first, and report success optimistically. Other targets are
unchanged. Own name via COURT_FETCH_SERVICE_PM2_NAME (default legal-court-fetch-service).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 09:09:08 +00:00
9ae49f0f70 Merge pull request 'feat(learning): מסלול נקי להעלאת החלטה סופית + פאנל-סגנון דו-סוכני (DeepSeek+Gemini)' (#158) from worktree-final-upload-pipeline into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 42s
2026-06-08 09:04:16 +00:00
f79c46a352 feat(learning): מסלול נקי להעלאת החלטה סופית + פאנל-סגנון דו-סוכני (DeepSeek+Gemini)
מוסיף מסלול ייעודי לקליטת ההחלטה החתומה של היו"ר, ומפעיל אותו דרך שני
שלבים אוטומטיים מדורגים עם פאנלי-סוכנים (אוטו-אישור + אסקלציה ליו"ר).

Backend (web/):
- POST /api/cases/{case}/final/upload — קליטת final חיצוני: שמירה קנונית
  (סופי-{case}.docx + עותק קורפוס-סגנון תחת case_number מלא כדי שבל"מ לא
  יתנגש עם ערר באותו מספר), פתיחת draft_final_pairs (final_received). לא נוגע
  ב-active_draft ולא מריץ retrofit (נבדל מ-exports/upload ו-mark-final → לא G2).
- POST .../final/run-learning + .../final/run-halacha — שלבים מדורגים שמעירים
  worker מקומי (claude/DeepSeek/Gemini מקומיים בלבד) דרך הרחבת
  wake_curator_for_final עם param task=learning|halacha.

פאנל-סגנון חדש (scripts/style_lesson_panel.py): שני שופטים (DeepSeek+Gemini)
על-גבי דיסטילציית-ה-Opus; הסכמה 2/2-keep → decision_lesson
(source=panel:deepseek+gemini); substance מדולג (INV-LRN5); הפיך + גיבוי CSV.
פאנל-הלכות: docstring/SCRIPTS.md עודכנו (--apply מחווט).

Frontend (web-ui/): כפתור "העלאת החלטה סופית של היו"ר" + שני כפתורים מדורגים
"הרץ למידת-קול"/"הרץ אימות-הלכות" ב-drafts-panel; כל התוויות בעברית
(badge מקור-לקח: "פאנל: דיפסיק+גמיני", "הרמס (סקירה)"...).

Spec: docs/spec/07-learning.md §0.6. Invariants: INV-LRN1/LRN4/LRN5, G10
(שער-יו"ר ידני להטמעה ל-SKILL.md/lessons.md — הפאנלים יוצרים הצעות בלבד);
G2 (מסלול-סופי הוא יכולת חסרה, לא מסלול-מקביל).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 09:03:26 +00:00
ae30a4d19a Merge pull request 'feat(ops): /operations — מוני-תור אחידים, "מה רץ עכשיו", וניהול-תהליכים כמו שירותי-Windows' (#157) from worktree-ops-controls into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m37s
2026-06-08 08:59:54 +00:00
638eef6803 feat(ops): /operations — מוני-תור אחידים, "מה רץ עכשיו", וניהול-תהליכים
הדף הציג את התורים באופן לא-אחיד (by_status גולמי), בלי הבחנה בין "ממתין"
(בקלוג: status=pending) ל"בתור" (התור הפעיל: requested_at IS NOT NULL), בלי
הצגת הפריט שרץ כרגע, ובלי שום שליטה בתהליכים.

מה נוסף:
1. כרטיסי-תור אחידים — בתור / ממתין(בקלוג) / בעיבוד / הושלם / נכשל + "רץ עכשיו"
   (citation/case_number של הפריט בעיבוד) לכל drain (אחזור-פסיקה, מטא-דאטה,
   הלכות, יומונים). שערי-אנוש (אישור-הלכות, פסיקה-חסרה) נשארים מוני-סטטוס.
2. פאנל ניהול-תהליכים בסגנון "שירותי Windows":
   - דמון (court-fetch-service/xvfb/chat/reaper): הפעל-מחדש / עצור / הפעל.
   - cron drain: "הרץ עכשיו" (pm2 restart) + מתג הפעל/כבה תזמון.
3. כל תגי-הסטטוס מתורגמים לעברית.

מנגנון:
- הפעל/כבה תזמון = דגל ב-DB (טבלה drain_controls). pm2 cron_restart מחיה תהליך
  שעוצר ב-stop, לכן ה"כיבוי" האמין הוא דגל שכל drain בודק ב-startup (no-op מיידי
  כשכבוי). הקונטיינר כותב/קורא ישירות מ-DB.
- הרץ-עכשיו + restart/stop/start = proxy ל-pm2 דרך endpoint חדש בגשר-המארח
  (court_fetch_service /pm2/control), מאובטח Bearer + whitelist ל-legal-* בלבד.
- יומונים: drain_digests הועבר מ-crontab ל-pm2 (legal-digest-drain.config.cjs)
  כדי שיופיע ויהיה שליט כמו כל drain. drain_halacha_queue.py הובא לבקרת-גרסאות.

Invariants: מקיים G2 (הרחבת /operations + הגשר הקיים, לא מסלול מקביל) ו-G1
(drain_controls = מקור-אמת יחיד לכיבוי, נורמליזציה במקור ולא תיקון-בקריאה).
אין בליעת שגיאות שקטה (הגשר מחזיר {ok,error}; המוטציות מציגות toast).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 08:57:23 +00:00
6647aa92e6 Merge pull request 'feat(storage): X14 Phase 2c — remaining sync write-sites through storage.py' (#156) from worktree-storage-minio-phase2c into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m26s
2026-06-08 08:26:34 +00:00
b2ea0c28dd feat(storage): X14 Phase 2c — route remaining sync write-sites through storage.py
Completes the write-side rewiring (INV-STG1) for the call-sites that run in
synchronous contexts, via a new blocking facade in storage.py
(put_bytes_sync / put_file_sync — asyncio.run, or a worker thread when a loop
is already running):
- services/extractor.py: multimodal thumbnail JPEGs → DERIVED (rendered in a
  to_thread worker)
- services/docx_reviser.py: track-changes save (_save_docx_xml) + empty-diff
  copy (copy_with_revisions) → DOCUMENTS
- services/docx_retrofit.py: in-place retrofit backup → DOCUMENTS

Each site keeps a fallback to a direct disk write when the target path is
outside DATA_DIR (caller-provided). Under the default STORAGE_BACKEND=
filesystem the bytes land exactly where they did before — zero behaviour
change.

Also: mcp_env_catalog MINIO_ENDPOINT default updated to the durable
container-name endpoint (http://minio-bx2ykvw94xbutsex41hz4vv8:9000), matching
the Coolify "Connect to Predefined Network" change made for network durability.

All binary write-sites now flow through storage.py. git-tracked text
(case.json/notes/research-md/draft-md) stays on disk by design (INV-STG7);
court-fetch temp files are ephemeral.

tests: +2 (thumbnail renderer routes through storage; put_bytes_sync
round-trip); 55 storage/docx/track-changes green; 244 collected, no import
breakage.

Keeps G2; completes INV-STG1 write coverage. Spec: docs/spec/X14-storage-minio.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 08:26:09 +00:00
bc5dd9ac48 Merge pull request 'feat(digests-ui): publication filter + 'מאמר'/source badges for bulletins' (#155) from worktree-bulletins-ui into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m30s
2026-06-08 08:14:40 +00:00
5745d36bb4 feat(digests-ui): publication filter + 'מאמר'/source badges for bulletins
משלים את #154 בצד-לקוח:
- פילטר "מקור" בדף /digests (כל המקורות / כל יום / עו"ד על נדל"ן) — backend:
  list_digests + /api/digests מקבלים publication.
- DigestCard: תג "מאמר" ל-digest_kind='article', ו-chip מקור לפרסום שאינו 'כל יום'.

build (webpack) עובר, lint נקי. digests = hand-written types (אין api:types).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 08:14:23 +00:00
05e8373d22 Merge pull request 'feat(bulletins): catalog monthly "עו"ד על נדל"ן" bulletins into the radar (X12)' (#154) from worktree-bulletins-catalog into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m36s
2026-06-08 08:08:10 +00:00
85f94a4f3f feat(bulletins): catalog monthly "עו"ד על נדל"ן" bulletins into the radar (X12)
עלון חודשי רב-נושאי (פרסום נפרד מהיומון היומי) → מתפצל ל-N שורות digest באותה
טבלה (publication='עו"ד על נדל"ן', לא קורפוס מקביל — G2):
- bulletin_splitter (LLM local-only, tools=""): מפצל ל-cases[]+articles[];
  עדכוני-חקיקה מדולגים (החלטת יו"ר).
- bulletin_library.ingest_bulletin: כל מצביע-פסיקה → digest_kind='decision'
  + embedding + autolink (כולל X13 court-fetch); כל מאמר → digest_kind='article'
  (טקסט-מלא + embedding, רקע בלבד — INV-DIG1 חל).
- content_hash per-item הוא מפתח-הדדאפ (yomon_number ריק) → אידמפוטנטי.
- db.create_digest: פרמטר digest_kind (זורם ל-INSERT + upsert).
- scripts/ingest_bulletins.py (host, venv) לעיבוד הארכיון.
- spec X12 §2.1.

אומת (dry-run, ללא DB): עלון 180 → 4 cases+1 article · עלון 201 → 4 cases
(כולל ערר-197) +1 article. עדכוני-חקיקה דולגו. claude_session נשאר local-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 08:07:45 +00:00
1e41125baa Merge pull request 'feat(storage): X14 Phase 2b — extracted-text + async DOCX exports through storage.py' (#153) from worktree-storage-minio-phase2b into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m28s
2026-06-08 08:05:52 +00:00
1f42a39ce4 feat(storage): X14 Phase 2b — route extracted-text + async DOCX exports through storage.py
Continue the write-site rewiring onto the unified storage layer (INV-STG1):
- services/processor.py: extracted-text .txt → DERIVED bucket (a derived
  artifact; the DB column is the source of truth per INV-STG5, so the write
  stays non-fatal)
- services/docx_exporter.py (export_decision): DOCX → DOCUMENTS bucket via
  BytesIO → put_bytes, with a fallback to a direct disk write when the caller
  passes an output_path outside DATA_DIR
- services/analysis_docx_exporter.py (build_analysis_docx): same pattern;
  out_path is always under DATA_DIR

Under the default STORAGE_BACKEND=filesystem the bytes land at the exact
legacy path (put_bytes → DATA_DIR/key), so behaviour is unchanged. The
disk-reading bits that must stay for now (export_dir glob in _next_version)
are kept; storage-native versioning is a cutover concern.

Still on disk (sync call-sites, follow-up Phase 2c): docx_reviser
(track-changes), docx_retrofit backup, and multimodal thumbnails (rendered in
a to_thread). git-tracked text (case.json/notes/research-md/draft-md) stays on
disk by design (INV-STG7).

tests: 38 storage + docx tests green (incl. test_export_qa_gate /
test_docx_exporter_bookmarks which exercise the real export path); 242
collected, no import breakage.

Keeps G2; advances INV-STG1. Spec: docs/spec/X14-storage-minio.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 08:05:25 +00:00
39f8cb7c15 Merge pull request 'feat(storage): X14 Phase 2a — route source-document writes through storage.py' (#152) from worktree-storage-minio-phase2 into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m30s
2026-06-08 08:01:00 +00:00