# Workflow INS Format Repair — ContractEditor Font Contamination Pattern

## 2026-07-13 洋励/安全生产/消防设施检测 连续验证

### 问题根因

ContractEditor库在处理文档时会**污染原文runs**——给原本没有显式属性的runs添加`eastAsia`、`cs`、`sz`。

典型对比：
```
原文(待审查):  rFonts={ascii=宋体, hAnsi=宋体, hint=eastAsia}, szCs=21, NO sz, NO eastAsia
v1中orig runs: rFonts={ascii=宋体, hAnsi=宋体, hint=eastAsia, cs=宋体, eastAsia=宋体}, szCs=21, sz=21
v1中WB INS:    rPr=空 (什么属性都没有)
```

**后果**：
1. 原文字号从继承docDefaults(如sz=22=11pt)变为显式sz=21(10.5pt)——整体缩小0.5pt
2. INS runs无属性→走docDefaults继承→11pt，与被改小的orig runs(10.5pt)不一致
3. wb-ins-font-verify报"orig=宋体/21 wb=None"——但这个"orig"已被污染，不是真实原文

### 诊断铁律

**永远对比待审查目录的原文，不信v1中的orig runs**：

```python
# 对比同一段落的run属性
for label, path in [('待审查原文', orig_path), ('交付v1', v1_path)]:
    # 读P4 first run rPr的所有子元素
    # 如果v1比原文多了eastAsia/cs/sz → 被污染
```

### 修复方法（三步）

**Step 1：清除orig runs的污染属性**
```python
for r in p.findall(f'{WNS}r'):  # 只处理原文runs（不在ins/del内的）
    rpr = r.find(f'{WNS}rPr')
    rf = rpr.find(f'{WNS}rFonts')
    if rf is not None:
        # 如果原文没有eastAsia，strip之
        if f'{WNS}eastAsia' in rf.attrib:
            del rf.attrib[f'{WNS}eastAsia']
        if f'{WNS}cs' in rf.attrib:
            del rf.attrib[f'{WNS}cs']
    # 如果原文没有sz（靠继承），strip之
    sz = rpr.find(f'{WNS}sz')
    if sz is not None:
        rpr.remove(sz)
```

**Step 2：设INS runs匹配真实原文**
```python
for ins in p.findall(f'.//{WNS}ins'):
    if ins.get(f'{WNS}author') != 'WB': continue
    for r in ins.findall(f'{WNS}r'):
        rf = rpr.find(f'{WNS}rFonts')
        # 设置为原文实际有的属性（如ascii=宋体, hAnsi=宋体）
        # 不设原文没有的（如eastAsia, cs）
        # hint按同段orig run的值设
```

**Step 3：逐段匹配hint**
不同段落的orig runs hint状态不同（有的有hint=eastAsia，有的没有）。必须逐段检查并匹配。

### 注意事项

- **不能一刀切**：同一文档不同段落的orig run属性可能不同（P4有hint, P19没hint; P20有完整rFonts, P36完全没rFonts）
- **docDefaults是真正的参考基准**：检查`word/styles.xml`的`docDefaults/rPrDefault`了解继承值
- **"MISSING HINT (无同段原文可比)"是已知限制**：整段WB INS的新增段落没有orig run对比，脚本报MISSING不是真实错误
- **洋励案实证**：120处orig runs被污染，修复后INS只剩14个MISSING HINT（全是新增段落）
