# Round trips and preservation

When a DOCX is read and written back, what is rebuilt from meaning, what is kept verbatim, and what is lost.

A round trip means reading a file with `parseDocx`, optionally changing the LitAST, and writing it back with `generateDocx`. `generateDocx` always **rebuilds the whole package** from LitAST rather than patching the original ZIP, so what can be written back depends on what the LitAST holds.

## Three kinds of preservation

### Rebuilt from meaning

Recognized content (paragraphs, text formatting, tables, images, headers and footers, fields, content controls, comments, tracked changes and more) becomes the matching nodes, and OOXML is generated again from those nodes on write. Change the nodes and the change appears in the output file.

### Elements kept verbatim

Unrecognized elements become `unknownBlock` (block-level) or `unknownInline` (inline) nodes with their original structure stored in `rawXml`, and are written back unchanged. `rawXml` is an internal serialization, not an XML string; do not edit it by hand.

Passing `preserveRawXml: false` when parsing drops these elements. Equations (OMML) are always kept in their original structure inside `math` nodes, regardless of this option.

### Parts kept verbatim

These parts are stored in `ast.meta.rawXmlFiles` and written back unchanged:

- Styles, numbering definitions, document settings, the font table and the theme
- Core and custom properties
- Comments, their extension parts and the comment people list
- Footnotes and endnotes

Chart source data (chart parts and embedded workbooks) is also kept and written back, but charts cannot be created or edited through LitAST.

## Phonetic guides

`ruby` writes native `w:ruby`, with base text in `children` and annotation in `attrs.rubyText`.
Edited text or modeled properties use their current values. Unchanged ordinary run formatting,
unmodeled rubyPr properties and explicit zero/false values are kept in `_rubyPreservation`;
do not edit this internal source record. `preserveRawXml: false` does not disable it.

Content with relationships or range identities does not replay stale XML. A link around the
whole ruby uses the shared relationship allocator; links inside either text layer violate the
OOXML ruby content model and are rejected on export. Complete lifecycles for nested fields,
comments and revisions remain unverified. Reopening, editing and saving were checked in Word
16.109.2; ordinary horizontal display was checked in WPS 12.1.28496. Other producers and
complex combinations remain unverified; cross-producer fidelity is not guaranteed.

## What is lost

The following are currently **not** kept through a round trip:

| Content | Notes |
| --- | --- |
| Building blocks (glossary) | Recorded in `rawXmlFiles.glossaryXml` when read, but not written back |
| Custom XML parts | Recorded in `ast.meta.customXmlParts` when read, but not written back |
| Any other part not listed above | Not copied into the output |

If your use case depends on any of these, check the output file after writing.

## Saving LitAST

LitAST can be saved with `JSON.stringify`. After `JSON.parse` it can still be passed to `generateDocx`, and verbatim content is written back with it.
