@beyondwork/docx-react-component 1.0.67 → 1.0.70

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 (384) hide show
  1. package/README.md +75 -932
  2. package/package.json +26 -27
  3. package/src/api/anchor-conversion.ts +43 -0
  4. package/src/api/editor-state-types.ts +2 -1
  5. package/src/api/public-types.ts +504 -101
  6. package/src/api/session-state.ts +4 -0
  7. package/src/api/v3/README.md +91 -0
  8. package/src/api/v3/_create.ts +146 -0
  9. package/src/api/v3/_layer-metadata.ts +362 -0
  10. package/src/api/v3/_mocks.ts +84 -0
  11. package/src/api/v3/_runtime-handle.ts +162 -0
  12. package/src/api/v3/_ux-response.ts +73 -0
  13. package/src/api/v3/ai/_metadata-audit.ts +225 -0
  14. package/src/api/v3/ai/attach.ts +235 -0
  15. package/src/api/v3/ai/bundle.ts +132 -0
  16. package/src/api/v3/ai/explain.ts +144 -0
  17. package/src/api/v3/ai/export.ts +54 -0
  18. package/src/api/v3/ai/inspect.ts +118 -0
  19. package/src/api/v3/ai/policy.ts +77 -0
  20. package/src/api/v3/ai/replacement.ts +341 -0
  21. package/src/api/v3/ai/resolve.ts +133 -0
  22. package/src/api/v3/index.ts +79 -0
  23. package/src/api/v3/runtime/chart.ts +310 -0
  24. package/src/api/v3/runtime/clipboard.ts +81 -0
  25. package/src/api/v3/runtime/collab.ts +331 -0
  26. package/src/api/v3/runtime/content.ts +236 -0
  27. package/src/api/v3/runtime/document.ts +282 -0
  28. package/src/api/v3/runtime/formatting.ts +186 -0
  29. package/src/api/v3/runtime/geometry.ts +349 -0
  30. package/src/api/v3/runtime/layout.ts +108 -0
  31. package/src/api/v3/runtime/review.ts +129 -0
  32. package/src/api/v3/runtime/search.ts +74 -0
  33. package/src/api/v3/runtime/table.ts +63 -0
  34. package/src/api/v3/runtime/workflow.ts +434 -0
  35. package/src/api/v3/ui/_context.ts +86 -0
  36. package/src/api/v3/ui/_create.ts +65 -0
  37. package/src/api/v3/ui/_types.ts +520 -0
  38. package/src/api/v3/ui/chrome-composition.ts +342 -0
  39. package/src/{ui-tailwind/chrome → api/v3/ui}/chrome-preset-model.ts +11 -1
  40. package/src/api/v3/ui/chrome.ts +476 -0
  41. package/src/api/v3/ui/debug.ts +124 -0
  42. package/src/api/v3/ui/index.ts +64 -0
  43. package/src/api/v3/ui/overlays-visibility.ts +170 -0
  44. package/src/api/v3/ui/overlays.ts +427 -0
  45. package/src/api/v3/ui/scope.ts +71 -0
  46. package/src/api/v3/ui/session.ts +100 -0
  47. package/src/api/v3/ui/surface.ts +170 -0
  48. package/src/api/v3/ui/viewport.ts +303 -0
  49. package/src/core/commands/index.ts +28 -6
  50. package/src/core/commands/list-commands.ts +3 -2
  51. package/src/core/commands/section-layout-commands.ts +9 -8
  52. package/src/core/schema/text-schema.ts +16 -0
  53. package/src/core/selection/mapping.ts +33 -72
  54. package/src/core/state/editor-state.ts +96 -189
  55. package/src/index.ts +23 -4
  56. package/src/io/chart-preview-resolver.ts +1 -1
  57. package/src/io/docx-session.ts +36 -4797
  58. package/src/io/export/build-app-properties-xml.ts +1 -1
  59. package/src/io/export/serialize-comments.ts +1 -1
  60. package/src/io/export/serialize-headers-footers.ts +6 -1
  61. package/src/io/export/serialize-main-document.ts +45 -0
  62. package/src/io/export/serialize-run-formatting.ts +17 -2
  63. package/src/io/export/twip.ts +1 -1
  64. package/src/io/normalize/normalize-text.ts +27 -20
  65. package/src/io/ooxml/chart/parse-series.ts +1 -1
  66. package/src/io/ooxml/chart/resolve-color.ts +2 -2
  67. package/src/io/ooxml/chart/types.ts +1 -1
  68. package/src/io/ooxml/classify-embedding.ts +83 -33
  69. package/src/io/ooxml/parse-fill.ts +1 -1
  70. package/src/io/ooxml/parse-main-document.ts +71 -1
  71. package/src/io/ooxml/parse-object.ts +14 -10
  72. package/src/io/ooxml/parse-run-formatting.ts +47 -1
  73. package/src/io/ooxml/property-grab-bag.ts +2 -2
  74. package/src/io/ooxml/units.ts +11 -0
  75. package/src/io/ooxml/workflow-payload.ts +282 -7
  76. package/src/model/anchor.ts +85 -0
  77. package/src/model/canonical-document.ts +351 -15
  78. package/src/model/chart-types.ts +1 -1
  79. package/src/model/layout/index.ts +83 -0
  80. package/src/model/layout/page-graph-types.ts +181 -0
  81. package/src/model/layout/page-layout-snapshot.ts +105 -0
  82. package/src/model/layout/resolved-layout-types.ts +47 -0
  83. package/src/model/layout/runtime-page-graph-types.ts +102 -0
  84. package/src/model/paragraph-scope-ids.ts +72 -0
  85. package/src/model/review/comment-types.ts +112 -0
  86. package/src/model/review/index.ts +2 -0
  87. package/src/model/review/revision-types.ts +215 -0
  88. package/src/model/snapshot.ts +32 -0
  89. package/src/review/store/comment-store.ts +21 -47
  90. package/src/review/store/revision-types.ts +40 -198
  91. package/src/runtime/collab/base-doc-fingerprint.ts +6 -1
  92. package/src/runtime/collab/runtime-collab-sync.ts +13 -3
  93. package/src/runtime/collab-session.ts +1 -1
  94. package/src/runtime/debug/build-debug-inspector-snapshot.ts +686 -0
  95. package/src/runtime/debug/event-ring-buffer.ts +64 -0
  96. package/src/runtime/debug/probability-sampler.ts +18 -0
  97. package/src/runtime/debug/runtime-debug-facet.ts +67 -0
  98. package/src/runtime/debug/stage-tokens.ts +31 -0
  99. package/src/runtime/debug/telemetry-bus.ts +271 -0
  100. package/src/runtime/debug/types.ts +275 -0
  101. package/src/runtime/debug/wrap-ref-for-telemetry.ts +118 -0
  102. package/src/runtime/document-layout.ts +8 -6
  103. package/src/runtime/document-runtime.ts +843 -1141
  104. package/src/runtime/document-search.ts +1 -1
  105. package/src/runtime/edit-ops/index.ts +1 -1
  106. package/src/runtime/external-send-runtime.ts +1 -1
  107. package/src/runtime/formatting/document-lookup.ts +235 -0
  108. package/src/runtime/formatting/field/registry.ts +41 -0
  109. package/src/runtime/{field-resolver.ts → formatting/field/resolver.ts} +27 -2
  110. package/src/runtime/formatting/font-resolution.ts +83 -0
  111. package/src/runtime/formatting/formatting-context.ts +903 -0
  112. package/src/runtime/formatting/formatting-types.ts +157 -0
  113. package/src/runtime/{hyperlink-color-resolver.ts → formatting/hyperlink-color.ts} +2 -2
  114. package/src/runtime/formatting/index.ts +125 -0
  115. package/src/runtime/{resolved-numbering-geometry.ts → formatting/numbering/geometry.ts} +1 -1
  116. package/src/runtime/{numbering-prefix.ts → formatting/numbering/prefix.ts} +170 -3
  117. package/src/runtime/formatting/paragraph-style-resolver.ts +92 -0
  118. package/src/runtime/formatting/projector.ts +75 -0
  119. package/src/runtime/formatting/resolve-effective.ts +407 -0
  120. package/src/runtime/formatting/revision-display.ts +105 -0
  121. package/src/runtime/{paragraph-style-resolver.ts → formatting/style-cascade.ts} +84 -141
  122. package/src/runtime/{table-style-resolver.ts → formatting/table-style-resolver.ts} +1 -1
  123. package/src/runtime/formatting/telemetry-bridge.ts +106 -0
  124. package/src/runtime/{theme-color-resolver.ts → formatting/theme-color.ts} +2 -30
  125. package/src/runtime/geometry/caret-geometry.ts +164 -0
  126. package/src/runtime/geometry/geometry-facet.ts +364 -0
  127. package/src/runtime/geometry/geometry-types.ts +256 -0
  128. package/src/runtime/geometry/hit-test.ts +125 -0
  129. package/src/runtime/geometry/index.ts +71 -0
  130. package/src/runtime/geometry/inert-geometry-facet.ts +43 -0
  131. package/src/runtime/geometry/invalidation.ts +35 -0
  132. package/src/runtime/geometry/object-handles.ts +77 -0
  133. package/src/runtime/geometry/overlay-rects.ts +85 -0
  134. package/src/runtime/geometry/project-anchors.ts +100 -0
  135. package/src/runtime/geometry/project-fragments.ts +216 -0
  136. package/src/runtime/geometry/projector.ts +129 -0
  137. package/src/runtime/geometry/replacement-envelope.ts +130 -0
  138. package/src/runtime/geometry/viewport.ts +218 -0
  139. package/src/runtime/layout/compat-input-ledger.ts +211 -0
  140. package/src/runtime/layout/index.ts +6 -1
  141. package/src/runtime/layout/inert-layout-facet.ts +12 -7
  142. package/src/runtime/layout/layout-engine-instance.ts +189 -11
  143. package/src/runtime/layout/layout-engine-version.ts +450 -1
  144. package/src/runtime/layout/layout-facet-types.ts +60 -0
  145. package/src/runtime/layout/layout-measurement-provider.ts +13 -0
  146. package/src/runtime/layout/measurement-backend-canvas.ts +14 -2
  147. package/src/runtime/layout/measurement-backend-empirical.ts +23 -4
  148. package/src/runtime/layout/page-graph.ts +62 -209
  149. package/src/runtime/layout/page-story-resolver.ts +7 -12
  150. package/src/runtime/layout/paginated-layout-engine.ts +186 -11
  151. package/src/runtime/layout/project-block-fragments.ts +11 -0
  152. package/src/runtime/layout/projector.ts +90 -0
  153. package/src/runtime/layout/public-facet.ts +187 -442
  154. package/src/runtime/layout/resolved-formatting-state.ts +158 -26
  155. package/src/runtime/layout/table-render-plan.ts +1 -1
  156. package/src/runtime/prerender/cache-envelope.ts +6 -1
  157. package/src/runtime/prerender/prerender-document.ts +18 -23
  158. package/src/runtime/render/decoration-resolver.ts +1 -1
  159. package/src/runtime/render/render-frame-types.ts +20 -0
  160. package/src/runtime/render/render-kernel.ts +94 -25
  161. package/src/runtime/scopes/_formatting-seam.ts +262 -0
  162. package/src/runtime/scopes/_scope-dependencies.ts +49 -0
  163. package/src/runtime/scopes/action-validation.ts +356 -0
  164. package/src/runtime/scopes/attach-explanation.ts +102 -0
  165. package/src/runtime/scopes/audit-bundle.ts +71 -0
  166. package/src/runtime/scopes/compile-scope-bundle.ts +163 -0
  167. package/src/runtime/scopes/compile-scope.ts +262 -0
  168. package/src/runtime/scopes/compiler-service.ts +431 -0
  169. package/src/runtime/scopes/create-issue.ts +107 -0
  170. package/src/runtime/scopes/enumerate-scopes.ts +543 -0
  171. package/src/runtime/scopes/evidence.ts +233 -0
  172. package/src/runtime/scopes/index.ts +150 -0
  173. package/src/runtime/scopes/position-map.ts +214 -0
  174. package/src/runtime/scopes/preservation-boundary.ts +91 -0
  175. package/src/runtime/scopes/projector.ts +49 -0
  176. package/src/runtime/scopes/replaceability.ts +87 -0
  177. package/src/runtime/scopes/replacement/apply.ts +228 -0
  178. package/src/runtime/scopes/replacement/compile.ts +59 -0
  179. package/src/runtime/scopes/replacement/propose.ts +42 -0
  180. package/src/runtime/scopes/resolve-reference.ts +347 -0
  181. package/src/runtime/scopes/review-bundle.ts +141 -0
  182. package/src/runtime/scopes/scope-kinds/_paragraph-text.ts +57 -0
  183. package/src/runtime/scopes/scope-kinds/_table-text.ts +42 -0
  184. package/src/runtime/scopes/scope-kinds/comment-thread.ts +59 -0
  185. package/src/runtime/scopes/scope-kinds/field.ts +65 -0
  186. package/src/runtime/scopes/scope-kinds/heading.ts +84 -0
  187. package/src/runtime/scopes/scope-kinds/list-item.ts +77 -0
  188. package/src/runtime/scopes/scope-kinds/paragraph.ts +182 -0
  189. package/src/runtime/scopes/scope-kinds/revision.ts +62 -0
  190. package/src/runtime/scopes/scope-kinds/table-cell.ts +57 -0
  191. package/src/runtime/scopes/scope-kinds/table-row.ts +61 -0
  192. package/src/runtime/scopes/scope-kinds/table.ts +55 -0
  193. package/src/runtime/scopes/scope-range.ts +208 -0
  194. package/src/runtime/scopes/semantic-scope-types.ts +454 -0
  195. package/src/runtime/scopes/workflow-overlap.ts +92 -0
  196. package/src/runtime/selection/index.ts +1 -1
  197. package/src/runtime/structure-ops/fragment-insert.ts +1 -1
  198. package/src/runtime/structure-ops/index.ts +1 -1
  199. package/src/runtime/surface-projection.ts +232 -262
  200. package/src/runtime/units.ts +4 -2
  201. package/src/runtime/workflow/coordinator.ts +1348 -0
  202. package/src/runtime/workflow/derived-scope-resolver.ts +125 -0
  203. package/src/runtime/workflow/index.ts +25 -0
  204. package/src/runtime/workflow/markup-mode-policy.ts +98 -0
  205. package/src/runtime/{workflow-markup.ts → workflow/markup.ts} +6 -6
  206. package/src/runtime/workflow/metadata-persistence.ts +306 -0
  207. package/src/runtime/workflow/metadata-writer.ts +123 -0
  208. package/src/runtime/workflow/overlay-store.ts +690 -0
  209. package/src/runtime/workflow/projector.ts +127 -0
  210. package/src/runtime/{query-scopes.ts → workflow/query-scopes.ts} +3 -3
  211. package/src/runtime/{workflow-rail-segments.ts → workflow/rail/compose.ts} +60 -165
  212. package/src/runtime/workflow/rail/types.ts +198 -0
  213. package/src/runtime/workflow/scope-rail-composer.ts +39 -0
  214. package/src/runtime/{scope-resolver.ts → workflow/scope-resolver.ts} +3 -3
  215. package/src/runtime/workflow/scope-writer.ts +188 -0
  216. package/src/runtime/{tamper-gate.ts → workflow/tamper-gate.ts} +1 -1
  217. package/src/runtime/workflow/visibility-policy.ts +129 -0
  218. package/src/session/_sync-legacy.ts +66 -0
  219. package/src/session/export/embedded-reconstitute.ts +104 -0
  220. package/src/session/export/export-diagnostics.ts +85 -0
  221. package/src/session/export/export-validation.ts +110 -0
  222. package/src/session/export/index.ts +34 -0
  223. package/src/session/export/preservation-reattach.ts +30 -0
  224. package/src/session/export/serialize-dispatch.ts +165 -0
  225. package/src/session/export/stateful-export-pipeline.ts +432 -0
  226. package/src/session/export/stateful-export.ts +684 -0
  227. package/src/session/import/canonical-assembly.ts +227 -0
  228. package/src/session/import/diagnostics-session.ts +54 -0
  229. package/src/session/import/embedded-discovery.ts +225 -0
  230. package/src/session/import/embedded-offload.ts +337 -0
  231. package/src/session/import/import-diagnostics.ts +69 -0
  232. package/src/session/import/loader-types.ts +313 -0
  233. package/src/session/import/loader.ts +1834 -0
  234. package/src/session/import/normalize.ts +195 -0
  235. package/src/session/import/package-parts.ts +217 -0
  236. package/src/session/import/package-read.ts +195 -0
  237. package/src/session/import/parse-orchestration.ts +105 -0
  238. package/src/session/import/part-constants.ts +70 -0
  239. package/src/session/import/part-discovery.ts +94 -0
  240. package/src/session/import/preservation-index.ts +46 -0
  241. package/src/{runtime/read-only-diagnostics-runtime.ts → session/import/read-only-diagnostics.ts} +24 -3
  242. package/src/session/import/review-import.ts +508 -0
  243. package/src/session/import/styles-consolidation.ts +281 -0
  244. package/src/session/import/workflow-scope-import.ts +256 -0
  245. package/src/session/index.ts +37 -0
  246. package/src/session/session-state.ts +69 -0
  247. package/src/session/session.ts +532 -0
  248. package/src/session/shared/protection.ts +228 -0
  249. package/src/session/shared/session-utils.ts +82 -0
  250. package/src/session/types.ts +499 -0
  251. package/src/shell/chart-snapshots.ts +96 -0
  252. package/src/shell/media-previews.ts +85 -0
  253. package/src/shell/overlay-anchor-bridge.ts +53 -0
  254. package/src/shell/paste-adapter.ts +23 -0
  255. package/src/shell/ref-commands.ts +1697 -0
  256. package/src/shell/ref-utilities.ts +48 -0
  257. package/src/shell/search.ts +51 -0
  258. package/src/{ui/editor-runtime-boundary.ts → shell/session-bootstrap.ts} +243 -67
  259. package/src/shell/ui-subscriber-channels.ts +81 -0
  260. package/src/shell/use-collab-sync.ts +116 -0
  261. package/src/ui/WordReviewEditor.tsx +496 -2051
  262. package/src/ui/editor-shell-view.tsx +30 -1
  263. package/src/ui/editor-surface-controller.tsx +49 -1
  264. package/src/ui/headless/revision-decoration-model.ts +83 -0
  265. package/src/{ui-tailwind/chrome → ui/headless}/role-action-sets.ts +1 -1
  266. package/src/ui/headless/scoped-chrome-policy.ts +2 -2
  267. package/src/ui/headless/selection-tool-context.ts +1 -1
  268. package/src/ui/headless/selection-tool-resolver.ts +1 -1
  269. package/src/ui/runtime-shortcut-dispatch.ts +46 -1
  270. package/src/ui/ui-controller-factory.ts +221 -0
  271. package/src/ui-tailwind/chart/ChartSurface.tsx +2 -2
  272. package/src/ui-tailwind/chart/layout/legend-layout.ts +1 -1
  273. package/src/ui-tailwind/chart/layout/plot-area.ts +2 -2
  274. package/src/ui-tailwind/chart/layout/title-layout.ts +1 -1
  275. package/src/ui-tailwind/chart/render/area.tsx +3 -3
  276. package/src/ui-tailwind/chart/render/bar-column.tsx +3 -3
  277. package/src/ui-tailwind/chart/render/bubble.tsx +3 -3
  278. package/src/ui-tailwind/chart/render/combo.tsx +2 -2
  279. package/src/ui-tailwind/chart/render/data-labels.tsx +2 -2
  280. package/src/ui-tailwind/chart/render/font-metrics.ts +2 -2
  281. package/src/ui-tailwind/chart/render/line.tsx +3 -3
  282. package/src/ui-tailwind/chart/render/pie.tsx +6 -6
  283. package/src/ui-tailwind/chart/render/scatter.tsx +3 -3
  284. package/src/ui-tailwind/chart/render/svg-primitives.ts +3 -3
  285. package/src/ui-tailwind/chart/render/unsupported.tsx +2 -2
  286. package/src/ui-tailwind/chrome/build-context-menu-entries.ts +88 -0
  287. package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +1 -1
  288. package/src/ui-tailwind/chrome/collab-send-to-supplier-button.tsx +1 -1
  289. package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +1 -1
  290. package/src/ui-tailwind/chrome/collab-top-nav-container.tsx +1 -1
  291. package/src/ui-tailwind/chrome/editor-action-registry.ts +553 -0
  292. package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +182 -0
  293. package/src/ui-tailwind/chrome/local-surface-arbiter.ts +534 -0
  294. package/src/ui-tailwind/chrome/resolve-target-kind.ts +226 -0
  295. package/src/ui-tailwind/chrome/tw-alert-banner.tsx +38 -4
  296. package/src/ui-tailwind/chrome/tw-context-band.tsx +125 -0
  297. package/src/ui-tailwind/chrome/tw-context-menu-portal.tsx +248 -0
  298. package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +42 -1
  299. package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +8 -7
  300. package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +38 -4
  301. package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +104 -6
  302. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +66 -7
  303. package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +54 -8
  304. package/src/ui-tailwind/chrome/tw-shortcut-hint.tsx +7 -1
  305. package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +33 -0
  306. package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +78 -1
  307. package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +16 -8
  308. package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +276 -0
  309. package/src/ui-tailwind/chrome/use-context-menu-controller.ts +201 -0
  310. package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +1 -1
  311. package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +22 -4
  312. package/src/ui-tailwind/chrome-overlay/tw-comment-balloon-layer.tsx +1 -1
  313. package/src/ui-tailwind/chrome-overlay/tw-locked-block-layer.tsx +1 -1
  314. package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +11 -5
  315. package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +197 -3
  316. package/src/ui-tailwind/chrome-overlay/tw-revision-margin-bar-layer.tsx +1 -1
  317. package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +35 -6
  318. package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +24 -16
  319. package/src/ui-tailwind/chrome-overlay/tw-table-continuation-header.tsx +1 -1
  320. package/src/ui-tailwind/debug/README.md +57 -0
  321. package/src/ui-tailwind/debug/index.ts +3 -0
  322. package/src/ui-tailwind/debug/tw-debug-overlay.tsx +186 -0
  323. package/src/ui-tailwind/debug/tw-debug-presentation.tsx +80 -0
  324. package/src/ui-tailwind/debug/tw-debug-top-bar.tsx +83 -0
  325. package/src/ui-tailwind/editor-surface/chart-node-view.tsx +2 -2
  326. package/src/ui-tailwind/editor-surface/float-wrap-resolver.ts +1 -1
  327. package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +135 -10
  328. package/src/ui-tailwind/editor-surface/pm-decorations.ts +40 -13
  329. package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +1 -1
  330. package/src/ui-tailwind/editor-surface/pm-schema.ts +1 -1
  331. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +3 -3
  332. package/src/ui-tailwind/editor-surface/predicted-tag-preflight.ts +1 -1
  333. package/src/ui-tailwind/editor-surface/remote-cursor-plugin.ts +2 -2
  334. package/src/ui-tailwind/editor-surface/scroll-anchor.ts +91 -9
  335. package/src/ui-tailwind/editor-surface/shape-renderer.ts +1 -1
  336. package/src/ui-tailwind/editor-surface/surface-layer.ts +1 -1
  337. package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +1 -1
  338. package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +23 -6
  339. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +132 -22
  340. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +1 -1
  341. package/src/ui-tailwind/index.ts +0 -5
  342. package/src/ui-tailwind/overlay-anchor-bridge-context.tsx +33 -0
  343. package/src/ui-tailwind/page-stack/floating-image-overlay-model.ts +66 -29
  344. package/src/ui-tailwind/page-stack/tw-floating-image-layer.tsx +25 -2
  345. package/src/ui-tailwind/review/comment-markdown-renderer.tsx +15 -0
  346. package/src/ui-tailwind/review/tw-review-rail.tsx +92 -4
  347. package/src/ui-tailwind/review/tw-workflow-tab.tsx +1 -1
  348. package/src/ui-tailwind/review-workspace/page-chrome.ts +210 -0
  349. package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +101 -0
  350. package/src/ui-tailwind/review-workspace/paragraph-layout.ts +115 -0
  351. package/src/ui-tailwind/review-workspace/selection-toolbar-placement.ts +97 -0
  352. package/src/ui-tailwind/review-workspace/tw-review-workspace-navigator.tsx +130 -0
  353. package/src/ui-tailwind/review-workspace/tw-review-workspace-page-toolbar.tsx +240 -0
  354. package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +59 -0
  355. package/src/ui-tailwind/review-workspace/types.ts +408 -0
  356. package/src/ui-tailwind/review-workspace/use-chrome-policy.ts +104 -0
  357. package/src/ui-tailwind/review-workspace/use-derived-view-state.ts +151 -0
  358. package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +70 -0
  359. package/src/ui-tailwind/review-workspace/use-grabbed-segment-offsets.ts +40 -0
  360. package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +55 -0
  361. package/src/ui-tailwind/review-workspace/use-page-markers.ts +130 -0
  362. package/src/ui-tailwind/review-workspace/use-pm-surface-capture.ts +60 -0
  363. package/src/ui-tailwind/review-workspace/use-review-rail-state.ts +63 -0
  364. package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +170 -0
  365. package/src/ui-tailwind/review-workspace/use-scroll-root-capture.ts +28 -0
  366. package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +113 -0
  367. package/src/ui-tailwind/review-workspace/use-shell-selection-anchor-bridge.ts +120 -0
  368. package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +55 -0
  369. package/src/ui-tailwind/review-workspace/use-viewport-dimensions.ts +43 -0
  370. package/src/ui-tailwind/review-workspace/use-workspace-arbiter.ts +25 -0
  371. package/src/ui-tailwind/review-workspace/use-workspace-composition.ts +86 -0
  372. package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +150 -0
  373. package/src/ui-tailwind/theme/editor-theme.css +25 -0
  374. package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +2 -2
  375. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +61 -98
  376. package/src/ui-tailwind/tw-review-workspace.tsx +521 -1802
  377. package/src/ui-tailwind/ui-api-context.tsx +43 -0
  378. package/src/ui-tailwind/ui-shell-channels-context.tsx +49 -0
  379. package/src/validation/compatibility-engine.ts +6 -6
  380. package/src/runtime/styles-cascade.ts +0 -33
  381. package/src/ui-tailwind/chrome/tw-mode-dock.tsx +0 -85
  382. /package/src/runtime/{page-number-format.ts → formatting/field/page-number-format.ts} +0 -0
  383. /package/src/runtime/{ai-action-policy.ts → workflow/ai-action-policy.ts} +0 -0
  384. /package/src/runtime/{scope-tag-registry.ts → workflow/scope-tag-registry.ts} +0 -0
