Files

2.5 KiB

WB INS Font Fix + Bold-Stripping Disaster (2026-06-10)

Problem

Doro rejected 【修】青浦精神卫生-委托检验协议(修).docx: WB insertions displayed in wrong font.

Terminal review passed 10 checks but missed basic font inconsistency.

Root Cause

contract_docx_lib.py's _ensure_rfonts_complete() only filled hAnsi/cs, missing:

  1. w:eastAsia — CJK falls back to docDefaults (Times New Roman vs 宋体)
  2. w:hint="eastAsia" — required for CJK rendering priority
  3. w:sz — not inherited inside w:ins; must be explicit

Fix Applied (contract_docx_lib.py, 4 locations)

1. _ensure_rfonts_complete() — fill all 4 + hint

2. _extract_formats() — ensure sz on body_rpr/title_rpr

3. tracked_replace() — ensure sz on INS rpr

4. tracked_replace() — fallback for hint-only rFonts runs

See previous version of this file for code details.

CRITICAL: Bold-Stripping Disaster

What happened

First fix attempt: after noticing font issues, batch-stripped ALL <w:b/> tags from all WB INS runs. This destroyed the original bold formatting:

  • P19: 风险律师费条件(原文加粗)→ stripped → not bold ✗
  • P18: 金额部分(原文加粗)→ stripped → not bold ✗
  • P30: "如若违反,律师费将另行重新计付"(原文加粗)→ stripped → not bold ✗

Doro: "要保持原文的格式不变"

Why it was wrong

tracked_replace correctly inherits the original run's rPr INCLUDING bold. When the original text "在代理过程中..." was bold, the replacement text "风险律师费仅按..." SHOULD also be bold — that's correct format preservation.

The rule

  • tracked_replace INS inherits original run's rPr → leave it alone
  • add_clause uses _body_rpr (no bold) or _title_rpr (bold) → correct by design
  • NEVER post-process WB INS to strip/add formatting attributes globally

Correct validation approach

Compare each WB INS run against the original run in the same paragraph, not against a global template. Use scripts/wb-ins-font-verify.py for document-agnostic validation.

Verification Script

scripts/wb-ins-font-verify.py <docx> — per-paragraph comparison, checks rFonts/sz/hint, exit code 0=pass 1=fail. Document-agnostic (no hardcoded font names).

Three font-source scenarios in tracked_replace

  1. Run has explicit font names → _ensure_rfonts_complete fills gaps
  2. Run has hint-only rFonts (no names) → fallback to _body_rpr font names
  3. Run has no rPr at all → use _body_rpr directly