# Strip numPr When Adding Manual Numbering to Auto-Numbered Paragraphs

## Problem (2026-07-01 反委托代发工资协议)

Original contract paragraphs have `<w:numPr>` with actual auto-numbering (e.g., `numId=3 → abstractNum decimal "%1." start=1`). When you insert manual "第X条" numbering as `w:ins` at paragraph start, OnlyOffice renders BOTH:

```
1. 第一条  乙方应严格按照...   ← "1." is auto-numbering, "第一条" is your INS
```

This looks broken — two different numbering systems stacked.

## Root Cause

The paragraph's `pPr/numPr` tells the rendering engine to prepend an automatic decimal number. Your INS adds a second, manual number. They coexist independently.

Additionally, if the paragraph has `pPr/pPrChange` (tracking the old paragraph formatting), the old `numPr` inside `pPrChange` can ALSO render in markup view.

## Fix (two-step)

After inserting manual numbering INS elements, strip auto-numbering from ALL affected paragraphs:

```python
for idx in target_paragraph_indices:
    p = paras[idx]
    ppr = p.find(f'{WNS}pPr')
    if ppr is not None:
        # Step 1: Remove direct numPr
        num_pr = ppr.find(f'{WNS}numPr')
        if num_pr is not None:
            ppr.remove(num_pr)
        
        # Step 2: Remove numPr inside pPrChange (old formatting record)
        ppr_change = ppr.find(f'{WNS}pPrChange')
        if ppr_change is not None:
            inner_ppr = ppr_change.find(f'{WNS}pPr')
            if inner_ppr is not None:
                inner_num = inner_ppr.find(f'{WNS}numPr')
                if inner_num is not None:
                    inner_ppr.remove(inner_num)
```

## When This Applies

- You're converting a contract from auto-numbered clauses to manual "第X条" heading-style numbering
- The original .doc/.docx used Word's list numbering for clause structure
- You're adding "第一条  " etc. as INS at paragraph start

## Verification

After fix:
1. `pdftotext -layout` of OnlyOffice render should show NO stray "1." / "2." / "3." before your "第X条"
2. Accept-revisions preview should also be clean (no residual auto-numbers)

## Scenario B: Auto-Numbering Resets Across Tracked-Deleted Paragraphs (2026-07-01 反委托代发工资协议)

### Problem

When paragraphs with `numPr` auto-numbering are interspersed with **entirely deleted paragraphs** (all content in `w:del`), OnlyOffice's auto-number counter **resets to 1** after the deleted block. This makes continuous numbering impossible with `numPr` alone.

Example structure:
```
P6:  numPr=1  INS content (clause 1) → renders "1."
P7:  numPr=1  continuation            → renders "2." (wrong if P7 shouldn't be numbered)
P8:  numPr=1  ALL w:del               → renders "3." with strikethrough
P9:  numPr=1  ALL w:del               → renders "4." with strikethrough
P10: numPr=1  INS content (clause 2)  → renders "1." ← RESETS! Should be "2."
```

The auto-numbering engine counts visible (non-deleted) items in the `numId` sequence, but deleted paragraphs **break the continuity** in OnlyOffice's rendering.

### Solution: Convert to Manual Text Numbering

Strip `numPr` from ALL paragraphs and insert "N. " as `w:ins` text at paragraph start. This gives identical visual output ("1. 2. 3. ...") without depending on the broken auto-number counter.

```python
# Step 1: Strip ALL numPr (including inside pPrChange)
for i, p in enumerate(paragraphs):
    pPr = p.find(f'{{{W}}}pPr')
    if pPr is not None:
        numPr = pPr.find(f'{{{W}}}numPr')
        if numPr is not None:
            pPr.remove(numPr)
        for pPrChange in pPr.findall(f'{{{W}}}pPrChange'):
            old_pPr = pPrChange.find(f'{{{W}}}pPr')
            if old_pPr is not None:
                old_numPr = old_pPr.find(f'{{{W}}}numPr')
                if old_numPr is not None:
                    old_pPr.remove(old_numPr)

# Step 2: Insert "N. " as w:ins text for each clause paragraph
# Only number paragraphs that have VISIBLE content (not entirely w:del)
clause_map = {6: 1, 10: 2, 11: 3, ...}  # para_index: clause_number

for para_idx, clause_num in clause_map.items():
    p = paragraphs[para_idx]
    # Build INS element with "N. " text
    ins_elem = ET.Element(f'{{{W}}}ins')
    ins_elem.set(f'{{{W}}}id', str(next_rev_id()))
    ins_elem.set(f'{{{W}}}author', rev_author)  # from existing INS in doc
    ins_elem.set(f'{{{W}}}date', rev_date)
    
    r_elem = ET.SubElement(ins_elem, f'{{{W}}}r')
    # Clone rPr from existing runs for font consistency
    rPr = get_run_rPr_from_paragraph(p)
    if rPr is not None:
        r_elem.append(copy.deepcopy(rPr))
    
    t_elem = ET.SubElement(r_elem, f'{{{W}}}t')
    t_elem.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve')
    t_elem.text = f"{clause_num}. "
    
    # Insert after pPr
    pPr = p.find(f'{{{W}}}pPr')
    if pPr is not None:
        p.insert(list(p).index(pPr) + 1, ins_elem)
    else:
        p.insert(0, ins_elem)
```

### When to Use This (vs Scenario A)

- **Scenario A** (above): You're CHANGING the numbering scheme (auto "1." → manual "第一条")
- **Scenario B** (this): You're KEEPING the same format ("1. 2. 3.") but converting from auto to manual because auto-numbering resets across w:del paragraphs
- **Trigger**: Original uses numPr auto-numbering + your edits create entirely-deleted paragraphs between numbered items → auto counter resets → switch to manual text

### Key Decision: Which Paragraphs to Number

Only number paragraphs that will be visible after accepting revisions:
- Paragraphs with ONLY `w:del` content → skip (they're deleted)
- Paragraphs that are continuations of the previous clause (no independent number) → skip
- New INS-only paragraphs (new clauses) → number them
- Rewritten paragraphs (mixed INS+DEL, first clause in sequence) → number them

### Verification

After conversion:
1. OnlyOffice render (x2t → PDF) should show continuous "1. 2. 3. ... 11." without resets
2. No stray auto-numbers from numPr remnants
3. Deleted paragraphs (entirely w:del) should NOT show any number

## Distinction from Existing Rules

- Rule 5 (A類 vs B類) talks about NEW clauses inheriting/stripping numPr
- Scenario A is EXISTING paragraphs where you're REPLACING their numbering scheme with a different format via INS
- Scenario B is EXISTING paragraphs where auto-numbering BREAKS due to tracked-deleted paragraphs, requiring conversion to same-format manual text
- numId=0 trap (Rule 5 sub-note) is about fake auto-numbering; BOTH scenarios here are about REAL auto-numbering that renders visible numbers
