# WPS Format Handling & Renumber Order Pitfall

## WPS File Conversion

邱律师有时发送 `.wps` 格式文件（WPS Office 原生格式）。python-docx 无法直接读取。

**转换命令：**
```bash
libreoffice --headless --convert-to docx "/path/to/file.wps" --outdir /tmp/contract-review/
```

**注意事项：**
- 转换后文件名保留原名但扩展名变为 .docx
- 转换后仍需复制为简短ASCII文件名避免路径问题
- 交付时文件名前加【修】，扩展名用 .docx（不恢复为 .wps）
- 设备清单可能是图片而非文字表格（WPS特有），需用vision检查 word/media/ 中的图片

## tracked_replace + add_clause 编号顺延的执行顺序

**铁律：先做所有 add_clause/add_clause_before 插入，最后统一 tracked_replace 重编号。**

**错误顺序（会报 lxml ValueError）：**
```python
editor.add_clause_before('第七条 转包', before_search='第七条不可抗力')
editor.tracked_replace('第七条不可抗力', '第八条不可抗力')  # ✅ OK
editor.add_clause_before('第八条 侵权', before_search='第八条不可抗力')
editor.tracked_replace('第八条不可抗力', '第九条不可抗力')  # ❌ FAIL - paragraph already modified
```

**正确顺序：**
```python
# 1. 先做所有插入（用原文文本定位）
editor.add_clause_before('第七条 转包\n...', before_search='第七条不可抗力')
editor.add_clause_before('第八条 侵权\n...', before_search='第七条不可抗力')
# 注意：两个都用原文"第七条不可抗力"定位，因为原文段落文本未变

# 2. 最后统一重编号（此时原文段落只被rename一次）
editor.tracked_replace('第七条不可抗力', '第九条不可抗力')
editor.tracked_replace('第八条争议解决', '第十条争议解决')
# ...
```

**根因：** `tracked_replace` 会把原文 run 删除并插入 `w:del` + `w:ins`，修改后的段落内部结构已变。再次对同一段落调用 `tracked_replace` 时，lxml 尝试 remove 已不在原位的 element，抛出 `ValueError: Element is not a child of this node`。

## 2026-07-13 实证

练塘硬件购销合同（璞石医疗）：新增第七条转包+第八条第三方侵权，原第七至十条顺延为第九至十二条。第一次尝试"插一个改一个"失败，改为"先全部插入再统一改编号"成功。
