@beyondwork/docx-react-component 1.0.105 → 1.0.108

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/package.json +19 -5
  2. package/src/api/geometry-overlay-rects.ts +5 -0
  3. package/src/api/package-version.ts +1 -1
  4. package/src/api/page-anchor-id.ts +5 -0
  5. package/src/api/public-types.ts +16 -9
  6. package/src/api/table-node-specs.ts +6 -0
  7. package/src/api/v3/_create.ts +10 -2
  8. package/src/api/v3/_page-anchor-id.ts +52 -0
  9. package/src/api/v3/_runtime-handle.ts +92 -1
  10. package/src/api/v3/ai/_audit-reference.ts +28 -0
  11. package/src/api/v3/ai/_audit-time.ts +5 -0
  12. package/src/api/v3/ai/_pe2-evidence.ts +310 -6
  13. package/src/api/v3/ai/attach.ts +29 -4
  14. package/src/api/v3/ai/bundle.ts +6 -2
  15. package/src/api/v3/ai/inspect.ts +6 -2
  16. package/src/api/v3/ai/replacement.ts +112 -18
  17. package/src/api/v3/ai/resolve.ts +2 -2
  18. package/src/api/v3/ai/review.ts +177 -3
  19. package/src/api/v3/index.ts +8 -0
  20. package/src/api/v3/runtime/collab.ts +462 -0
  21. package/src/api/v3/runtime/document.ts +503 -20
  22. package/src/api/v3/runtime/geometry.ts +97 -0
  23. package/src/api/v3/runtime/layout.ts +744 -0
  24. package/src/api/v3/runtime/perf-probe.ts +14 -0
  25. package/src/api/v3/runtime/viewport.ts +9 -8
  26. package/src/api/v3/ui/_types.ts +202 -55
  27. package/src/api/v3/ui/chrome-preset-model.ts +5 -5
  28. package/src/api/v3/ui/debug.ts +115 -2
  29. package/src/api/v3/ui/index.ts +17 -0
  30. package/src/api/v3/ui/overlays.ts +0 -8
  31. package/src/api/v3/ui/surface.ts +56 -0
  32. package/src/api/v3/ui/viewport.ts +119 -9
  33. package/src/core/commands/image-commands.ts +1 -0
  34. package/src/core/commands/index.ts +6 -0
  35. package/src/core/schema/text-schema.ts +43 -5
  36. package/src/core/selection/mapping.ts +8 -1
  37. package/src/core/selection/review-anchors.ts +5 -1
  38. package/src/core/state/text-transaction.ts +8 -2
  39. package/src/io/export/serialize-revisions.ts +149 -1
  40. package/src/io/normalize/normalize-text.ts +6 -0
  41. package/src/io/ooxml/parse-bookmark-references.ts +55 -0
  42. package/src/io/ooxml/parse-fields.ts +24 -2
  43. package/src/io/ooxml/parse-headers-footers.ts +38 -5
  44. package/src/io/ooxml/parse-main-document.ts +153 -9
  45. package/src/io/ooxml/parse-numbering.ts +20 -0
  46. package/src/io/ooxml/parse-revisions.ts +19 -8
  47. package/src/io/opc/package-reader.ts +98 -8
  48. package/src/model/anchor.ts +4 -3
  49. package/src/model/canonical-document.ts +220 -2
  50. package/src/model/canonical-hash.ts +221 -0
  51. package/src/model/canonical-layout-inputs.ts +245 -6
  52. package/src/model/layout/index.ts +1 -0
  53. package/src/model/layout/page-graph-types.ts +147 -1
  54. package/src/model/review/revision-types.ts +14 -3
  55. package/src/preservation/store.ts +20 -4
  56. package/src/review/README.md +1 -1
  57. package/src/review/store/revision-actions.ts +14 -2
  58. package/src/runtime/collab/event-types.ts +67 -1
  59. package/src/runtime/collab/runtime-collab-sync.ts +177 -5
  60. package/src/runtime/diagnostics/layout-guard-warning.ts +18 -0
  61. package/src/runtime/document-heading-outline.ts +147 -0
  62. package/src/runtime/document-navigation.ts +8 -243
  63. package/src/runtime/document-runtime.ts +279 -115
  64. package/src/runtime/edit-dispatch/dispatch-text-command.ts +11 -0
  65. package/src/runtime/formatting/layout-inputs.ts +38 -5
  66. package/src/runtime/formatting/numbering/geometry.ts +28 -2
  67. package/src/runtime/geometry/adjacent-geometry-intake.ts +835 -0
  68. package/src/runtime/geometry/caret-geometry.ts +5 -6
  69. package/src/runtime/geometry/geometry-facet.ts +60 -10
  70. package/src/runtime/geometry/geometry-index.ts +661 -16
  71. package/src/runtime/geometry/geometry-types.ts +59 -0
  72. package/src/runtime/geometry/hit-test.ts +11 -1
  73. package/src/runtime/geometry/overlay-rects.ts +5 -3
  74. package/src/runtime/geometry/project-anchors.ts +1 -1
  75. package/src/runtime/geometry/word-layout-v2-line-intake.ts +323 -0
  76. package/src/runtime/layout/index.ts +6 -0
  77. package/src/runtime/layout/layout-engine-instance.ts +6 -1
  78. package/src/runtime/layout/layout-engine-version.ts +188 -16
  79. package/src/runtime/layout/layout-facet-types.ts +6 -0
  80. package/src/runtime/layout/page-graph.ts +23 -4
  81. package/src/runtime/layout/paginated-layout-engine.ts +149 -15
  82. package/src/runtime/layout/project-block-fragments.ts +351 -14
  83. package/src/runtime/layout/public-facet.ts +162 -24
  84. package/src/runtime/layout/table-row-continuation-contract.ts +107 -0
  85. package/src/runtime/layout/table-row-split.ts +92 -35
  86. package/src/runtime/prerender/cache-envelope.ts +2 -2
  87. package/src/runtime/prerender/cache-key.ts +5 -4
  88. package/src/runtime/prerender/customxml-cache.ts +0 -1
  89. package/src/runtime/render/render-kernel.ts +1 -1
  90. package/src/runtime/revision-runtime.ts +112 -10
  91. package/src/runtime/scopes/_scope-dependencies.ts +1 -0
  92. package/src/runtime/scopes/action-validation.ts +22 -2
  93. package/src/runtime/scopes/capabilities.ts +316 -0
  94. package/src/runtime/scopes/compile-scope-bundle.ts +14 -0
  95. package/src/runtime/scopes/compiler-service.ts +108 -4
  96. package/src/runtime/scopes/content-control-evidence.ts +79 -0
  97. package/src/runtime/scopes/create-issue.ts +5 -5
  98. package/src/runtime/scopes/evidence.ts +91 -0
  99. package/src/runtime/scopes/formatting/apply.ts +2 -0
  100. package/src/runtime/scopes/geometry-evidence.ts +130 -0
  101. package/src/runtime/scopes/index.ts +54 -0
  102. package/src/runtime/scopes/issue-lifecycle.ts +224 -0
  103. package/src/runtime/scopes/layout-evidence.ts +374 -0
  104. package/src/runtime/scopes/multi-paragraph-refusal.ts +37 -0
  105. package/src/runtime/scopes/preservation-boundary.ts +7 -1
  106. package/src/runtime/scopes/replacement/apply.ts +97 -34
  107. package/src/runtime/scopes/scope-kinds/paragraph.ts +108 -12
  108. package/src/runtime/scopes/semantic-scope-types.ts +242 -3
  109. package/src/runtime/scopes/visualization.ts +28 -0
  110. package/src/runtime/surface-projection.ts +44 -5
  111. package/src/runtime/telemetry/perf-probe.ts +216 -0
  112. package/src/runtime/virtualized-rendering.ts +36 -1
  113. package/src/runtime/workflow/ai-issue-lifecycle.ts +253 -0
  114. package/src/runtime/workflow/coordinator.ts +39 -11
  115. package/src/runtime/workflow/derived-scope-resolver.ts +63 -9
  116. package/src/runtime/workflow/index.ts +4 -0
  117. package/src/runtime/workflow/overlay-lane-types.ts +58 -0
  118. package/src/runtime/workflow/overlay-lanes.ts +386 -0
  119. package/src/runtime/workflow/overlay-store.ts +2 -2
  120. package/src/runtime/workflow/redline-posture-calibration.ts +257 -0
  121. package/src/runtime/workflow/word-field-matrix-calibration.ts +231 -0
  122. package/src/session/_sync-legacy.ts +17 -27
  123. package/src/session/import/loader.ts +6 -4
  124. package/src/session/import/source-package-evidence.ts +186 -2
  125. package/src/session/index.ts +5 -6
  126. package/src/session/session.ts +30 -56
  127. package/src/session/types.ts +8 -13
  128. package/src/shell/session-bootstrap.ts +155 -81
  129. package/src/ui/WordReviewEditor.tsx +520 -12
  130. package/src/ui/editor-shell-view.tsx +14 -4
  131. package/src/ui/editor-surface-controller.tsx +5 -3
  132. package/src/ui/headless/selection-tool-resolver.ts +1 -2
  133. package/src/ui/presence-overlay-lane.ts +130 -0
  134. package/src/ui/ui-controller-factory.ts +17 -0
  135. package/src/ui-tailwind/chrome/build-context-menu-entries.ts +5 -1
  136. package/src/ui-tailwind/chrome/editor-action-registry.ts +105 -5
  137. package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +7 -0
  138. package/src/ui-tailwind/chrome/layer-debug-contracts.ts +208 -0
  139. package/src/ui-tailwind/chrome/resolve-target-kind.ts +13 -0
  140. package/src/ui-tailwind/chrome/tw-alert-banner.tsx +11 -3
  141. package/src/ui-tailwind/chrome/tw-command-palette.tsx +36 -6
  142. package/src/ui-tailwind/chrome/tw-context-menu.tsx +6 -1
  143. package/src/ui-tailwind/chrome/tw-display-mode-selector.tsx +42 -109
  144. package/src/ui-tailwind/chrome/tw-inline-find-bar.tsx +26 -6
  145. package/src/ui-tailwind/chrome/tw-navigation-command-bar.tsx +328 -0
  146. package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +8 -4
  147. package/src/ui-tailwind/chrome/tw-runtime-repl-dialog.tsx +129 -1
  148. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +19 -5
  149. package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +5 -1
  150. package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +28 -12
  151. package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +30 -3
  152. package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +116 -10
  153. package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +223 -94
  154. package/src/ui-tailwind/chrome-overlay/tw-presence-overlay-lane.tsx +157 -0
  155. package/src/ui-tailwind/chrome-overlay/tw-review-overlay-lane-markers.tsx +259 -0
  156. package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +5 -2
  157. package/src/ui-tailwind/chrome-overlay/tw-substrate-overlay-lanes.tsx +314 -0
  158. package/src/ui-tailwind/debug/README.md +4 -1
  159. package/src/ui-tailwind/debug/layer11-consumer-readiness.ts +272 -0
  160. package/src/ui-tailwind/debug/layer11-word-field-matrix-evidence.ts +160 -0
  161. package/src/ui-tailwind/editor-surface/perf-probe.ts +14 -215
  162. package/src/ui-tailwind/editor-surface/pm-decorations.ts +42 -0
  163. package/src/ui-tailwind/editor-surface/pm-position-map.ts +38 -2
  164. package/src/ui-tailwind/editor-surface/pm-schema.ts +14 -4
  165. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +34 -5
  166. package/src/ui-tailwind/editor-surface/runtime-decoration-plugin.ts +9 -19
  167. package/src/ui-tailwind/editor-surface/surface-build-keys.ts +2 -2
  168. package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +145 -0
  169. package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +16 -11
  170. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +8 -10
  171. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +3 -0
  172. package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +4 -2
  173. package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +60 -20
  174. package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +16 -11
  175. package/src/ui-tailwind/review/tw-health-panel.tsx +36 -17
  176. package/src/ui-tailwind/review/tw-review-rail.tsx +7 -4
  177. package/src/ui-tailwind/review-workspace/diagnostics-visibility.ts +44 -0
  178. package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +11 -0
  179. package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +16 -1
  180. package/src/ui-tailwind/review-workspace/types.ts +26 -12
  181. package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +40 -11
  182. package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +2 -1
  183. package/src/ui-tailwind/review-workspace/use-page-markers.ts +15 -26
  184. package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +35 -18
  185. package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +41 -32
  186. package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +2 -1
  187. package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +2 -1
  188. package/src/ui-tailwind/status/tw-status-bar.tsx +6 -5
  189. package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +52 -80
  190. package/src/ui-tailwind/toolbar/tw-shell-header.tsx +12 -48
  191. package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +9 -4
  192. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +328 -361
  193. package/src/ui-tailwind/tw-review-workspace.tsx +152 -286
