@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
@@ -0,0 +1,282 @@
1
+ /**
2
+ * @endStateApi v3 — `runtime.document` family.
3
+ *
4
+ * See docs/reference/public-api.md § runtime.document. Three functions:
5
+ * `load` (partial — runtime pre-load is the caller's responsibility; v3
6
+ * exposes a re-mount semantic later), `export` (live; delegates to
7
+ * `runtime.exportDocx`), `validate` (partial; read live, write mock).
8
+ */
9
+
10
+ import type { RuntimeApiHandle } from "../_runtime-handle.ts";
11
+ import type {
12
+ EditorError,
13
+ ExportDocxOptions,
14
+ ExportResult,
15
+ PersistedEditorSnapshot,
16
+ } from "../../public-types.ts";
17
+ import { mockPayload } from "../_mocks.ts";
18
+ import type { ApiV3FnMetadata, MockPayload } from "../_layer-metadata.ts";
19
+ import { emitUxResponse } from "../_ux-response.ts";
20
+ import { loadDocxSessionAsync } from "../../../session/import/loader.ts";
21
+ import { createLoadScheduler } from "../../../io/load-scheduler.ts";
22
+
23
+ /* ================================================================== */
24
+ /* load */
25
+ /* ================================================================== */
26
+
27
+ export interface LoadInput {
28
+ readonly bytes: Uint8Array | ArrayBuffer;
29
+ /**
30
+ * Document identity for the newly-loaded session. Required by
31
+ * `loadDocxSessionAsync` — when omitted, v3 synthesizes a stable
32
+ * `v3-load-<timestamp>` id so agents calling without host-assigned
33
+ * ids still get deterministic-enough output.
34
+ */
35
+ readonly documentId?: string;
36
+ readonly sourceLabel?: string;
37
+ }
38
+
39
+ /**
40
+ * Live result of loading a DOCX package via the session-layer loader
41
+ * (`src/session/import/loader.ts::loadDocxSessionAsync`). Under the
42
+ * L07 Option-B contract (arch §R8) v3 does NOT construct a new
43
+ * `DocumentRuntime` — `createDocumentRuntime` stays synchronous and
44
+ * requires a fully-loaded `EditorSessionState`. The v3 `load()`
45
+ * returns the serializable `snapshot` + status so callers can mount
46
+ * a new runtime themselves or persist / rehydrate via
47
+ * `DocxSession.reopenFromSnapshot` (L01 coord §2).
48
+ *
49
+ * Every field is live from the actual parse:
50
+ * - `documentId` — echoes the input (or synthesized default).
51
+ * - `bytes` — byte-length of the source package.
52
+ * - `readOnly` — protection state the loader detected.
53
+ * - `embeddedDocumentsCount` — count of embedded sub-documents
54
+ * discovered via P8 embedded-document discovery.
55
+ * - `snapshot` — the `PersistedEditorSnapshot` the loader produced.
56
+ * - `fatalError` — present when `status === "fatal"`.
57
+ * - `status` — `"loaded"` on success, `"fatal"` when the package
58
+ * couldn't be parsed (corrupt bytes, unsupported schema, etc.).
59
+ */
60
+ export interface LoadResult {
61
+ readonly documentId: string;
62
+ readonly bytes: number;
63
+ readonly readOnly: boolean;
64
+ readonly embeddedDocumentsCount: number;
65
+ readonly snapshot: PersistedEditorSnapshot;
66
+ readonly fatalError?: EditorError;
67
+ readonly status: "loaded" | "fatal";
68
+ }
69
+
70
+ export const loadMetadata: ApiV3FnMetadata = {
71
+ name: "runtime.document.load",
72
+ status: "live",
73
+ sourceLayer: "package-session",
74
+ // Full live — direct delegation to loadDocxSessionAsync. No adapter
75
+ // debt: v3 doesn't construct a runtime (Option B contract, §R8),
76
+ // but the parse itself is the shipped session-layer contract.
77
+ // Returns the serializable snapshot + fatalError + readOnly fields
78
+ // the loader produced; v3 is a thin shape-projection over that.
79
+ liveEvidence: {
80
+ runnerTest: "test/api/v3/live-parity.test.ts",
81
+ commit: "refactor-07-document-load-live-post-eb7d14fa",
82
+ },
83
+ uxIntent: { uiVisible: true, expectsUxResponse: "surface-refresh", expectedDelta: "editor surface replaces with newly-loaded document" },
84
+ agentMetadata: { readOrMutate: "compound", boundedScope: "session", auditCategory: "document-load" },
85
+ stateClass: "A-canonical",
86
+ persistsTo: "canonical",
87
+ rwdReference:
88
+ "§Runtime API § runtime.document.load. Graduation (2026-04-22, post-eb7d14fa): `live` via direct delegation to `loadDocxSessionAsync` (src/session/import/loader.ts). Returns a PersistedEditorSnapshot the caller can pass to DocxSession.reopenFromSnapshot or persist for later rehydrate. Note per arch §R8 Option B: v3 does NOT construct the receiving DocumentRuntime — that's the caller's job via createDocumentRuntime(initialSessionState).",
89
+ };
90
+
91
+ /* ================================================================== */
92
+ /* export */
93
+ /* ================================================================== */
94
+
95
+ export const exportMetadata: ApiV3FnMetadata = {
96
+ name: "runtime.document.export",
97
+ status: "live",
98
+ sourceLayer: "package-session",
99
+ liveEvidence: {
100
+ runnerTest: "services/debug/lib/session-manager.test.ts",
101
+ probeScript: "services/debug/scripts/probe-channel-emissions.ts",
102
+ commit: "6aca0666",
103
+ },
104
+ uxIntent: { uiVisible: true, expectsUxResponse: "toast", expectedDelta: "toast shows export bytes size + completion" },
105
+ agentMetadata: { readOrMutate: "read", boundedScope: "document", auditCategory: "document-export" },
106
+ stateClass: "A-canonical",
107
+ persistsTo: "canonical",
108
+ rwdReference: "§Runtime API § runtime.document.export",
109
+ };
110
+
111
+ /* ================================================================== */
112
+ /* validate */
113
+ /* ================================================================== */
114
+
115
+ export interface ValidateResult {
116
+ readonly reportVersion: "compatibility-report/1";
117
+ readonly blockExport: boolean;
118
+ readonly warningCount: number;
119
+ readonly errorCount: number;
120
+ readonly featureEntriesCount: number;
121
+ readonly interactionGuard: {
122
+ readonly mode: string;
123
+ readonly readOnly: boolean;
124
+ };
125
+ readonly __mock?: true;
126
+ }
127
+
128
+ export const validateMetadata: ApiV3FnMetadata = {
129
+ name: "runtime.document.validate",
130
+ status: "live-with-adapter",
131
+ sourceLayer: "package-session",
132
+ liveEvidence: {
133
+ runnerTest: "test/api/v3/live-parity.test.ts",
134
+ commit: "phase-p-prime",
135
+ },
136
+ mockShape: {
137
+ deterministic: true,
138
+ seededFrom: "hash",
139
+ shapeDescription: "Fallback ValidateResult with zeroed counts when any of the three runtime reads is unavailable; never returned on a healthy runtime.",
140
+ carriesMockFlag: true,
141
+ },
142
+ uxIntent: { uiVisible: true, expectsUxResponse: "warning-added", expectedDelta: "compatibility drawer summary updates" },
143
+ agentMetadata: { readOrMutate: "read", boundedScope: "document", auditCategory: "document-validate" },
144
+ stateClass: "A-canonical",
145
+ persistsTo: "canonical",
146
+ rwdReference:
147
+ "§Runtime API § runtime.document.validate. Adapter composes three shipped runtime reads — getCompatibilityReport() + getWarnings() + getInteractionGuardSnapshot() — into one bundled ValidateResult. Promotes to `live` when a first-class runtime.validate() lands.",
148
+ };
149
+
150
+ /* ================================================================== */
151
+ /* family factory */
152
+ /* ================================================================== */
153
+
154
+ export function createDocumentFamily(runtime: RuntimeApiHandle) {
155
+ return {
156
+ async load(input: LoadInput): Promise<LoadResult> {
157
+ // @endStateApi — live. Delegates directly to the session-layer
158
+ // loader `loadDocxSessionAsync`. v3 projects the returned
159
+ // `LoadedDocxEditorSession` into the serializable `LoadResult`
160
+ // shape — drops the `exportDocx` closure (R5: no runtime-
161
+ // instance leakage) and surfaces `snapshot` + fatalError + read-
162
+ // only for callers that mount via `createDocumentRuntime(
163
+ // initialSessionState)` themselves (Option B, §R8) or rehydrate
164
+ // via `DocxSession.reopenFromSnapshot(snapshot)` (L01 coord §2).
165
+ const byteLength = input.bytes instanceof Uint8Array
166
+ ? input.bytes.byteLength
167
+ : input.bytes.byteLength;
168
+ const documentId = input.documentId ?? `v3-load-${Date.now()}`;
169
+ const loaded = await loadDocxSessionAsync({
170
+ bytes: input.bytes,
171
+ documentId,
172
+ ...(input.sourceLabel ? { sourceLabel: input.sourceLabel } : {}),
173
+ scheduler: createLoadScheduler(),
174
+ telemetryBus: runtime.debug.bus,
175
+ });
176
+ const result: LoadResult = {
177
+ documentId,
178
+ bytes: byteLength,
179
+ readOnly: loaded.readOnly,
180
+ embeddedDocumentsCount: loaded.embeddedDocumentManifests?.length ?? 0,
181
+ snapshot: loaded.initialSnapshot,
182
+ status: loaded.fatalError ? "fatal" : "loaded",
183
+ ...(loaded.fatalError ? { fatalError: loaded.fatalError } : {}),
184
+ };
185
+ emitUxResponse(runtime, {
186
+ apiFn: loadMetadata.name,
187
+ intent: loadMetadata.uxIntent.expectedDelta ?? "",
188
+ mockOrLive: "live",
189
+ uiVisible: true,
190
+ expectedDelta: loadMetadata.uxIntent.expectedDelta,
191
+ actualDelta: {
192
+ kind: "surface-refresh",
193
+ payload: { documentId: result.documentId, bytes: result.bytes, status: result.status },
194
+ },
195
+ });
196
+ return result;
197
+ },
198
+
199
+ async export(options?: ExportDocxOptions): Promise<ExportResult> {
200
+ // @endStateApi — live. Delegates to the shipped runtime export path.
201
+ const result = await runtime.exportDocx(options);
202
+ emitUxResponse(runtime, {
203
+ apiFn: exportMetadata.name,
204
+ intent: exportMetadata.uxIntent.expectedDelta ?? "",
205
+ mockOrLive: "live",
206
+ uiVisible: true,
207
+ expectedDelta: exportMetadata.uxIntent.expectedDelta,
208
+ actualDelta: { kind: "toast", payload: { bytes: result.bytes?.byteLength ?? 0 } },
209
+ });
210
+ return result;
211
+ },
212
+
213
+ validate(): ValidateResult & Partial<MockPayload> {
214
+ // @endStateApi — live-with-adapter. Composes three shipped runtime
215
+ // reads into a bundled ValidateResult:
216
+ // - getCompatibilityReport() for blockExport + counts + feature entries
217
+ // (with getRenderSnapshot().compatibility as a secondary fallback)
218
+ // - getWarnings() augments the warning count with runtime-emitted ones
219
+ // - getInteractionGuardSnapshot() for mode + readOnly
220
+ // Falls back to a mock-flagged shape only when both the compat read
221
+ // and the guard read are unavailable (e.g. pre-mount). The adapter
222
+ // promotes to `live` when a first-class runtime.validate() surfaces.
223
+ const report = runtime.getCompatibilityReport() as
224
+ | {
225
+ blockExport?: boolean;
226
+ warningCount?: number;
227
+ errorCount?: number;
228
+ featureEntries?: ReadonlyArray<unknown>;
229
+ }
230
+ | undefined
231
+ | null;
232
+ const snapshotCompat = runtime.getRenderSnapshot().compatibility;
233
+ const bundledReport = report ?? snapshotCompat;
234
+ const warnings = runtime.getWarnings();
235
+ const guard = runtime.getInteractionGuardSnapshot() as
236
+ | { mode?: string; readOnly?: boolean }
237
+ | undefined
238
+ | null;
239
+ if (!bundledReport && !guard) {
240
+ const fallback = mockPayload(
241
+ "no compatibility report or interaction guard available (pre-mount or test double)",
242
+ "ValidateResult",
243
+ {
244
+ reportVersion: "compatibility-report/1" as const,
245
+ blockExport: false,
246
+ warningCount: 0,
247
+ errorCount: 0,
248
+ featureEntriesCount: 0,
249
+ interactionGuard: { mode: "unknown", readOnly: false },
250
+ },
251
+ );
252
+ emitUxResponse(runtime, {
253
+ apiFn: validateMetadata.name,
254
+ intent: validateMetadata.uxIntent.expectedDelta ?? "",
255
+ mockOrLive: "mock",
256
+ uiVisible: true,
257
+ expectedDelta: validateMetadata.uxIntent.expectedDelta,
258
+ });
259
+ return fallback;
260
+ }
261
+ const result: ValidateResult = {
262
+ reportVersion: "compatibility-report/1",
263
+ blockExport: bundledReport?.blockExport ?? false,
264
+ warningCount: (bundledReport?.warningCount ?? 0) + warnings.length,
265
+ errorCount: bundledReport?.errorCount ?? 0,
266
+ featureEntriesCount: bundledReport?.featureEntries?.length ?? 0,
267
+ interactionGuard: {
268
+ mode: guard?.mode ?? "unknown",
269
+ readOnly: guard?.readOnly ?? false,
270
+ },
271
+ };
272
+ emitUxResponse(runtime, {
273
+ apiFn: validateMetadata.name,
274
+ intent: validateMetadata.uxIntent.expectedDelta ?? "",
275
+ mockOrLive: "live-with-adapter",
276
+ uiVisible: true,
277
+ expectedDelta: validateMetadata.uxIntent.expectedDelta,
278
+ });
279
+ return result;
280
+ },
281
+ };
282
+ }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * @endStateApi v3 — `runtime.formatting` family.
3
+ *
4
+ * getEffective (live) / resolveRunWithProvenance (live). Adapter delegates
5
+ * to Layer-03's `resolveEffectiveFormatting` façade + `FormattingContext`
6
+ * provenance path. No new logic lives here — the adapter only routes
7
+ * nodeRefs from the public API surface to the already-shipped L03 entry
8
+ * points.
9
+ *
10
+ * Cross-layer-coord reference: `docs/plans/cross-layer-coord-03.md` §2
11
+ * (L07 runtime.formatting.* public surface).
12
+ */
13
+
14
+ import type { RuntimeApiHandle } from "../_runtime-handle.ts";
15
+ import type { ApiV3FnMetadata } from "../_layer-metadata.ts";
16
+ import {
17
+ resolveEffectiveFormatting,
18
+ createFormattingContext,
19
+ type EffectiveFormatting,
20
+ type RunProvenance,
21
+ } from "../../../runtime/formatting/index.ts";
22
+ import {
23
+ findParagraphByBlockId,
24
+ resolveDirectRunFormattingAtSegment,
25
+ } from "../../../runtime/formatting/document-lookup.ts";
26
+ import type { RuntimeTelemetryEvent } from "../../../runtime/debug/types.ts";
27
+
28
+ /**
29
+ * Public nodeRef shape for `runtime.formatting.getEffective`. Structurally
30
+ * a subset of L03's internal `NodeRef` — the `field` kind's optional
31
+ * `pageGraph` is omitted from the public surface because threading the
32
+ * layout page-graph through is a separate integration tracked in the
33
+ * cross-layer-coord doc. Callers passing `{ kind: "field", ... }` get a
34
+ * `refreshStatus: "unresolved"` result, which is honest for now.
35
+ */
36
+ export type FormattingNodeRef =
37
+ | { readonly kind: "paragraph"; readonly blockId: string }
38
+ | { readonly kind: "run"; readonly blockId: string; readonly runId: string }
39
+ | { readonly kind: "table"; readonly blockId: string }
40
+ | {
41
+ readonly kind: "table-cell";
42
+ readonly blockId: string;
43
+ readonly rowIndex: number;
44
+ readonly cellIndex: number;
45
+ }
46
+ | { readonly kind: "field"; readonly blockId: string; readonly runId: string }
47
+ | {
48
+ readonly kind: "drawing-frame";
49
+ readonly blockId: string;
50
+ readonly inlineId: string;
51
+ };
52
+
53
+ export interface FormattingGetEffectiveOpts {
54
+ readonly revisionMarkupMode?: "clean" | "simple" | "all";
55
+ }
56
+
57
+ export const getEffectiveMetadata: ApiV3FnMetadata = {
58
+ name: "runtime.formatting.getEffective",
59
+ status: "live",
60
+ sourceLayer: "formatting-semantics",
61
+ // Direct delegation to `resolveEffectiveFormatting` — the Layer-03
62
+ // external façade. L03's cascade-parity + entry-delegation tests prove
63
+ // behavioral parity with the production hot path (`FormattingContext`).
64
+ liveEvidence: {
65
+ runnerTest:
66
+ "test/runtime/formatting/entry-delegation.test.ts,test/runtime/formatting/cascade-parity.test.ts,test/api/v3/runtime/formatting-adapter.test.ts",
67
+ commit: "refactor-03-runtime-formatting-adapter-2026-04-22",
68
+ },
69
+ // State-classes (Slice X2, f6051c07). Formatting output is derived
70
+ // from the canonical document (styles + revisions + theme etc.); it
71
+ // lives in the canonical tree and has no session-shared or local-pref
72
+ // surface. Derived read → no broadcastsVia.
73
+ stateClass: "A-canonical",
74
+ persistsTo: "canonical",
75
+ uxIntent: { uiVisible: false, expectsUxResponse: "none" },
76
+ agentMetadata: {
77
+ readOrMutate: "read",
78
+ boundedScope: "scope",
79
+ auditCategory: "formatting-read",
80
+ },
81
+ rwdReference:
82
+ "§Runtime API § runtime.formatting.getEffective. Adapter over Layer-03's resolveEffectiveFormatting façade — same code path the production hot path (FormattingContext) exercises.",
83
+ };
84
+
85
+ export const subscribeTelemetryMetadata: ApiV3FnMetadata = {
86
+ name: "runtime.formatting.subscribeTelemetry",
87
+ status: "live",
88
+ sourceLayer: "formatting-semantics",
89
+ liveEvidence: {
90
+ runnerTest: "test/api/v3/runtime/formatting-adapter.test.ts",
91
+ commit: "refactor-07-coord-03-formatting-subscribe-2026-04-22",
92
+ },
93
+ // Derived from canonical document (cascade resolution). Subscribe is
94
+ // a pass-through to the telemetry bus's `formatting` channel —
95
+ // consumers observe cache-miss / cascade-resolve events without
96
+ // importing the bus directly. The channel itself exists on the bus;
97
+ // L07 owns the v3 surface that gates access to it per the R-exposed
98
+ // patterns.
99
+ stateClass: "A-canonical",
100
+ persistsTo: "canonical",
101
+ uxIntent: { uiVisible: false, expectsUxResponse: "none" },
102
+ agentMetadata: {
103
+ readOrMutate: "read",
104
+ boundedScope: "document",
105
+ auditCategory: "formatting-subscribe",
106
+ },
107
+ rwdReference:
108
+ "§Runtime API § runtime.formatting.subscribeTelemetry. Pass-through to handle.debug.bus — enables the 'formatting' channel and forwards events to the listener. Returned closure unsubscribes. Used by L10 debug pane + agent-facing observers without reaching into the bus module directly.",
109
+ };
110
+
111
+ export const resolveRunWithProvenanceMetadata: ApiV3FnMetadata = {
112
+ name: "runtime.formatting.resolveRunWithProvenance",
113
+ status: "live",
114
+ sourceLayer: "formatting-semantics",
115
+ // Live delegation to FormattingContext.resolveRunWithProvenance. L03
116
+ // provenance test pins the per-field source map across the four
117
+ // cascade tiers (direct / characterStyle / style / docDefaults).
118
+ liveEvidence: {
119
+ runnerTest:
120
+ "test/runtime/formatting/provenance.test.ts,test/api/v3/runtime/formatting-adapter.test.ts",
121
+ commit: "refactor-03-runtime-formatting-adapter-2026-04-22",
122
+ },
123
+ stateClass: "A-canonical",
124
+ persistsTo: "canonical",
125
+ uxIntent: { uiVisible: false, expectsUxResponse: "none" },
126
+ agentMetadata: {
127
+ readOrMutate: "read",
128
+ boundedScope: "scope",
129
+ auditCategory: "formatting-read",
130
+ },
131
+ rwdReference:
132
+ "§Runtime API § runtime.formatting.resolveRunWithProvenance. Agent-facing provenance view — `source ∈ {direct, characterStyle, style, docDefaults}` plus `sourceId` for style tiers. Substrate for ai.explainFormatting (L09).",
133
+ };
134
+
135
+ export function createFormattingFamily(runtime: RuntimeApiHandle) {
136
+ return {
137
+ getEffective(
138
+ nodeRef: FormattingNodeRef,
139
+ opts?: FormattingGetEffectiveOpts,
140
+ ): EffectiveFormatting {
141
+ // @endStateApi — live. Delegates to L03's external façade against
142
+ // the current canonical document. Read-only; no side effects.
143
+ const doc = runtime.getCanonicalDocument();
144
+ return resolveEffectiveFormatting(doc, nodeRef, {
145
+ ...(opts?.revisionMarkupMode ? { revisionMarkupMode: opts.revisionMarkupMode } : {}),
146
+ });
147
+ },
148
+
149
+ subscribeTelemetry(
150
+ channel: "formatting",
151
+ listener: (event: RuntimeTelemetryEvent) => void,
152
+ ): () => void {
153
+ // @endStateApi — live. Pass-through to the runtime's telemetry bus.
154
+ // Enables the channel if it's off (otherwise the subscription
155
+ // attaches but never fires). Returns the bus's own unsubscribe
156
+ // closure — callers must retain + invoke it.
157
+ const bus = runtime.debug.bus;
158
+ if (!bus.isEnabled(channel)) {
159
+ bus.enable(channel);
160
+ }
161
+ return bus.subscribe([channel], listener);
162
+ },
163
+
164
+ resolveRunWithProvenance(input: {
165
+ readonly blockId: string;
166
+ readonly runId: string;
167
+ }): RunProvenance | null {
168
+ // @endStateApi — live. Looks up the canonical paragraph + inline
169
+ // at (blockId, runId), then calls FormattingContext.resolveRun
170
+ // WithProvenance to get the { run, properties } map. Returns null
171
+ // when the lookup misses (unknown blockId or segment out of range)
172
+ // — callers differentiate that from a real resolution with no
173
+ // populated fields.
174
+ const doc = runtime.getCanonicalDocument();
175
+ const foundPara = findParagraphByBlockId(doc, input.blockId);
176
+ if (!foundPara) return null;
177
+ const direct = resolveDirectRunFormattingAtSegment(foundPara.paragraph, input.runId);
178
+ const ctx = createFormattingContext(doc);
179
+ return ctx.resolveRunWithProvenance({
180
+ paragraphStyleId: foundPara.paragraph.styleId,
181
+ characterStyleId: direct?.characterStyleId,
182
+ direct,
183
+ });
184
+ },
185
+ };
186
+ }