Skip to main content

ooxml-integrity

CI PyPI Python License: MIT

Preflight for machine-edited .docx and .pptx. Catches what Word, LibreOffice and every schema validator accept without complaint: a reviewer's comment silently detached from its text, tracked changes lost, footnotes orphaned, and deck text that does not fit its box.

No model calls, no rendering, no network. It reads the zip and the font files, so it runs on documents you cannot send anywhere.

pip install ooxml-integrity
ooxml-integrity check edited.docx --against original.docx
edited.docx: 2 error(s), 0 warning(s), 0 info
  [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)

Same word count, same page count, opens in Word without a warning. The only thing missing is the note that said "Confirm this figure against the source table before circulation" — which vanished at the moment the figure changed.

Why this exists

The failure is not exotic. Assigning paragraph.text in python-docx — the first thing most agents reach for — drops every run in the paragraph and creates one new run. Comment anchors, footnote references, character styles and tracked-change markup live between those runs, so they go too. The result is schema-valid, renders correctly and opens without complaint.

Two agents were given the same contract and the same three-figure edit. The careful one produced a correct multi-author redline in 23 tool calls; the fast one used python-docx in 5:

fast agent careful agent
Reviewer comment in margin absent present, anchored to the figure
Table edits untracked (0 w:ins, 0 w:del) tracked (9 w:ins, 2 w:del)
Word warning on open none none
Word count 118 118

On the six defect classes tested, well-formedness checks, schema validation and render-to-PDF-and-look each caught 0 of 6. This checker caught 6 of 6 with zero false positives across eight real agent runs.

Full experiment, agent transcripts, renderer calibration and every limitation: docs/research.md.

Two questions

A document stripped of every style, footnote and revision is perfectly self-consistent. So the tool asks two things, and you usually want both:

Did this file survive editing? Internal references resolve — comments, footnotes, styles, numbering, relationships, tracked changes.

ooxml-integrity check report.docx

What did the edit lose? Compared against the source, by construct count and by text — catches the file that is stripped of everything but otherwise clean.

ooxml-integrity check edited.docx --against original.docx

Exit codes are the CI contract: 0 clean, 1 findings at or above --fail-on (default error), 2 usage error. --json for machine-readable output, --quiet to print only what fails.

Decks: does the text fit the box?

ooxml-integrity check deck.pptx
deck.pptx: 6 error(s), 4 warning(s), 1 info
  [ERROR] PPT001  text needs 144pt in a 40pt box - 104pt too tall (260% over), 3 line(s)
            -> slide1/OVER_huge_type_tiny_box
  [ERROR] PPT003  word wrap is off and the longest line is 304pt in a 182pt box
                  - 122pt runs outside the shape
            -> slide2/OVER_nowrap_single_line
  [WARN ] PPT004  shape extends 142pt past the right edge - content will be cut off
            -> slide3/OFFCANVAS_right
  [WARN ] PPT006  overlaps 'OVERLAP_upper_right' over 23% of the smaller shape
            -> slide3/OVERLAP_lower_left

This is the part python-pptx has declined for a decade: it needs text measurement, and text measurement needs the effective font size, resolved through run, paragraph, list style, layout and master placeholders, presentation defaults and theme. Widths come from the font's own hmtx/cmap tables via fontTools; nothing is rasterised.

Validated against real PowerPoint: 21 of 21 shapes got the predicted verdict with the line count exact on every one. Where renderers disagree with each other (they do, at the margin), the finding is PPT002 borderline, not overflow. When a font is missing, the tool says so (PPT007) instead of guessing quietly. How it was validated.

In CI

- uses: Dmitry-Kov/ooxml-integrity@v0.4.0
  with:
    files: "out/**/*.docx"
    against: templates/master.docx   # optional, enables the fidelity check
    fail-on: error

Put it on the step after anything that edits documents programmatically — a generation script, an agent, a template merge. That is where these defects come from, and the only place they are still cheap to find.

The action writes a summary to the job page, can emit a JSON report and can produce SARIF so findings land in the pull request as code-scanning annotations. Severity overrides, path-scoped ignores with a required reason, and counted baselines for adopting the checker in a repository that already has findings: docs/configuration.md.

From Python

from ooxml_integrity import check, compare

for f in check("edited.docx"):
    print(f.code, f.severity.value, f.message, f.where)

for f in compare("original.docx", "edited.docx"):
    print(f.code, f.message)

Python 3.9+. Two dependencies: lxml, fonttools (plus tomli on 3.10 and older, only to read the config file). If the console script is not on your PATH, python -m ooxml_integrity check report.docx works anywhere.

What it reports, and how much it covered

Every finding has a stable code, a severity, and a part, shape or XPath where one can be identified. The rule: losing something that makes content or an audit trail invisible is an error, because nothing downstream will report it. Losing something that only changes how the document looks is a warning.

.docx:

