מקור-תבנית-יחיד לכל מפיקי-מסמכי-ההחלטה: כולם מחילים סגנונות דרך skills/docx/decision_template.docx בלבד; אסור hand-setting של פונט/גודל. - docs/spec/06-export.md — INV-EX4 חדש (מקור-תבנית-יחיד, →G2) - docx_reviser: מסלול-העריכה (revise_draft/apply_user_edit) הכניס פסקאות עם jc=right קשיח + David/sz ידני → איבד יישור דו-צדדי של התבנית. עכשיו מחיל pStyle מן-הטמפלט (Normal/Heading 2/Quote) + jc=both קנוני, בלי rFonts/sz ידני (הגופן/גודל מגיעים מהסגנון). - שומר-CI test_docx_template_single_source — נכשל על בניית rFonts/sz במפיקים מחוץ לטמפלט (חריג מסומן # INV-EX4-ok ל-_mark_run_rtl, שמחזק את גופן-התבנית David כעקיפת באג-RTL של Word). - אומת: build_party_claims_summary_docx (סיכום-מנהלים, WS3) + export_decision (סופי/טיוטת-ביניים) כבר תבניתיים ותואמי-INV-EX4. - ארכוב scripts/exec_summary_1043.py (one-off; הוחלף ב-build_party_claims_summary_docx). - עדכון 2 טסטים שאימתו את ההתנהגות הישנה (rFonts על run מוכנס). Invariants: מקיים INV-EX4 (חדש), INV-G2 (מקור-יחיד, אין מסלול-סגנון מקביל), INV-EX1 (DOCX נגזר). נוגע ב-docx_reviser/docx_exporter/analysis_docx_exporter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
18 KiB
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 הוא הנגזר
החלטה מאוחסנת כ-בלוקים מובְנים ב-DB — decision_blocks (12 בלוקים, מפתח קנוני
UNIQUE(decision_id, block_id)) תחת decisions (UNIQUE(case_id, version)); ראה
02-data-model.md §1. ה-DOCX נגזר מהבלוקים האלה ואינו מקור-אמת עצמאי:
מחיקתו אינה מאבדת תוכן, וייצוא חוזר מאותם בלוקים מפיק מסמך שקול.
מסלול-הייצוא הקנוני (הסופי):
export_docx(case_number)(tools/drafting.py:384, נחשףserver.py:557) שולף את התיק, ואז קורא ל-docx_exporter.export_decision(case_id, …, mode="final")(services/docx_exporter.py:306).export_decisionשולף את הבלוקים ישירות מ-decision_blocks(SELECT block_id, block_index, title, content, word_count … ORDER BY block_index,docx_exporter.py:336-342) — אין מקור-תוכן אחר.- טוען את טמפלט-דפנה (
skills/docx/decision_template.docx,docx_exporter.py:27-29,364), מנקה את גוף-המסמך (_clear_body), וכותב כל בלוק עם bookmark עוטף (אנקור ל-revisions עתידיים,_wrap_block_with_bookmarks,docx_exporter.py:367-382). - שומר לקובץ מגורסן
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_block→write_block, G2 — אין מסלול-ייצור מקביל), אך כעת נעוצים למודל יחיד (claude-opus-4-8) עםeffortper-בלוק ובפרומפט- מבני קבוע (למשל בלוק-ה פותח תמיד ב"לפנינו ערר…"). התוצאה: אותו תיק מפיק את אותו מבנה בכל ריצה (אי-עקביות-הניסוח הקודמת נבעה מפרומפט-חופשי + מודל-ברירת-מחדל לא-נעוץ). טמפרטורה אינה במסלול (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):
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.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).
הפרה ידועה — ✅ מגודרת (FU-7, GAP-17): אחרי revise_draft/apply_user_edit ה-DOCX
המסומן active_draft_path משמש כאנקור לעריכות-Track-Changes העוקבות, ובלוקי-ה-DB אינם
מתעדכנים חזרה — סטייה אפשרית בין הבלוקים למסמך-החי. התיקון שנבחר (חוזה מפורש, לא re-sync):
active_draft_path הוא אנקור-revision בלבד, לא מקור-תוכן מתחרה — ה-DB נשאר מקור-האמת. סטייה
נלכדת בדגל cases.blocks_stale (V22, db.py:1142-1148): revise_draft/apply_user_edit
מסמנים mark_blocks_stale(case_id, True) (drafting.py:688,789) ו-export_docx מנקה
(mark_blocks_stale(case_id, False), drafting.py:504) — הדגל הוא ה-drift-detection שחושף מתי
ה-DOCX-החי נסחף מהבלוקים. ראה §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
אכיפה — ✅ hard-block בקוד (FU-6, GAP-15): export_docx (drafting.py:462) בודק לעצמו
לפני כל ייצוא — db.qa_run_exists (אם QA לא רץ כלל → חסום) ו-db.get_critical_qa_failures
(אם יש כשל-קריטי → חסום) — לפני הגישה ל-docx_exporter.export_decision. אלו SELECT זולים
על ה-qa_results המאוחסנים (לא הרצת-LLM חוזרת). נוסף על export_blocked = critical_failures > 0
ברמת-הזרימה ועל משמעת-הסוכן legal-exporter (.claude/agents/legal-exporter.md:71,149) — כך
שאי-אפשר לעקוף את השער אפילו בקריאה ישירה ל-export_docx.
הפרה ידועה — ✅ נסגרה (FU-6, GAP-15): בעבר export_docx ניגש ישירות ל-exporter בלי לבדוק
export_blocked (אכוף-זרימה בלבד, ניתן-לעקיפה). נסגר ע"י ה-hard-block לעיל; מאומת ב-
test_export_qa_gate.py (חסום ללא-QA · חסום בכשל-קריטי · עובר כשנקי).
INV-EX4: מקור-תבנית-יחיד — כל מפיק-מסמך מחיל סגנונות-טמפלט בלבד (→G2)
כלל: כל מפיק של מסמך-Word הקשור-להחלטה — סופי (export_docx), טיוטת-ביניים
(export_interim_draft), סיכום-מנהלים (party-claims-summary), ומסמך-הניתוח
(build_analysis_docx), וכן מסלול-העריכה (revise_draft/apply_user_edit →
docx_reviser) — חייב לטעון את הטמפלט היחיד skills/docx/decision_template.docx
ולהחיל עיצוב אך-ורק דרך שמות-הסגנונות שמוגדרים בו (paragraph.style = "…" /
<w:pStyle w:val="…"/>). אסור hand-setting של משפחת-גופן (rFonts), גודל-גופן
(sz/szCs), או שוליים — אלה נגזרים מ-styles.xml של הטמפלט (cascade). היחיד שמותר
לכפות מפורשות הוא יישור-הגוף הקנוני jc=both היכן שהוא דורס סגנון שמגיע ממורכז
(_set_paragraph_jc, docx_exporter.py:80) — כי זו ההתנהגות-הקנונית, לא עיצוב-אד-הוק.
סמני-כיווניות (<w:bidi>, run <w:rtl/>) מותרים (כיווניות, לא עיצוב). טמפלט אחד = מקור-סגנון
יחיד; אין שכבת-סגנון מקבילה.
מקורות: SSOT (Single Source of Truth) · Martin Fowler — Canonical Data Model · ECMA-376
(OOXML) §17.7.2 — הורשת-סגנונות-פסקה (paragraph style inheritance / cascade) | סטטוס: verified
אכיפה: docx_exporter ו-analysis_docx_exporter טוענים TEMPLATE_PATH ומחילים style-by-name
(ראה §2); docx_reviser מחיל pStyle מן-הטמפלט + jc=both (לא פונט/גודל ידני). שומר-CI
test_docx_template_single_source.py גורף את מודולי-מפיקי-ה-DOCX ונכשל על rFonts/sz/szCs
ידני מחוץ לטוען-הטמפלט. אוכף את
INV-G2 בשכבת-הרינדור.
הפרה ידועה — ✅ נסגרה: docx_reviser._build_paragraph כפה jc=right + David/sz ידני על כל
פסקה שהוכנסה במסלול-העריכה (revise_draft/apply_user_edit) → פלט מסלול-העריכה איבד את היישור
הדו-צדדי של הטמפלט והכניס עיצוב-אד-הוק. נסגר ע"י החלת pStyle מן-הטמפלט; מאומת ב-
test_docx_reviser.py + test_docx_template_single_source.py.
5. Current vs Target
- שער-ייצוא — ✅ hard-block בקוד (INV-EX3 / INV-QA3, FU-6 / GAP-15).
export_docx(drafting.py:462-494) בודקdb.qa_run_exists+db.get_critical_qa_failuresודוחה לפני הגישה ל-docx_exporter.export_decision— לא ניתן לעקוף בקריאה ישירה. מאומת ב-test_export_qa_gate.py(3 מקרים: ללא-QA / כשל-קריטי / נקי). active_draft_pathכ-derived (INV-EX1, FU-7 / GAP-17) — ✅ מגודר בחוזה מפורש. ה-DB נשאר מקור-האמת;active_draft_pathהוא אנקור-revision בלבד. ה-drift בין הבלוקים ל-DOCX-החי נלכד בדגלcases.blocks_stale: נדלק ב-revise_draft/apply_user_edit(drafting.py:688,789), כובה ב-export_docx(drafting.py:504). שארית (low-pri): health-check שמתריע עלblocks_stale=trueעתיק — תיעוד-המשך, לא חוסם.
6. הפניות-אחיות
- 00-constitution.md — INV-G2 (derived-data / מקור-יחיד) · INV-G9 (עקיבוּת) · INV-G10 (שערים).
- 02-data-model.md —
decisions/decision_blocks(המקור שממנו מייצאים). - 04-analysis-writing.md — כתיבת הבלוקים שמהם נגזר ה-DOCX.
- 05-qa-review.md — INV-QA3 (שער-הייצוא הקריטי שקודם לשלב זה).
- 07-learning.md —
ingest_final_version+ Hermes על ההחלטה הסופית. - X5-audit-provenance.md — audit-trail (commit git) ועקיבוּת-מקור.
skills/dafna-decision-template/SKILL.md— המקור הסמכותי לכללי-הסגנון (line classification · dash policy · placeholder · RTL-runs).