Skip to content

test(docx): ask a drawing to follow text only where a paragraph carries it - #982

Merged
DemchaAV merged 3 commits into
2.5-devfrom
fix/docx-follow-text-acceptance-denominator
Oct 30, 2026
Merged

DemchaAV merged 3 commits into
2.5-devfrom
fix/docx-follow-text-acceptance-denominator

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

Why

The editing protocol asks of every floating drawing whether it followed the text it stands beside
when an edit moved that text. A drawing nailed to the sheet cannot: wp:positionV relativeFrom="page" places it from the top of the page it is drawn on and from nothing else, so the
text beside it has no claim on where it stands. Measured on the self-check's two alike probe
documents, with the paragraph above lengthened by two lines: such a drawing moved 0.00pt in Word
16 and 0.00pt in LibreOffice 24.2
while its own text moved 32.04 and 52.50pt, where the same
drawing carried by that text's paragraph in the other document moved 31.96 and 52.50pt with it.
Both editors, by construction.

Counting that as a drawing which failed to follow measures which anchor the export chose, not
whether the export holds a drawing to its text — and which anchor the export chose has an instrument
of its own. DocxDrawingAnchorGuardTest names every drawing of the corpus still placed from the
page, one by one with the reason it is there, and fails when one is added to that list or taken off
it. So the figure this protocol reports was made of two questions at once, and the one it is asked
for could not be read off it.

What changed

scripts/docx-visual/edit-protocol-corpus.ps1

  • What a drawing is placed down from is read from Word, per drawing. Get-DrawingPlaces carries
    RelativeVerticalPosition beside the place and the left edge. Measured over the corpus both ways
    round: the files hold 774 wp:anchor in the body and Word names 774 shapes there, with no anchor
    the one reading has and the other has not, and wp:positionV relativeFrom agrees with Word on
    every one — 46 from the page, 14 of them page fills, and 728 from their paragraph, with no third
    answer and no name carried twice. The 32 drawings left are the 32 the guard's ledger names,
    document for document and name for name (invoice-payments 13, invoice-workspace 8,
    invoice-merchant 4, invoice-luma_studio_long 6, invoice-obsidian_long 1). The 18 further
    anchors the files hold outside the body are page fills in headers, which this reading, being of
    the main story, does not reach.
  • The nailed drawings are measured as the carried ones are, named with what they did, and left out
    of the verdict.
    Measure-Following is the one measuring of a set — how many stood beside text
    the edit moved and moved with it, how many stood beside text it left standing and stood still —
    and it is run over both sets. The detail names every nailed drawing of the document, with the
    counts for the set and by name for each one that left its text or lost its place. Nothing is set
    aside quietly: the number is printed, the names are printed, and what the set did is printed.
  • A drawing that ought to follow stays in the verdict whether or not nailed drawings stand beside
    it
    , since what is read is each drawing's own anchor and not the document it stands in. The
    corpus shows it: invoice-merchant sets its four nailed drawings aside and still fails, on
    Drawing 15, which a paragraph carries and which crosses onto the page after while the text it
    stands beside stays.
  • Nothing may leave the verdict by carrying an answer the scenario has no question for. A
    drawing placed down from anything that is neither its paragraph nor the page fails with its own
    reason — the export writes only those two (DocxDrawings and DocxPageBackgrounds are the only
    writers of wp:positionV relativeFrom) and the corpus holds nothing else, so this is a hole
    closed rather than a case seen. The same hole was already open for a name Word gives to more than
    one drawing, which Get-DrawingPlaces reads as no drawing at all and the scenario passed over in
    silence: such a name is now named and fails, and is reported on a line of its own rather than
    among the places the page geometry does not give, since the geometry is not what failed there and
    a reason naming the wrong cause sends the next reader after a defect that is not there. It
    predates this change, and is in scope because this change makes the principle explicit in three
    files.
  • A drawing the reading no longer finds is counted apart from one whose own text cannot be placed
    again, and fails for either set
    , of the drawings each set measures. The two were one count
    before. The first — Word does not name the drawing after the save and the reopen, or names it and
    another alike so neither can be told from the other — is a drawing gone from the document or one
    that can no longer be told apart, which is not a question of what it was placed from, so taking
    the nailed drawings out of the verdict must not take that with them. The second is the instrument
    losing the paragraph a drawing was held to, which answers nothing about a drawing nothing is asked
    of, so it fails for the carried set alone. Both are nought over the corpus.
  • A document whose drawings are all nailed is measured rather than recorded as having nothing to
    edit, which would say something untrue of it; its detail names them beside the nought carried
    drawings held to the verdict.