@@ -1,18 +1,20 @@
1
1
  /**
2
- * Layout engine version markerbump when **any** file under
3
- * `src/runtime/layout/**` or `src/runtime/render/**` changes, or when
4
- * the page-break widget DOM shape under `src/ui-tailwind/editor-surface/`
5
- * changes in a way that affects cached render-frame diffs or persisted
6
- * layout caches.
2
+ * Layout engine version markersco-touch this file when **any** file under
3
+ * `src/runtime/layout/**` or `src/runtime/render/**` changes, or when the
4
+ * page-break widget DOM shape under `src/ui-tailwind/editor-surface/` changes
5
+ * in a way that affects render-frame diffs or persisted layout caches.
7
6
  *
8
7
  * Enforcement: `scripts/ci-check-layout-engine-version.mjs` inspects the
9
- * PR diff; if any file in the watched trees is touched without this
10
- * constant being co-touched, CI fails. See CLAUDE.md → *Performance
8
+ * PR diff; if any file in the watched trees is touched without this file
9
+ * being co-touched, CI fails. See CLAUDE.md → *Performance
11
10
  * Invariants* for the full contract.
12
11
  *
13
- * Persisted caches should key their stored snapshots on this version so a
14
- * bump automatically invalidates stale entries no corruption path
15
- * exists because the version is the cache's top-level discriminator.
12
+ * `LAYOUT_ENGINE_VERSION` is the layout-output correctness discriminator used
13
+ * by persisted laycache envelopes, projection, telemetry, debug, and public
14
+ * layout readers. Bump it when the same canonical input can produce different
15
+ * pagination, graph semantics, measurement/page geometry, render-frame output,
16
+ * or cache-key semantics. When only the laycache envelope or cached payload
17
+ * shape grows, leave this value alone and bump `LAYCACHE_SCHEMA_VERSION`.
16
18
  *
17
19
  * History:
18
20
  * 1 — initial materialization (L8 Phase B).
@@ -1074,14 +1076,172 @@
1074
1076
  * table header rows, and vertical-merge carry metadata. Cache envelopes
1075
1077
  * from v67 invalidate because fragment payloads can now include
1076
1078
  * continuation state. Shipped via pe2 commit `33fbf45ac`.
1079
+ *
1080
+ * 69 — PE2 Slice 3 measured layout-object descriptors (Layer 04). Body
1081
+ * fragments and footnote-area fragments now carry a twips/plain
1082
+ * `layoutObject` row with stable object id, source block id, object kind,
1083
+ * pagination role, measured extent, and field-family hints where applicable.
1084
+ * Cache envelopes from v68 invalidate because fragment payloads can now
1085
+ * include layout-object descriptors. Shipped via pe2 commit `9c4417418`.
1086
+ *
1087
+ * 70 — PE2 review follow-up: page-local header/footer anchored-object
1088
+ * ledgers now mint instance-stable object ids for reused image/drawing
1089
+ * relationships and keep media/blip references as metadata. Cache
1090
+ * envelopes from v69 invalidate because page-frame object ids, signatures,
1091
+ * and divergence ids can change when a story reuses the same image
1092
+ * relationship. Shipped via pe2 commit `788bebef3`.
1093
+ *
1094
+ * 71 — PE2 Slice 1 cleanup: the standalone document navigation snapshot
1095
+ * adapter now delegates page stack and active-page derivation to the L04
1096
+ * layout engine graph instead of running its own `buildPageStack` path.
1097
+ * Cache envelopes from v70 invalidate because public navigation snapshots
1098
+ * are now sourced from graph-derived page truth. Shipped via pe2 commit
1099
+ * `cfd568942`.
1100
+ *
1101
+ * 72 — PE2 Slice 2 public graph surface: `PublicPageLocalStoryInstance`
1102
+ * now publishes the graph-owned `resolvedFields` ledger for page-local
1103
+ * header/footer PAGE / NUMPAGES / SECTIONPAGES fields. Cache envelopes
1104
+ * from v71 invalidate so public page-frame consumers cannot observe the
1105
+ * old story projection shape. Shipped via pe2 commit `e887a042d`.
1106
+ *
1107
+ * 73 — PE2 Slice 4 public divergence handles: `PublicLayoutDivergence`
1108
+ * now publishes graph-owned `objectIds` for object-scoped divergences
1109
+ * such as unsupported wrap and preserve-only placeholders. Cache envelopes
1110
+ * from v72 invalidate so public consumers can join divergence rows back
1111
+ * to page-local anchored-object ledgers without reconstructing ids.
1112
+ * Shipped via pe2 commit `e39766d6b`.
1113
+ *
1114
+ * 74 — Ship-side rollup: pe2 commits b58c0d45c (collapsed-selection
1115
+ * caret rect now carries an explicit `precision: "exact"` tag) and
1116
+ * de9b32423 (page-overlay rect projection requires complete frame
1117
+ * geometry) changed geometry projections without bumping the engine
1118
+ * version on pe2. Cache envelopes from v73 invalidate so persisted
1119
+ * selection-rect / page-overlay payloads cannot leak the older
1120
+ * precision-tag and overlay shapes through.
1121
+ *
1122
+ * 75 — Ship-side rollup: pe2 commit d4ac70a06 ("fix(05): tag anchor
1123
+ * hit target rects") added precision tagging to anchor hit-target
1124
+ * rects in `geometry-index.ts` + `hit-test.ts` without bumping the
1125
+ * engine version on pe2. Cache envelopes from v74 invalidate so
1126
+ * persisted hit-target payloads cannot leak the older untagged
1127
+ * shape through.
1128
+ *
1129
+ * 76 — KI-005 precision-geometry prerequisite: fragment layout-object rows
1130
+ * for numbered paragraphs now carry resolved numbering source facts
1131
+ * (marker text/suffix, list instance + level, marker lane, text column, tab
1132
+ * stops, and marker justification) as twips/plain graph truth. Cache
1133
+ * envelopes from v75 invalidate because fragment payloads can now include
1134
+ * numbering facts consumed by geometry/debug projections. Shipped via pe2
1135
+ * commit `8ff418fed`.
1136
+ *
1137
+ * 77 — PE2 L07 blocker service: public page-frame records now carry an
1138
+ * explicit `completeness` discriminator (`complete` / `partial` / `absent`)
1139
+ * derived from the L04 twips region ledger. Cache envelopes from v76
1140
+ * invalidate so runtime/API consumers can distinguish realized empty
1141
+ * page-local story ledgers from missing frame substrate. Shipped via pe2
1142
+ * commits `96b89b221` + `da704503b`.
1143
+ *
1144
+ * 78 — Ship-side rollup: pe2 commit 2b2cd7c2f ("feat(04): expose page-local
1145
+ * object wrap evidence") added a `wrapMode` field to page-local
1146
+ * anchored-object rows in the runtime graph and public page-frame surface,
1147
+ * plus pe2 commits 8d94bb10e and 246b2d299 (event telemetry / export safety)
1148
+ * that brushed `src/runtime/layout/page-graph.ts` and `public-facet.ts`,
1149
+ * without bumping the engine version on pe2. Cache envelopes from v77
1150
+ * invalidate so persisted page-frame story signatures and anchored-object
1151
+ * payloads cannot leak the older shape through.
1152
+ *
1153
+ * 79 — Ship-side rollup: pe2 commit 6389423bb ("perf(05): avoid duplicate
1154
+ * marker projection") changed how geometry coverage summaries read
1155
+ * numbering-marker precision/status metadata without rebuilding the marker
1156
+ * rect projection solely for counts; pe2 also brushed
1157
+ * `src/runtime/layout/public-facet.ts` via 6fcf11477 ("Route L04 oracle
1158
+ * unlock evidence work") without bumping on pe2. Pixel geometry is
1159
+ * unchanged, but geometry is a watched runtime projection surface, so the
1160
+ * version advances with the implementation slice. Cache envelopes from v78
1161
+ * invalidate.
1162
+ *
1163
+ * 80 — Ship-side rollup: pe2 commit b76c9a026 ("test(05): harden geometry
1164
+ * cleanup slice") brushed `src/runtime/layout/public-facet.ts` and the
1165
+ * layout-guard diagnostics helper as part of the L05 guard-warning
1166
+ * dependency cleanup. The pe2 history-block bumped to v76 in isolation, but
1167
+ * ship-preview is already at v79, so this rollup advances to v80 to keep
1168
+ * persisted laycache envelopes from leaking the older facet shape through.
1169
+ * Pixel geometry is unchanged.
1170
+ *
1171
+ * 81 — Ship-side rollup: pe2 commit 118171efd ("feat(10): add object drag
1172
+ * lifecycle") added a UI API drag session for mounted object handles
1173
+ * (update/commit/cancel) and commits image resize/reposition through the
1174
+ * existing runtime mutation path. Layout geometry is invalidated by those
1175
+ * committed mutations; the pe2 history-block bumped to v77 in isolation, so
1176
+ * ship-preview's rollup advances to v81. Cache envelopes from v80
1177
+ * invalidate so object-handle chrome cannot replay against a pre-lifecycle
1178
+ * surface.
1179
+ *
1180
+ * 82 — Ship-side rollup: pe2 commit 348fcaf66 ("feat(05): clip table geometry
1181
+ * to continuation rows") brushed `src/runtime/geometry/geometry-index.ts`
1182
+ * to clip table geometry to continuation rows, without bumping on pe2.
1183
+ * `src/runtime/geometry/**` is in the CI guard's watched-prefixes set; cache
1184
+ * envelopes from v81 invalidate so persisted geometry projections cannot
1185
+ * replay against the pre-clipping shape.
1186
+ *
1187
+ * 83 — Ship-side rollup: pe2 commits cf6f54878 ("Add L04 D-8 table split-row
1188
+ * contract") + b704efa82 ("Implement L04 split-row carry slices") added L04
1189
+ * D-8 table split-row carry: table pagination can now include a splittable
1190
+ * overflowing row on both adjacent row slices, with typed `splitRowCarry`
1191
+ * continuation metadata and runtime projection overlap readbacks. The pe2
1192
+ * history-block bumped to v78 in isolation; ship-preview's rollup advances
1193
+ * to v83. Cache envelopes from v82 invalidate because table fragment row
1194
+ * ranges and continuation cursor payloads can change for splittable
1195
+ * cross-page rows.
1196
+ *
1197
+ * 84 — Ship-side rollup: pe2 commit 763047797 ("Calibrate L04 auto-height
1198
+ * table splits") landed L04 D-8 auto-height table calibration: table row
1199
+ * pagination now uses resolved cell-content height only for materially
1200
+ * taller auto-height rows in non-repeated-header tables, and uses that
1201
+ * calibrated height to emit bounded split-row carry on CCEP D-8 targets.
1202
+ * The pe2 history-block bumped to v79 in isolation; ship-preview's rollup
1203
+ * advances to v84. Cache envelopes from v83 invalidate because auto-height
1204
+ * table row ranges and continuation cursor payloads can change.
1205
+ *
1206
+ * 85 — Ship-side rollup: pe2 commit a1b4a2e10 ("Carry default table rows
1207
+ * across pages") landed L04 D-8 default table-row carry: default
1208
+ * non-`cantSplit` / non-`exact` rows can now emit split-row carry, matching
1209
+ * Word's default row-break posture for newly unlocked clean D-8 table data
1210
+ * without broadening the resolved-height calibration gate. The pe2
1211
+ * history-block bumped to v80 in isolation; ship-preview's rollup advances
1212
+ * to v85. Cache envelopes from v84 invalidate because table row ranges and
1213
+ * continuation cursor payloads can change.
1214
+ *
1215
+ * 86 — Ship-side rollup: pe2 commits 3458b8c53 ("feat(05): expose table
1216
+ * split row carry geometry") + 68e9e8528 ("feat(05): ingest word layout
1217
+ * line geometry") + 089536b59 ("perf(05): cache geometry index
1218
+ * projection") + 805b42af5 ("fix(l11): relocate perf probe telemetry")
1219
+ * brushed `src/runtime/geometry/**` and `src/runtime/render/**` without
1220
+ * bumping on pe2. The pe2 history-block stayed at v80; ship-preview's
1221
+ * rollup advances to v86. Cache envelopes from v85 invalidate because
1222
+ * geometry projections (split-row carry geometry, word layout line
1223
+ * geometry, cached geometry index) and render-side perf probe telemetry
1224
+ * shapes can change.
1225
+ *
1226
+ * 87 — Ship-side rollup: pe2 commit a4dc6f6a3 ("Close L04 final-gap D8
1227
+ * table behavior") landed L04 final-gap D-8 table behavior — long
1228
+ * non-header auto tables now get a bounded per-row soft content-height
1229
+ * allowance, and long compact authored-height tables cap dense auto rows
1230
+ * while suppressing synthetic header reservation for split math. This
1231
+ * moves the repaired clean D-8 table candidates toward Word row ranges
1232
+ * without applying broad resolved heights to every long table. The pe2
1233
+ * history-block bumped to v81 in isolation; ship-preview's rollup advances
1234
+ * to v87. Cache envelopes from v86 invalidate because table row ranges and
1235
+ * continuation cursor payloads can change.
1077
1236
  */
1078
- export const LAYOUT_ENGINE_VERSION = 68 as const;
1237
+ export const LAYOUT_ENGINE_VERSION = 87 as const;
1079
1238
 
1080
1239
  /**
1081
- * Serialization schema version for the LayCache payload (the cache envelope
1082
- * stored in IndexedDB, and post Plan B the customXml editor-state
1083
- * namespace). Bump independently of LAYOUT_ENGINE_VERSION when the
1084
- * envelope shape changes but the layout engine itself has not.
1240
+ * Serialization schema version for the LayCache envelope and cached payload
1241
+ * shape. This is the cache-shape discriminator for IndexedDB and customXml
1242
+ * laycache entries. Bump independently of `LAYOUT_ENGINE_VERSION` when the
1243
+ * envelope shape or cached graph/surface payload grows, but the same canonical
1244
+ * input would still produce layout-compatible pagination output.
1085
1245
  *
1086
1246
  * History:
1087
1247
  * 1 — initial envelope shape: { schemaVersion, engineVersion,
@@ -1103,5 +1263,17 @@ export const LAYOUT_ENGINE_VERSION = 68 as const;
1103
1263
  * written without the report are still valid; readers fall through
1104
1264
  * to the live `buildCompatibilityReport` call. v2 envelopes are
1105
1265
  * rejected cleanly on v3 readers (schemaVersion mismatch).
1266
+ * 4 — Pass-8 versioning discipline: graph/surface payload-shape changes now
1267
+ * route here instead of a separate cache-engine discriminator. The
1268
+ * envelope still stores `engineVersion`, but that field is the
1269
+ * `LAYOUT_ENGINE_VERSION` correctness tag for layout-output changes.
1270
+ * Additive cached-payload fields route to this schema discriminator.
1271
+ * 5 — L04 field-region runtime readback: fragment layout objects can now
1272
+ * carry source/canonical field-region identities for Debug/L05 joins.
1273
+ * Pagination output is unchanged, but cached graph payload shape grows.
1274
+ * 6 — L04 numbering runtime readback: fragment layout objects can now carry
1275
+ * `numberingRows[]` for all numbered paragraphs represented by the
1276
+ * fragment, including table/SDT-nested paragraphs. Pagination output is
1277
+ * unchanged, but cached graph payload shape grows.
1106
1278
  */
