ooxml-integrity

Word opened this edit without a warning.
The reviewer's comment was gone.

In a recorded Word for Mac comparison, one table edit preserved the reviewer's comment and tracked the changes. Another used python-docx and detached the comment when replacing paragraph text. Both files opened without a warning. The note remained in comments.xml but disappeared from the margin.

Services Agreement

Schedule 2 — Milestones and fees

MilestoneDueFee
DiscoveryWeek 2EUR 8,000
BuildWeek 8EUR 12,00014,000
HandoverWeek 12EUR 6,0007,500

Fees are payable within thirty days of the invoice date for each completed milestone.

Services Agreement

Schedule 2 — Milestones and fees

MilestoneDueFee
DiscoveryWeek 2EUR 8,000
BuildWeek 8EUR 14,000
HandoverWeek 12EUR 7,500

Fees are payable within thirty days of the invoice date for each completed milestone.

Illustration: edits tracked, comment anchored to the figure. Edits untracked, comment still stored in the package but anchored to nothing.

Opening successfully does not establish that review information survived. The checker inspects references inside the file and compares supported content with the original. See the recorded Word comparison and its limits.

Run it on your own file

The real Python package, running in your browser through WebAssembly. Files stay in this tab and are never uploaded. Add the original to see what an edit lost.

Starting Python in your browser…Startup log
    Required
    Optional
    Or try an example
    Waiting for a file
    Choose your files above, or try an example.
    
    The original enables --against: checks for what an edit lost,
    even when the resulting document has no broken references.

    This is a checker, not an Office renderer. In the browser, Calibri is measured with Carlito, Cambria with Caladea, and Arial, Times New Roman and Courier New with Liberation Sans, Serif and Mono. Substituted measurements are reported as estimates. What runs where

    Two questions, because one is not enough

    A document can lose comments or revisions while its remaining references stay consistent. Check both the edited file and what changed from the original.

    Did this file survive editing?

    Check supported comment anchors, footnote references, styles, numbering, relationships and tracked-change structures for inconsistencies.

    ooxml-integrity check report.docx

    What did the edit lose?

    Compare supported construct counts and text against the original. This can reveal losses even when the edited file has no broken references.

    ooxml-integrity check edited.docx --against original.docx
    [ERROR] CMT005  comment id=1 is orphaned - present in comments.xml but
                    anchored to nothing - the reviewer's note is invisible in Word
    [ERROR] FID001  comment anchors: 2 -> 1 (1 lost)

    Six controlled defects, two controls

    Hand-written mutations modelled editing mistakes on one reference contract. All six defect cases triggered findings. XML parsing, a Word namespace/root/body check and successful LibreOffice PDF conversion did not distinguish them from the controls. Full XSD validation and systematic visual review were not run.

    Scroll sideways to see all columns.

    Controlled editXML parsesRoot/body checkPDF createdChecker findings
    python-docx open/save controlyespassedyesnone
    Replace text with paragraph.textyespassedyesself + source
    Targeted XML value-edit controlyespassedyesnone
    Clone a clause with its revision IDsyespassedyesself
    Reformat XML, losing whitespace markersyespassedyesself
    Delete a paragraph holding a footnoteyespassedyesself + source
    Rename a style, leave references danglingyespassedyesself
    Round-trip through Markdownyespassedyessource

    Self checks internal consistency; source compares with the original. The table lists checks that reported ERROR or WARN findings. Method, results and limits.

    Separately, eight recorded agent runs on copies of one contract produced six outputs with no structural findings and two with detached comments. Tasks and prompts varied, including preservation and speed instructions; tool choice was not a controlled variable. These runs do not measure how often agents damage documents. Agent-run observations.

    Decks: does the text fit the box?

    The checker estimates fit from font advance tables and supported text properties, including size inherited from run, paragraph, list, layout, master and presentation defaults. It does not render the deck. The evidence below covers specific strings, fonts and renderer configurations.

    Example report with desktop fonts; browser substitutions can differ.

    [ERROR] PPT001  text needs 144pt in a 40pt box - 104pt too tall (260% over), 3 line(s)
              -> slide1/OVER_huge_type_tiny_box
    [WARN ] PPT006  overlaps 'OVERLAP_upper_right' over 23% of the smaller shape
              -> slide3/OVERLAP_lower_left
    [INFO ] PPT007  Segoe UI is not installed and has no known substitute; measured
                    with DejaVu Sans - widths are a guess. 1 shape(s) affected
    21 of 21
    non-excluded reference shapes matched fit and line count in PowerPoint for Mac editing view, using the same Calibri file. Three cases were excluded. Comparison record.
    1.2 × size
    default line pitch observed in a LibreOffice probe with six faces at 12pt and 20pt. This supports the model for those samples. Measurement method.
    0.26–0.58 %
    width difference in five letter samples measured at 18pt: Carlito was wider than Calibri. A digits sample matched. This is not a bound for other strings or fonts. Font comparison.
    2 vs 3 lines
    for one near-limit shape: PowerPoint for Mac used two lines; LibreOffice and ONLYOFFICE used three. The checker applies a tolerance, without predicting every renderer. Observed disagreement.

    Put it after the step that edits documents

    Run after a generation script, agent edit or template merge, with the original available for comparison. Python 3.9+, with lxml and fonttools (plus tomli on Python 3.9–3.10). Installed checks need no model calls or network.

    Command line

    pip install ooxml-integrity
    ooxml-integrity check out/*.docx --against templates/master.docx
    ooxml-integrity check deck.pptx --coverage

    Exit 0: no findings at the failure threshold; 1: findings at or above --fail-on; 2: usage error. Use coverage to see what was checked and --json for machines.

    GitHub Action

    - uses: Dmitry-Kov/ooxml-integrity@v0.4.4
      with:
        files: "out/**/*.docx"
        against: templates/master.docx
        fail-on: error
        sarif: ooxml-integrity.sarif

    SARIF output can be uploaded to GitHub code scanning for pull-request annotations. Ignores, severity overrides and baselines: configuration.

    Python

    from ooxml_integrity import check, compare
    
    for f in compare("original.docx", "edited.docx"):
        print(f.code, f.severity.value, f.message)

    Stable rule codes identify findings; suppressions and baselines record accepted findings. Support matrix.

    What it does not do

    The next step is a public benchmark of docx editing tools and agent harnesses on a real corpus. If your agents edit Office files that a person then reviews, I would like to hear what breaks for you. Open an issue