Skip to content

fix(validate): accept Word's revision marks inside a math run - #31

Open
xsvm wants to merge 1 commit into
kklimuk:mainfrom
xsvm:fix/validate-math-run-revisions
Open

xsvm wants to merge 1 commit into
kklimuk:mainfrom
xsvm:fix/validate-math-run-revisions

Conversation

@xsvm

@xsvm xsvm commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

Summary

docx validate rejected every document Word saved with a tracked equation edit:

word/document.xml: 8 errors
  Element '{…/wordprocessingml/2006/main}del': This element is not expected. (line 1)
  …

Word records a tracked edit inside an equation per math run: <m:r><w:del …><w:rPr>…</w:rPr><m:t>E</m:t></w:del></m:r> (one mark per run, plus one in each m:ctrlPr). ECMA-376's CT_R has no slot for w:ins/w:del, but Microsoft documents it as supported Word behavior: MS-OI29500, Part 1 §22.1.2.87 (e), "Word supports the w:ins and w:del elements inside a math run." (The m:ctrlPr marks are already valid.)

This also hits docx-cli's own edits. equations edit --track writes <w:del><m:oMath>…</m:oMath></w:del><w:ins>…</w:ins>, which validates; once a user opens and saves that file in Word, Word rewrites it into the per-run shape above and validate reports 6 errors. Reproduced with Word 365 on Windows (open + SaveAs2 via COM). The same false errors land in the raw gate's baseline.

The fix

validationXmlFor already preprocesses a clone (MCE strip) because real Word markup is valid OOXML the base schema doesn't know. It now also unwraps w:ins/w:del that sit directly inside an m:r, so what they wrap (m:rPr, w:rPr, m:t) is still validated against CT_R. The schemas stay as published, per src/core/raw/CLAUDE.md. Doc note added there.

Related: #27's fixture uses this same Word shape, so it now passes docx validate too.

Test plan

  • bunx biome check ., bunx knip, bunx tsc --noEmit
  • 2 new tests in tests/core/raw.test.ts: Word's w:del/w:ins inside a math run validate clean (failed before the fix); content inside the mark is still checked (a bogus element there is still reported)
  • raw / validate test suites pass (136 tests)
  • Two Word-saved files (a Word tracked deletion of two equations; a docx-cli tracked edit re-saved by Word) now report valid
  • Full suite: CI on this PR

Word records a tracked equation edit inside each math run,
<m:r><w:del …><m:t>x</m:t></w:del></m:r>, and documents it as supported
(MS-OI29500, Part 1 §22.1.2.87 (e)), but ECMA-376's CT_R has no slot for it.
So `docx validate` and the raw gate's baseline reported "del: This element
is not expected" for every file Word saved with such an edit, including a
docx-cli `<w:del><m:oMath>` edit once Word re-saved it (Word rewrites it to
its own shape).

validationXmlFor now unwraps those marks in its clone, next to the MCE
pass; what they wrap is still checked against CT_R. The schemas stay as
published.
@kklimuk

kklimuk commented Oct 29, 2026

Copy link
Copy Markdown
Owner

🤖 docx-cli triage

Thanks @xsvm, this is a clean, well-scoped fix. I reviewed head 30d47dd.

Claim: docx validate and the raw gate's schema check reported false errors for the per-math-run revision marks Word writes (<m:r><w:del>…<m:t>…</m:t></w:del></m:r>, MS-OI29500 Part 1 §22.1.2.87 (e)). The PR unwraps w:ins/w:del that sit directly inside an m:r, only in the copy that gets validated.

Before/after (minimal docx from create --from with $E=mc^2$, then the XML hand-edited):

case main this PR
Word shape: w:del + w:ins inside m:r 2 errors (del/ins not expected) valid — 5 parts checked
w:del inside a regular w:r 1 error 1 error (still caught)
w:del directly in m:e wrapping a bare m:t 1 error 1 error (still caught)
content wrong inside the mark (m:t before m:rPr) 1 error (del) 1 error (m:rPr not expected, so the real problem is now named)
nested w:ins><w:del inside m:r 1 error 1 error (only the outer mark is unwrapped)
raw insert --xml '<w:p><m:oMath><m:r><w:del …><m:rPr>…</m:rPr><m:t>x</m:t></w:del></m:r></m:oMath></w:p>' VALIDATION_FAILED (1 new error) accepted as p1; the written document.xml keeps the <m:r><w:del …> untouched
raw insert of <w:r><w:del><w:t> VALIDATION_FAILED VALIDATION_FAILED

So the unwrap only touches the validation copy and only applies inside m:r. Wrong content inside the mark is still reported. Both sides of the raw gate's before/after comparison go through validationXmlFor (cli/raw/commit.ts, cli/raw/part.ts, cli/validate), so the fix affects them the same way.

Checks: bun run check ✅, bun run test:unit ✅ (1911 pass, 0 fail). /simplify single pass: no changes. I did not run /code-review this run, and I pushed nothing.

Docs: the src/core/raw/CLAUDE.md addition matches the code. Small optional nit: the docstring on validateWmlXml (validate.ts ~L43) still describes only the markup-compatibility clean-up and could mention the new unwrap too.

Decisions for the maintainer

  • Do you want this at all? No issue asked for it. It fixes false validate errors on files Word saved with tracked equation edits, including docx-cli's own equations edit --track output after a Word re-save.
  • Follow-up, outside this PR: the reader doesn't see these math-run marks either, on main or here. track-changes list says "no tracked changes" for the Word-shaped file. read renders $Ec^2$, dropping both the deleted = and the inserted m. A raw-inserted deleted run reads as a live $x$. Now that the raw gate accepts this shape, that's a gap in the "every change shows up on the next read" rule. Worth an issue?

Action needed: approve/merge — PR #31 is ready as-is (I pushed nothing, so your own approval satisfies the last-push rule). Please also decide on the two checklist items above.


Generated by Claude Code

@kklimuk

kklimuk commented Oct 30, 2026

Copy link
Copy Markdown
Owner

@xsvm hold off from making further changes till i've had a bit of time to read through and do my own reviews, it's gonna take me a few days.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants