Skip to content

docs(matrix): align the DOCX column with the code and map report subjects to rows - #1014

Merged
DemchaAV merged 3 commits into
2.5-devfrom
docs/docx-capability-matrix-against-code
Nov 5, 2026
Merged

DemchaAV merged 3 commits into
2.5-devfrom
docs/docx-capability-matrix-against-code

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Nov 5, 2026 •

Copy link
Copy Markdown
Owner

Why

docs/architecture/backend-capability-matrix.md is the stated source of truth for what each backend can do. Its DOCX column had drifted from the code. Some rows were false: DOCX ServiceLoader discovery was marked n/a, though DocxBackendProvider is registered, and the table-cell direction row said a cell's textAnchor reaches no cell. Some ✅ marks sat on capabilities the export reports losses for. And nothing listed the subjects DocxExportReport names, so a caller reading a note could not find the row that explains it.

Each DOCX row was checked against the code: its mark, every class, method and report subject it names, and its load-bearing claims, each at the call site or by the test that pins it. Measurements of what Word and LibreOffice do are not code and were left as they stand.

What changed

Docs only: docs/architecture/backend-capability-matrix.md, one bullet of docs/recipes/docx-export.md, and a CHANGELOG entry.

  • False claims corrected
    • ServiceLoader discovery, n/a → ✅ DocxBackendProvider, resolved by SemanticBackendProviders.forFormat. Pinned by DocxSessionExportTest#theProviderIsFoundOnTheClasspath.
    • The DocumentSession convenience row named only session.export(new DocxSemanticBackend(...)). It now names buildDocx / writeDocx / toDocxBytes on DocumentSession and MultiSectionDocument, and the MissingBackendException they raise when the backend is absent. These methods take a default backend, so they have no report sink and write live dates; the Deterministic output row now says so too.
    • Writing direction in a table cell: "Cell alignment is written on no cell" was false. applyVerticalAnchor writes w:vAlign and the paragraph gets w:jc; see DocxCellAnchorTest#eachAnchorMapsToItsWordAlignment. The Table rows row now adds that a top anchor writes no w:vAlign, since top is Word's default.
    • Rectangle shape:
      • a side border is a filled bar centred on its edge (DocxDrawings.edge), not a line;
      • the lost corner radius is named in the report for each panel (corner radius), not only logged once.
    • Intro: a shape or a path painted only with a gradient, with no outline, is reported DROPPED at its node's kind, in a table cell as anywhere (DocxRuleTest#aDividerPaintedOnlyWithAGradientIsDroppedAndNamed, DocxCarriedWithoutReportTest#aShapeComposedInACellPaintedOnlyWithAGradientIsDroppedForThat), not only logged. The SPI list gains requiresResolvedLayout().
    • Inline chips: the left padding is written in the fill of a chip right before it, when there is one (DocxInlineBackgroundTest#twoChipsSideBySideAreSpacedByBothTheirPaddings). It is read from the runs, not the lines.
    • Keep a block on one page: five places decide which rows carry w:cantSplit, not four. DocxTimelineRails comes last, and gives it back to a timeline's entry rows.
  • Marks brought to the legend (⚠️ = supported with a documented deviation):
    • ✅ → ⚠️ where the export reports a loss for the capability: anchor markers, bookmark markers, font portability, image, timeline rail, repeating headers/footers, page zones, keep together, multi-section.
    • Viewer preferences, n/a → ❌: the option reaches the semantic export and is reported.
    • Document outline, ❌ → ⚠️: bookmark levels become HeadingN styles, from which Word builds its Navigation Pane.
  • Gradient rows now say what happens to a gradient: dropped, outline kept, icon drawn flat, chart series in its first colour. Each case is named in the report.
  • New row: a node kind of the caller's own (DocumentNode with its own NodeDefinition), per backend. The DOCX cell is pinned by DocxReportedLossesTest#anUnknownNodeKindIsReportedWithWhatIsLostWithIt; the PDF and PPTX cells by their backends' Builder.addHandler and the UnsupportedNodeCapabilityException an unhandled payload throws.
  • New section: DOCX export report subjects. Every subject the export emits, with its severity, what the file holds instead, and the matrix row that explains it. The list was taken from every report.add / set / insert / replace / addTo site in render-docx, the subject resolved where it is a constant, a ternary or a node's kind.
  • Recipe: a panel's corner radius is no longer listed as left undone rather than approximated; the report names it on each panel (corner radius).

Verification

At the head ba69bdd37:

  • Full gate: the reactor clean verify as CI runs it — 5904 tests, 0 failures, 4 skipped — the four JDK 17 knowledge checks, core javadoc with 0 warnings, then install and the examples tests (93, 0 failures, CommittedAssetDriftTest included).
  • Core documentation guards: ./mvnw -B -ntp test -pl :graph-compose-core "-Dtest=com.demcha.documentation.*Test" ran 30 classes and 172 tests, with 0 failures. This includes DocumentationLinkGuardTest, which checks the new in-page anchor.
  • qa documentation guards: ./mvnw -B -ntp test -f qa/pom.xml "-Dtest=DocumentationExamplesTest,DocumentationSnippetCompileTest" ran 12 + 6 tests, with 0 failures.
  • No code changed, so the DOCX corpus output is unchanged by construction.

…report subject to its row

The DOCX column of the capability matrix had drifted from the export. The
ServiceLoader row said discovery was n/a, though DocxBackendProvider is
registered as a SemanticBackendProvider. The convenience row said the backend
is named rather than discovered, though buildDocx, writeDocx and toDocxBytes
find it. The table-cell direction row said a cell's textAnchor reaches no
cell, though it is written as w:vAlign and w:jc. A rectangle's side border is
a filled bar, not a line. The lost corner radius and a gradient-only drawing
are named in the report, not only logged. A chip's left padding goes in the
fill of a chip right before it.

Marks follow the legend: a capability the report names a loss for is ⚠️, not
✅; viewer preferences, which reach the export, are ❌; the outline is ⚠️,
since bookmark levels become HeadingN styles.

New: a row for a node kind of the caller's own, and a table mapping every
subject DocxExportReport emits to its severity, what the file holds instead
and its row. The DOCX recipe no longer lists the corner radius as left undone.
…d; complete the subject severities

A shape or path painted only with a gradient is dropped at its own node kind
in a table cell as anywhere else; only one with an outline is the table's
drawing, whose cell drawing note names the gradient. The subject table gives
timeline rail and cell drawing their DROPPED case (nothing carries them on a
page no paragraph is written on), adds the clipped <kind> fallback, the notes
a node's kind carries for a hidden drawing, an anchor with no bookmark and a
page reference written as a number, and the unmeasured overlapping layer. The
recipe says the corner radius is logged once per export, as the matrix does.
@DemchaAV DemchaAV changed the title docs(matrix): make the DOCX column agree with the code and map every report subject to its row docs(matrix): align the DOCX column with the code and map report subjects to rows Nov 5, 2026
…cover

The table's cell drawing note lists a gradient among what it does not carry, whatever the cell draws; the drawing subject's DROPPED case is for shapes no node owns; a dropped node's note carries its anchor's missing bookmark too.
@DemchaAV
DemchaAV marked this pull request as ready for review November 5, 2026 22:45
@DemchaAV
DemchaAV merged commit df2376a into 2.5-dev Nov 5, 2026
11 checks passed
@DemchaAV
DemchaAV deleted the docs/docx-capability-matrix-against-code branch November 5, 2026 22:47
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