fix(docx): continue counters across numIds that share an abstract (#96) - #129
Open
Mr-Neutr0n wants to merge 2 commits into
Open
fix(docx): continue counters across numIds that share an abstract (#96)#129Mr-Neutr0n wants to merge 2 commits into
Mr-Neutr0n wants to merge 2 commits into
Conversation
…recrawl#96) Word treats every w:num referencing one w:abstractNum as a single logical list; startOverride exists precisely to break away from it. Counters were keyed per numId instead, so documents whose outline is split across several instances of one abstract restarted at every switch: headings came out as Section 1, 2, 1(!), 1.1(!), 3 ... exactly the reported multiple-section-1 / 4.x-to-1.1 symptom in firecrawl#96. Reapplying the paragraph style clears it because it drops the direct numPr pointing at the second instance, collapsing the document back to one numId. Counters are now keyed by the resolved abstract definition. Entering a list through an instance that carries lvlOverride restarts exactly its overridden levels (nested w:lvl or startOverride); everything else keeps counting. The real-world text.docx fixture shows why this direction is right: consecutive items use numId 5 then numId 4 and the source itself labels them four, five -- previously rendered as IV, I. Snapshot updates: handmade-numbering's "Two-one independent counter" now continues the shared sequence (5.) rather than restarting (1.), and the style-referenced paragraph follows the merged sequence (8.). The override-driven cases (10., 7)) still restart as before. If the intent was that bare shared instances stay independent in anydoc despite Word, this is easy to flip behind a flag -- but Word parity is what firecrawl#96 asks for.
There was a problem hiding this comment.
All reported issues were addressed across 6 files
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
Mr-Neutr0n
added a commit
to Mr-Neutr0n/anydoc
that referenced
this pull request
Aug 23, 2026
Cubic review follow-ups on firecrawl#129, both real: - last_num is now Option<u64>: a document may legally carry numId=18446744073709551615 (xsd:int clamps were only applied to start values), and a u64::MAX sentinel would have swallowed the instance switch that triggers an override restart. - Overridden levels restart on their first USE under the entering instance (fresh_overrides) instead of eagerly marking pending bits at the switch. Eager marking let a following plain instance consume a restart it never earned: n1(1), n2[startOverride](unused at L0), n3 plain restarted to 1 instead of continuing at 2. Regression test walks nested lists and asserts the continuation.
Mr-Neutr0n
added a commit
to Mr-Neutr0n/anydoc
that referenced
this pull request
Aug 23, 2026
Cubic review round on firecrawl#130, all addressed: - CLI: a path conversion with a password but no --format dropped the password entirely; such conversions now go through toMarkdownBytes with content detection. -p/--password without a value is a usage error instead of silently falling back to the environment variable. - CLI: the asset pass re-read the still-encrypted container after a successful password-protected Markdown conversion and died with Encrypted. The container is now decrypted once, up front, so Markdown and assets see the same plaintext. - Library: to_markdown_with_password no longer fails with Unsupported before decrypting when an encrypted file has no recognizable extension; unresolved formats flow through to the byte-level entry point. - crypto: the decrypted payload is bounded by MAX_TOTAL_BYTES before any part is read, and is validated by actually opening it as an archive — a wrong password whose noise happens to start with PK now still ends in Encrypted instead of Malformed. - is_encrypted_ooxml / decrypt_ooxml are re-exported for embedders. - Python binding doc: removed the duplicated summary line. - Carries the firecrawl#129 per-instance override-restart fix so the two branches do not conflict.
Cubic review follow-ups on firecrawl#129, both real: - last_num is now Option<u64>: a document may legally carry numId=18446744073709551615 (xsd:int clamps were only applied to start values), and a u64::MAX sentinel would have swallowed the instance switch that triggers an override restart. - Overridden levels restart on their first USE under the entering instance (fresh_overrides) instead of eagerly marking pending bits at the switch. Eager marking let a following plain instance consume a restart it never earned: n1(1), n2[startOverride](unused at L0), n3 plain restarted to 1 instead of continuing at 2. Regression test walks nested lists and asserts the continuation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #96
Summary
Heading and list numbering now continues across
w:numinstances that share onew: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-
numPrvs 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
Counterskeys state by the resolved abstract definition (after numStyleLink indirection). Entering through an instance carryinglvlOverriderestarts exactly its overridden levels; plain instances continue the shared sequence.startOverridestarts are honored as before.Evidence this matches Word: the real-world
text.docxfixture 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)
Verification
instances_sharing_an_abstract_continue_one_sequence(continues across n1→n2, restarts at startOverride=10).This change was prepared with AI assistance under human direction and review.
Summary by cubic
Continue DOCX list and heading counters across
w:numinstances that resolve to the samew:abstractNum, matching Word. Previously counters keyed bynumIdrestarted on each instance switch; now they key by the resolved abstract and restart only levels overridden byw:lvlOverride/w:startOverride.w:numStyleLinkresolution). Track per-instance overridden levels and restart them on first use under that instance; plain instances continue the shared sequence.Option<u64>to avoid sentinel collisions with legal maxnumIdvalues.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.Written for commit 52dfa5e. Summary will update on new commits.