moonbitlang/docx2html/docx does not have a README file

    AnnotationAnchor

    pub struct AnnotationAnchor {
    // private fields
    }

    One anchor of a comment: a paired range (start+end), a dangling half-range, or a point (references only). Paths are full agent paths ("/body/p[2]"); references are the comment-reference positions attached to this anchor, in document order.

    AnnotationAnchor::end

    fn AnnotationAnchor::end(self : AnnotationAnchor) -> String?

    The range end's containing projection path, when present.

    AnnotationAnchor::end_boundary

    The end marker's boundary relative to end, when present.

    AnnotationAnchor::references

    fn AnnotationAnchor::references(self : AnnotationAnchor) -> Array[String]

    Comment-reference positions attached to this anchor, in document order.

    AnnotationAnchor::start

    fn AnnotationAnchor::start(self : AnnotationAnchor) -> String?

    The range start's containing projection path, when present.

    AnnotationAnchor::start_boundary

    The start marker's boundary relative to start, when present.

    AnnotationAnchor::story

    fn AnnotationAnchor::story(self : AnnotationAnchor) -> String

    The story this anchor lives in ("/body", "/header[1]", ...).

    AnnotationBoundary

    pub enum AnnotationBoundary {
    Before
    InsideStart
    InsideEnd
    After
    } derive(Eq)

    Where a marker sits relative to its rendered projection node — the plan's boundary distinction, preserved so "before p[3]" and "after p[2]" do not collapse into the same position.

    AnnotationBoundary::equal

    AnnotationBoundary::not_equal

    AnnotationBoundary::output

    fn AnnotationBoundary::output(self : AnnotationBoundary, logger : &Logger) -> Unit

    AnnotationBoundary::to_string

    fn AnnotationBoundary::to_string(self : AnnotationBoundary) -> String

    AnnotationIndex

    pub struct AnnotationIndex {
    // private fields
    }

    The annotation index. Opaque: fields stay private so the surface can evolve additively.

    AnnotationIndex::comments

    Comments: one entry per definition (comments.xml order), then marker-only ids.

    AnnotationIndex::covering_comment_ids

    fn AnnotationIndex::covering_comment_ids(self : AnnotationIndex, path : String) -> Array[String]

    The ids of comments whose anchors INTERSECT the projection element at path ("/body/p[2]" style), in definition order — the reverse link J2's comment_ids exposes. Point anchors cover their reference's paragraph.

    AnnotationIndex::endnotes

    Endnotes with their reference positions.

    AnnotationIndex::footnotes

    fn AnnotationIndex::footnotes(self : AnnotationIndex) -> Array[NoteInfo]

    Footnotes with their reference positions.

    AnnotationIndex::revisions

    Tracked changes across every publicly addressable story, in document order (story order, then position within the story).

    AnnotationIndex::warnings

    fn AnnotationIndex::warnings(self : AnnotationIndex) -> Array[String]

    Non-fatal diagnostics gathered while building the index.

    CommentInfo

    pub struct CommentInfo {
    // private fields
    }

    One comment: identity and metadata from comments.xml (defined is false for a dangling id that only appears in markers), threading from commentsExtended when present, and anchors from the story scans in the total order the plan fixes (story rank, then position).

    CommentInfo::anchors

    Anchors in the plan's total order (story rank, then position).

    CommentInfo::author

    fn CommentInfo::author(self : CommentInfo) -> String?

    The w:author attribute, when present.

    CommentInfo::body_paragraphs

    fn CommentInfo::body_paragraphs(self : CommentInfo) -> Int

    Number of body paragraphs in the comment definition.

    CommentInfo::date

    fn CommentInfo::date(self : CommentInfo) -> String?

    The w:date attribute, LEXICAL (never converted), when present.

    CommentInfo::defined

    fn CommentInfo::defined(self : CommentInfo) -> Bool

    False when the id appears only in markers (no definition).

    CommentInfo::done

    fn CommentInfo::done(self : CommentInfo) -> Bool?

    w15 resolution state; None when commentsExtended is absent.

    CommentInfo::id

    fn CommentInfo::id(self : CommentInfo) -> String

    The comment id, as spelled in comments.xml.

    CommentInfo::initials

    fn CommentInfo::initials(self : CommentInfo) -> String?

    The w:initials attribute, when present.

    CommentInfo::last_para_id

    fn CommentInfo::last_para_id(self : CommentInfo) -> String?

    The definition's LAST body paragraph w14:paraId (the commentsExtended key), or None when the paragraph is unstamped.

    CommentInfo::parent_id

    fn CommentInfo::parent_id(self : CommentInfo) -> String?

    The parent comment id for replies (w15 paraIdParent, last-paragraph rule).

    CommentSpec

    pub struct CommentSpec {
    // private fields
    }

    One comment to attach to the written body: WHO (author, optional initials and xsd:dateTime date), WHERE (an inclusive range of top-level body block indexes with both endpoints paragraphs — or, for a reply, the earlier comment it answers), optionally a done resolution flag, and WHAT (paragraph-only body content). Construct with comment_spec (anchored) or comment_reply (anchorless), which fail-close on everything a spec can get wrong in isolation.

    DocxAnnotatedResult

    pub struct DocxAnnotatedResult {
    // private fields
    }

    The package read plus its annotation index. Opaque. Carries the annotation BODIES as (id, body) pairs in reader order — exactly the shape @paths.resolve_annotation_path consumes (J2's read surface).

    The retained source bytes, story scans, and mutation-planning topology of a returned result form a source-pinned IMMUTABLE snapshot: in mutation-safe mode its index scans ARE the retained reader-projection scans (one scan per story part, shared by every consumer). Applying surgery never patches a retained scan in place — the plan writes a new archive, and reading that archive is the only way to observe the mutation.

    DocxAnnotatedResult::annotation_sidecars

    fn DocxAnnotatedResult::annotation_sidecars(self : DocxAnnotatedResult) -> Array[String]

    Relationship types of annotation SIDECARS this tooling cannot keep consistent when mutating comments (Word's modern comment identity and people parts). Per the L0 matrix rule these are detected by RELATIONSHIP TYPE from the main part — their presence makes mutating commands fail closed. commentsExtended is NOT here: the add operation never touches it (matrix row), and L2 owns it.

    DocxAnnotatedResult::annotations

    The annotation index built from the same bytes.

    DocxAnnotatedResult::body_paragraph_span

    fn DocxAnnotatedResult::body_paragraph_span(self : DocxAnnotatedResult, relative_path : String) -> NodeSpan?

    The span of the body-story paragraph at relative_path — the story-relative ORDINAL path exactly as the index emits it ("p[3]", "tbl[1]/tr[2]/tc[1]/p[1]") — or None when no such paragraph was projected. Offsets index into main_story_part's original bytes.

    DocxAnnotatedResult::body_run_span

    fn DocxAnnotatedResult::body_run_span(self : DocxAnnotatedResult, relative_path : String) -> NodeSpan?

    The span of the body-story RUN at relative_path ("p[3]/r[2]", the index's ordinal form), or None. Runs carry the same offsets as paragraphs (content_start past a leading rPr) so L1 can rewrite a self-closing <w:r/> by its own extent too.

    DocxAnnotatedResult::comment_bodies

    Comment (id, body) pairs in comments.xml order.

    DocxAnnotatedResult::comments_extended_part

    fn DocxAnnotatedResult::comments_extended_part(self : DocxAnnotatedResult) -> String?

    The zip entry holding the commentsExtended part (resolved by RELATIONSHIP TYPE), or None when the package has none — L2 then creates it.

    DocxAnnotatedResult::comments_part

    fn DocxAnnotatedResult::comments_part(self : DocxAnnotatedResult) -> String?

    The zip entry holding the comments part (resolved by RELATIONSHIP TYPE from the main part, never by filename), or None when the package has no comments part yet — L1 then creates it.

    DocxAnnotatedResult::comments_story_source

    fn DocxAnnotatedResult::comments_story_source(self : DocxAnnotatedResult) -> DocxStoryPartSource?

    Physical source for the comments story, when one was read.

    DocxAnnotatedResult::endnote_bodies

    Endnote (id, body) pairs in reader order.

    DocxAnnotatedResult::endnotes_story_source

    fn DocxAnnotatedResult::endnotes_story_source(self : DocxAnnotatedResult) -> DocxStoryPartSource?

    Physical source for the endnotes story, when one was read.

    DocxAnnotatedResult::footer_story_sources

    Physical sources for rendered footer stories in package-result order.

    DocxAnnotatedResult::footnote_bodies

    Footnote (id, body) pairs in reader order.

    DocxAnnotatedResult::footnotes_story_source

    fn DocxAnnotatedResult::footnotes_story_source(self : DocxAnnotatedResult) -> DocxStoryPartSource?

    Physical source for the footnotes story, when one was read.

    DocxAnnotatedResult::header_story_sources

    Physical sources for rendered header stories in package-result order.

    DocxAnnotatedResult::main_story_part

    fn DocxAnnotatedResult::main_story_part(self : DocxAnnotatedResult) -> String

    The zip entry name of the MAIN document part the body-story spans index into (resolved through the officeDocument relationship, never hardcoded).

    DocxAnnotatedResult::main_story_source

    Physical source and authority for the body story.

    DocxAnnotatedResult::paragraph_style_ids

    fn DocxAnnotatedResult::paragraph_style_ids(self : DocxAnnotatedResult) -> Array[String]

    The PARAGRAPH style ids the styles part declares — a COPY, for insertion's style-reference verification.

    DocxAnnotatedResult::result

    The package-level read (identical to read_docx_package).

    DocxAnnotatedResult::revision_spans

    Every tracked-change element across every scanned story, in story order then document order. Offsets index into the part that backs each story.

    The list is complete BY CONSTRUCTION: the scanner records a site for every tracked-change element it walks, without the suppression and projection gates the reading index applies, and retraction never removes one. A resolver can therefore treat an empty result as proof that the package carries no tracked changes at all.

    DocxAnnotatedResult::story_paragraph_span

    fn DocxAnnotatedResult::story_paragraph_span(self : DocxAnnotatedResult, story : String, relative_path : String) -> NodeSpan?

    The span of a paragraph in ANY scanned story ("/comments" included), by its story-relative ordinal path ("comment[2]/p[1]") — offsets index into that story's part bytes. L2's paraId retrofit edits the parent comment's LAST body paragraph through this.

    DocxAnnotatedResult::story_root_span

    fn DocxAnnotatedResult::story_root_span(self : DocxAnnotatedResult, story : String) -> NodeSpan?

    The ROOT element's span for a scanned story ("/body", "/comments", "/footnotes", "/endnotes"), or None when the story was not scanned. L1 splices a new comment definition just before the comments story's close_tag_start; a self-closing root reports no interior and must be rewritten by its own extent first.

    DocxAnnotatedResult::story_row_span

    fn DocxAnnotatedResult::story_row_span(self : DocxAnnotatedResult, story : String, relative_path : String) -> NodeSpan?

    The span of one table ROW in any scanned story, addressed by the story key ("/body", "/header[1]", ...) and the story-relative ordinal path ("tbl[1]/tr[2]"). The scanner already records tr nodes with full spans; template repetition replaces a row's byte region with filled clones through this.

    DocxAnnotatedResult::story_run_span

    fn DocxAnnotatedResult::story_run_span(self : DocxAnnotatedResult, story : String, relative_path : String) -> NodeSpan?

    The span of one text RUN in any scanned story, addressed by the story key ("/body", "/header[1]", ...) and the story-relative ordinal path ("p[3]/r[2]", "p[1]/hyperlink[1]/r[1]"). The scanner already records run nodes with full spans in every story; this generalizes the body-only lookup so template merging can rewrite header and footer runs through the same byte-span contract.

    DocxDeleteCutWitness

    pub struct DocxDeleteCutWitness {
    // private fields
    }

    What the published story part must read like once the cut lands: the source it is cut from, and the span removed. The published part must equal the source with exactly this span gone, byte for byte.

    WHAT THIS PROVES, precisely: that the splice APPLIED as planned — no second edit landed on the part, no engine bug moved the cut, no zip round trip altered it. It does NOT prove the plan addressed the paragraph the caller meant: the witness is built from the same span the edit uses, so a mis-resolved address moves both together. The check that binds an address to content is --expect-text against the receipt's own projection. Held by reference, so proving it costs a comparison and no copy.

    DocxDeleteCutWitness::expected_length

    fn DocxDeleteCutWitness::expected_length(self : DocxDeleteCutWitness) -> Int

    The published part's exact byte length once the cut lands.

    DocxDeleteCutWitness::matches

    fn DocxDeleteCutWitness::matches(self : DocxDeleteCutWitness, candidate : BytesView) -> Bool

    Whether candidate is exactly the source with the planned span removed. Compared in place, so a large story costs no copy.

    DocxDeleteCutWitness::part

    fn DocxDeleteCutWitness::part(self : DocxDeleteCutWitness) -> String

    The story part the cut applies to.

    DocxDeleteReceipt

    pub struct DocxDeleteReceipt {
    // private fields
    }

    What one planned deletion will do: the path that stops resolving, the identity that leaves with it, the text it carried (the reader projection, for the caller's own guard), and the successor's identity — the paragraph that will answer at the deleted path after publication, when one exists.

    DocxDeleteReceipt::anchor_status

    fn DocxDeleteReceipt::anchor_status(self : DocxDeleteReceipt) -> String

    The target's anchor judgment in the planning snapshot.

    DocxDeleteReceipt::cut

    What the published part must read like once this plan lands. The transaction verifies it applied exactly — see the witness for what that does and does not prove about ADDRESSING.

    DocxDeleteReceipt::para_id

    fn DocxDeleteReceipt::para_id(self : DocxDeleteReceipt) -> String?

    The deleted paragraph's canonical w14:paraId, when it uniquely carried one.

    DocxDeleteReceipt::path

    fn DocxDeleteReceipt::path(self : DocxDeleteReceipt) -> String

    The direct body path this deletion removes.

    DocxDeleteReceipt::predecessor_para_id

    fn DocxDeleteReceipt::predecessor_para_id(self : DocxDeleteReceipt) -> String?

    The unique identity of the paragraph immediately BEFORE the target, when it carries one. A readback witness, not a report field.

    DocxDeleteReceipt::predecessor_path

    fn DocxDeleteReceipt::predecessor_path(self : DocxDeleteReceipt) -> String?

    The path the paragraph before the target answers at — unchanged by the deletion, because a splice at p[N] moves no path below N.

    DocxDeleteReceipt::predecessor_text

    fn DocxDeleteReceipt::predecessor_text(self : DocxDeleteReceipt) -> String?

    The projection of the paragraph immediately BEFORE the target. The deletion does not move it, so it must read the same at the same path afterwards — the leg that binds address to content on a document with no identities whose target is the last paragraph.

    DocxDeleteReceipt::successor_para_id

    fn DocxDeleteReceipt::successor_para_id(self : DocxDeleteReceipt) -> String?

    The unique identity of the paragraph that will answer at the deleted path after publication, when the successor carries one.

    DocxDeleteReceipt::successor_text

    fn DocxDeleteReceipt::successor_text(self : DocxDeleteReceipt) -> String?

    The projection of the paragraph that will answer at the deleted path after publication — the readback's text evidence, which a document carrying no unique identities still has.

    DocxDeleteReceipt::text

    fn DocxDeleteReceipt::text(self : DocxDeleteReceipt) -> String

    The deleted paragraph's reader projection — what an agent verifies against before trusting an ordinal address.

    DocxDirectFormat

    pub struct DocxDirectFormat {
    // private fields
    } derive(Eq,
    Debug
    )

    The v1 absolute-set request: None = untouched, Some(false) = an EXPLICIT off override (never "clear to inherited" — that waits for effective-value provenance). Color is a canonical six-digit uppercase RGB value; bold and italic couple their complex-script twins (w:bCs/w:iCs) as an office.mbt guarantee. Fields are private: the ONLY constructor is docx_direct_format, so an unvalidated color can never reach a planner.

    DocxDirectFormat::bold

    fn DocxDirectFormat::bold(self : DocxDirectFormat) -> Bool?

    The requested bold state: Some(true)/Some(false) forces it, None leaves it untouched.

    DocxDirectFormat::color

    fn DocxDirectFormat::color(self : DocxDirectFormat) -> String?

    The requested color as canonical uppercase RRGGBB, or None when no color was requested.

    DocxDirectFormat::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxDirectFormat::equal(DocxDirectFormat, DocxDirectFormat) -> Bool

    DocxDirectFormat::italic

    fn DocxDirectFormat::italic(self : DocxDirectFormat) -> Bool?

    The requested italic state: Some(true)/Some(false) forces it, None leaves it untouched.

    DocxDirectFormat::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxDirectFormat::not_equal(x : DocxDirectFormat, y : DocxDirectFormat) -> Bool

    DocxDirectFormat::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxDirectFormat::to_repr(DocxDirectFormat) ->
    Repr

    DocxDirectFormat::underline

    fn DocxDirectFormat::underline(self : DocxDirectFormat) -> Bool?

    The requested underline state: Some(true)/Some(false) forces it, None leaves it untouched.

    DocxFormatAffected

    pub struct DocxFormatAffected {
    path : String
    expected : String
    para_id : String?
    anchor_status : String
    runs_changed : Int
    runs_already_satisfied : Int
    splits : Int
    }

    One affected paragraph: its identity, the projection it must STILL read afterwards (formatting never moves text), and what the plan did to its runs.

    DocxFormatAffected::anchor_status

    fn DocxFormatAffected::anchor_status(self : DocxFormatAffected) -> String

    The paragraph's anchor status.

    DocxFormatAffected::expected

    fn DocxFormatAffected::expected(self : DocxFormatAffected) -> String

    The projection the paragraph must still read after the edit.

    DocxFormatAffected::para_id

    fn DocxFormatAffected::para_id(self : DocxFormatAffected) -> String?

    The paragraph's canonical anchor paraId, when it carries one.

    DocxFormatAffected::path

    fn DocxFormatAffected::path(self : DocxFormatAffected) -> String

    The paragraph's body-relative path.

    DocxFormatAffected::runs_already_satisfied

    fn DocxFormatAffected::runs_already_satisfied(self : DocxFormatAffected) -> Int

    How many of the paragraph's touched runs already held the request.

    DocxFormatAffected::runs_changed

    fn DocxFormatAffected::runs_changed(self : DocxFormatAffected) -> Int

    How many of the paragraph's runs the plan rewrites.

    DocxFormatAffected::splits

    fn DocxFormatAffected::splits(self : DocxFormatAffected) -> Int

    How many of the paragraph's runs the plan clone-splits.

    DocxFormatReceipt

    pub struct DocxFormatReceipt {
    mode : String
    requested_text : String?
    requested_within : String?
    requested_nth : Int?
    requested_range : (Int, Int)?
    selected : Array[Int]
    spans : Array[DocxFormatSpan]
    affected : Array[DocxFormatAffected]
    runs_changed : Int
    runs_already_satisfied : Int
    splits : Int
    byte_edits : Int
    }

    What a planned formatting batch will do.

    DocxFormatReceipt::affected

    The affected paragraphs with their unchanged projections.

    DocxFormatReceipt::byte_edits

    fn DocxFormatReceipt::byte_edits(self : DocxFormatReceipt) -> Int

    How many byte edits the plan carries. Zero means the document already held the request everywhere it was asked.

    DocxFormatReceipt::mode

    fn DocxFormatReceipt::mode(self : DocxFormatReceipt) -> String

    text or range — which selector produced the spans.

    DocxFormatReceipt::requested_nth

    fn DocxFormatReceipt::requested_nth(self : DocxFormatReceipt) -> Int?

    The ordinal the caller selected, if any. None with one span means "all candidates, and there was one" — a distinction a count alone cannot make.

    DocxFormatReceipt::requested_range

    fn DocxFormatReceipt::requested_range(self : DocxFormatReceipt) -> (Int, Int)?

    The explicit range the caller addressed, in range mode.

    DocxFormatReceipt::requested_text

    fn DocxFormatReceipt::requested_text(self : DocxFormatReceipt) -> String?

    The needle the caller asked for, in text mode.

    DocxFormatReceipt::requested_within

    fn DocxFormatReceipt::requested_within(self : DocxFormatReceipt) -> String?

    The subtree the caller restricted to, if any — and in range mode, the paragraph it addressed.

    DocxFormatReceipt::runs_already_satisfied

    fn DocxFormatReceipt::runs_already_satisfied(self : DocxFormatReceipt) -> Int

    How many touched runs already held every requested property — the no-op accounting a changed=false report rests on.

    DocxFormatReceipt::runs_changed

    fn DocxFormatReceipt::runs_changed(self : DocxFormatReceipt) -> Int

    How many runs the plan rewrites.

    DocxFormatReceipt::selected

    fn DocxFormatReceipt::selected(self : DocxFormatReceipt) -> Array[Int]

    The candidate ordinals this plan formats, in document order. Empty in range mode, which addresses coordinates rather than candidates.

    DocxFormatReceipt::spans

    The selected spans.

    DocxFormatReceipt::splits

    fn DocxFormatReceipt::splits(self : DocxFormatReceipt) -> Int

    How many runs the plan clone-splits.

    DocxFormatSpan

    pub struct DocxFormatSpan {
    path : String
    para_id : String?
    anchor_status : String
    start : Int
    end : Int
    text : String
    source_runs : Array[String]
    }

    One selected span, as the receipt reports it.

    DocxFormatSpan::anchor_status

    fn DocxFormatSpan::anchor_status(self : DocxFormatSpan) -> String

    The paragraph's anchor status (unique, missing, invalid, duplicate).

    DocxFormatSpan::copy

    A span that shares nothing with this one, so a caller handed it cannot reach back into the receipt it came from.

    DocxFormatSpan::end

    fn DocxFormatSpan::end(self : DocxFormatSpan) -> Int

    The span's paragraph-local UTF-16 end offset, exclusive.

    DocxFormatSpan::para_id

    fn DocxFormatSpan::para_id(self : DocxFormatSpan) -> String?

    The paragraph's canonical anchor paraId, when it carries one.

    DocxFormatSpan::path

    fn DocxFormatSpan::path(self : DocxFormatSpan) -> String

    The paragraph the span belongs to, body-relative.

    DocxFormatSpan::source_runs

    fn DocxFormatSpan::source_runs(self : DocxFormatSpan) -> Array[String]

    The runs the span drew from BEFORE the edit — a snapshot, because a split changes what runs exist.

    DocxFormatSpan::start

    fn DocxFormatSpan::start(self : DocxFormatSpan) -> Int

    The span's paragraph-local UTF-16 start offset.

    DocxFormatSpan::text

    fn DocxFormatSpan::text(self : DocxFormatSpan) -> String

    The projected text the span selects.

    DocxInsertContent

    pub(all) struct DocxInsertContent {
    style : String?
    runs : Array[DocxInsertRun]
    } derive(Eq,
    Debug
    )

    The dedicated docx.paragraph/1 content payload: an optional paragraph style reference (verified against the TARGET's styles part) and resource-free runs.

    DocxInsertContent::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxInsertContent::equal(DocxInsertContent, DocxInsertContent) -> Bool

    DocxInsertContent::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxInsertContent::not_equal(x : DocxInsertContent, y : DocxInsertContent) -> Bool

    DocxInsertContent::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxInsertContent::to_repr(DocxInsertContent) ->
    Repr

    DocxInsertReceipt

    pub struct DocxInsertReceipt {
    // private fields
    }

    What one planned insertion did: the minted id (canonical uppercase, allocated fresh against the whole document's inventory) and the ordinal path the new paragraph will answer to after publication.

    DocxInsertReceipt::para_id

    fn DocxInsertReceipt::para_id(self : DocxInsertReceipt) -> String

    The minted paragraph id (canonical uppercase) this insertion received.

    DocxInsertReceipt::planned_path

    fn DocxInsertReceipt::planned_path(self : DocxInsertReceipt) -> String

    The ordinal path the new paragraph will answer to after publication.

    DocxInsertRun

    pub(all) struct DocxInsertRun {
    text : String
    bold : Bool
    italic : Bool
    underline : Bool
    } derive(Eq,
    Debug
    )

    One resource-free run of insertion content: text with direct formatting only. Hyperlinks, images, notes, and list bullets are v1 refusals — they need relationship, media, or numbering surgery.

    DocxInsertRun::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxInsertRun::equal(DocxInsertRun, DocxInsertRun) -> Bool

    DocxInsertRun::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxInsertRun::not_equal(x : DocxInsertRun, y : DocxInsertRun) -> Bool

    DocxInsertRun::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxInsertRun::to_repr(DocxInsertRun) ->
    Repr

    DocxMatch

    pub struct DocxMatch {
    ordinal : Int
    story : String
    path : String
    start : Int
    end : Int
    text : String
    context_before : String
    context_after : String
    runs : Array[String]
    run_kinds : Array[String]
    actionable : Bool
    reason : String
    para_id : String?
    anchor_status : String
    physical_para_ids : Array[String]
    }

    One candidate the literal matcher found in a story.

    actionable is not a second opinion about editability. It is the PLANNER's own answer: each candidate is offered to plan_paragraph_text_edits as an identity replacement, which runs every structural check and plans no bytes. So a candidate reported actionable here is one the mutation surface accepts, by construction rather than by a parallel classifier that could drift out of step.

    DocxMatch::actionable

    fn DocxMatch::actionable(self : DocxMatch) -> Bool

    Whether the RANGE is structurally editable.

    Precisely: whether the mutation surface accepts an edit over these coordinates, judged by everything it can know from the document alone — regions, ancestry, boundaries, carriers.

    It is NOT a promise that a particular replacement will be accepted. Validity of the new TEXT belongs to the write and is checked there: a replacement carrying a control character is refused over a range this reports actionable, and correctly so, because that refusal is about the caller's string rather than the document.

    DocxMatch::anchor_status

    fn DocxMatch::anchor_status(self : DocxMatch) -> String

    unique, missing, invalid, duplicate, or multi_physical.

    DocxMatch::context_after

    fn DocxMatch::context_after(self : DocxMatch) -> String

    Bounded projection text immediately after the match.

    DocxMatch::context_before

    fn DocxMatch::context_before(self : DocxMatch) -> String

    Bounded projection text immediately before the match.

    DocxMatch::copy

    fn DocxMatch::copy(self : DocxMatch) -> DocxMatch

    A match that shares nothing with this one.

    DocxMatch::end

    fn DocxMatch::end(self : DocxMatch) -> Int

    Paragraph-relative UTF-16 end, exclusive.

    DocxMatch::ordinal

    fn DocxMatch::ordinal(self : DocxMatch) -> Int

    Position among all candidates in document order, from 1.

    DocxMatch::para_id

    fn DocxMatch::para_id(self : DocxMatch) -> String?

    The canonical w14:paraId, present for unique and duplicate anchor statuses.

    DocxMatch::path

    fn DocxMatch::path(self : DocxMatch) -> String

    The candidate's paragraph, as a body-relative scanner path.

    DocxMatch::physical_para_ids

    fn DocxMatch::physical_para_ids(self : DocxMatch) -> Array[String]

    For multi_physical anchors: the participating physical ids, bounded — joined from several w:p, or sharing one.

    DocxMatch::reason

    fn DocxMatch::reason(self : DocxMatch) -> String

    Why the candidate is not actionable; empty when it is.

    The vocabulary names the construct rather than the mechanism, since what an agent needs is what to do instead: field-region, hyperlink-boundary, tracked-region, sdt-content, alternate-content, textbox, cdata, visible-barrier, suppressed-region, multi-physical-paragraph, non-scalar-boundary, ambiguous-boundary, unsupported-source, checkbox-control, duplicate-source, cross-paragraph-reuse, no-synthesis-carrier, refused-field, malformed-field, field-instruction, internal.

    DocxMatch::run_kinds

    fn DocxMatch::run_kinds(self : DocxMatch) -> Array[String]

    The source kinds the match draws from, deduplicated and in document order: text, tab, no-break-hyphen, soft-hyphen, symbol. A match reading as ordinary prose can still be carried by an atom, and an agent that assumes otherwise will address the wrong thing.

    DocxMatch::runs

    fn DocxMatch::runs(self : DocxMatch) -> Array[String]

    The runs the match draws from, as body-relative paths, in document order. A match crossing run boundaries names each one.

    DocxMatch::start

    fn DocxMatch::start(self : DocxMatch) -> Int

    Paragraph-relative UTF-16 start of the match, over the PROJECTION -- the text a reader sees, not the bytes.

    DocxMatch::story

    fn DocxMatch::story(self : DocxMatch) -> String

    The story the candidate sits in. "body" in v1; the field is reserved so header, footer and note stories can join without a schema break.

    DocxMatch::text

    fn DocxMatch::text(self : DocxMatch) -> String

    The matched projection text.

    DocxMatchList

    pub struct DocxMatchList {
    matches : Array[DocxMatch]
    total : Int
    }

    What a search found: the examined candidates, and how many exist.

    The two are separated because they cost differently. Counting a candidate is a scan step; EXAMINING one runs the planner. So a search counts everything and examines at most limit, and the caller is told both numbers rather than being left to infer the total from a list that was deliberately cut short.

    DocxMatchList::matches

    fn DocxMatchList::matches(self : DocxMatchList) -> Array[DocxMatch]

    The examined candidates, in document order, at most limit of them.

    DocxMatchList::total

    fn DocxMatchList::total(self : DocxMatchList) -> Int

    How many candidates EXIST, which may exceed the examined list.

    DocxMatchList::truncated

    fn DocxMatchList::truncated(self : DocxMatchList) -> Bool

    Whether candidates exist that were counted but not examined.

    DocxPackageResult

    Everything read_docx_with_messages returns, plus sections and header/footer stories.

    DocxPackageResult::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxPackageResult::equal(DocxPackageResult, DocxPackageResult) -> Bool

    DocxPackageResult::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxPackageResult::not_equal(x : DocxPackageResult, y : DocxPackageResult) -> Bool

    DocxPackageResult::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxPackageResult::to_repr(DocxPackageResult) ->
    Repr

    DocxParaIdCarrierResolution

    pub enum DocxParaIdCarrierResolution {
    ResolvedCarrier(Int)
    CarrierInvalid
    CarrierNotFound
    CarrierAmbiguous(Array[Int])
    CarrierInMultiPhysical
    }

    A carrier-level resolution: the identity judgment WITHOUT the tree step. Its own type, so no consumer can mistake a carrier answer for a tree occurrence.

    DocxParaIdResolution

    pub enum DocxParaIdResolution {
    ResolvedOccurrence(Int, Int)
    ParaIdInvalid
    ParaIdNotFound
    ParaIdAmbiguous(Array[Int])
    ParaIdInMultiPhysical
    ParaIdUnjoined(Int)
    }

    One stable-selector resolution outcome. p[id="…"] resolves to a TREE OCCURRENCE only through the whole chain — validated id, exactly one addressable carrier, sound tree join — and every other state is its own typed refusal. There is no first-wins and no ordinal fallback anywhere in this enum.

    DocxParagraphAnchor

    pub struct DocxParagraphAnchor {
    // private fields
    }

    One logical paragraph's stable-anchor judgment.

    path is where the paragraph is in THIS snapshot; the anchor is what the paragraph IS across structural edits. The two are deliberately separate dimensions — and both are separate from planner editability (actionable), which this layer never touches.

    DocxParagraphAnchor::para_id

    fn DocxParagraphAnchor::para_id(self : DocxParagraphAnchor) -> String?

    The canonical (uppercase) paraId when the spelling is valid and the anchor is a carrier (unique or duplicate); None otherwise.

    DocxParagraphAnchor::physical_para_ids

    fn DocxParagraphAnchor::physical_para_ids(self : DocxParagraphAnchor) -> Array[String]

    For multi_physical anchors only: the valid canonical ids of the participating physical paragraphs, in document order, bounded.

    DocxParagraphAnchor::status

    fn DocxParagraphAnchor::status(self : DocxParagraphAnchor) -> String

    The anchor status: unique, missing, invalid, duplicate, or multi_physical.

    DocxParagraphAnchorIndex

    pub struct DocxParagraphAnchorIndex {
    // private fields
    }

    Per-story anchor index. The AUTHORITATIVE key is the logical paragraph's projection index — paths are NOT unique (a tolerated nested paragraph makes two logical paragraphs share one physical head, hence one path), so a path-keyed lookup refuses collided paths rather than answering for either claimant.

    DocxParagraphAnchorIndex::anchor_at

    Path-keyed lookup for callers that only hold a path. A path claimed by MORE than one logical paragraph returns None: an ambiguous name must not resolve to either claimant's judgment.

    DocxParagraphAnchorIndex::anchor_of_paragraph

    fn DocxParagraphAnchorIndex::anchor_of_paragraph(self : DocxParagraphAnchorIndex, paragraph_index : Int) -> DocxParagraphAnchor?

    The judgment for one projected logical paragraph, by its index in the projection — the join find and the planners already hold.

    DocxParagraphAnchorIndex::paragraphs_with_para_id

    fn DocxParagraphAnchorIndex::paragraphs_with_para_id(self : DocxParagraphAnchorIndex, canonical : String) -> Array[Int]

    Projection indices of the ADDRESSABLE carriers of a canonical id.

    DocxParagraphAnchorIndex::resolve_para_id_carrier

    fn DocxParagraphAnchorIndex::resolve_para_id_carrier(self : DocxParagraphAnchorIndex, raw : String) -> DocxParaIdCarrierResolution

    The identity judgment WITHOUT the tree step: resolve an as-spelled paraId to its single addressable carrier's projection index, or the typed reason it never resolves. Scan-path consumers (find scopes, the write verbs) build on this; tree surfaces add the join step.

    DocxParagraphAnchorIndex::scan_path_of_paragraph

    fn DocxParagraphAnchorIndex::scan_path_of_paragraph(self : DocxParagraphAnchorIndex, paragraph_index : Int) -> String?

    The scanner paragraph path a projection paragraph answers to in THIS snapshot.

    DocxParagraphAnchorJoinIndex

    pub struct DocxParagraphAnchorJoinIndex {
    // private fields
    }

    The tree/projection join for one story (paraId R1b): tree paragraph occurrences in erase order, each mapped to at most one projection paragraph by source-vector bijection.

    DocxParagraphAnchorJoinIndex::anchor_index

    The anchor index this join was judged against, for callers that need scan paths or per-paragraph anchors beside the resolution.

    DocxParagraphAnchorJoinIndex::join_of_occurrence

    fn DocxParagraphAnchorJoinIndex::join_of_occurrence(self : DocxParagraphAnchorJoinIndex, occurrence : Int) -> DocxParagraphJoin?

    The join for the Nth tree Paragraph occurrence, in the depth-first order the erased tree presents them. None when the occurrence is out of range — a caller whose own enumeration disagrees with the provenance channel must treat EVERY paragraph as unjoined.

    DocxParagraphAnchorJoinIndex::occurrence_count

    Number of paragraph occurrences represented by this story join.

    DocxParagraphAnchorJoinIndex::occurrence_of_paragraph

    fn DocxParagraphAnchorJoinIndex::occurrence_of_paragraph(self : DocxParagraphAnchorJoinIndex, paragraph_index : Int) -> Int?

    The R2a seam: the unique tree occurrence a projection paragraph joined to, if the bijection held in both directions.

    DocxParagraphAnchorJoinIndex::resolve_para_id

    Resolve one as-spelled paraId to a tree occurrence.

    DocxParagraphJoin

    pub enum DocxParagraphJoin {
    Joined(Int, DocxParagraphAnchor)
    Unjoined(String)
    }

    One tree paragraph occurrence's relationship to the projection: the judgment travels ONLY across a proven bijection. Unjoined is a JOIN outcome, not a sixth anchor status — the engine vocabulary is unchanged, and a tree surface reporting it says "no sound correspondence", never a borrowed judgment.

    DocxReadResult

    Document tree plus diagnostics produced while reading a DOCX package.

    DocxReadResult::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxReadResult::equal(DocxReadResult, DocxReadResult) -> Bool

    DocxReadResult::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxReadResult::not_equal(x : DocxReadResult, y : DocxReadResult) -> Bool

    DocxReadResult::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn DocxReadResult::to_repr(DocxReadResult) ->
    Repr

    DocxReplaceAffected

    pub struct DocxReplaceAffected {
    path : String
    expected : String
    para_id : String?
    anchor_status : String
    }

    One affected paragraph: its path, and the full projection text it must carry after the splice.

    The expectation is the WHOLE paragraph projection, precomputed at plan time — never a substring probe, because the replacement text may pre-exist elsewhere in the same paragraph and a substring check would pass on a splice that landed in the wrong place.

    DocxReplaceAffected::anchor_status

    fn DocxReplaceAffected::anchor_status(self : DocxReplaceAffected) -> String

    The paragraph's anchor status (unique, missing, invalid, duplicate), copied from its selected matches. Never multi_physical: the planner refuses those.

    DocxReplaceAffected::expected

    fn DocxReplaceAffected::expected(self : DocxReplaceAffected) -> String

    The full projection text the paragraph must read after the edit.

    DocxReplaceAffected::para_id

    fn DocxReplaceAffected::para_id(self : DocxReplaceAffected) -> String?

    The paragraph's canonical anchor paraId, when the source carries one (the anchor judgment copied from its selected matches).

    DocxReplaceAffected::path

    fn DocxReplaceAffected::path(self : DocxReplaceAffected) -> String

    The paragraph's body-relative path.

    DocxReplaceReceipt

    pub struct DocxReplaceReceipt {
    selected : Array[Int]
    replaced : Int
    affected : Array[DocxReplaceAffected]
    matches : Array[DocxMatch]
    }

    What a planned replacement will do, and what the document must read afterwards.

    DocxReplaceReceipt::affected

    The affected paragraphs with their expected post-edit projections.

    DocxReplaceReceipt::matches

    The selected candidates themselves — the same entries find would report, so a dry-run can print the matches payload the roadmap promises rather than a summary that hides ranges and runs.

    DocxReplaceReceipt::replaced

    fn DocxReplaceReceipt::replaced(self : DocxReplaceReceipt) -> Int

    How many replacements the plan performs.

    DocxReplaceReceipt::selected

    fn DocxReplaceReceipt::selected(self : DocxReplaceReceipt) -> Array[Int]

    The candidate ordinals this plan replaces, in document order.

    DocxStoryPartAuthority

    pub enum DocxStoryPartAuthority {
    RelationshipBacked
    LegacyFilenameFallback
    }

    How the reader selected a physical story part.

    DocxStoryPartAuthority::name

    Stable protocol spelling for story-part authority.

    DocxStoryPartSource

    pub struct DocxStoryPartSource {
    // private fields
    }

    The physical ZIP entry used for one logical DOCX story and how it was selected. The type is opaque so more provenance can be added later without exposing mutable reader internals.

    DocxStoryPartSource::authority

    Whether this part was relationship-backed or a legacy filename fallback.

    DocxStoryPartSource::part

    fn DocxStoryPartSource::part(self : DocxStoryPartSource) -> String

    The exact physical ZIP entry read for this story.

    HeaderFooterSpec

    pub struct HeaderFooterSpec {
    // private fields
    }

    One header or footer story attached to the written document's section. Construct with header_footer_spec, which fail-closes on everything the story can get wrong in isolation.

    NodeSpan

    pub struct NodeSpan {
    // private fields
    }

    The byte extent of one BODY-story projection node (paragraph or run) in the original word-processing part, plus the two insertion offsets annotation surgery uses: content_start (just past the open tag AND past a leading pPr/rPr — the property container leads its sequence, so content and markers must land after it) and close_tag_start (the '<' of the close tag). Both are None for a self-closing form, which has no interior — the splice layer must first rewrite it to the open form (a byte edit of this node's own span).

    NodeSpan::byte_end

    fn NodeSpan::byte_end(self : NodeSpan) -> Int

    Offset just past the '>' of the paragraph's close tag (exclusive).

    NodeSpan::byte_start

    fn NodeSpan::byte_start(self : NodeSpan) -> Int

    Offset of the '<' of the paragraph's open tag.

    NodeSpan::close_tag_start

    fn NodeSpan::close_tag_start(self : NodeSpan) -> Int?

    Offset of the '<' of the close tag, or None for a self-closing paragraph.

    NodeSpan::content_start

    fn NodeSpan::content_start(self : NodeSpan) -> Int?

    Earliest interior insertion offset (past the open tag and any leading pPr), or None for a self-closing paragraph.

    NodeSpan::self_closing

    fn NodeSpan::self_closing(self : NodeSpan) -> Bool

    True when the paragraph is the self-closing <w:p/> form.

    NoteInfo

    pub struct NoteInfo {
    // private fields
    }

    One footnote/endnote: its id and every body position referencing it (multi-reference notes are representable per the plan).

    NoteInfo::id

    fn NoteInfo::id(self : NoteInfo) -> String

    The note id, as spelled.

    NoteInfo::references

    fn NoteInfo::references(self : NoteInfo) -> Array[String]

    Every body position referencing this note, in document order.

    NoteSpec

    pub struct NoteSpec {
    // private fields
    }

    One footnote or endnote body: plain-content, paragraph-only, and no note references of its own (notes do not nest). Construct with note_spec.

    RevisionInfo

    pub struct RevisionInfo {
    // private fields
    }

    One tracked change: what kind of revision it is, who made it, when they said they made it, and the projection path of the paragraph that contains it.

    The reader flattens w:ins into the accepted text and drops w:del entirely, so a revision has no representation in the parsed document at all. This record is the only place the identity survives, and it is read-only: text still returns the accepted view, unchanged.

    id, author and date are the attributes AS SPELLED and stay absent when the source omits them. All three are optional in CT_TrackChange; a defaulted author or date would make the index assert authorship the document never recorded.

    RevisionInfo::author

    fn RevisionInfo::author(self : RevisionInfo) -> String?

    The w:author attribute, when present.

    RevisionInfo::date

    fn RevisionInfo::date(self : RevisionInfo) -> String?

    The w:date attribute, LEXICAL (never converted), when present.

    RevisionInfo::id

    fn RevisionInfo::id(self : RevisionInfo) -> String?

    The w:id attribute, as spelled, when present.

    RevisionInfo::kind

    fn RevisionInfo::kind(self : RevisionInfo) -> String

    "ins" for an insertion, "del" for a deletion.

    RevisionInfo::path

    fn RevisionInfo::path(self : RevisionInfo) -> String

    The story-qualified projection path of the containing paragraph ("/body/p[2]"), degrading to the nearest verifiable ancestor.

    RevisionNameEdit

    pub struct RevisionNameEdit {
    // private fields
    }

    One element-name rewrite: the byte range of an element's LOCAL NAME in the original part, and the name it becomes. Rejecting a deletion turns every w:delText back into w:t through these ranges, which leaves the namespace prefix, xml:space, and every other byte of the tag untouched.

    RevisionNameEdit::end

    fn RevisionNameEdit::end(self : RevisionNameEdit) -> Int

    Offset just past the last byte of the local name (exclusive).

    RevisionNameEdit::replacement

    fn RevisionNameEdit::replacement(self : RevisionNameEdit) -> String

    The local name that replaces the range ("t" or "instrText").

    RevisionNameEdit::start

    fn RevisionNameEdit::start(self : RevisionNameEdit) -> Int

    Offset of the first byte of the local name.

    RevisionSpan

    pub struct RevisionSpan {
    // private fields
    }

    One tracked-change ELEMENT in the original bytes: what it is, who recorded it, and the byte extent a resolver needs to unwrap or remove it.

    This is the MUTATION view of a revision and is deliberately wider than AnnotationIndex::revisions, which is the READING view. Reading reports the content insertions and deletions the reader's projection retains; resolving must additionally see every construct it cannot act on, because a construct it cannot see is a construct it would silently leave behind. supported separates the two: it is true only for content w:ins and w:del, false for property revisions, moves, and every *PrChange.

    RevisionSpan::author

    fn RevisionSpan::author(self : RevisionSpan) -> String?

    The w:author attribute, as spelled, when present.

    RevisionSpan::byte_end

    fn RevisionSpan::byte_end(self : RevisionSpan) -> Int

    Offset just past the '>' that ends the element (exclusive).

    RevisionSpan::byte_start

    fn RevisionSpan::byte_start(self : RevisionSpan) -> Int

    Offset of the '<' of the element's open tag.

    RevisionSpan::close_tag_start

    fn RevisionSpan::close_tag_start(self : RevisionSpan) -> Int?

    Offset of the '<' of the close tag, or None for the self-closing form.

    RevisionSpan::container_path

    fn RevisionSpan::container_path(self : RevisionSpan) -> String?

    The story-relative projection path of the innermost containing node ("p[2]", "tbl[1]/tr[1]/tc[1]/p[1]"), or None at story level.

    RevisionSpan::content_start

    fn RevisionSpan::content_start(self : RevisionSpan) -> Int?

    Offset just past the '>' of the open tag, or None for the self-closing form — which has no content to keep, so all four resolutions of it collapse to removing the element.

    RevisionSpan::date

    fn RevisionSpan::date(self : RevisionSpan) -> String?

    The w:date attribute, LEXICAL (never converted), when present.

    RevisionSpan::declares_namespaces

    fn RevisionSpan::declares_namespaces(self : RevisionSpan) -> Bool

    True when the element's own start tag binds a namespace prefix. Unwrapping it would drop the binding while its former children still use it, so an unwrap resolution must refuse; removing the whole element stays safe.

    RevisionSpan::id

    fn RevisionSpan::id(self : RevisionSpan) -> String?

    The w:id attribute, as spelled, when present.

    RevisionSpan::kind

    fn RevisionSpan::kind(self : RevisionSpan) -> String

    The WML local name of the element ("ins", "del", "moveFrom", "rPrChange").

    RevisionSpan::name_edits

    fn RevisionSpan::name_edits(self : RevisionSpan) -> Array[RevisionNameEdit]

    The w:delText/w:delInstrText names inside this deletion, in document order; empty for an insertion. Rejecting the deletion applies all of them.

    RevisionSpan::story

    fn RevisionSpan::story(self : RevisionSpan) -> String

    The story key the span's offsets index into ("/body", "/header[1]").

    RevisionSpan::supported

    fn RevisionSpan::supported(self : RevisionSpan) -> Bool

    True only for a content w:ins/w:del a resolver can accept or reject.

    RunFormatEdit

    pub struct RunFormatEdit {
    // private fields
    }

    One slice-relative byte edit: replace [start, end) with the replacement text (encoded as UTF-8 by the consumer).

    RunFormatEdit::end

    fn RunFormatEdit::end(self : RunFormatEdit) -> Int

    The byte offset just past the text the edit replaces (slice-relative).

    RunFormatEdit::replacement

    fn RunFormatEdit::replacement(self : RunFormatEdit) -> String

    The replacement text (encoded as UTF-8 by the consumer).

    RunFormatEdit::start

    fn RunFormatEdit::start(self : RunFormatEdit) -> Int

    The byte offset where the edit's replacement begins (slice-relative).

    RunFormatPlan

    pub struct RunFormatPlan {
    // private fields
    }

    The planned edits for one run: slice-relative, non-overlapping, in ascending order (stable — equal-offset insertions keep their schema-rank order). changed=false means every requested property already holds explicitly — nothing is rewritten.

    RunFormatPlan::changed

    fn RunFormatPlan::changed(self : RunFormatPlan) -> Bool

    Whether the plan rewrites anything: false means every requested property already holds explicitly.

    RunFormatPlan::edits

    A defensive copy — the plan's sorted/non-overlapping invariant cannot be mutated away by a caller.

    RunTextReceipt

    pub struct RunTextReceipt {
    // private fields
    }

    What an addressed run replacement planned: the story part, the address that named the run, the reader-visible text the caller expected (and the plan replaces), and how many byte edits carry it.

    RunTextReceipt::at_relative

    fn RunTextReceipt::at_relative(self : RunTextReceipt) -> String

    The story-relative ordinal run path that named the run (for example p[1]/r[2]), echoed back once it has resolved to exactly one run in this story -- unique among the scan's run nodes AND among the projected runs. Against this same snapshot it stays valid, so a caller may re-plan with expect=replaced_text(). Once the plan is APPLIED the address is only meaningful again after a fresh mutation-safe read, since ordinals are snapshot-relative.

    RunTextReceipt::edit_count

    fn RunTextReceipt::edit_count(self : RunTextReceipt) -> Int

    How many byte edits the plan carries. It is a size, not a count of runs or characters -- one addressed run can need several edits. Zero means the replacement was the run's own text: the address, the expectation and the run's writability were all still checked, and the plan edits nothing rather than re-encoding bytes that already say it.

    RunTextReceipt::replaced_text

    fn RunTextReceipt::replaced_text(self : RunTextReceipt) -> String

    The expect string the caller passed, returned only after it was checked equal to the run's reader-visible text. So this is both what the caller asserted and what the run actually held: a receipt exists only when those agree.

    RunTextReceipt::result_text

    fn RunTextReceipt::result_text(self : RunTextReceipt) -> String

    The text the addressed run holds once this plan is applied to the package it was built from: reading that result back through the reader reproduces exactly this for that run. The plan pins only the story part, so applying it to a different archive that happens to carry the same story bytes is not covered by that claim. When result_text equals replaced_text the run already holds it and the plan is empty.

    RunTextReceipt::story_part

    fn RunTextReceipt::story_part(self : RunTextReceipt) -> String

    The story part the addressed run lives in, spelled exactly as the annotated read exposed it (for example word/document.xml). It is the only part the returned plan targets: the plan pins it, and any edit the plan carries is an edit to it. A self-replacement carries none.

    MAX_AUTHORED_MEDIA_BYTES

    let MAX_AUTHORED_MEDIA_BYTES : Int64

    Maximum aggregate emitted-media bytes, summed over image occurrences rather than unique assets.

    MAX_AUTHORED_MEDIA_PARTS

    let MAX_AUTHORED_MEDIA_PARTS : Int

    Maximum distinct media parts a fresh-authoring script may emit (one per image OCCURRENCE, not per unique asset), and the aggregate emitted-media byte ceiling summed over occurrences. Enforced BEFORE the writer graph is built, so a script that references one asset thousands of times is refused as a typed media limit rather than after materializing every part.

    author_docx_bytes

    Builds a fresh DOCX from an already-parsed docx.batch/2 script and the image bytes its image_paths() referenced. Body/comment/note construction errors surface as Unsupported carrying the script op address; a bounded serialization or emitted-media ceiling breach surfaces as WriteResourceLimit. Nothing is written — the caller publishes the returned bytes through its own transaction/atomic-write boundary.

    comment_anchor_fragments

    fn comment_anchor_fragments(id~ : String, wordprocessing_namespace? : String) -> (String, String)

    The two anchor fragments for comment id: the range start (spliced at the from-paragraph's content_start) and the range end plus the reference run (spliced at the to-paragraph's close_tag_start) — the same canonical shape the K1 writer emits, in self-contained form.

    comment_definition_fragment

    fn comment_definition_fragment(spec : CommentSpec, id~ : String, para_ids? : Array[String], max_output_bytes? : Int, wordprocessing_namespace? : String) -> String raise
    DocxError

    The w:comment definition fragment for spec (whose anchored range is ignored here — the splice layer owns placement). The body is re-validated (the arrays stay caller-mutable) and serialized through the same body writers as the packaging path, under the same fail-closed guard against relationship-bearing content.

    comment_reply

    fn comment_reply(author~ : String, initials? : String, date? : String, reply_to~ : Int, done? : Bool, body : Array[
    DocumentElement
    ]) -> CommentSpec raise
    DocxError

    Validates and builds an anchorless REPLY: reply_to is the 0-based index of an EARLIER spec in the array passed to write_docx_with_comments (checked against the array there; chains are allowed — a reply may answer another reply). Per the locked policy a reply emits NO range or reference markers: its parent's anchor is logically its own, and the thread linkage lives in word/commentsExtended.xml (w15:paraIdParent). Everything else — author/initials/date rules, the plain-content paragraph-only body — matches comment_spec.

    comment_spec

    fn comment_spec(author~ : String, initials? : String, date? : String, from~ : Int, to~ : Int, done? : Bool, body : Array[
    DocumentElement
    ]) -> CommentSpec raise
    DocxError

    Validates and builds a CommentSpec. from/to are 0-based indexes into the body array later passed to write_docx_with_comments (the inclusive anchored range); bounds against that body are checked at write time, everything spec-local is checked here so callers can attribute the failure to the exact comment: non-empty attribute-safe author, non-empty attribute-safe initials (when given), a lexically valid xsd:dateTime date (when given), an ordered non-negative range, and a non-empty paragraph-only body. Bodies are PLAIN CONTENT by the roadmap's locked rule — hyperlinks (even relationship-free anchor-only ones) and images are rejected here, and again at write time because the arrays stay caller-mutable.

    convert

    fn convert(docx : BytesView, output_format? :
    OutputFormat
    , style_map? : Array[String], include_default_style_map? : Bool, include_embedded_style_map? : Bool, ignore_empty_paragraphs? : Bool, id_prefix? : String, pretty_print? : Bool, convert_image? : (
    Image
    ) ->
    ImageConversion
    , transform_document? : (
    DocumentElement
    ) ->
    DocumentElement
    , external_file_access? : Bool, read_external_file? : (String) -> Bytes?) ->
    ConversionResult
    raise
    DocxError

    Converts DOCX bytes using the requested output format.

    convert_to_html

    fn convert_to_html(docx : BytesView, style_map? : Array[String], include_default_style_map? : Bool, include_embedded_style_map? : Bool, ignore_empty_paragraphs? : Bool, id_prefix? : String, pretty_print? : Bool, convert_image? : (
    Image
    ) ->
    ImageConversion
    , transform_document? : (
    DocumentElement
    ) ->
    DocumentElement
    , external_file_access? : Bool, read_external_file? : (String) -> Bytes?) ->
    ConversionResult
    raise
    DocxError

    Converts DOCX bytes to HTML.

    convert_to_markdown

    fn convert_to_markdown(docx : BytesView, style_map? : Array[String], include_default_style_map? : Bool, include_embedded_style_map? : Bool, ignore_empty_paragraphs? : Bool, id_prefix? : String, convert_image? : (
    Image
    ) ->
    ImageConversion
    , transform_document? : (
    DocumentElement
    ) ->
    DocumentElement
    , external_file_access? : Bool, read_external_file? : (String) -> Bytes?) ->
    ConversionResult
    raise
    DocxError

    Converts DOCX bytes to Markdown.

    docx_delete_refusal_prose

    fn docx_delete_refusal_prose(message : String) -> String

    The prose half of a refusal this planner raised, or the message unchanged when it came from somewhere else.

    docx_delete_refusal_slug

    fn docx_delete_refusal_slug(message : String) -> String?

    The slug half, when this planner raised it.

    docx_direct_body_paragraph_count

    fn docx_direct_body_paragraph_count(annotated : DocxAnnotatedResult) -> Int raise
    DocxError

    The number of DIRECT body paragraphs, counted on the element tree — the same proof surface the deletion planner trusts. Anchor-index probing undercounts when a collided or revision-joined path is tombstoned; the tree does not.

    docx_direct_format

    fn docx_direct_format(bold? : Bool, italic? : Bool, underline? : Bool, color? : String) -> DocxDirectFormat raise
    DocxError

    Validate and canonicalize a direct-format request. Color accepts RRGGBB or #RRGGBB (either case) and canonicalizes to uppercase. A request that touches nothing is refused — a formatting command must state at least one property.

    docx_paragraph_anchor_index

    Build the anchor index for one story.

    Duplicate detection is PART-SCOPED over every WML w:p the scan retained (the reader-selected view of the part) — not merely the projected logical paragraphs — because Word's uniqueness rule is per part, and a collision hiding in suppressed content still makes the id unaddressable. Only VALID spellings can collide: an invalid value is not an identity, so it neither claims nor contests one.

    docx_paragraph_anchor_join_index

    Build the story's tree/projection join.

    A tree occurrence joins a projection paragraph only when ALL hold: the source vectors are exactly equal; exactly one occurrence and one projection paragraph claim that vector; and every physical source in the vector participates in exactly one projection paragraph. The last condition kills the false match the nested-paragraph shape offers (the outer tree paragraph's [host] superficially equals the post-half projection paragraph's [host], but the host also participates in the joined head) — refusing beats first-wins.

    docx_paragraph_direct_format

    fn docx_paragraph_direct_format(annotated : DocxAnnotatedResult, story : DocxStoryPartSource, path~ : String, start~ : Int, end~ : Int, format~ : DocxDirectFormat) -> String? raise
    DocxError

    The positive check over ONE span — the batched judgment applied to a single range.

    docx_paragraph_direct_format_spans

    fn docx_paragraph_direct_format_spans(annotated : DocxAnnotatedResult, story : DocxStoryPartSource, path~ : String, spans~ : Array[(Int, Int)], format~ : DocxDirectFormat) -> String? raise
    DocxError

    The readback's direct-format judgment: does every run whose projected text lies inside [start, end) of paragraph path carry every requested property EXPLICITLY?

    This is the check the projection cannot make — the projection is unchanged by formatting, so only the runs themselves can say whether the edit landed. Returns None when satisfied, or the first discrepancy's description. None for a missing paragraph is not possible: an unresolvable path is itself a discrepancy.

    docx_paragraph_format_preserved

    fn docx_paragraph_format_preserved(before : DocxAnnotatedResult, before_story : DocxStoryPartSource, after : DocxAnnotatedResult, after_story : DocxStoryPartSource, path~ : String, spans~ : Array[(Int, Int)], format~ : DocxDirectFormat) -> String? raise
    DocxError

    The readback's PRESERVATION judgment: did formatting stay inside the spans it was asked for?

    The positive check cannot answer this. A run outside the union may have carried the property all along, so presence proves nothing — provenance does. The comparison is made PER PROJECTION UNIT rather than per run: splitting changes which runs exist and how their contributions are grouped, but it must never change which properties apply to a given character. Every unit outside the requested spans must therefore carry exactly the run properties it carried before, and the runs that project no text at all (a note reference alone in its run) must keep theirs too, compared in document order.

    SCOPE: this judges the PARAGRAPH's own formatting — its runs, its carriers, its mark. Formatting that lives outside the paragraph (a table cell's w:tcPr, a style definition) is not compared here, and does not need to be: a plan's declared byte edits bound what it can touch, so anything outside them is preserved by the splice itself rather than by this check.

    spans are the paragraph-local ranges the plan was asked to format. Returns None when preserved, or the first discrepancy.

    docx_paragraph_projection

    fn docx_paragraph_projection(annotated : DocxAnnotatedResult, story : DocxStoryPartSource, path~ : String) -> String?

    One paragraph's full projection text, by its body-relative path.

    This is the readback half of the replace contract: after a splice is applied, the transaction re-reads the candidate and compares each affected paragraph's projection — through THIS accessor — against the receipt's precomputed expectation. None means the path names no paragraph in the story, which a readback must treat as a mismatch rather than a pass.

    docx_paragraphs_direct_format

    fn docx_paragraphs_direct_format(annotated : DocxAnnotatedResult, story : DocxStoryPartSource, requests~ : Array[(String, Array[(Int, Int)])], format~ : DocxDirectFormat) -> Array[String?] raise
    DocxError

    The same judgment for many paragraphs of one story, with the path lookup built once for the whole batch. Answers are returned in the order asked.

    docx_paragraphs_format_preserved

    fn docx_paragraphs_format_preserved(before : DocxAnnotatedResult, before_story : DocxStoryPartSource, after : DocxAnnotatedResult, after_story : DocxStoryPartSource, requests~ : Array[(String, Array[(Int, Int)])], format~ : DocxDirectFormat) -> Array[String?] raise
    DocxError

    The same judgment for many paragraphs of one story, with each document's path lookup built once for the whole batch. Answers are returned in the order asked.

    docx_paragraphs_projection

    fn docx_paragraphs_projection(annotated : DocxAnnotatedResult, story : DocxStoryPartSource, paths~ : Array[String]) -> Array[String?]

    The projections of many paragraphs of one story, with the path lookup built once for the whole batch: asking per paragraph costs the whole story per question. Answers are returned in the order asked, None where the path names no paragraph.

    embed_style_map

    fn embed_style_map(docx : BytesView, style_map : String) -> Bytes raise
    DocxError

    Embeds or replaces the DOCX style map part.

    extract_raw_text

    fn extract_raw_text(docx : BytesView, external_file_access? : Bool, read_external_file? : (String) -> Bytes?) ->
    ConversionResult
    raise
    DocxError

    Extracts raw text from DOCX bytes.

    find_docx_matches

    fn find_docx_matches(annotated : DocxAnnotatedResult, story : DocxStoryPartSource, needle~ : String, within? : String, context? : Int, limit? : Int) -> DocxMatchList raise
    DocxError

    List every literal candidate for needle, in document order.

    This is a READ. Zero matches is an empty list and not a refusal -- only a mutation fails closed on finding nothing. What can still refuse is the request itself: an empty needle names every position, and a story with no retained projection cannot be searched.

    within restricts to a subtree by body-relative path prefix, so p[3] takes one paragraph and tbl[1] takes a whole table.

    At most limit candidates are EXAMINED. Every examined candidate costs a planner run, so the bound is on work rather than only on output; candidates past it are counted through ordinal but carry no verdict, and the caller sees fewer entries than the last ordinal.

    Validates and builds one header/footer story. variant is the OOXML reference type (default, first or even); the body is non-empty and block-level (paragraphs and tables), plain content all the way down.

    mint_para_id

    fn mint_para_id(used : Array[String]) -> String raise
    DocxError

    Mint a fresh paraId: the smallest canonical value not in used. Deterministic by design — tests assert validity and freshness, never an allocator sequence — and conservative: used should carry every id seen anywhere in the package, buried and invalid spellings included, so a mint can never collide with anything a future repair might surface.

    new_blank_docx

    fn new_blank_docx() -> Bytes

    Builds a minimal, schema-valid blank docx: one empty paragraph, a body-final section (Letter, one-inch margins), and a Normal style. All inputs are compile-time constants, so builder failures are programming errors — hence the abort rather than a raise.

    new_blank_docx_limited

    Like new_blank_docx, but serialized under limits so a fresh-creation transaction can bound the candidate BEFORE allocation (the blank package is a small constant, so this never actually breaches — it keeps the create path on the same bounded-writer contract as authored documents). An over- limit ceiling surfaces as the typed WriteResourceLimit.

    note_spec

    Validates and builds a NoteSpec. The body rules match comment bodies (non-empty, paragraph-only, plain content) plus the no-nesting rule; they are re-checked at write time because the arrays stay caller-mutable. Which KIND the note is (footnote or endnote) is decided by which array it is passed in, so one spec type serves both.

    para_id_inventory_archive_limited

    The document's per-part w14:paraId inventory: every reachable story part mapped to its raw attribute values in document order. No judgment is applied — invalid spellings and duplicates are listed as they stand, because the caller's question is "what did the operation CHANGE about the identity state", not "is the identity state clean". The delta judgment lives in para_id_state_delta_violation.

    para_id_state_delta_violation

    fn para_id_state_delta_violation(source : Map[String, Array[String]], candidate : Map[String, Array[String]]) -> String?

    The identity DELTA judgment for a mutation's candidate against its source, part-scoped per Word's uniqueness rule. Existing dirt may SURVIVE — real documents carry duplicate and invalid ids, and a text edit must not be hostage to them — and removals are always fine (consumed content takes its ids with it). What a write may never do:

    • introduce an invalid spelling the part did not already carry (per raw spelling, count-bounded by the source), or
    • increase a valid id's per-part occupancy beyond one — creating a NEW collision or deepening an existing one. Case-insensitive: 1a… and 1A… are the same identity.

    Returns the first violation's description, or None when the delta is acceptable. Cross-part equality is NOT a violation — identity scope is the part.

    plan_comment_addition

    fn plan_comment_addition(annotated : DocxAnnotatedResult, original : BytesView, at_relative~ : String, to_relative~ : String, spec : CommentSpec, max_fragment_bytes? : Int) -> (
    SplicePlan
    , String) raise
    DocxError

    Builds the splice plan that adds one comment to the ORIGINAL package: anchor markers into the main part at scanner offsets (self-closing paragraphs rewritten by their own extent), the definition into the existing comments part (self-closing roots rewritten too) or a fresh part derived from the MAIN part's directory, wired with a parsed-not-guessed relationship id and a content-type Override located at the BYTE level. Returns the plan and the allocated comment id.

    plan_comment_addition_archive

    fn plan_comment_addition_archive(annotated : DocxAnnotatedResult, archive :
    Archive
    , at_relative~ : String, to_relative~ : String, spec : CommentSpec, xml_budget? :
    XmlReadBudget
    , max_fragment_bytes? : Int) -> (
    SplicePlan
    , String) raise
    DocxError

    Archive-backed form used by preservation-safe edit sessions. It reuses the caller's already bounded, materialized package and never inflates the DOCX a second time.

    plan_comment_reply

    fn plan_comment_reply(annotated : DocxAnnotatedResult, original : BytesView, parent_id~ : String, spec : CommentSpec, max_fragment_bytes? : Int) -> (
    SplicePlan
    , String) raise
    DocxError

    Builds the splice plan for docx annotate reply: the reply's definition (paraId-stamped) into comments.xml plus the whole-part commentsExtended update (parent retrofit included). Returns the plan and the reply's new comment id.

    plan_comment_reply_archive

    fn plan_comment_reply_archive(annotated : DocxAnnotatedResult, archive :
    Archive
    , parent_id~ : String, spec : CommentSpec, xml_budget? :
    XmlReadBudget
    , max_fragment_bytes? : Int) -> (
    SplicePlan
    , String) raise
    DocxError

    Archive-backed reply planner for bounded preservation sessions.

    plan_comment_resolution

    fn plan_comment_resolution(annotated : DocxAnnotatedResult, original : BytesView, comment_id~ : String, done~ : Bool) ->
    SplicePlan
    raise
    DocxError

    Builds the splice plan for docx annotate resolve|unresolve: the comment's commentsExtended entry flips (or gains) its w15:done flag, with the same paraId retrofit as replies when the definition is unstamped.

    plan_comment_resolution_archive

    Archive-backed resolution planner for bounded preservation sessions.

    plan_docx_format

    fn plan_docx_format(annotated : DocxAnnotatedResult, story : DocxStoryPartSource, format~ : DocxDirectFormat, text? : String, within? : String, nth? : Int, range? : (Int, Int)) -> (
    SplicePlan
    , DocxFormatReceipt) raise
    DocxError

    Plan absolute direct formatting over spans of the body story.

    Exactly one selector: text (find's literal enumeration, with within restricting the subtree and nth selecting one candidate by ordinal) or range (paragraph-local UTF-16 coordinates inside the single paragraph within names). Selection happens BEFORE formatting actionability, and any refusal aborts the whole batch — formatting never silently skips what it selected.

    DocxMatch::actionable is deliberately NOT consulted: it is the identity-replacement verdict, and a span crossing a hyperlink boundary is unreplaceable yet formattable. The formatting planner raises its own refusals instead.

    Zero candidates plans nothing and returns an empty receipt; whether that is an error is the caller's policy, not this engine's fact.

    The returned plan is pinned to the annotated read's retained bytes, so applying it to any other snapshot refuses as stale.

    plan_docx_paragraph_deletion

    Plan one paragraph deletion at a DIRECT body paragraph.

    at is the direct body ordinal path ("p[3]") — the same anchor grammar insertion uses, proven a physical child of w:body on the element tree (the path grammar flattens wrappers, so the path alone proves nothing). The returned plan splices ONLY the deletion; the receipt names what leaves and who answers at the path afterwards.

    plan_docx_paragraph_insertion

    fn plan_docx_paragraph_insertion(annotated : DocxAnnotatedResult, at~ : String, before~ : Bool, content~ : DocxInsertContent, used_para_ids~ : Array[String]) -> (
    SplicePlan
    , DocxInsertReceipt) raise
    DocxError

    Plan one paragraph insertion beside a DIRECT body paragraph.

    at is the direct body ordinal path ("p[3]" — nested paragraphs are not insertion anchors); before picks which side of it the new paragraph lands on. used_para_ids is the caller's complete inventory (the transaction already holds it for the delta gate). The returned plan splices ONLY the insertion; the receipt carries the minted id and the path the paragraph will answer to.

    plan_docx_replacements

    fn plan_docx_replacements(annotated : DocxAnnotatedResult, story : DocxStoryPartSource, needle~ : String, replacement~ : String, within? : String, nth? : Int) -> (
    SplicePlan
    , DocxReplaceReceipt) raise
    DocxError

    Plan replacing needle with replacement in the body story.

    The locked selection semantics, verbatim from the roadmap:

    • Ordinals run over ALL candidates in document order, including restricted ones — the same ordinals find reports.
    • nth selects ONE candidate by that ordinal, BEFORE actionability is considered; selecting a restricted candidate is a refusal that names its reason, not a skip.
    • Without nth, every candidate is selected, and ANY restricted candidate in scope refuses — replace never silently skips what find reports.

    Zero candidates plans nothing and returns an empty receipt; whether that is an error belongs to the caller (--allow-zero is CLI policy, not engine fact).

    The returned plan is pinned to the annotated read's retained bytes, so applying it to any other snapshot refuses as stale.

    plan_run_format

    fn plan_run_format(run_slice : BytesView, prefix~ : String, attr_prefix? : String, extension_prefixes? : Array[String], format~ : DocxDirectFormat) -> RunFormatPlan raise
    DocxError

    Plan the minimal edits that make format hold explicitly on one run, given the run's complete byte slice and the document's WML binding: prefix is the ELEMENT prefix ("" for a default-namespace document), attr_prefix (default: prefix) is the prefix WML attributes carry — never empty, because default namespaces do not apply to attributes — and extension_prefixes lists the prefixes the caller warrants are bound to recognized rPr extension namespaces.

    plan_run_text_replacement

    fn plan_run_text_replacement(annotated : DocxAnnotatedResult, story : DocxStoryPartSource, at_relative~ : String, expect~ : String, text~ : String) -> (
    SplicePlan
    , RunTextReceipt) raise
    DocxError

    Plans the replacement of one addressed run's whole text with text.

    story must be a story part source the annotated result itself exposed, and the result must come from a MUTATION-SAFE read: only those retain the classified projection this planner consumes. at_relative is the story-relative ordinal run path (p[3]/r[2]), resolved against the projection's own physical scan. expect is REQUIRED and must equal the run's reader-visible text: addresses are snapshot-relative, and a stale expectation refuses rather than editing whatever now sits at the path.

    Every failure is a typed refusal; nothing falls back. The planner takes NO archive: it plans against the exact source bytes the annotated read retained beside the projection, so a mismatched archive cannot be smuggled in -- and the returned plan is pinned to those same bytes, so applying it to anything else refuses as stale.

    read_docx

    fn read_docx(docx : BytesView, external_file_access? : Bool, read_external_file? : (String) -> Bytes?) ->
    DocumentElement
    raise
    DocxError

    Reads DOCX bytes into a document tree.

    read_docx_annotated

    fn read_docx_annotated(docx : BytesView, external_file_access? : Bool, read_external_file? : (String) -> Bytes?) -> DocxAnnotatedResult raise
    DocxError

    Reads DOCX bytes into the package representation PLUS the annotation index. The package half is identical to read_docx_package.

    read_docx_annotated_archive

    fn read_docx_annotated_archive(archive :
    Archive
    , external_file_access? : Bool, read_external_file? : (String) -> Bytes?) -> DocxAnnotatedResult raise
    DocxError

    Builds the same package and annotation indexes from a caller-owned archive snapshot. Payload buffers are shared; the DOCX reader does not inflate the package a second time. Duplicate entry names fail before the map-backed view is constructed.

    read_docx_annotated_archive_joined_projection_limited

    fn read_docx_annotated_archive_joined_projection_limited(archive :
    Archive
    , xml_budget :
    XmlReadBudget
    , external_file_access? : Bool, read_external_file? : (String) -> Bytes?, max_diagnostics? : Int, max_diagnostic_chars? : Int, expected_main_document_path? : String) -> DocxAnnotatedResult raise
    DocxError

    Builds a read-only projection with the joined story reader while retaining tolerant annotation identities. This is the projection command's single read path: strict story correspondence is available for paragraph anchors, but mutation-only identity gates remain disabled.

    read_docx_annotated_archive_limited

    fn read_docx_annotated_archive_limited(archive :
    Archive
    , xml_budget :
    XmlReadBudget
    , external_file_access? : Bool, read_external_file? : (String) -> Bytes?, max_diagnostics? : Int, max_diagnostic_chars? : Int, expected_main_document_path? : String) -> DocxAnnotatedResult raise
    DocxError

    Builds package and annotation indexes from an existing archive while every XML part shares one cumulative parser budget. Source bytes are charged before UTF-8 decoding and parser tokens before DOM allocation. Reader diagnostics are deduplicated in first-seen order and bounded during production by max_diagnostics and max_diagnostic_chars.

    read_docx_annotated_archive_tolerant_limited

    fn read_docx_annotated_archive_tolerant_limited(archive :
    Archive
    , xml_budget :
    XmlReadBudget
    , external_file_access? : Bool, read_external_file? : (String) -> Bytes?, max_diagnostics? : Int, max_diagnostic_chars? : Int, expected_main_document_path? : String) -> DocxAnnotatedResult raise
    DocxError

    Builds the bounded annotation-aware projection used by tolerant read-only commands. Broken section header/footer references are already warned and omitted by DocxPackageResult; they do not activate mutation-only identity gates. Edit transactions continue to use read_docx_annotated_archive_limited and fail closed on the same input.

    read_docx_package

    fn read_docx_package(docx : BytesView, external_file_access? : Bool, read_external_file? : (String) -> Bytes?) -> DocxPackageResult raise
    DocxError

    Reads DOCX bytes into the package-level representation: the body document tree (identical to read_docx_with_messages), header/footer parts (each a block-level story, deduplicated by part path in first-reference order), and the sections that reference them.

    read_docx_with_messages

    fn read_docx_with_messages(docx : BytesView, external_file_access? : Bool, read_external_file? : (String) -> Bytes?) -> DocxReadResult raise
    DocxError

    Reads DOCX bytes into a document tree and diagnostics.

    read_embedded_style_map

    fn read_embedded_style_map(docx : BytesView) -> String? raise
    DocxError

    Reads the embedded style map from DOCX bytes, if present.

    sweep_archive_para_id_values

    A PACKAGE-GLOBAL paraId value sweep for the mint's used set: every archive part that parses as strict XML contributes its decoded w14:paraId values — quote style, attribute whitespace, and entity encodings all normalized by the parser, any prefix bound to the w14 URI normalized by the namespace map. FAIL-CLOSED where the sweep cannot judge: each part gets a FRESH budget (earlier parts can never starve later ones), a part that exhausts its own budget refuses the caller's operation, and a UTF-16 part — which the strict reader cannot decode and a byte belt cannot match — refuses too. Only parts that are not XML at all are skipped, and the caller keeps a lexical belt for those.

    validate_annotation_identity_state

    fn validate_annotation_identity_state(annotated : DocxAnnotatedResult) -> Unit raise
    DocxError

    Rejects annotation state that cannot safely serve as the result of a comment mutation. This is the candidate-side counterpart to the planners' source gate and catches duplicate or ambiguous identities introduced by a caller-supplied generic splice plan.

    validate_global_para_id_state_archive_limited

    Validates every reachable story's w14:paraId values under one cumulative XML budget. This is the candidate-side gate for generic splice plans; the reply/resolution planners use the same traversal before allocating IDs.

    validated_para_id

    fn validated_para_id(raw : String) -> String?

    Validate one as-spelled paraId and return its canonical uppercase form: exactly eight ASCII hex digits (either case), nonzero, and below 0x80000000 (MS-DOCX: greater than zero, high bit clear). Anything else is not an identity.

    Distinct from the comments layer's canonical_para_id, which only case-normalizes conforming spellings for comparison and passes everything else through verbatim — this is the ADDRESSING judgment, and it rejects what it cannot vouch for.

    verify_run_format

    fn verify_run_format(run_slice : BytesView, prefix~ : String, attr_prefix? : String, extension_prefixes? : Array[String], format~ : DocxDirectFormat) -> String? raise
    DocxError

    Verify that every requested property holds EXPLICITLY on the run slice by EXTRACTING each property's observed value and comparing it semantically — independent of the planner's edit generation (the two share only the lexical scanner and the rPr classification). Returns None when satisfied, or the FIRST discrepancy in property order (b, bCs, i, iCs, u, color). As a final cross-check the planner must also consider a satisfied slice a fixed point; a disagreement between the two readings is itself reported.

    write_docx

    Serializes body content into a complete docx package. Supported today: paragraphs (style id, alignment, list numbering) containing runs (bold, italic, underline, strikethrough, caps, super/subscript, font, size, highlight), text, tabs, line breaks; and tables with spans. Headings use the Heading1..Heading6 style ids, emitted into the styles part so Word's outline and this repo's own outline command both recognize them; list paragraphs reference the fixed bullet/decimal definitions in the numbering part.

    write_docx_with_annotations

    The full annotation writer: write_docx plus comments (see write_docx_with_comments) plus footnotes and endnotes. Notes are referenced from body runs by note_reference(kind, index) where index is the 0-based position in the matching array here — each supplied note must be referenced EXACTLY ONCE (the canonical shape; unreferenced notes would be invisible orphans, duplicate references are not what Word produces). Note bodies are plain-content paragraph-only, may not carry note references themselves, and land in word/footnotes.xml / word/endnotes.xml as MAIN-part relationships, complete with the separator/continuationSeparator plumbing notes and the in-note footnoteRef/endnoteRef mark run.

    write_docx_with_comments

    write_docx plus comments. The body serializes exactly as write_docx would (an empty comments array is byte-identical); each comment then decorates its anchored paragraphs — range start markers right after pPr in the from paragraph, range end plus the id's reference run appended to the to paragraph — and its definition is written to word/comments.xml. Both anchor endpoints must be top-level paragraphs (tables cannot carry the canonical intra-paragraph shape). REPLIES (comment_reply) must answer an EARLIER spec in this array and emit no markers at all. Comment BODIES reuse the body writers, with a fail-closed guard: content that allocates relationships or media (hyperlinks, images) raises instead of emitting references that would dangle in the comments part. Threading or resolution anywhere adds w14:paraId stamps and word/commentsExtended.xml; otherwise output is byte-identical to the threading-free writer.