Files
hermes-skills/skills/legal/contract-editor/references/operation-ordering-renumber.md
T

1.8 KiB

ContractEditor Operation Ordering: Add Clauses Before Renumbering

2026-07-13 练塘硬件购销合同教训

Problem

When interleaving add_clause_before() and tracked_replace() for renumbering, lxml throws:

ValueError: Element is not a child of this node.

in tracked_replace()parent.remove(runs[idx]).

Root Cause

add_clause_before() / add_clause() mutate the XML tree (insert new <w:p> elements). After insertion, previously-found element references held by later tracked_replace() calls may point to nodes whose parent relationship has shifted. The parent.remove() call inside tracked_replace fails because the run's parent <w:p> is no longer the same object the code expects.

Fix: Two-Phase Approach (铁律)

Phase 1 — All structural additions:

  • add_clause() / add_clause_before() for new clauses
  • Content-level tracked_replace() that don't touch clause titles being renumbered

Phase 2 — Renumbering (after all additions are done):

  • tracked_replace('第七条不可抗力', '第九条不可抗力') etc.

Example (correct order)

# Phase 1: add new clauses
editor.add_clause_before('第七条 转包与分包\n...', before_search='第七条不可抗力')
editor.add_clause_before('第八条 第三方侵权\n...', before_search='第七条不可抗力')

# Phase 2: renumber old clauses (all additions done)
editor.tracked_replace('第七条不可抗力', '第九条不可抗力')
editor.tracked_replace('第八条争议解决', '第十条争议解决')

WPS/DOC File Handling

WPS .wps and .doc files must be converted to .docx before ContractEditor can process them:

libreoffice --headless --convert-to docx input.wps --outdir /tmp/contract-review/

Then copy to a simple ASCII filename to avoid python-docx path issues with Chinese characters.