@@ -48,6 +48,14 @@
48
48
 
49
49
  import * as React from "react";
50
50
  import type { WordReviewEditorLayoutFacet } from "../../api/public-types";
51
+ import { incrementInvalidationCounter } from "../editor-surface/perf-probe";
52
+ import {
53
+ resolvePageOverlayRectsFromGeometry as resolvePageOverlayRectsFromGeometryImpl,
54
+ type GeometryFacet,
55
+ type OverlayVisiblePageIndexRange,
56
+ } from "../../runtime/geometry/index.ts";
57
+ import type { ApiV3Ui } from "../../api/v3/ui";
58
+ import { useUiApi } from "../ui-api-context";
51
59
 
52
60
  // ---------------------------------------------------------------------------
53
61
  // Measurement
@@ -394,6 +402,22 @@ function resolveOffsetHeight(widget: HTMLElement): number {
394
402
  export interface TwPageStackOverlayLayerProps {
395
403
  /** Layout facet — source of the page count. */
396
404
  facet: WordReviewEditorLayoutFacet;
405
+ /**
406
+ * Geometry facet — source of per-page rects when the render kernel has
407
+ * produced a frame (refactor/05 Slice 3b). When provided and
408
+ * `geometryFacet.getPage(0)` resolves, the overlay reads page rects
409
+ * directly from the kernel frame (tagged `space: "frame"`, which
410
+ * coincides with the overlay root's coordinate space — the overlay is
411
+ * a direct child of `wre-page-surface` at z-0 per v22 N1). This
412
+ * eliminates the overlay's G2 violation entirely for the warm path.
413
+ *
414
+ * When omitted, or when `getPage(0)` returns null (cold-open, before
415
+ * first render frame), the overlay falls back to the DOM-measurement
416
+ * path via `measureWidgetsViaBoundingRect` /
417
+ * `measureWidgetsViaOffsetChain` — preserved as the cold-open seam per
418
+ * architecture 05 Slice 3 exit criteria.
419
+ */
420
+ geometryFacet?: GeometryFacet;
397
421
  /** Scroll root element whose page-boundary widgets drive measurement. */
398
422
  scrollRoot: HTMLElement | null;
399
423
  /**
@@ -407,6 +431,76 @@ export interface TwPageStackOverlayLayerProps {
407
431
  "data-testid"?: string;
408
432
  }
409
433
 
434
+ /**
435
+ * Slice 3b · Re-export of the pure geometry-projection helper that now
436
+ * lives in `src/runtime/geometry/overlay-rects.ts`. The `L05` layer
437
+ * owns the projection math; the overlay component re-exports from this
438
+ * module for back-compat with existing imports.
439
+ *
440
+ * Known coordinate-space caveat documented in
441
+ * `src/runtime/geometry/overlay-rects.ts` — the kernel's page-stacking
442
+ * gap (16 px) diverges from the DOM chrome's inter-page gap (48 px).
443
+ * Until Slice 3c reconciles them, production consumers should not pass
444
+ * a `geometryFacet` to this overlay — the DOM-measurement path remains
445
+ * the default.
446
+ */
447
+ export const resolvePageOverlayRectsFromGeometry =
448
+ resolvePageOverlayRectsFromGeometryImpl;
449
+
450
+ /**
451
+ * DS-C2 (designsystem.md §8.8.1 "Page / ruler / header-footer bands"
452
+ * row) — resolve per-page overlay rects via `ui.overlays.getAnchor` so
453
+ * the overlay's primary read seam is the public UI API, not the
454
+ * geometry facet directly. Returns `null` when `ui` cannot resolve the
455
+ * first page (cold-open or no controller bound); caller falls back to
456
+ * the geometry-facet / DOM paths below.
457
+ *
458
+ * `pageIds` is supplied by the caller when available (from the
459
+ * geometry facet's `getPage(i).pageId` metadata). When absent, the
460
+ * helper synthesizes `page-${index}` ids for the React `key=` slot —
461
+ * stable within a run, unstable across reloads. The L10 follow-up
462
+ * ticket on `ui.overlays` page-id enumeration (see
463
+ * `cross-layer-coord-10.md §1.7`) retires the synthesis path.
464
+ */
465
+ export function resolvePageOverlayRectsFromUiApi(
466
+ ui: ApiV3Ui,
467
+ pageCount: number,
468
+ visiblePageIndexRange: VisiblePageIndexRange | null | undefined,
469
+ pageIds: readonly string[] | null,
470
+ ): readonly PageOverlayRect[] | null {
471
+ if (pageCount <= 0) return [];
472
+ const firstAnchor = ui.overlays.getAnchor({ kind: "page", value: 0 });
473
+ if (!firstAnchor) return null;
474
+ const start = visiblePageIndexRange?.start ?? 0;
475
+ const end = Math.min(
476
+ visiblePageIndexRange?.end ?? pageCount,
477
+ pageCount,
478
+ );
479
+ // Flicker-remediation 2026-04-22 (all-or-nothing policy): a single
480
+ // missing visible-page anchor returns null so the caller falls
481
+ // through to the geometry/DOM path instead of rendering a partial
482
+ // rect set. Under the prior "skip missing rows" policy a transiently-
483
+ // unresolved anchor during relayout would drop the paper background
484
+ // for pages 2..N while page 1 stayed painted — visibly gray bands
485
+ // between white papers. Atomic resolution forces consistency.
486
+ const rects: PageOverlayRect[] = [];
487
+ for (let i = start; i < end; i += 1) {
488
+ const rect =
489
+ i === 0 ? firstAnchor : ui.overlays.getAnchor({ kind: "page", value: i });
490
+ if (!rect) {
491
+ return null;
492
+ }
493
+ rects.push({
494
+ pageId: pageIds?.[i] ?? `page-${i}`,
495
+ pageIndex: i,
496
+ topPx: rect.topPx,
497
+ bottomPx: rect.topPx + rect.heightPx,
498
+ heightPx: rect.heightPx,
499
+ });
500
+ }
501
+ return rects;
502
+ }
503
+
410
504
  /**
411
505
  * The layer itself. Renders one decorative `<div>` per page with the
412
506
  * same card-shadow + rounded border treatment that `.wre-page-chrome`
@@ -417,12 +511,34 @@ export interface TwPageStackOverlayLayerProps {
417
511
  */
418
512
  export const TwPageStackOverlayLayer: React.FC<TwPageStackOverlayLayerProps> = ({
419
513
  facet,
514
+ geometryFacet,
420
515
  scrollRoot,
421
516
  renderFrameRevision,
422
517
  visiblePageIndexRange,
423
518
  "data-testid": testId,
424
519
  }) => {
425
- const [rects, setRects] = React.useState<readonly PageOverlayRect[]>([]);
520
+ // DS-C2 prefer `ui.overlays.getAnchor({ kind: "page", ... })` as
521
+ // the page-rect read seam when a `UiApiProvider` is mounted. Returns
522
+ // null here when headless / off-provider; the overlay then falls
523
+ // through to the existing geometry-facet / DOM paths.
524
+ const ui = useUiApi();
525
+ // Flicker-remediation 2026-04-22: compute initial rects synchronously
526
+ // from the geometry facet when the kernel is already warm, so the
527
+ // first paint has correct paper cards instead of an empty overlay
528
+ // that only populates after `useEffect` ticks. Cold-open paths where
529
+ // `geometryFacet` isn't passed / returns null still fall back to
530
+ // the empty initial state + the fallback paper rendered below.
531
+ const [rects, setRects] = React.useState<readonly PageOverlayRect[]>(() => {
532
+ if (!geometryFacet) return [];
533
+ const pageCount = facet.getPageCount();
534
+ if (pageCount <= 0) return [];
535
+ const warm = resolvePageOverlayRectsFromGeometry(
536
+ geometryFacet,
537
+ pageCount,
538
+ visiblePageIndexRange,
539
+ );
540
+ return warm ?? [];
541
+ });
426
542
  // P3.d fix: the overlay root acts as the **measurement origin** so
427
543
  // widget `topPx` / `bottomPx` are expressed in the exact coordinate
428
544
  // space the overlay paints in. Using `scrollRoot` as origin (P3.b
@@ -457,6 +573,61 @@ export const TwPageStackOverlayLayer: React.FC<TwPageStackOverlayLayerProps> = (
457
573
  }
458
574
  const origin = overlayRootRef.current;
459
575
  const pageCount = facet.getPageCount();
576
+
577
+ // DS-C2 — first try the UI API seam so presentation code does not
578
+ // reach into the geometry facet directly. Page-ids come from the
579
+ // geometry facet when the caller forwarded one; synthesized
580
+ // otherwise. When `ui.overlays.getAnchor` returns null for page 0
581
+ // the geometry-direct and DOM paths below still run.
582
+ //
583
+ // §4.10 telemetry (2026-04-23) — the all-or-nothing resolution
584
+ // policy above is correct but unprobed. `overlay.page.ui_api.hit`
585
+ // increments when the UI-API path resolves the full visible-range;
586
+ // `overlay.page.ui_api.fallthrough` increments when the path
587
+ // returns null and we continue to the geometry/DOM fallback. The
588
+ // ratio lets a future bench assert fall-through stays below a
589
+ // threshold during steady-state typing (follow-up work — bench
590
+ // setup for F01/F08 typing scenarios is a separate task).
591
+ if (ui) {
592
+ const pageIds: string[] | null = geometryFacet
593
+ ? Array.from({ length: pageCount }, (_, i) => {
594
+ const page = geometryFacet.getPage(i);
595
+ return page?.pageId ?? `page-${i}`;
596
+ })
597
+ : null;
598
+ const uiRects = resolvePageOverlayRectsFromUiApi(
599
+ ui,
600
+ pageCount,
601
+ visiblePageIndexRange,
602
+ pageIds,
603
+ );
604
+ if (uiRects !== null) {
605
+ incrementInvalidationCounter("overlay.page.ui_api.hit");
606
+ setRects(uiRects);
607
+ return;
608
+ }
609
+ incrementInvalidationCounter("overlay.page.ui_api.fallthrough");
610
+ } else {
611
+ incrementInvalidationCounter("overlay.page.ui_api.unavailable");
612
+ }
613
+
614
+ // Slice 3b: when the geometry facet resolves page 0 through the
615
+ // render kernel, read rects directly from the kernel frame — zero
616
+ // DOM measurement, zero forced layouts. The DOM path below remains
617
+ // for the cold-open window (first frame not yet emitted) and for
618
+ // wiring sites that haven't handed over a geometry facet.
619
+ if (geometryFacet) {
620
+ const geometryRects = resolvePageOverlayRectsFromGeometry(
621
+ geometryFacet,
622
+ pageCount,
623
+ visiblePageIndexRange,
624
+ );
625
+ if (geometryRects !== null) {
626
+ setRects(geometryRects);
627
+ return;
628
+ }
629
+ }
630
+
460
631
  if (origin) {
461
632
  const widgets = measureWidgetsViaBoundingRect(scrollRoot, origin, {
462
633
  pageCount,
@@ -486,7 +657,7 @@ export const TwPageStackOverlayLayer: React.FC<TwPageStackOverlayLayerProps> = (
486
657
  }),
487
658
  );
488
659
  }
489
- }, [facet, scrollRoot, visiblePageIndexRange]);
660
+ }, [facet, geometryFacet, scrollRoot, ui, visiblePageIndexRange]);
490
661
 