CONTRIBUTING.md says what the scenario asks of whom and what holds the rest; CHANGELOG.md
carries it under Tests. The export is untouched, so docs/recipes/docx-export.md and the capability
matrix are unchanged, and no public API moved, so the knowledge pack is unchanged.

Verification

  • Over the template corpus, 71 documents, run five times across the builds of this change,
    agreeing exactly on the status and all five counts of every one of the 71 every time:
    • 305 of the 320 drawings a paragraph carries standing beside text the edit moved follow it —
      95.3%
      — and 400 of the 408 beside text it leaves standing stand still too.
    • The 32 nailed to the sheet, measured the same way: 13 stood beside text that moved and none
      followed it, 19 stood beside text that stayed and all 19 stood still.
    • Added back together those are 305 of 333, 91.6%, and 419 of 427 — the two figures this
      protocol last reported, to the drawing. So the denominator is all that changed, and the run is
      comparable to that one count for count rather than by assertion.
    • 30 documents pass, 8 fail, 33 have nothing to measure, where it was 28, 10 and 33. The two
      that pass now failed only on nailed drawings: invoice-payments, whose eleven line-item tiles
      do not move while their text moves 40pt, and invoice-luma_studio_long, two of its six. No
      other document's verdict changed.
  • -SelfCheck: 15 of 15, where it ran 10. One probe changed and five are new: the drawing
    nailed to the sheet at the place it already stands, now held to passing and to naming what it did;
    a document holding a nailed drawing beside a carried one that leaves its text, where the carried
    one must still fail; a drawing nailed to a page with no text on it, which is the one disposition
    the corpus does not reach; a nailed drawing whose place the geometry cannot give, paired with the
    document where a carried drawing fails for that same reason; a drawing placed down from the
    page's margin; and two drawings sharing a name. The last three are written here because nothing
    the export produces reaches those cases.
    • A paragraph holding only a page break was measured and refused as the "no text on its page"
      probe: the break is a character of that paragraph's text, so Word places the paragraph on the
      page before the break and draws a drawing nailed from it on that page too — where the probe
      found the body's own paragraph to stand beside. A tall untexted row pushed onto the page after
      reaches the case.
  • Thirteen sabotages, nine caught by the probe written for each, the file restored byte for
    byte from a copy taken at the start of each run and asserted against it by sha256:
    • a nailed drawing let into the verdict again → the nailed probe fails;
    • what it is placed down from no longer read from Word → the same probe fails;
    • the nailed drawings no longer named in the detail → the same probe fails on its reason;
    • the ones that left their text no longer named one by one → the same probe fails on its reason;
    • the nailed drawings counted but no longer measured → the same probe fails on its reason;
    • every drawing of a document holding a nailed one let off → the mixed document passes, which
      is the false pass this change had to be written not to buy;
    • anything but a paragraph taken for nailed → the margin probe's document passes where it must
      fail, so that probe fails;
    • an unreadable nailed drawing failing the scenario again → the paired probe fails;
    • a shared name passed over in silence again → the two-of-one-name probe's document passes where
      it must fail, so that probe fails.
    • Four more are reached by nothing, and are run to measure that rather than to pass. A
      drawing the reading no longer finds no longer failing, once on the carried side and once on the
      nailed one: no document can make Word drop a shape or give two shapes one name over an edit. And
      the two exclusions the nailed set carries of its own — a drawing whose own text cannot be placed
      again, and one whose place the geometry stops giving after the edit — which are counted and
      reported and fail nothing, rightly by this change's own reasoning, but which no probe reaches
      either. All four were broken on purpose and nothing caught them.
    • Two more things go unprobed and are named rather than claimed away: the order the names print
      in, which no probe has two entries to distinguish and which changes no verdict; and one path out
      of the verdict older than this change — a carried drawing whose page holds no paragraph the
      reading could place is counted as standing beside no text, and a document can pass with it. The
      corpus reaches neither.
      Each run is read for the probe's own name among the failures and for the count line saying 15
      checks, so a sabotage that stopped the script before it measured anything cannot pass for one that
      was caught.
  • The export is untouched: the corpus was exported again from this tree and compared with the
    export the measurements were taken on — 71 documents, no part changed, the report's notes 1497
    either way.
  • ./mvnw clean verify over the reactor, the four knowledge checks, core javadoc at 0 warnings,
    and the examples suite (93 tests, CommittedAssetDriftTest among them): all pass
    on the tree as
    it ships. The documentation guards that read CONTRIBUTING.md were run on their own as well — 24
    tests, 0 failures.

