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
| Milestone | Due | Fee |
|---|---|---|
| Discovery | Week 2 | EUR 8,000 |
| Build | Week 8 | EUR |
| Handover | Week 12 | EUR |
Fees are payable within thirty days of the invoice date for each completed milestone.
Services Agreement
Schedule 2 — Milestones and fees
| Milestone | Due | Fee |
|---|---|---|
| Discovery | Week 2 | EUR 8,000 |
| Build | Week 8 | EUR 14,000 |
| Handover | Week 12 | EUR 7,500 |
Fees are payable within thirty days of the invoice date for each completed milestone.
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
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 edit | XML parses | Root/body check | PDF created | Checker findings |
|---|---|---|---|---|
python-docx open/save control | yes | passed | yes | none |
Replace text with paragraph.text | yes | passed | yes | self + source |
| Targeted XML value-edit control | yes | passed | yes | none |
| Clone a clause with its revision IDs | yes | passed | yes | self |
| Reformat XML, losing whitespace markers | yes | passed | yes | self |
| Delete a paragraph holding a footnote | yes | passed | yes | self + source |
| Rename a style, leave references dangling | yes | passed | yes | self |
| Round-trip through Markdown | yes | passed | yes | source |
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 DOCX corpus has 50 synthetic sources and 220 labelled pairs across five producers: 120 clean controls and 100 seeded defects. It records 111 error-level true positives, zero false positives and zero false negatives. The 100 % precision/recall applies to that corpus; 14 rules are measured and 30 are unmeasured. Customer-document accuracy is unknown. Corpus results and denominators.
- Eight agent runs is a small sample, on one document, on one day.
- PPTX evidence covers specific PowerPoint for Mac editing-view and export cases. Windows and Slide Show mode remain untested. GPOS kerning and complex shaping are not implemented. Groups, tables, SmartArt and charts are outside the model; rotated-shape geometry is only partly checked. PPTX support limits.
- Full schema validation, malware scanning and visual comparison are outside this checker. With coverage enabled, reports distinguish checked, estimated, skipped and unsupported content. No findings does not establish that the entire file is correct.
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