feat(export): INV-EX4 single-template source + fix edit-path justification
מקור-תבנית-יחיד לכל מפיקי-מסמכי-ההחלטה: כולם מחילים סגנונות דרך 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>
This commit is contained in:
76
mcp-server/tests/test_docx_template_single_source.py
Normal file
76
mcp-server/tests/test_docx_template_single_source.py
Normal file
@@ -0,0 +1,76 @@
|
||||
"""שומר INV-EX4 — מקור-תבנית-יחיד לכל מפיקי-מסמכי-ההחלטה.
|
||||
|
||||
כל מפיק של מסמך-Word הקשור-להחלטה חייב להחיל עיצוב דרך הסגנונות שמוגדרים
|
||||
בטמפלט היחיד (skills/docx/decision_template.docx), ולא לקבוע פונט/גודל ידנית
|
||||
(``rFonts`` / ``sz`` / ``szCs``) — אלה נגזרים מ-styles.xml של הטמפלט.
|
||||
|
||||
הטסט גורף את מודולי-המפיקים ונכשל אם נבנה אלמנט ``w:rFonts`` / ``w:sz`` /
|
||||
``w:szCs`` בקוד, אלא אם השורה נושאת את הסמן המפורש ``# INV-EX4-ok`` (חריג
|
||||
מתועד — למשל חיזוק גופן-התבנית עצמו David כעקיפת באג-RTL של Word).
|
||||
|
||||
ספ: docs/spec/06-export.md §INV-EX4.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from legal_mcp.services import (
|
||||
analysis_docx_exporter,
|
||||
docx_exporter,
|
||||
docx_reviser,
|
||||
docx_retrofit,
|
||||
)
|
||||
|
||||
# Every module that builds/edits a decision-related Word document.
|
||||
_PRODUCER_MODULES = [
|
||||
docx_exporter,
|
||||
analysis_docx_exporter,
|
||||
docx_reviser,
|
||||
docx_retrofit,
|
||||
]
|
||||
|
||||
# Construction (not lookup) of a hand-set font/size element:
|
||||
# OxmlElement("w:rFonts") (python-docx producers)
|
||||
# etree.SubElement(rPr, _w("sz")) (raw-lxml producer: docx_reviser)
|
||||
_HANDSET_RE = re.compile(
|
||||
r'OxmlElement\(\s*["\']w:(?:rFonts|sz|szCs)["\']'
|
||||
r'|SubElement\([^)]*_w\(\s*["\'](?:rFonts|sz|szCs)["\']'
|
||||
)
|
||||
|
||||
# Producers that build a document FROM SCRATCH must load the single template.
|
||||
# (docx_reviser/docx_retrofit operate on an already-templated existing doc.)
|
||||
_FROM_SCRATCH_MODULES = [docx_exporter, analysis_docx_exporter]
|
||||
|
||||
|
||||
def _module_path(module) -> Path:
|
||||
return Path(module.__file__)
|
||||
|
||||
|
||||
def test_no_handset_font_or_size_in_producers() -> None:
|
||||
"""INV-EX4: no hand-set rFonts/sz/szCs in any producer (only via the
|
||||
template's named styles), unless explicitly marked ``# INV-EX4-ok``."""
|
||||
violations: list[str] = []
|
||||
for module in _PRODUCER_MODULES:
|
||||
path = _module_path(module)
|
||||
for lineno, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
|
||||
if _HANDSET_RE.search(line) and "INV-EX4-ok" not in line:
|
||||
violations.append(f"{path.name}:{lineno}: {line.strip()}")
|
||||
assert not violations, (
|
||||
"INV-EX4 violation — hand-set font/size outside the template styles "
|
||||
"(use a named template style, or mark with # INV-EX4-ok):\n "
|
||||
+ "\n ".join(violations)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("module", _FROM_SCRATCH_MODULES)
|
||||
def test_from_scratch_producers_load_the_single_template(module) -> None:
|
||||
"""INV-EX4: from-scratch producers reference the one template file."""
|
||||
source = _module_path(module).read_text(encoding="utf-8")
|
||||
assert "decision_template.docx" in source, (
|
||||
f"{_module_path(module).name} must load the single template "
|
||||
"skills/docx/decision_template.docx (INV-EX4)."
|
||||
)
|
||||
Reference in New Issue
Block a user