Repository navigation
fix(docx): hold a row's auto column's editor point in the gap after it - #948
Merged
Merged
Conversation
- A row column sized to its content is given a point for an editor's face. It came out of the row's weight columns and moved what stood right of it a point right: ReceiptModern's leaders and EditorialProposal's signature lines started 0.9 to 1pt right of the page's in Word. - The column already holds the next child's left margin, and a paragraph's own right side gives what the paragraph does not write as an indent (writtenSides, now shared with writeParagraph). A paragraph set left takes what that leaves from the gap after its column, which then stands where the page sets it. - What neither holds still comes out of the weight columns, and the row is named (right end) unless they hold only spacers or it is under a tenth of a point: ReceiptModern's amounts at the row's end and VioletGrid's section heading rules, among twenty rows nothing named before. - A rule in a row's column counts its left margin once. Counted again, CharcoalGold's heading rules started 9.25pt right of the page's in Word and VioletGrid's credential ones 12.3pt. - Measured on Windows, in Word: leaders within 0.06pt, signature lines within 0.18pt, credential rules within 0.07pt; no word moves in Word or LibreOffice. - Tests: the gap holding the point, the last column taking it from the weight column, a neighbour's margin and a paragraph's own right side as room, a thin gap, a section and a centred paragraph, the row's padding, a spacer, a tenth of a point, and a rule's margin in a row's column.
DemchaAV
marked this pull request as draft
October 23, 2026 10:06
- A row cell holds a paragraph's side at its text, so a right margin below zero gives an auto column no room: counted, a label pulled 2pt into a neighbour's 2pt margin got no point. - writtenSides names its paragraph and says a cell holds a side below zero at its text. - The rule test checks the right end of a rule in a row's column too. - The CHANGELOG, the recipe and the javadoc give ReceiptModern's amounts as measured on all eight rows, 0.84 to 1.1pt left in Word and 0.86 to 1.02pt in LibreOffice, and the leaders and signature lines 0.88 to 1.04pt right before. The CHANGELOG says no line breaks differently or moves down, and no word moves across by more than 0.4pt.
DemchaAV
marked this pull request as ready for review
October 23, 2026 10:17
This was referenced Oct 28, 2026
DemchaAV
added a commit
that referenced
this pull request
Oct 29, 2026
… a line moved (#976) * test(qa): hold the DOCX fidelity corpus to its baseline whichever way a line moved The fidelity gate failed a document only when it moved away from the page: a line more than 0.5pt further than its baseline held it, a line no longer found, or a page count further from the engine's. Measured on the gate as it stood, everything else passed in silence — a line 1.10pt nearer the page, one 5pt nearer, a page count arriving on the engine's own, a line newly found, a line more drawn on the page, and `+3.00 -> -3.00pt`, which is six points of movement that a rule comparing which of two drifts is further from the page cannot see at all, since both stand three points away. Silence there is not tidiness. A move nearer the page that nothing writes down leaves the further value in the baseline, so a later change may walk the line back to it and spend the 0.5pt on top; held that way, the Word baseline went stale in 1609 of its 5165 rows over 74 commits without one red run, 227 of them standing as much as a point nearer the page across after #944 and #948, until three documents stood 0.48pt further and the next change to touch them would have failed for drift it did not cause. So each measurement is now held as a step from where the baseline puts it: `FidelityBaseline.divergences` fails a line whose drift moves more than 0.5pt, down or across, nearer the page or further; a document the editor sets on another number of pages, or that the engine draws on another number of pages or lines; a document whose set of found lines is not the set the baseline holds; and a line the baseline holds a place across for that is measured without one. Each failure names the step and its difference, so its direction is in the message, and the remedy is in the assertion: a change that moves documents, nearer the page included, rewrites the baseline in the same commit, and that diff is the record. The slack stays one number for both directions, because it is rounding and rounding is the same size whichever way a line rounds; the row aggregates are deliberately held to nothing, since they follow from the lines, which are held one by one. The export does not change — the 71-document corpus exports byte for byte as before — and the Word baseline needs no rewrite: Word 16.0.20527 measures all 71 documents and 5165 line rows exactly as word-windows.tsv holds them, not a row differing. DocxFidelityGateTest covers each rule in both directions, 32 tests from 27, including that a step of exactly half a point is rounding for every drift from 0 to 5pt either way. Thirteen sabotages — every rule removed, and every rule that has a direction made one-sided again — were each caught by those tests. libreoffice-windows.tsv is left as it stands and named as stale instead. Neither LibreOffice baseline has been shot whole since #898, and the local run is red already under the one-sided rule: 2 documents, 8 lines no longer found, 2 page counts and 65 lines more than half a point further, 8 of them proposal-indigo's, 10.25pt lower than it holds them on the LibreOffice build the baseline names. Rewriting it here would bury a 10pt export move in a baseline diff; it wants attributing to the commit that moved it first, as the Word baseline's drift was attributed before #975 rewrote it. * test(qa): shoot the Linux LibreOffice baseline whole, and close the gate's own NaN hole The first run of the two-sided gate went red on the Linux LibreOffice baseline: 8 documents, 230 lines. Measured against the old predicate the same run is green, and of the 230 steps past the slack every one stands nearer the engine's PDF and not one further, with no line lost or gained and no page or line count moved, on the build the file names. Not shot whole since #898 and patched since only where the one-sided gate went red, the baseline was stale on 1778 of its 5149 rows purely in improvements that rule had swallowed. It is re-shot from that run, and its note records the run and the reckoning; the note explaining where cv-teal_pulse's email line stands is carried over, and three notes that only marked which run a document's rows came from are dropped, since a whole re-shoot makes them untrue. libreoffice-windows.tsv is the opposite case and is left alone, marked stale in the file rather than only in CONTRIBUTING: nothing in CI runs it, and it fails even one-sidedly on 2 documents — 8 lines no longer found, 2 page counts, 65 lines more than half a point further, 8 of them proposal-indigo's at 10.25pt on the build it names. A move further from the page wants attributing to the commit that made it before the file is shot again. Three holes the gate had, found by reading it against its own thesis: - A baseline row whose drift or place across was not a number was read, and held its line to nothing: every comparison against NaN is false, so a line 500pt from where the baseline put it produced no divergence. These files are patched by hand, so one mistyped cell was enough. Such a row is now refused, which is the mirror of the rule this change added for a measurement carrying no place across. - A rewrite dropped every hand-written note the file carried, and a rewrite is now the ordinary answer to a document moving. FidelityBaseline.write keeps them under the new header, for the author to prune. - The page's own line count was not held, so a line added to the page with the same ones found passed in silence. It is held beside the pages the engine draws. The drift figures the javadoc, the changelog and CONTRIBUTING quote were wrong and are recounted from the committed rows: of the Word baseline's 1609 stale rows, 1388 moved down the page — 717 nearer it, 635 further, 36 crossing it to stand the same distance on the other side — and 229 moved across, 228 of them nearer by as much as 1.10pt. 228 rows had moved more than the slack, 226 across and 2 down, and no row's distance from the page had grown by more than 0.41pt, which is why a rule reading distances stayed quiet. CONTRIBUTING also gains the two engine-side rules it did not list, and both it and the javadoc now say that the slack is read afresh against each rewrite and so bounds no total. 34 tests from 27, and 17 sabotages — every rule removed, every rule that has a direction made one-sided again, the non-finite refusals removed and note-keeping dropped — each caught by DocxFidelityGateTest. * test(qa): count the drift the gate's own reckoning quotes, and fail closed on both axes The figure the javadoc, the changelog and the pull request quoted for how far the stale rows had grown — 0.41pt — was the largest growth among the rows whose step passed the slack, not among the rows that moved, and it contradicted the next clause of its own sentence. Recounted from the committed rows: no row's distance from the page grew by more than 0.48pt, 21 rows of cv-serif_headline, cv-panel and invoice-obsidian by that much and the rest by 0.36pt or less, and those three documents are the ones that ended 0.48pt further. The argument is the same and now agrees with itself: 0.48 against half a point of slack is why a rule reading distances stayed quiet. Three things the gate still let through: - A measurement carrying no number for its drift down passed every rule, since Math.round(NaN) is 0 and the step against it compares false. The across axis had that guard; the down axis did not, so the mirror the last change claimed was one-sided. Both axes fail closed now. - A baseline row's median and p90 were read unchecked, and a median that is not a number reads as passing every limit it is put to. They are refused as the drift already is. - Keeping a file's notes did not reach the path the contributor is told to take: a measured run writes its own file, which carries no notes, and a run on a machine the baseline cannot be shot on is copied over the baseline from there. write takes the notes from the baseline, so the copy carries them. Where a file's header stands is now its shape rather than a guess. The header cannot be told from a note by its text — both are a # row of prose — so a note written above it could not be kept without dropping the header in its place and leaving the file naming a build it was never shot on. notesOf takes the first line to be the header and refuses a file that does not open with one. CONTRIBUTING no longer says neither LibreOffice baseline has been shot whole since #898, which the Linux one now has, and it, the changelog and the job comment name the engine's two rules in their lists. 37 tests from 27, and 20 sabotages — each rule removed, each rule that has a direction made one-sided, both NaN guards reopened, every non-finite refusal removed, note-keeping dropped from either file and the header's place made a guess — every one caught by DocxFidelityGateTest.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A row column sized to its content (
DocumentRowColumn.auto()) is given a point of slack (EDITOR_COLUMN_SLACK_POINTS). An editor setting its text in its own face would otherwise wrap it: a table of contents' label broke mid-word in LibreOffice without it.withRowEditorSlackalways took that point out of the row's weight columns. The auto column was written a point wider, and whatever stood right of it moved a point right. Nothing named it.A rule in a placed row's column also counted its left margin twice. The column already starts past the child's margin (
leftMarginInCell), andwriteRuleadded it again as the rule's indent.Measured on Windows, in Word:
ReceiptModern's 8 leadersEditorialProposal's 3 signature linesVioletGrid's credential heading rulesCharcoalGold's heading rulesWhat changed
withRowEditorSlackcounts the room an auto column already has (roomInItsColumn):CharcoalGold's heading words have the 9pt their rule stands in by, and take no point at all.EDITOR_SLACK_POINTS). A side a margin below zero pulls out stands at the cell's text, so it counts as nothing. The arithmetic is now one helper,writtenSides, shared withwriteParagraph.withoutTheRowsPadding).right end). The note is skipped where the weight columns giving it hold only spacers, or the remainder is under a tenth of a point. Twenty corpus rows are named that nothing named before:ReceiptModern's amounts at the row's end, 0.84 to 1.1pt left in Word and 0.86 to 1.02pt in LibreOffice;VioletGrid's section heading rules, a point right;SerifHeadline's section headings, Orange Ops' contact strip and Subscription's masthead.writeRulecounts a rule's left margin once in a placed row's column.ROW_AUTO_ROOM).Verification
DocxEditorSlackTest(+10 new, 3 updated):DocxRuleTest(+1): a rule with a 9pt margin in a row's column starts and ends at Word's reach in from its cell's text.VioletGrid's credential rules within 0.07pt.CharcoalGold's heading rules stand with their words, which stand 0.7pt left in both editors.EditorialProposal's "Date:" stands 0.17pt right of the page's in Word, where it stood 0.19pt left.cv-charcoal_gold,cv-violet_grid,proposal-editorial,receipt-modern). Notes go from 1365 to 1385../mvnw -B -ntp clean verify -pl <core, render-pdf, render-docx, render-pptx, templates, testing, qa, coverage> -am→ BUILD SUCCESS: core 821, render-pdf 339, render-docx 2083, testing 5, render-pptx 142, templates 127, qa 1828../mvnw -f examples/pom.xml test→ BUILD SUCCESS, 93 tests. The committedword-export-companion.docxdoes not change.Notes for review:
Lane: shared-engine (render-docx): no public API change.