1107
- export const LAYCACHE_SCHEMA_VERSION = 3 as const;
1279
+ export const LAYCACHE_SCHEMA_VERSION = 6 as const;
@@ -44,14 +44,20 @@ export type {
44
44
  PublicLineBox,
45
45
  PublicNoteAllocation,
46
46
  PublicPageAnchor,
47
+ PublicPageFrame,
48
+ PublicPageLocalStoryInstance,
47
49
  PublicPageSpan,
48
50
  PublicSectionNode,
49
51
  PublicResolvedPageStories,
52
+ PublicResolvedStoryField,
50
53
  PublicResolvedParagraphFormatting,
51
54
  PublicResolvedRunFormatting,
55
+ PublicStoryAnchoredObject,
56
+ PublicTwipsRect,
52
57
  PublicBlockMeasurement,
53
58
  PublicMeasurementFidelity,
54
59
  PublicFieldDirtinessReport,
60
+ PublicLayoutDivergence,
55
61
 
56
62
  // Events + invalidation ----------------------------------------------
57
63
  LayoutFacetEvent,
@@ -65,6 +65,7 @@ export type {
65
65
  RuntimeLayoutDivergenceKind,
66
66
  RuntimeLayoutDivergence,
67
67
  RuntimePageFrame,
68
+ RuntimePageFrameCompleteness,
68
69
  RuntimePageLocalStoryInstance,
69
70
  RuntimeResolvedStoryField,
70
71
  RuntimeStoryAnchoredObject,
@@ -72,6 +73,8 @@ export type {
72
73
  RuntimeParagraphContinuationCursor,
73
74
  RuntimeTableContinuationCursor,
74
75
  RuntimeTableVerticalMergeCarry,
76
+ RuntimeFragmentLayoutObjectKind,
77
+ RuntimeFragmentLayoutObject,
75
78
  RuntimeBlockFragment,
76
79
  RuntimeLineBox,
77
80
  RuntimeNoteAllocation,
@@ -451,6 +454,7 @@ function buildPageFrame(input: {
451
454
  const divergences = [...input.divergences, ...pageLocalStoryResult.divergences];
452
455
  const pageLocalStories = pageLocalStoryResult.instances;
453
456
  const divergenceIds = divergences.map((d) => d.divergenceId);
457
+ const completeness = resolvePageFrameCompleteness(regions);
454
458
  return {
455
459
  frame: {
456
460
  frameId: input.frameId,
@@ -458,6 +462,7 @@ function buildPageFrame(input: {
458
462
  pageIndex: input.pageIndex,
459
463
  sectionIndex: input.sectionIndex,
460
464
  displayPageNumber: input.displayPageNumber,
465
+ completeness,
461
466
  physicalBoundsTwips: rect(0, 0, input.layout.pageWidth, input.layout.pageHeight),
462
467
  regions,
463
468
  pageLocalStories,
@@ -613,6 +618,8 @@ function buildPageLocalStorySignature(input: {
613
618
  object.extentTwips?.widthTwips ?? "",
614
619
  object.extentTwips?.heightTwips ?? "",
615
620
  object.relationshipIds?.join(",") ?? "",
621
+ object.mediaIds?.join(",") ?? "",
622
+ object.wrapMode ?? "",
616
623
  object.preserveOnly ? "preserve-only" : "renderable",
617
624
  object.divergenceIds.join(","),
618
625
  ].join(":"),
@@ -738,7 +745,6 @@ function collectStoryAnchoredObjects(
738
745
  object: Omit<RuntimeStoryAnchoredObject, "objectId" | "divergenceIds"> & {
739
746
  objectId?: string;
740
747
  preserveHint?: PreserveOnlyObjectSizing;
741
- wrapMode?: string;
742
748
  },
743
749
  ): void => {
744
750
  const objectId =
@@ -780,7 +786,7 @@ function collectStoryAnchoredObjects(
780
786
  });
781
787
  }
782
788
 
783
- const { preserveHint: _preserveHint, wrapMode: _wrapMode, ...ledger } = object;
789
+ const { preserveHint: _preserveHint, ...ledger } = object;
784
790
  objects.push({
785
791
  ...ledger,
786
792
  objectId,
@@ -813,9 +819,10 @@ function collectStoryAnchoredObjects(
813
819
  switch (inline.type) {
814
820
  case "image": {
815
821
  pushObject({
816
- objectId: inline.mediaId,
822
+ objectId: `${context.storyKey}:image-${ordinal}`,
817
823
  sourceType: "image",
818
824
  display: inline.display === "floating" ? "floating" : "inline",
825
+ mediaIds: [inline.mediaId],
819
826
  preserveOnly: false,
820
827
  wrapMode: inline.floating?.wrap,
821
828
  });
@@ -834,6 +841,9 @@ function collectStoryAnchoredObjects(
834
841
  inline.anchor.extent.heightEmu,
835
842
  ),
836
843
  ...(relationshipIds.length > 0 ? { relationshipIds } : {}),
844
+ ...(inline.content.type === "picture" && inline.content.mediaId
845
+ ? { mediaIds: [inline.content.mediaId] }
846
+ : {}),
837
847
  preserveOnly: Boolean(preserveHint),
838
848
  ...(preserveHint ? { preserveHint } : {}),
839
849
  wrapMode: inline.anchor.wrapMode,
@@ -927,7 +937,7 @@ function getDrawingFrameObjectId(
927
937
  ordinal: number,
928
938
  ): string {
929
939
  if (inline.anchor.docPr?.id) return `${storyKey}:drawing-${inline.anchor.docPr.id}`;
930
- if (inline.content.type === "picture") return `${storyKey}:picture-${inline.content.blipRef}`;
940
+ if (inline.content.type === "picture") return `${storyKey}:picture-${ordinal}:${inline.content.blipRef}`;
931
941
  return `${storyKey}:drawing-${ordinal}`;
932
942
  }
933
943
 
@@ -1051,6 +1061,7 @@ function buildPageFrameSignature(
1051
1061
  });
1052
1062
  return [
1053
1063
  "page-frame",
1064
+ resolvePageFrameCompleteness(input.regions),
1054
1065
  input.pageIndex,
1055
1066
  input.sectionIndex,
1056
1067
  input.displayPageNumber,
@@ -1062,6 +1073,14 @@ function buildPageFrameSignature(
1062
1073
  ].join("|");
1063
1074
  }
1064
1075
 
1076
+ function resolvePageFrameCompleteness(
1077
+ regions: RuntimePageRegions,
1078
+ ): RuntimePageFrame["completeness"] {
1079
+ return collectRegions(regions).every((region) => region.rectTwips !== undefined)
1080
+ ? "complete"
1081
+ : "partial";
1082
+ }
1083
+
1065
1084
  function detectFrameDivergences(
1066
1085
  frameId: string,
1067
1086
  regions: RuntimePageRegions,
@@ -86,6 +86,7 @@ import {
86
86
  computeRepeatedHeaderHeight,
87
87
  extractRowFlags,
88
88
  findTableRowSplit,
89
+ measureTableRowHeightProfile,
89
90
  measureTableRowHeights,
90
91
  } from "./table-row-split.ts";
91
92
 
@@ -998,6 +999,9 @@ export function requiresFullRecompute(reason: LayoutInvalidationReason): boolean
998
999
 
999
1000
  const MIN_BLOCK_HEIGHT_TWIPS = 240;
1000
1001
  const FOOTNOTE_REFERENCE_RESERVATION_TWIPS = 180;
1002
+ const MIN_SPLIT_ROW_FRAGMENT_TWIPS = 720;
1003
+ const LONG_TABLE_SOFT_AUTO_ROW_DELTA_TWIPS = 60;
1004
+ const COMPACT_AUTHORED_ROW_HEIGHT_TWIPS = 1500;
1001
1005
 
1002
1006
  /**
1003
1007
  * Per-invocation measurement cache keyed by `(block, columnWidth)`.
@@ -1508,6 +1512,36 @@ interface SectionLocalTableSlice {
1508
1512
  columnIndex?: number;
1509
1513
  }
1510
1514
 
1515
+ interface TablePaginationProgress {
1516
+ startRow: number;
1517
+ carriedRowIndex?: number;
1518
+ carriedRowUsesCalibratedHeight?: boolean;
1519
+ }
1520
+
1521
+ function hasOnlyCompactAuthoredAutoRows(
1522
+ block: Extract<SurfaceBlockSnapshot, { kind: "table" }>,
1523
+ ): boolean {
1524
+ return (
1525
+ block.rows.length > 10 &&
1526
+ block.rows.every((row) => {
1527
+ const heightRule = row.heightRule ?? "auto";
1528
+ return heightRule !== "exact" && (row.height ?? 0) > 0 && (row.height ?? 0) <= 60;
1529
+ })
1530
+ );
1531
+ }
1532
+
1533
+ function shouldUseSoftLongTableAutoHeight(
1534
+ block: Extract<SurfaceBlockSnapshot, { kind: "table" }>,
1535
+ hasRepeatedHeaderRows: boolean,
1536
+ ): boolean {
1537
+ return (
1538
+ block.rows.length > 10 &&
1539
+ !hasRepeatedHeaderRows &&
1540
+ block.rows.every((row) => (row.height ?? 0) <= 1440) &&
1541
+ block.rows.every((row) => (row.heightRule ?? "auto") !== "exact")
1542
+ );
1543
+ }
1544
+
1511
1545
  interface SectionPaginationResult {
1512
1546
  pages: Omit<DocumentPageSnapshot, "pageIndex">[];
1513
1547
  splits: {
@@ -1670,10 +1704,11 @@ export function paginateSectionBlocksWithSplits(
1670
1704
  list.push(slice);
1671
1705
  tableSplitsByBlock.set(blockId, list);
1672
1706
  };
1673
- // P6.c: per-table progress when a table is being split row-by-row
1674
- // across pages. Map<blockId, nextRowIndexToPlace>. Cleared once a
1675
- // table is fully placed.
1676
- const tableProgress = new Map<string, number>();
1707
+ // P6.c/D-8: per-table progress when a table is being split row-by-row
1708
+ // across pages. `startRow` is the next row to place. `carriedRowIndex`
1709
+ // marks a row that already began on the prior page, so the next page must
1710
+ // not immediately re-split that same row and loop forever.
1711
+ const tableProgress = new Map<string, TablePaginationProgress>();
1677
1712
 
1678
1713
  // Contextual-spacing pair mask — precomputed once so the inner pagination
1679
1714
  // loop can fold suppression in O(1) per block without re-scanning neighbors.
@@ -1791,6 +1826,16 @@ export function paginateSectionBlocksWithSplits(
1791
1826
  to: refRange.blockTo,
1792
1827
  heightTwips: heightTwips + FOOTNOTE_REFERENCE_RESERVATION_TWIPS,
1793
1828
  kind: "whole",
1829
+ layoutObject: {
1830
+ objectId: `footnote-body:${fragmentId}`,
1831
+ kind: "footnote-body",
1832
+ sourceBlockId: `note-body-${noteKind}-${noteId}`,
1833
+ paginationRole: "whole",
1834
+ measuredExtentTwips: {
1835
+ heightTwips: heightTwips + FOOTNOTE_REFERENCE_RESERVATION_TWIPS,
1836
+ widthTwips: effectiveColumnWidth,
1837
+ },
1838
+ },
1794
1839
  };
1795
1840
 
1796
1841
  allocations.push(allocation);
@@ -1911,20 +1956,77 @@ export function paginateSectionBlocksWithSplits(
1911
1956
  // degrade to atomic placement (visual overflow, but offset
1912
1957
  // ranges stay clean — same as pre-P6.c behavior).
1913
1958
  if (block.kind === "table") {
1914
- const startRow = tableProgress.get(block.blockId) ?? 0;
1959
+ const progress = tableProgress.get(block.blockId);
1960
+ const startRow = progress?.startRow ?? 0;
1961
+ const carriedRowIndex = progress?.carriedRowIndex;
1915
1962
  const remainingForTable =
1916
1963
  usableHeight - columnHeight - reservedNoteHeight;
1917
- const rowHeights = measureTableRowHeights({
1964
+ const { cantSplitFlags, isHeaderFlags } = extractRowFlags(block);
1965
+ const hasRepeatedHeaderRows = isHeaderFlags.some(Boolean);
1966
+ const hasCompactAuthoredAutoRows = hasOnlyCompactAuthoredAutoRows(block);
1967
+ const canUseAutoHeightCalibration =
1968
+ !hasRepeatedHeaderRows && block.rows.length <= 10;
1969
+ const rowHeightProfile = measureTableRowHeightProfile({
1918
1970
  block,
1919
1971
  columnWidth,
1920
1972
  measurementProvider,
1921
1973
  defaultTabInterval,
1922
1974
  themeFonts,
1975
+ contentMode: canUseAutoHeightCalibration
1976
+ ? "auto-height-calibrated"
1977
+ : "legacy-min",
1923
1978
  });
1924
- const { cantSplitFlags, isHeaderFlags } = extractRowFlags(block);
1979
+ const shouldUseSoftLongTableHeights =
1980
+ shouldUseSoftLongTableAutoHeight(block, hasRepeatedHeaderRows);
1981
+ const resolvedRowHeights =
1982
+ hasCompactAuthoredAutoRows || shouldUseSoftLongTableHeights
1983
+ ? measureTableRowHeights({
1984
+ block,
1985
+ columnWidth,
1986
+ measurementProvider,
1987
+ defaultTabInterval,
1988
+ themeFonts,
1989
+ contentMode: "resolved",
1990
+ })
1991
+ : null;
1992
+ const legacyRowHeights = progress?.carriedRowUsesCalibratedHeight === true
1993
+ ? measureTableRowHeights({
1994
+ block,
1995
+ columnWidth,
1996
+ measurementProvider,
1997
+ defaultTabInterval,
1998
+ themeFonts,
1999
+ })
2000
+ : null;
2001
+ const rowHeights = [...rowHeightProfile.heights];
2002
+ if (resolvedRowHeights) {
2003
+ for (let rowIndex = 0; rowIndex < rowHeights.length; rowIndex += 1) {
2004
+ const resolvedHeight = resolvedRowHeights[rowIndex] ?? rowHeights[rowIndex] ?? 0;
2005
+ if (hasCompactAuthoredAutoRows) {
2006
+ rowHeights[rowIndex] = Math.min(
2007
+ Math.max(rowHeights[rowIndex] ?? 0, resolvedHeight),
2008
+ COMPACT_AUTHORED_ROW_HEIGHT_TWIPS,
2009
+ );
2010
+ } else if (resolvedHeight > (rowHeights[rowIndex] ?? 0)) {
2011
+ rowHeights[rowIndex] = (rowHeights[rowIndex] ?? 0) + LONG_TABLE_SOFT_AUTO_ROW_DELTA_TWIPS;
2012
+ }
2013
+ }
2014
+ }
2015
+ const calibratedAutoRowIndexes = new Set(rowHeightProfile.calibratedAutoRowIndexes);
2016
+ if (
2017
+ carriedRowIndex !== undefined &&
2018
+ progress?.carriedRowUsesCalibratedHeight === true &&
2019
+ carriedRowIndex === startRow &&
2020
+ calibratedAutoRowIndexes.has(carriedRowIndex)
2021
+ ) {
2022
+ rowHeights[carriedRowIndex] = Math.min(
2023
+ rowHeights[carriedRowIndex] ?? 0,
2024
+ legacyRowHeights?.[carriedRowIndex] ?? rowHeights[carriedRowIndex] ?? 0,
2025
+ );
2026
+ }
1925
2027
  const repeatedHeaderHeightTwips = computeRepeatedHeaderHeight(
1926
2028
  rowHeights,
1927
- isHeaderFlags,
2029
+ hasCompactAuthoredAutoRows ? rowHeights.map(() => false) : isHeaderFlags,
1928
2030
  );
1929
2031
  const headerReservation =
1930
2032
  startRow > 0 ? repeatedHeaderHeightTwips : 0;
@@ -1947,6 +2049,13 @@ export function paginateSectionBlocksWithSplits(
1947
2049
  }
1948
2050
  return height;
1949
2051
  };
2052
+ const isRowSplittableAcrossPages = (rowIndex: number): boolean => {
2053
+ const row = block.rows[rowIndex];
2054
+ if (!row) return false;
2055
+ if (cantSplitFlags[rowIndex] === true) return false;
2056
+ if (row.heightRule === "exact") return false;
2057
+ return true;
2058
+ };
1950
2059
 
1951
2060
  // Case 1: remainder fits — place and break.
1952
2061
  if (remainderHeight <= remainingForTable) {
@@ -1980,29 +2089,54 @@ export function paginateSectionBlocksWithSplits(
1980
2089
  });
1981
2090
  if (decision.rowsOnCurrentPage > 0) {
1982
2091
  const splitHeight = sliceHeight(startRow, decision.splitRowIndex);
2092
+ const splitRowIndex = decision.splitRowIndex;
2093
+ const splitRowVisibleHeight = remainingForTable - splitHeight;
2094
+ const canCarrySplitRow =
2095
+ decision.continuationRequired &&
2096
+ splitRowIndex < rowHeights.length &&
2097
+ splitRowIndex !== carriedRowIndex &&
2098
+ isRowSplittableAcrossPages(splitRowIndex) &&
2099
+ splitRowVisibleHeight >= MIN_SPLIT_ROW_FRAGMENT_TWIPS;
2100
+ const currentSliceEndRow = canCarrySplitRow
2101
+ ? Math.min(rowHeights.length, splitRowIndex + 1)
2102
+ : splitRowIndex;
2103
+ const currentSliceHeight = canCarrySplitRow
2104
+ ? splitHeight + splitRowVisibleHeight
2105
+ : splitHeight;
1983
2106
  recordColumnPlacement(block.blockId);
1984
2107
  appendTableSlice(block.blockId, {
1985
2108
  pageInSection,
1986
2109
  rowRange: {
1987
2110
  from: startRow,
1988
- to: decision.splitRowIndex,
2111
+ to: currentSliceEndRow,
1989
2112
  totalRows: rowHeights.length,
1990
2113
  },
1991
- heightTwips: splitHeight,
2114
+ heightTwips: currentSliceHeight,
1992
2115
  ...(isMultiColumn ? { columnIndex } : {}),
1993
2116
  });
1994
2117
  recordFragmentMeasurement(block.blockId, {
1995
- heightTwips: splitHeight,
2118
+ heightTwips: currentSliceHeight,
1996
2119
  widthTwips: columnWidth,
1997
2120
  });
1998
- columnHeight += splitHeight;
1999
- tableProgress.set(block.blockId, decision.splitRowIndex);
2121
+ columnHeight += currentSliceHeight;
2122
+ tableProgress.set(
2123
+ block.blockId,
2124
+ canCarrySplitRow
2125
+ ? {
2126
+ startRow: splitRowIndex,
2127
+ carriedRowIndex: splitRowIndex,
2128
+ ...(calibratedAutoRowIndexes.has(splitRowIndex)
2129
+ ? { carriedRowUsesCalibratedHeight: true }
2130
+ : {}),
2131
+ }
2132
+ : { startRow: splitRowIndex },
2133
+ );
2000
2134
  if (columnIndex < maxColumns - 1) {
2001
2135
  columnIndex += 1;
2002
2136
  columnHeight = 0;
2003
2137
  continue;
2004
2138
  }
2005
- pushPage(rowOffset(decision.splitRowIndex));
2139
+ pushPage(rowOffset(splitRowIndex));
2006
2140
  continue;
2007
2141
  }
2008
2142
 
@@ -2035,7 +2169,7 @@ export function paginateSectionBlocksWithSplits(
2035
2169
  if (index === blocks.length - 1) pushPage(section.end);
2036
2170
  break;
2037
2171
  }
2038
- tableProgress.set(block.blockId, forcedEndRow);
2172
+ tableProgress.set(block.blockId, { startRow: forcedEndRow });
2039
2173
  if (columnIndex < maxColumns - 1) {
2040
2174
  columnIndex += 1;
2041
2175
  columnHeight = 0;