Files
legal-ai/docs/spec/06-export.md
Chaim aad2de9205
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 4s
Lint — undefined names / undefined-names (pull_request) Successful in 10s
feat(drafting): טיוטת-ביניים דטרמיניסטית — נעיצת Opus 4.8 + effort per-בלוק (#204)
מנגנון-הייצור (claude_session→claude -p) לא העביר model/effort: BLOCK_CONFIG
הגדיר temp+model per-בלוק שהיו מטא-דאטה-מת (block_writer.py:447 העביר רק
prompt/timeout/tools). הייצור רץ על מודל ברירת-המחדל של ה-CLI עם פרומפטים-חופשיים
→ מקור אי-העקביות בטיוטת-הביניים.

תיקון (עקביות-מבנית, WS5):
- נעיצת model="claude-opus-4-8" (GENERATION_MODEL) לכל בלוקי-ה-AI + effort per-בלוק
  שמועבר בפועל דרך claude_session.query → `claude -p --model --effort`.
  מפת-effort: ה=medium · ו=medium · ז=high · ח=medium · ט=high · יא=high · י=xhigh.
- ניסוח-פתיחה קבוע לבלוק-ה (תמיד "לפנינו ערר…", סוף ל-OR "עניינה של החלטה זו").
- מבנה-פנימי קבוע לבלוק-ה; סדר-בלוקים בייצוא כבר קבוע (_INTERIM_BLOCK_ORDER).
- הסרת שדות temp/model המתים מ-BLOCK_CONFIG; "temp" deprecated (Opus 4.7/4.8 דוחים
  temperature→400). decision_blocks.temperature נשמר=0 לתאימות-עמודה בלבד.
- timeout נגזר מ-effort (לא מפיצול sonnet/opus שכבר לא קיים).
- עדכון endpoint reference /api/settings/mcp/blocks + blocks-tab + McpBlock לחשוף effort.
- ספ: docs/block-schema.md §3 (effort מחליף temperature), docs/spec/06-export.md
  (דטרמיניזם-מבני של טיוטת-הביניים).

G2 (מקור-אמת יחיד) — אין מסלול-ייצור מקביל: write_interim_draft מתזמר את אותו
write_and_store_block→write_block של ההחלטה המלאה.
claude_session-local-only — הייצור נשאר דרך גשר-ה-CLI, לא SDK/קונטיינר.
INV-EX1 — סדר-ייצוא דטרמיניסטי נשמר; G11 — עקרונות-הכתיבה ל-12 הבלוקים נשמרים.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 11:18:56 +00:00

15 KiB
Raw Blame History

06 — ייצוא DOCX (Export Contract)

קובץ-תחום זה כפוף ל-חוקת המערכת ומגדיר את חוזה-הייצוא של עוזר משפטי: הרינדור של החלטה ל-DOCX מעוצב (גופן David, RTL, סגנונות-טמפלט). העיקרון המכונן — ה-DB הוא מקור-האמת היחיד, וה-DOCX הוא נתון נגזר (derived) הניתן לשחזור. הקובץ אוכף את INV-G2 (מקור-אמת יחיד / נתון-נגזר משוחזר) ואת INV-G9 (עקיבוּת-מקור), והוא השלב שאחרי שער-הייצוא הקריטי של 05-qa-review.md / INV-QA3.

כללי-סגנון — סמכות אחת. מכניקת העיצוב (line classification, dash policy, placeholder, מיפוי-סגנונות, RTL-runs) מתועדת במלואה בסקיל dafna-decision-template/SKILL.mdהוא המקור הסמכותי. הקובץ הזה מסכם ומפנה, לא משכפל. כללי-הסגנון עצמם הם תוכן-משפטי-דומייני (סמכות היו"ר + הסקיל), בעוד שחוזה-ה-derived-data (INV-EX1) ועקיבוּת-המקור (INV-EX2) הם invariants הנדסיים הנושאים מקורות + סטטוס.


1. חוזה-הייצוא — DB הוא המקור, DOCX הוא הנגזר

החלטה מאוחסנת כ-בלוקים מובְנים ב-DBdecision_blocks (12 בלוקים, מפתח קנוני UNIQUE(decision_id, block_id)) תחת decisions (UNIQUE(case_id, version)); ראה 02-data-model.md §1. ה-DOCX נגזר מהבלוקים האלה ואינו מקור-אמת עצמאי: מחיקתו אינה מאבדת תוכן, וייצוא חוזר מאותם בלוקים מפיק מסמך שקול.

מסלול-הייצוא הקנוני (הסופי):

  1. export_docx(case_number) (tools/drafting.py:384, נחשף server.py:557) שולף את התיק, ואז קורא ל-docx_exporter.export_decision(case_id, …, mode="final") (services/docx_exporter.py:306).
  2. export_decision שולף את הבלוקים ישירות מ-decision_blocks (SELECT block_id, block_index, title, content, word_count … ORDER BY block_index, docx_exporter.py:336-342) — אין מקור-תוכן אחר.
  3. טוען את טמפלט-דפנה (skills/docx/decision_template.docx, docx_exporter.py:27-29,364), מנקה את גוף-המסמך (_clear_body), וכותב כל בלוק עם bookmark עוטף (אנקור ל-revisions עתידיים, _wrap_block_with_bookmarks, docx_exporter.py:367-382).
  4. שומר לקובץ מגורסן data/cases/{case_number}/exports/טיוטה-v{N}.docx (גרסה אוטומטית עולה, docx_exporter.py:384-400).

שני מסלולי-ייצוא לפי מקור-התוכן (לא מסלולים-מקבילים מתפצלים):

  • docx_exporter.pyההחלטה הסופית מ-12 הבלוקים ב-decision_blocks (mode="final"), וגם טיוטת-ביניים (mode="interim" — תת-קבוצת בלוקים בסדר חדש: רקע→תכניות→טענות→הליכים, export_interim_draft, drafting.py:511). שני המצבים שולפים מאותה טבלה — וריאציית-תצוגה של אותו מקור-אמת, לא מסלול שני.

דטרמיניזם-מבני של טיוטת-הביניים (#204 / WS5). סדר-בלוקי-הביניים בייצוא קבוע ב-docx_exporter._INTERIM_BLOCK_ORDER (רקע→תכניות→טענות→הליכים, עם בלוקי-תבנית א–ה אופציונליים בתחילה). הבלוקים עצמם נכתבים דרך אותו מסלול-כתיבה קנוני של ההחלטה המלאה (block_writer.write_and_store_blockwrite_block, G2 — אין מסלול-ייצור מקביל), אך כעת נעוצים למודל יחיד (claude-opus-4-8) עם effort per-בלוק ובפרומפט- מבני קבוע (למשל בלוק-ה פותח תמיד ב"לפנינו ערר…"). התוצאה: אותו תיק מפיק את אותו מבנה בכל ריצה (אי-עקביות-הניסוח הקודמת נבעה מפרומפט-חופשי + מודל-ברירת-מחדל לא-נעוץ). טמפרטורה אינה במסלול (Opus 4.7/4.8 דוחים אותה); ראה block_writer.GENERATION_MODEL

  • BLOCK_CONFIG[*].effort.
  • analysis_docx_exporter.py (build_analysis_docx, :401) — מייצא את מסמך הניתוח המשפטי (analysis-and-research.md) שכתב legal-analyst, לא את בלוקי-ההחלטה. זהו תוצר-עזר שונה (שלב ניתוח, לא החלטה) — והוא המסלול שהסקיל מתעד בעיקר. שניהם חולקים את אותו טמפלט ואותם כללי-סגנון, כנדרש מ-INV-G2 (סימטריה — לא שתי שכבות-סגנון מתפצלות).

2. כללי-הסגנון — סיכום (הסמכות: הסקיל)

ה-service מחיל את סגנונות-הטמפלט בלבד (paragraph.style = "Heading 2") — בלי font/size/indent ידני; העיצוב (David, RTL, גדלים) מגיע מ-styles.xml. הפירוט המלא + ה-XML של כל סגנון: SKILL.md + references/.

  • סיווג-שורות (_classify_line): כל שורה מסווגת לאחת מ-6 קטגוריות — label_heading, inline_label, numbered, bullet, heb_letter, plain — שקובעות את הסגנון המוחל (Heading 2 / Normal / List Paragraph). ראה references/line-classification.md.
  • מדיניות-מקפים (_no_dash): דפנה ביקשה "בלי מקפים בכלל" — (U+2014) ו- (U+2013) מוסרים מכל טקסט נכתב; מקף רגיל (-) נשמר.
  • שדות-placeholder: chair_position עם סימן-ריק ([ימולא ע"י יו"ר הוועדה] וכד') מוחלף ב-[טרם מולאה עמדת ועדת הוועדה] ב-italic — סימן ויזואלי שנותר להשלים (תואם INV-G10 — היו"ר משלימה, לא המערכת).
  • RTL-runs: כל run מסומן <w:rtl/> (_mark_run_rtl) — אחרת Word נופל ל-Times New Roman במקום David. ראה references/rtl-runs.md.
  • מספור: מספור אוטומטי רק ב-List Paragraph (decimal); שורות (א)(ב) מקבלות List Paragraph עם _strip_numpr() (המספור העברי בטקסט).

3. רישום הגרסה — active_draft_path + git

לאחר כתיבת ה-DOCX, export_docx (drafting.py:404-408):

  1. set_active_draft_path(case_id, path) (db.py:1177) — רושם את ה-DOCX שיוצא כ- active-draft הנוכחי (cases.active_draft_path, db.py:189). שדה זה הוא האנקור לעריכות עוקבות (revise_draft/apply_user_edit/list_bookmarks), לא מקור-אמת-תוכן מתחרה ל-DB.
  2. git_sync.commit_and_push(case_dir, "ייצוא DOCX: …") (drafting.py:408) — מקבע את הקובץ ב-git של תיקיית-התיק (audit-trail של פלט, INV-G9; ראה X5-audit-provenance.md).

אותו דפוס (set_active_draft_path + commit) חוזר ב-export_interim_draft (drafting.py:533,536), revise_draft (drafting.py:692,695) ו-apply_user_edit (drafting.py:579,582).


4. Invariants של התחום

INV-EX1: ייצוא דטרמיניסטי ומשוחזר מהבלוקים — DOCX הוא נתון-נגזר (→G2)

כלל: הייצוא דטרמיניסטי וניתן-לשחזור מבלוקי-ההחלטה המאוחסנים ב-decision_blocks: אותם בלוקים + אותו טמפלט מפיקים מסמך שקול. ה-DOCX הוא נתון-נגזר (derived)לעולם לא מקור-אמת עצמאי. אסור מסלול-תוכן שני שכותב DOCX ממקור שאינו ה-DB; וריאציות (final/interim) הן תצוגות של אותו מקור. מקורות: Martin Kleppmann — Designing Data-Intensive Applications (O'Reilly, 2017, system-of-record מול derived data, ושחזור derived מהמקור) · Martin Fowler (Canonical Data Model / Single Source of Truth) · SSOT (Single Source of Truth principle) | סטטוס: verified אכיפה: export_decision שולף אך-ורק מ-decision_blocks (docx_exporter.py:336-342); פלט מגורסן + idempotent מבחינת-תוכן; אוכף את INV-G2 וכלל-ההנדסה "סימטריה" (חוקה §6). הפרה ידועה: אחרי revise_draft/apply_user_edit, ה-DOCX המסומן active_draft_path הופך ל"מקור-האמת" לעריכות-Track-Changes העוקבות (db.py:185-188), ובלוקי-ה-DB אינם מתעדכנים חזרה — הנתון-הנגזר זוחל למקור-אמת בפועל בלי סנכרון לאחור. יעד: או re-sync מהבלוקים, או חוזה מפורש ש-active_draft_path הוא רק אנקור-revision ולא מקור-תוכן → ראה §5.

INV-EX2: עקיבוּת-מקור נשמרת בהחלטה המיוצאת (→G9)

כלל: ההחלטה המיוצאת שומרת על עקיבוּת-מקור היכן שנדרש — סמכויות-משפטיות מצוטטות ניתנות-לאיתור (citation resolvable), והפלט מקובע ב-audit-trail (commit git). הפניות-פסיקה בבלוקים אינן מאבדות את מקורן בעת הרינדור. מקורות: Council of Europe / CEPEJ — European Ethical Charter on AI in judicial systems (2018, traceability/transparency) · ISO 15489-1:2016 (records authenticity/integrity) · Lewis et al. (2020, NeurIPS — RAG attribution) | סטטוס: verified אכיפה: export_docx מקבע כל פלט ב-git (git_sync.commit_and_push, drafting.py:408) + רושם active_draft_path (db.py:1177); עקיבוּת-המקור של הציטוטים עצמם נאכפת במעלה-הזרם (חילוץ-טענות/הלכות + provenance, 04-analysis-writing.md, X5-audit-provenance.md). אוכף את INV-G9. הפרה ידועה:

INV-EX3: אין ייצוא בכשל-QA קריטי (restate של INV-QA3 →G10)

כלל: הייצוא חסום כל עוד שער-QA קריטי נכשל (claims_coverage / structural_integrity); export_blocked חייב להיבדק לפני ייצוא. זהו אותו invariant של INV-QA3, בצד-הייצוא. מקורות: NCSC/JTC — Principles & Practices for AI Use in Courts (controlled, auditable output) · Council of Europe / CEPEJ (2018, under user control) · Federal Judicial Center — Judicial Writing Manual (2d ed.) | סטטוס: verified אכיפה: export_blocked = critical_failures > 0 (qa_validator.py:362); נאכף ברמת- הזרימה/agent בלבד — הסוכן legal-exporter מחויב להריץ validate_decision ולבדוק כשלים-קריטיים לפני ייצוא (.claude/agents/legal-exporter.md:71,149). הפרה ידועה: export_docx (drafting.py:384) אינו קורא ל-validate_decision בעצמו — הוא ניגש ישירות ל-docx_exporter.export_decision בלי לבדוק export_blocked. החסימה תלויה במשמעת-הסוכן ואינה hard-block בקוד-הייצוא → ראה §5 (תואם 05-qa-review §4).


5. Current vs Target

  • שער-ייצוא אכוף-זרימה ולא אכוף-קוד (INV-EX3 / INV-QA3). אומת בקוד: export_docx (drafting.py:384-419) קורא ישירות ל-docx_exporter.export_decision (:403) ללא קריאה ל-qa_validator.validate_decision ובלי בדיקת export_blocked. החסימה מתקיימת רק כי הסוכן legal-exporter מחויב להריץ QA קודם (legal-exporter.md:71,149) — אדם/סוכן שיקרא ל-export_docx ישירות יעקוף את השער. יעד: hard-block בתוך export_docx — שליפת qa_results/export_blocked ודחייה לפני כתיבת ה-DOCX, כך שאי-אפשר לעקוף.
  • active_draft_path כ-derived-שזוחל-למקור (INV-EX1). ה-DOCX נגזר מהבלוקים בייצוא הראשון, אך אחרי עריכה (revise_draft/apply_user_edit) ה-DOCX הופך ל"מקור-האמת" לעריכות הבאות (db.py:185-188) בלי לעדכן את decision_blocks חזרה — סטייה אפשרית בין הבלוקים למסמך-החי. יעד: חוזה מפורש — או re-sync מהבלוקים, או הגדרת active_draft_path כאנקור-revision בלבד (לא מקור-תוכן), עם בדיקת-בריאות לגילוי drift בין הבלוקים ל-DOCX הפעיל.

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