Repository navigation
Fix ODT comments leaking into paragraph text - #206
crown-sports wants to merge 1 commit into
Conversation
rahul05ranjan
left a comment
There was a problem hiding this comment.
Traced the leak mechanism and the fix is correct. The old "annotation" entry sat inside the text:-namespace match, but ODF annotations are office:annotation — so that arm could never match a real comment, and an office:annotation child fell out of the match straight into the bottom-of-arm walk_inlines(child, ...) recursion, which walked its text:p children and inlined the comment text into the annotated paragraph. The new top-of-arm child.is(ns::OFFICE, "annotation") skip is namespace-correct, and the ranged test binding comments: to the same office URI is a nice touch that proves prefix-independence.
I also checked the other paths an annotation can take, since the fix is inline-walker only: at block level (direct child of office:text or a table cell) parse_block_elem drops non-text:, non-table:table children silently, and parse_list skips non-list-item/list-header children — so walk_inlines was indeed the only leaking path and the fix covers it.
Dropping "annotation" from the text-ns list is fine — ODF has no text:annotation element, so that arm was dead code matching the wrong namespace (which is presumably how the bug got in). One thing worth knowing, though not a request: a hypothetical text:annotation would now fall to _ => {} and recurse into its children rather than being skipped outright.
Beyond correctness this is also a privacy fix worth noting: review comments are metadata the author expects to stay out of converted output, and on main they were being published into the markdown body — anyone converting an ODT that still had comments in it and publishing the result would have exposed the review conversation.
ODT comments currently become part of the paragraph they annotate. On the reproduction in #203,
Lamb+ comment +dawordbecomesLambAuthor2026-01-01T00:00:00COMMENTTEXTdaword. This change keepsLambdawordintact and omits the comment's author, date, and body.walk_inlineschecked forannotationin the text namespace, while ODF comments use the office namespace. Skip that subtree before recursing into inline children. The check uses the resolved namespace URI, so alternate XML prefixes work too.Two integration tests construct ODT ZIPs and call
to_markdown_bytes: a point comment inside a word, and a ranged comment inside a link/span using an alternate prefix. They check that adjacent text and the link survive. Both tests fail before the production fix and pass afterward.Related to #203. This fixes the annotation portion only; nested list numbering is unchanged and the issue should remain open for that work.
Validation on macOS arm64:
cargo test --locked: 300 passed, 1 existing ignored local-samples test.cargo fmt --all --check: passed.PYO3_PYTHON=/opt/homebrew/opt/python@3.12/bin/python3.12 cargo clippy --locked --workspace --all-targets --all-features -- -D warnings: passed.Text with a comment on Lambdaword here.AI assistance was used for implementation, testing, and review. Node, Python, and Wasm runtime suites were not run locally; upstream CI remains the cross-platform check.
Summary by cubic
Fixes ODT comments leaking into the paragraph they annotate. Previously, a comment between
LambanddawordproducedLambAuthor2026-01-01T00:00:00COMMENTTEXTdaword; now the adjacent text stays intact and the comment's author, date, and body are omitted.walk_inlinesonly checked text-namespaceannotationelements, while ODF comments use the office namespace. Skip that subtree before recursing into inline children; the check uses the resolved namespace URI, so alternate prefixes work too.Written for commit 5c65459. Summary will update on new commits.