fix(docx): continue counters across numIds that share an abstract (#96)
Fixes #96
Summary
Heading and list numbering now continues across w:num instances that share one w:abstractNum, instead of restarting at every instance switch.
Root cause
Counters were keyed per numId. Word documents (and converter output) routinely split one logical outline across several numIds of the same abstract, so every direct-numPr vs style-inherited switch reset the sequence: the reported file renders "Section 4 → 4.1 → 1.1 → 4.2" with multiple "Section 1"s. Reapplying the style "fixes" it only because it removes the direct numPr, collapsing everything to a single numId.
Reproduced with a minimal OOXML fixture: two numIds sharing abstract 0 produce Section 1, Section 2, Section 1, 1.1 on this branch's base commit.
What changed
Counters keys state by the resolved abstract definition (after numStyleLink indirection). Entering through an instance carrying lvlOverride restarts exactly its overridden levels; plain instances continue the shared sequence. startOverride starts are honored as before.
Evidence this matches Word: the real-world text.docx fixture has consecutive items on numId 5 then numId 4 whose source text labels them "Roman starting at four", "Roman five" - previously rendered IV then I; now IV then V.
Snapshot updates (intentional, flagged)
- handmade-numbering: "Two-one independent counter" now continues (5.) rather than restarting (1.), and the style-referenced paragraph follows the merged count (8.). Override cases (10., 7)) unchanged. If bare shared instances were meant to stay independent despite Word behavior, that contract can be restored behind an option -- but parity with Word is what #96 reports as missing.
- text.docx / malformed variants: "I." becomes "V.", matching the document's own labels.
Verification
- New regression test
instances_sharing_an_abstract_continue_one_sequence(continues across n1→n2, restarts at startOverride=10). - Full suite: 287 passed incl. snapshots; clippy clean; fmt clean.
This change was prepared with AI assistance under human direction and review.
Summary by cubic
Continue DOCX list and heading counters across w:num instances that resolve to the same w:abstractNum, matching Word. Previously counters keyed by numId restarted on each instance switch; now they key by the resolved abstract and restart only levels overridden by w:lvlOverride/w:startOverride.
- Key counters by abstract identity (after
w:numStyleLinkresolution). Track per-instance overridden levels and restart them on first use under that instance; plain instances continue the shared sequence. - Store the last active instance as
Option<u64>to avoid sentinel collisions with legal maxnumIdvalues. - Add regression tests
instances_sharing_an_abstract_continue_one_sequenceandoverride_restart_does_not_leak_into_the_next_instance. Update snapshots where shared instances now continue (e.g., "Two-one independent counter" -> 5., "I." -> "V."); override-driven restarts are unchanged.