code check
PKG001-008 OPC package integrity, content types, archive budgets, unsafe part names
XML001 well-formedness of every XML part
REL001-003 every r:id / r:embed resolves; targets exist; unreferenced relationships
STY001-002 paragraph, run and table styles resolve; basedOn / next / link resolve
NUM001-004 numId → w:num → abstractNumId → w:abstractNum; ilvl defined
FTN001-002 footnote references resolve; orphaned footnotes
CMT001-005 commentRangeStart ↔ commentRangeEnd ↔ commentReference ↔ comments.xml
REV001-003 revision-id uniqueness; w:del carries w:delText, respecting legal w:ins > w:del nesting
TBL001-002 tblGrid present; cells per row vs grid columns, accounting for gridSpan
SDT001-002 content-control integrity
TXT001 edge whitespace in runs without xml:space="preserve"
FID001-003 losses and additions relative to the source, by construct count; drop in text volume
FID004-006 a comment, footnote or endnote whose text survives but under no id at all
FID007-008 header/footer story missing or changed; tracked constructs lost from headers/footers

.pptx:

code check
PPT000 text could not be measured at all — an error, never "clean"
PPT001 text taller than its box, beyond the measurement tolerance
PPT002 within tolerance of overflowing — borderline, renderers may disagree
PPT003 line runs outside the usable width: wrap off, or a single overwide glyph
PPT004 shape extends past the slide edge, or sits entirely outside it
PPT005 shrink-to-fit requested but no fontScale stored — result depends on the renderer
PPT006 two text-bearing shapes overlap
PPT007 declared font unavailable; measurements for those shapes are estimates

A clean result is only as good as what was actually checked. --coverage distinguishes checked, not-present, estimated, skipped and unsupported surfaces per file, and a result with a gap says no findings in checked surfaces, not clean. ooxml-integrity doctor reports what the machine can and cannot measure before you run a deck through it. Exact boundaries: support matrix, coverage and doctor.

Limitations

  • Evidence is synthetic: 50 sources and 220 labelled pairs across five producers (Word for Windows, Word for Mac, Word Online, LibreOffice, python-docx). 100% error-level precision applies to the 14 measured rules on that corpus, not to your documents.
  • Eight real agent runs is a small sample, on one document, on one day.
  • PPTX layout is validated against PowerPoint for Mac in the editing view. Windows and Slide Show mode are untested. No GPOS kerning or shaping, so complex scripts and heavily-ligatured faces are estimates.
  • Groups, rotations, tables, SmartArt and charts in decks are reported as unsupported, not silently approximated.
  • Only the Carlito/Calibri metric-compatible pairing has been measured.

The full list, with the numbers behind each, is in docs/research.md.

Where this is going

The agent runs reframed the problem. The variance between pipelines is total and invisible: same task, same document, one produces a correct redline and the other detaches the reviewer's warning. So the useful question is less "is this file broken" than "which of my document pipelines is safe" — which argues for a public benchmark across docx editing tools and agent harnesses, on a real corpus.

That needs a corpus. If you have workflows where an agent edits Office files that someone else then reviews, I would like to hear what breaks for you — open an issue.

Repository layout

src/ooxml_integrity/   inspector, fidelity, fonts, pptx layout and checks,
                       coverage, doctor, policy, sarif, cli
tests/                 labelled-corpus, story-fidelity and false-positive regressions
research/              corpus builders, mutators, calibration, renderer comparison
docs/                  research notes, configuration, support matrix, validation records
corpus/                reference .docx and .pptx, byte-reproducible
evidence/docx-beta/    50 producer sources and 220 labelled DOCX pairs
runs/                  eight real agent outputs, used as fixtures
action.yml             the GitHub Action
AUDIT_PLAN.md          readiness priorities and release gates

License

MIT.

Release files for ooxml-integrity 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ooxml-integrity 0.4.0
File Size Uploaded
ooxml_integrity-0.4.0.tar.gz 7.4 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for ooxml-integrity 0.4.0
File Interpreter ABI Platform
ooxml_integrity-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 7.5 MB

Release files / ooxml_integrity-0.4.0.tar.gz

Download URL ooxml_integrity-0.4.0.tar.gz
Size 7.4 MB
Tags Source
SHA-256 checksum
How to use checksums
1c4d864f73a84eb9893838895f235a57b984a9f88096a9476a6149bd21b14990
BLAKE2b-256 checksum
How to use checksums
c3216af2a49f980ff186412c4568143a58be927b03d0b8056273d89ea8f2a4f9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release files / ooxml_integrity-0.4.0-py3-none-any.whl

Download URL ooxml_integrity-0.4.0-py3-none-any.whl
Size 69.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e23bac9df720abfe60c73d19f265b82ae9f6e4e53cadfd1480171bda858c34da
BLAKE2b-256 checksum
How to use checksums
e7385202287953d755b979b6f7fa78149bd53258e516c1ba94fee5e0771bd383
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release history Release notifications | RSS feed

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

This release

0.4.0 This release

2 release files

0.3.1

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page