table/read.ts's assembleBlocks reconstructs a table's shared column grid as the exact-integer union of every row's own rgdxaCenter boundary values (fixed in #895, see doc-codec's own README Tables section). That union has no tolerance: two rows that are meant to describe the identical grid but differ by even one twip, or that carry a different left inset (a real Word pattern, e.g. -108 vs 0), produce a phantom extra column and a spurious colSpan on cells in both rows, instead of recognising the rows as sharing one column layout.
Confirmed by hand-assembling bytes and comparing against #897's own head/base:
- Two rows with boundaries differing by one twip: reads back as columnWidthsPt=[50,0.05,49.95,50] (a phantom 0.05pt column) with a spurious colSpan:2 on cells in both rows, instead of [50,50,50] with no spans.
- Two rows with a different left inset (-108 vs 0): reads back as [5.4,50,100] with a spurious colSpan:2, instead of [55.4,100].
None of doc-codec's own LibreOffice-verified fixtures trip this, since LibreOffice's own writer uses identical boundaries across a table's rows -- but doc-codec has no real-world conformance corpus (its vitest.config.ts states this explicitly), so nothing else would catch a genuine third-party .doc that does vary by a twip or an inset between rows.
A fix needs a tolerance or snapping strategy for the grid union (e.g. treating two boundaries within some small twip delta as the same column) rather than raw exact-integer equality -- worth designing deliberately rather than picking an arbitrary threshold.
Not a regression: the exact-integer union in #897 is strictly better than the code it replaced for every other case tested (independent per-row layouts, vertical merges across rows with different physical cell counts, vertical-merge anchor placement). This is a pre-existing sharp edge in the reconstruction approach, surfaced by an adversarial review of #897 rather than something #897 introduced.
table/read.ts's assembleBlocks reconstructs a table's shared column grid as the exact-integer union of every row's own rgdxaCenter boundary values (fixed in #895, see doc-codec's own README Tables section). That union has no tolerance: two rows that are meant to describe the identical grid but differ by even one twip, or that carry a different left inset (a real Word pattern, e.g. -108 vs 0), produce a phantom extra column and a spurious colSpan on cells in both rows, instead of recognising the rows as sharing one column layout.
Confirmed by hand-assembling bytes and comparing against #897's own head/base:
None of doc-codec's own LibreOffice-verified fixtures trip this, since LibreOffice's own writer uses identical boundaries across a table's rows -- but doc-codec has no real-world conformance corpus (its vitest.config.ts states this explicitly), so nothing else would catch a genuine third-party .doc that does vary by a twip or an inset between rows.
A fix needs a tolerance or snapping strategy for the grid union (e.g. treating two boundaries within some small twip delta as the same column) rather than raw exact-integer equality -- worth designing deliberately rather than picking an arbitrary threshold.
Not a regression: the exact-integer union in #897 is strictly better than the code it replaced for every other case tested (independent per-row layouts, vertical merges across rows with different physical cell counts, vertical-merge anchor placement). This is a pre-existing sharp edge in the reconstruction approach, surfaced by an adversarial review of #897 rather than something #897 introduced.