What the figure is and is not: it is taken over the drawings the export already anchors in a
paragraph, so it says how well those keep to their text and nothing about the 32 the ledger still
holds — and that ledger is of work to do, not of cases where the sheet is right. The eight failing
documents answer for 23 carried drawings: 15 that do not follow text that moved and 8 that move from
text that did not. The margin is thin and worth knowing before the figure is quoted as settled: each
further carried stray costs about a third of a percentage point, and 304 of 320 is exactly 95 in a
hundred.

The protocol needs Word and is run by hand, so no CI job covers it; -SelfCheck is what to run
after changing how a place is read, how an owner is chosen, or what the verdict is taken over.

…es it

The editing protocol asked of every floating drawing whether it followed the
text beside it when an edit moved that text. A drawing nailed to the sheet
cannot: wp:positionV relativeFrom="page" places it from the top of the page it
is drawn on and from nothing else. Measured on the probe document, with the
paragraph above lengthened by two lines, such a drawing moved 0.00pt in Word 16
and 0.00pt in LibreOffice 24.2 while its own text moved 32.04 and 52.50pt, where
the same drawing carried by that text's paragraph moved 31.96 and 52.50pt with
it. Counting that as a drawing which failed to follow measured which anchor the
export chose, which DocxDrawingAnchorGuardTest holds instead, naming every
drawing of the corpus still placed from the page one by one with its reason.

What a drawing is placed down from is now read from Word, per drawing, and is
the same thing the file says: over the corpus the files hold 774 wp:anchor in
the body and Word names 774 shapes there, and relativeFrom agrees with
RelativeVerticalPosition on every one — 46 from the page, 14 of them page
fills, and 728 from their paragraph. The 32 drawings left are the 32 the guard's
ledger names, document for document and name for name.

The nailed drawings are measured as the carried ones are, named in the detail
with what each of them did, and left out of the verdict; a drawing that ought to
follow stays in it whether or not nailed drawings stand beside it, since what is
read is each drawing's own anchor and not the document it stands in. Nothing can
leave the verdict by carrying an answer the scenario has no question for: a
drawing placed down from a third thing fails with its own reason, and so does a
name Word gives to more than one drawing, which was passed over in silence. A
drawing Word no longer names after the save and the reopen is counted apart from
one whose own text cannot be placed again and fails for either set, being
content gone from the document rather than a question of its anchor.

