feat: export core Hermes skills
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# Split-Run Numbering in docx XML
|
||||
|
||||
## Problem
|
||||
Contract numbering like `(5)` is often split across multiple `<w:r>` runs in the XML:
|
||||
```xml
|
||||
<w:r><w:t>(</w:t></w:r>
|
||||
<w:r><w:t>5</w:t></w:r>
|
||||
<w:r><w:t>)委托方</w:t></w:r>
|
||||
```
|
||||
|
||||
A naive `tracked_replace("(5)", "(6)")` searching for the complete string in a single `<w:t>` will **silently fail** — no match, no error, no renumbering.
|
||||
|
||||
## Solution: Multi-run concatenation + split
|
||||
|
||||
### Algorithm
|
||||
```python
|
||||
def tracked_replace_split_number(p, old_num, new_num):
|
||||
"""Handle (old_num) spread across multiple runs."""
|
||||
target = f'({old_num})'
|
||||
new_target = f'({new_num})'
|
||||
|
||||
# 1. Collect all plain runs (not inside w:ins or w:del)
|
||||
plain_runs = [(index, run, text) for each child of p]
|
||||
|
||||
# 2. Slide a window: concatenate adjacent run texts until target is found
|
||||
for start in range(len(plain_runs)):
|
||||
concat = ""
|
||||
for end in range(start, start+4): # max 4 runs for a number
|
||||
concat += plain_runs[end].text
|
||||
if target in concat:
|
||||
# Found! Extract before/after text around the number
|
||||
runs_to_wrap = plain_runs[start:end+1]
|
||||
# ...proceed to replace
|
||||
|
||||
# 3. Remove original runs, insert:
|
||||
# - [before_run if text before number]
|
||||
# - DEL element with delText=target
|
||||
# - INS element with t=new_target
|
||||
# - [after_run if text after number, e.g. "委托方"]
|
||||
|
||||
# 4. Set rsid attributes: rsidDel on DEL runs, rsidR on INS runs
|
||||
```
|
||||
|
||||
### Critical: Process order
|
||||
**Always renumber from bottom to top** (last paragraph first) to avoid index shifting:
|
||||
```python
|
||||
# CORRECT
|
||||
renumber = [(P113, '10', '11'), (P112, '9', '10'), (P111, '7', '8')]
|
||||
|
||||
# WRONG - P112 was already renumbered when we get to it
|
||||
renumber = [(P111, '7', '8'), (P112, '9', '10'), (P113, '10', '11')]
|
||||
```
|
||||
|
||||
### Edge cases encountered (2026-06-08)
|
||||
- `(` + `10)` (two runs, not three) — the closing `)` merged with the digit
|
||||
- `(` + `5` + `)委托方` — closing `)` merged with following text, must split run to preserve "委托方"
|
||||
- Copy `w:rPr` from original runs to all new DEL/INS runs to preserve font/size
|
||||
|
||||
## Lesson
|
||||
This was the root cause of a terminal review failure where 3 new clauses were inserted without numbering, and subsequent numbering was not renumbered. The `tracked_replace` function matched nothing because it expected `(5)` as a single text node.
|
||||
Reference in New Issue
Block a user