491
662
  const refreshRects = React.useCallback(() => {
492
663
  if (!scrollRoot) {
@@ -597,6 +768,16 @@ export const TwPageStackOverlayLayer: React.FC<TwPageStackOverlayLayerProps> = (
597
768
  // frames until the next `renderFrameRevision` tick. Keeping the
598
769
  // root element present + empty is cheap (one `<div>`) and makes the
599
770
  // ref resolve during the first layout-effect pass.
771
+ //
772
+ // Flicker-remediation 2026-04-22: when rects are not yet available
773
+ // (cold-open; geometry facet has no kernel yet; DOM not measured),
774
+ // paint a full-area paper-color fallback card so the user sees a
775
+ // white page rather than the gray workspace canvas flashing through.
776
+ // The fallback uses the same paper chrome (bg / border / shadow /
777
+ // radius) as individual page cards, rendered as `inset-0` so it
778
+ // spans whatever region the scroll root currently occupies. When
779
+ // `rects` populates on the next refresh pass the fallback is
780
+ // replaced by N discrete cards.
600
781
  if (rects.length === 0) {
601
782
  return (
602
783
  <div
@@ -605,7 +786,20 @@ export const TwPageStackOverlayLayer: React.FC<TwPageStackOverlayLayerProps> = (
605
786
  aria-hidden="true"
606
787
  data-testid={testId ?? "page-stack-overlay"}
607
788
  data-page-count="0"
608
- />
789
+ data-fallback-paper="true"
790
+ >
791
+ <div
792
+ className="wre-page-stack-overlay-frame wre-page-stack-overlay-frame--fallback absolute inset-0"
793
+ aria-hidden="true"
794
+ style={{
795
+ backgroundColor: "var(--color-page-bg, white)",
796
+ border: "1px solid var(--color-page-border, rgba(148,163,184,0.2))",
797
+ borderRadius: "var(--radius-page, 4px)",
798
+ boxShadow:
799
+ "0 8px 24px -20px var(--color-page-shadow, rgba(15,23,42,0.38))",
800
+ }}
801
+ />
802
+ </div>
609
803
  );
610
804
  }
611
805
 
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import type { RenderBlockDecoration } from "../../runtime/render/render-frame-types";
2
+ import type { RenderBlockDecoration } from "../../api/public-types.ts";
3
3
  import { AUTHOR_PALETTE } from "../../ui/headless/revision-decoration-model";
4
4
 
5
5
  const BAR_WIDTH_PX = 3;
@@ -24,21 +24,33 @@ import {
24
24
  type OverlayCoordinateSpace,
25
25
  } from "./chrome-overlay-projector";
26
26
  import { TwScopeCard } from "./tw-scope-card";
27
+ import { useLocalSurfaceRequest } from "../chrome/local-surface-arbiter";
27
28
  import type {
28
29
  EditorRole,
29
30
  ScopeCardModel,
30
31
  ScopeIssueAction,
31
32
  WorkflowScopeMode,
32
33
  } from "../../api/public-types";
33
- import type { RenderFrameRect } from "../../runtime/render";
34
- import type { WordReviewEditorLayoutFacet } from "../../runtime/layout";
34
+ import type { RenderFrameRect } from "../../api/public-types.ts";
35
+ import type { WordReviewEditorLayoutFacet } from "../../api/public-types.ts";
36
+ import type { WorkflowFacet } from "../../api/public-types.ts";
35
37
 
36
38
  // ---------------------------------------------------------------------------
37
39
  // Types
38
40
  // ---------------------------------------------------------------------------
39
41
 
40
42
  export interface TwScopeCardLayerProps {
43
+ /**
44
+ * Layout facet — still required for `getRenderFrame()` etc. Scope-
45
+ * card data now flows through `workflowFacet` per Layer-06 Slice 4.
46
+ */
41
47
  facet: WordReviewEditorLayoutFacet;
48
+ /**
49
+ * Workflow facet — canonical source of scope card models
50
+ * (`runtime.workflow.getAllScopeCardModels()`). `null` is treated as
51
+ * "no cards".
52
+ */
53
+ workflowFacet: WorkflowFacet | null;
42
54
  activeScopeId: string | null;
43
55
  onClose: () => void;
44
56
  onModeChange: (scopeId: string, mode: WorkflowScopeMode) => void;
@@ -77,6 +89,7 @@ const CARD_FALLBACK_TOP_PX = 16;
77
89
 
78
90
  export const TwScopeCardLayer: React.FC<TwScopeCardLayerProps> = ({
79
91
  facet,
92
+ workflowFacet,
80
93
  activeScopeId,
81
94
  onClose,
82
95
  onModeChange,
@@ -106,10 +119,7 @@ export const TwScopeCardLayer: React.FC<TwScopeCardLayerProps> = ({
106
119
  // The effective scope is the pinned one if it still resolves to a
107
120
  // model, else the active one. When a pinned scope disappears
108
121
  // (e.g. the host cleared the overlay), drop the pin.
109
- const models =
110
- typeof facet.getAllScopeCardModels === "function"
111
- ? facet.getAllScopeCardModels()
112
- : [];
122
+ const models = workflowFacet?.getAllScopeCardModels() ?? [];
113
123
 
114
124
  const pinnedModel = pinnedScopeId
115
125
  ? models.find((m) => m.scopeId === pinnedScopeId) ?? null
@@ -128,10 +138,29 @@ export const TwScopeCardLayer: React.FC<TwScopeCardLayerProps> = ({
128
138
  }, [pinnedScopeId, models]);
129
139
 
130
140
  const effectiveScopeId = pinnedModel ? pinnedScopeId : activeScopeId;
141
+ const isPinnedEffective = pinnedScopeId !== null && pinnedScopeId === effectiveScopeId;
142
+
143
+ // Phase F.3 — request the scope-card slot from the shared arbiter.
144
+ // Pinned scope cards go into the orthogonal pinned slot so the rail
145
+ // (or a peer surface) can coexist; non-pinned scope cards take the
146
+ // single active slot at priority 7 and displace every lower peer.
147
+ // The hook MUST be called unconditionally — pass `null` when no
148
+ // scope is effective, which is a safe no-op.
149
+ const isArbiterActive = useLocalSurfaceRequest(
150
+ effectiveScopeId
151
+ ? {
152
+ kind: "scope-card",
153
+ id: effectiveScopeId,
154
+ pinned: isPinnedEffective,
155
+ }
156
+ : null,
157
+ );
158
+
131
159
  if (!effectiveScopeId) return null;
132
160
  const model: ScopeCardModel | undefined =
133
161
  pinnedModel ?? models.find((m) => m.scopeId === effectiveScopeId);
134
162
  if (!model) return null;
163
+ if (!isArbiterActive) return null;
135
164
 
136
165
  const projectorSpace: OverlayCoordinateSpace =
137
166
  space ?? { originLeftPx: 0, originTopPx: 0 };
@@ -17,17 +17,29 @@ import {
17
17
  projectRectToOverlay,
18
18
  type OverlayCoordinateSpace,
19
19
  } from "./chrome-overlay-projector";
20
- import type { RenderFrame, RenderFrameRect } from "../../runtime/render";
21
- import type { ScopeRailSegment, ScopeRailPosture } from "../../runtime/layout";
22
- import type { WordReviewEditorLayoutFacet } from "../../runtime/layout";
20
+ import type { RenderFrame, RenderFrameRect } from "../../api/public-types.ts";
21
+ import type { ScopeRailSegment, ScopeRailPosture } from "../../api/public-types.ts";
22
+ import type { WorkflowFacet } from "../../api/public-types.ts";
23
+ import type { GeometryFacet } from "../../api/public-types";
23
24
 
24
25
  // ---------------------------------------------------------------------------
25
26
  // Types
26
27
  // ---------------------------------------------------------------------------
27
28
 
28
29
  export interface TwScopeRailLayerProps {
29
- /** Layout facet that provides segments + render frame. */
30
- facet: WordReviewEditorLayoutFacet;
30
+ /**
31
+ * Geometry facet — used for `getRenderFrame()`. Migrated from
32
+ * `facet: WordReviewEditorLayoutFacet` in refactor/05 cross-lane-coord
33
+ * §8.4 pass. Rail-segment + scope-card data flows through
34
+ * `workflowFacet` per Layer-06 Slice 4's seam inversion.
35
+ */
36
+ geometryFacet: GeometryFacet;
37
+ /**
38
+ * Workflow facet — canonical source of scope rail segments + scope
39
+ * card models (`runtime.workflow.*`). Required for the layer to
40
+ * render anything; passing `null` makes the layer a no-op.
41
+ */
42
+ workflowFacet: WorkflowFacet | null;
31
43
  /** Overlay's coordinate space. Defaults to the overlay's own origin. */
32
44
  space?: OverlayCoordinateSpace;
33
45
  /** Horizontal pad (px) the rail gutter occupies to the left of body. */
@@ -80,7 +92,8 @@ const LABEL_WIDTH_PX = 40;
80
92
  const STACK_OFFSET_PX = 6;
81
93
 
82
94
  export const TwScopeRailLayer: React.FC<TwScopeRailLayerProps> = ({
83
- facet,
95
+ geometryFacet,
96
+ workflowFacet,
84
97
  space,
85
98
  railLaneWidthPx = DEFAULT_RAIL_LANE_PX,
86
99
  activeScopeId,
@@ -88,10 +101,8 @@ export const TwScopeRailLayer: React.FC<TwScopeRailLayerProps> = ({
88
101
  onSegmentClick,
89
102
  "data-testid": testId,
90
103
  }) => {
91
- const frame = typeof facet.getRenderFrame === "function"
92
- ? facet.getRenderFrame() ?? null
93
- : null;
94
- const segments = facet.getAllScopeRailSegments();
104
+ const frame = geometryFacet.getRenderFrame() ?? null;
105
+ const segments = workflowFacet?.getAllRailSegments() ?? [];
95
106
 
96
107
  if (!frame || segments.length === 0) {
97
108
  return null;
@@ -99,12 +110,9 @@ export const TwScopeRailLayer: React.FC<TwScopeRailLayerProps> = ({
99
110
 
100
111
  // P2: which scopes currently have a `source: "ai"` candidate
101
112
  // overlapping — drives the agent-pending shimmer class on their
102
- // tints. Reads from the facet's card-model projection so the
103
- // shimmer logic lives in the runtime, not the overlay.
104
- const cardModels =
105
- typeof facet.getAllScopeCardModels === "function"
106
- ? facet.getAllScopeCardModels()
107
- : [];
113
+ // tints. Reads from the workflow facet's card-model projection so the
114
+ // shimmer logic lives in the Layer-06 runtime, not the overlay.
115
+ const cardModels = workflowFacet?.getAllScopeCardModels() ?? [];
108
116
  const agentPendingByScope = new Map<string, boolean>();
109
117
  for (const model of cardModels) {
110
118
  if (model.agentPending) {
@@ -11,7 +11,7 @@
11
11
 
12
12
  import React from "react";
13
13
  import type { SurfaceTableRowSnapshot } from "../../api/public-types.ts";
14
- import type { WordReviewEditorLayoutFacet } from "../../runtime/layout/public-facet.ts";
14
+ import type { WordReviewEditorLayoutFacet } from "../../api/public-types.ts";
15
15
 
16
16
  export interface TwTableContinuationHeaderProps {
17
17
  blockId: string;
@@ -0,0 +1,57 @@
1
+ # Phase Q — Debug UX (reserved)
2
+
3
+ Target for the runtime-embedded debug UX consumed through `ui.debug.attach()`
4
+ (layer 10, refactor/10 Slice 5). This directory is **reserved** — the Slice 5
5
+ ship includes the UI API substrate (`src/api/v3/ui/debug.ts` +
6
+ `UiController.attachDebug` hook), while the React presentation components +
7
+ the public `debugMode` prop + the visibility invariant test are a **Phase Q
8
+ follow-up** per `docs/plans/refactor/10-ui-api.md` Risk #3:
9
+
10
+ > **Phase Q UX surface area.** `src/ui-tailwind/debug/**` is a new substantial
11
+ > UI surface. *Mitigation:* ship substrate in M4 Slice 5; polish in follow-up.
12
+
13
+ ## Planned files (follow-up)
14
+
15
+ | File | Purpose |
16
+ |---|---|
17
+ | `tw-debug-top-bar.tsx` | Minimal top bar when `debugMode: "top-bar"` — document hash, scope count, invalidation counter |
18
+ | `tw-debug-overlay.tsx` | Full overlay when `debugMode: "full"` — renders `DebugInspectorSnapshot` sections |
19
+ | `tw-debug-repl.tsx` | REPL with `api`, `runtime`, `debug` in scope; localStorage-persisted history |
20
+ | `tw-debug-event-tail.tsx` | Tail of the last N events on active telemetry channels |
21
+ | `keybindings.ts` | Cmd/Ctrl+Shift+D toggles top-bar ↔ full |
22
+
23
+ ## Planned prop (follow-up)
24
+
25
+ Add `debugMode?: "off" | "top-bar" | "full"` to `WordReviewEditorProps`.
26
+ **Default MUST be `"off"`** per CLAUDE.md Protected Invariants § "Phase Q
27
+ placeholder" — this default has regressed multiple times in predecessor
28
+ surfaces (`showUnsupportedObjectPreviews`, `unsupportedPreviewsPolicy`).
29
+
30
+ ## Planned test (follow-up)
31
+
32
+ `test/ui/debug-mode-visibility-invariant.test.ts` — asserts:
33
+ - `debugMode: "off"` → no debug UI renders
34
+ - `debugMode: "top-bar"` → only the top bar renders
35
+ - `debugMode: "full"` → overlay renders
36
+
37
+ ## How Slice 5 consumers wire today
38
+
39
+ Until the Phase Q React components land, Slice 5 ships only the contract:
40
+
41
+ ```ts
42
+ import { createUiApi } from "@beyondwork/docx-react-component/api/v3/ui";
43
+
44
+ const ui = createUiApi(handle);
45
+ ui.session.bind({
46
+ kind: "runtime-direct",
47
+ id: "my-mount",
48
+ attachDebug(session) {
49
+ // bind-side: wire runtime.debug.bus + getSnapshot to your debug surface
50
+ const off = runtime.debug.bus.on(/* ... */, (evt) => {/* render */});
51
+ return () => off();
52
+ },
53
+ });
54
+ const attachment = ui.debug.attach({ id: "s1", channels: ["api", "render"] });
55
+ // later:
56
+ attachment.detach();
57
+ ```
@@ -0,0 +1,3 @@
1
+ export { TwDebugTopBar, type TwDebugTopBarProps } from "./tw-debug-top-bar.tsx";
2
+ export { TwDebugOverlay, type TwDebugOverlayProps } from "./tw-debug-overlay.tsx";
3
+ export { TwDebugPresentation, type TwDebugPresentationProps } from "./tw-debug-presentation.tsx";