Over the corpus 305 of the 320 carried drawings beside text the edit moved
follow it, 95.3%, and 400 of 408 beside text it leaves standing stand still. The
32 nailed ones give 13 beside text that moved, none following, and 19 beside
text that stayed, all standing; added back together the counts are 305 of 333
and 419 of 427, the two figures last reported, so the denominator is all that
changed. 30 documents pass, 8 fail and 33 have nothing to measure, where it was
28, 10 and 33: invoice-payments and invoice-luma_studio_long failed only on
nailed drawings, while invoice-merchant sets its four aside and still fails on a
carried one. -SelfCheck runs 15 probes where it ran 10. Of eleven sabotages, nine
are each caught by the probe written for it; the other two, a drawing the reading
no longer finds no longer failing on either side, are reached by nothing, since
no document can make Word drop a shape or give two shapes one name, and that is
recorded rather than claimed.
… covered

A name Word gives to more than one drawing was reported among the drawings
whose place the page geometry does not give. The geometry is not what failed
there — the name is read as no drawing at all, so nothing was asked of the
geometry — and a reason that names the wrong cause sends the next reader after
a defect that is not there. It gets a line of its own, and the rule that holds
a document with nothing left to measure accounts for it, so such a document
fails rather than being recorded as having nothing to edit.

The order the nailed drawings are named in keyed on every digit of the line,
and the lines that carry a reason hold other numbers: "Drawing 1 stands in 2
rectangles of its own 20x10pt" sorted as 122010, behind every drawing of a
document with ten. The key now reads the first number of the line.

The counts beside the nailed roster are of the ones that found text beside
them, and are now said to be, since they do not sum to the number nailed
wherever one of them stood beside none. Every nailed drawing is named where
the sets the verdict rests on name their first three beside a count, and that
asymmetry is written down: a figure is only as good as the exclusion it was
taken over, so the exclusion is given in full.

Four rules no probe reaches are broken on purpose and recorded as caught by
nothing: a drawing the reading no longer finds no longer failing, on either
side, and the two the nailed set carries of its own — a drawing whose own text
cannot be placed again and one whose place the geometry stops giving after the
edit, both counted and reported and failing nothing. CONTRIBUTING said there
was one; the self-check roster counted fourteen probes where fifteen run; and
the CHANGELOG declared an acceptance met that a reader of this repository
cannot find. Each now says what the code does, and the CHANGELOG states the
measurement, what the figure excludes, and that 305 of 320 clears 95% by a
single drawing.

The probe switch for a page break goes with it: the probe it was added for was
measured, refused and rewritten, and nothing passes it.

-SelfCheck 15/15 and thirteen sabotages, nine caught by the probe written for
each and four reached by nothing. The corpus run is unchanged by all of this:
three runs over the 71 documents, on three builds of this change, agree on the
status and all five counts of every one of them.
…failure

The error raised when no drawing of a document was both read and found text to
stand beside carries what the reading did find, so that a shared name or a third
anchor is not named nowhere at all. It left out the drawings that stood beside
no text, which the detail does report, so that one way out of the scenario could
still lose them. Every bucket of drawings the detail reports goes into the
message now.

A nailed drawing whose place the geometry stops giving over the edit is named
with its reason, as the carried one beside it already was; only a drawing the
reading no longer finds and one whose own text cannot be placed again stay
counts, there being no reason to give for either, and that holds for both sets.

The prose is cut back to the mechanism and the measurement. What it claimed and
the code does not: that a drawing placed down from a third thing had been passed
over before, where no anchor was read at all and such a drawing was measured
against its text like any other — only a shared name was passed over; that the
nailed roster is one ordering, where it is the ones with text beside them
followed by the rest, each group ordered by the number in the name; that each
nailed drawing's own conduct is printed, where that holds for the ones that left
their text or lost their place and the rest are in the set's counts; that the
raise carries what the reading found, which is true of one of the three raises;
and that every verdict-bearing list is given as three of a stated count, which
is true of two of them. The CHANGELOG no longer reads as though a lost paragraph
fails for both sets, and names the two the nailed set is excused.
@DemchaAV
DemchaAV marked this pull request as ready for review October 30, 2026 21:22
@DemchaAV
DemchaAV merged commit c486874 into 2.5-dev Oct 30, 2026
11 checks passed
@DemchaAV
DemchaAV deleted the fix/docx-follow-text-acceptance-denominator branch October 30, 2026 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant