@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,127 @@
1
+ /**
2
+ * Layer-06 Slice 3 — `WorkflowDebugEntry` projector.
3
+ *
4
+ * Produces a richer debug snapshot over the workflow overlay, metadata
5
+ * entries, interaction guard, tamper gate, and AI-action policy. The
6
+ * runtime's `buildDebugInspectorSnapshot` plugs this projector in when
7
+ * the `scope` or `warning` telemetry channels are on.
8
+ *
9
+ * Contract W-projector (plan §Slice 3): fields are counts and compact
10
+ * summaries, not full payloads. The projector walks the overlay once;
11
+ * cost scales linearly with scope + entry count and is acceptable only
12
+ * on-demand (not every commit).
13
+ */
14
+
15
+ import type {
16
+ InteractionGuardSnapshot,
17
+ WorkflowMetadataDefinition,
18
+ WorkflowMetadataEntry,
19
+ WorkflowOverlay,
20
+ } from "../../api/public-types.ts";
21
+ import {
22
+ AI_ACTION_POLICIES,
23
+ type AIActionCategory,
24
+ } from "./ai-action-policy.ts";
25
+
26
+ export interface WorkflowDebugEntry {
27
+ readonly overlay: {
28
+ readonly present: boolean;
29
+ readonly scopeCount: number;
30
+ readonly candidateCount: number;
31
+ /**
32
+ * Count of `WorkflowMarkupSnapshot.protectedRanges` — the stored,
33
+ * marker-backed analog of the UI-derived `WorkflowLockedZone`.
34
+ * Not the runtime derivation from `deriveVisibleWorkflowLockedZones`
35
+ * (that needs a surface + lives in the UI layer).
36
+ */
37
+ readonly protectedRangeCount: number;
38
+ readonly workItemCount: number;
39
+ readonly activeWorkItemId: string | null;
40
+ readonly metadataPersistenceMode: string | null;
41
+ };
42
+ readonly metadata: {
43
+ readonly definitionCount: number;
44
+ readonly entryCount: number;
45
+ readonly inlineEntryCount: number;
46
+ readonly externalEntryCount: number;
47
+ };
48
+ readonly scopes: {
49
+ readonly markerBackedCount: number;
50
+ readonly overlayOnlyCount: number;
51
+ readonly detachedCount: number;
52
+ };
53
+ readonly guard: {
54
+ readonly effectiveMode: InteractionGuardSnapshot["effectiveMode"];
55
+ readonly matchedScopeId: string | null;
56
+ readonly blockedReasonsCount: number;
57
+ };
58
+ readonly aiPolicy: {
59
+ readonly operationCount: number;
60
+ readonly categoryCount: number;
61
+ };
62
+ }
63
+
64
+ export interface ProjectWorkflowDebugEntryInput {
65
+ readonly overlay: WorkflowOverlay | null;
66
+ readonly metadataDefinitions: readonly WorkflowMetadataDefinition[];
67
+ readonly metadataEntries: readonly WorkflowMetadataEntry[];
68
+ readonly protectedRangeCount: number;
69
+ readonly scopeCounts: {
70
+ readonly markerBacked: number;
71
+ readonly overlayOnly: number;
72
+ readonly detached: number;
73
+ };
74
+ readonly guard: InteractionGuardSnapshot | null;
75
+ }
76
+
77
+ export function projectWorkflowDebugEntry(
78
+ input: ProjectWorkflowDebugEntryInput,
79
+ ): WorkflowDebugEntry {
80
+ const overlay = input.overlay;
81
+ let inlineEntryCount = 0;
82
+ let externalEntryCount = 0;
83
+ for (const entry of input.metadataEntries) {
84
+ if (entry.metadataPersistence === "external") {
85
+ externalEntryCount += 1;
86
+ } else {
87
+ inlineEntryCount += 1;
88
+ }
89
+ }
90
+
91
+ const uniqueCategories = new Set<AIActionCategory>();
92
+ for (const policy of AI_ACTION_POLICIES) {
93
+ uniqueCategories.add(policy.category);
94
+ }
95
+
96
+ return {
97
+ overlay: {
98
+ present: overlay !== null,
99
+ scopeCount: overlay?.scopes.length ?? 0,
100
+ candidateCount: overlay?.candidates?.length ?? 0,
101
+ protectedRangeCount: input.protectedRangeCount,
102
+ workItemCount: overlay?.workItems?.length ?? 0,
103
+ activeWorkItemId: overlay?.activeWorkItemId ?? null,
104
+ metadataPersistenceMode: overlay?.metadataPersistence ?? null,
105
+ },
106
+ metadata: {
107
+ definitionCount: input.metadataDefinitions.length,
108
+ entryCount: input.metadataEntries.length,
109
+ inlineEntryCount,
110
+ externalEntryCount,
111
+ },
112
+ scopes: {
113
+ markerBackedCount: input.scopeCounts.markerBacked,
114
+ overlayOnlyCount: input.scopeCounts.overlayOnly,
115
+ detachedCount: input.scopeCounts.detached,
116
+ },
117
+ guard: {
118
+ effectiveMode: input.guard?.effectiveMode ?? "edit",
119
+ matchedScopeId: input.guard?.matchedScopeId ?? null,
120
+ blockedReasonsCount: input.guard?.blockedReasons.length ?? 0,
121
+ },
122
+ aiPolicy: {
123
+ operationCount: AI_ACTION_POLICIES.length,
124
+ categoryCount: uniqueCategories.size,
125
+ },
126
+ };
127
+ }
@@ -7,9 +7,9 @@ import type {
7
7
  WorkflowOverlay,
8
8
  WorkflowScope,
9
9
  WorkflowWorkItem,
10
- } from "../api/public-types.ts";
11
- import type { CanonicalDocument } from "../model/canonical-document.ts";
12
- import type { CanonicalDocumentEnvelope } from "../core/state/editor-state.ts";
10
+ } from "../../api/public-types.ts";
11
+ import type { CanonicalDocument } from "../../model/canonical-document.ts";
12
+ import type { CanonicalDocumentEnvelope } from "../../core/state/editor-state.ts";
13
13
  import { collectScopeLocations } from "./scope-resolver.ts";
14
14
 
15
15
  function storyTargetsEqual(a: EditorStoryTarget, b: EditorStoryTarget): boolean {
@@ -10,87 +10,73 @@
10
10
  * left-gutter label column and the flat block-tint.
11
11
  *
12
12
  * The segments are pure reads over canonical state; no DOM, no PM.
13
+ *
14
+ * ## Layer boundary rationale (Slice 4 closure note)
15
+ *
16
+ * The contents of this module span five data sources: workflow
17
+ * overlay (L06), page graph (L04 input), anchor index (L05 input),
18
+ * issue + review-action metadata markup (L06), and suggestion
19
+ * snapshot (L11 input). That range prompted the adversarial review
20
+ * to flag the file as "too broad." The answer is: this IS the
21
+ * integration site for W7 (scope rail page-anchored). Rail
22
+ * composition is inherently cross-layer — you cannot produce a
23
+ * page-anchored scope-rail segment without joining workflow state,
24
+ * page geometry, and anchor rects. Splitting further would push
25
+ * the join elsewhere and make the W7 contract harder to audit.
26
+ *
27
+ * Guard rails instead of split:
28
+ * - `collectScopeRailSegments` consumes its inputs through a
29
+ * value-typed `CollectScopeRailSegmentsInput` — it does not
30
+ * reach back into the runtime.
31
+ * - `attachScopeCardModel` consumes an optional `anchorIndex`,
32
+ * optional `suggestions` snapshot, optional metadata arrays —
33
+ * all opt-in, all value-typed. Callers that don't wire a
34
+ * resolver get a card without external-metadata resolution.
35
+ * - `buildExternalResolutions` is the ONE async helper; callers
36
+ * who don't use external metadata never touch it.
37
+ * - No imports from `src/runtime/render` or `src/ui*`. Page
38
+ * graph + anchor index come through Layer-04/05 type files,
39
+ * not through facet imports.
40
+ *
41
+ * If the rail needs to grow (e.g., adding a new metadata family),
42
+ * the composer extends here. The module is ~500 lines because the
43
+ * W7 join has ~5 inputs; it will grow slowly, not change shape.
13
44
  */
14
45
 
15
46
  import type {
16
47
  EditorAnchorProjection,
17
- EditorStoryTarget,
18
48
  IssueMetadataValue,
19
49
  ReviewActionMetadataValue,
20
50
  ScopeCardModel,
21
- ScopeMetadataResolver,
22
51
  SuggestionGroup,
23
52
  SuggestionsSnapshot,
24
- WorkflowBlockedCommandReason,
25
53
  WorkflowCandidateRange,
26
- WorkflowLockedZone,
27
54
  WorkflowMetadataMarkup,
28
55
  WorkflowScope,
29
- } from "../api/public-types";
30
- import { ISSUE_METADATA_ID, REVIEW_ACTION_METADATA_ID } from "../api/public-types";
31
- import { MAIN_STORY_TARGET, storyTargetsEqual } from "../core/selection/mapping.ts";
32
- import type { RuntimePageGraph } from "./layout/page-graph.ts";
56
+ } from "../../../api/public-types";
57
+ import { ISSUE_METADATA_ID, REVIEW_ACTION_METADATA_ID } from "../../../api/public-types";
58
+ import { MAIN_STORY_TARGET, storyTargetsEqual } from "../../../core/selection/mapping.ts";
59
+ import type { RuntimePageGraph } from "../../layout/page-graph.ts";
33
60
  import type {
34
- RenderAnchorIndex,
35
- RenderFrameRect,
36
- } from "./render/render-frame-types.ts";
37
-
38
- // ---------------------------------------------------------------------------
39
- // Public shape
40
- // ---------------------------------------------------------------------------
41
-
42
- export type ScopeRailPosture =
43
- | "edit"
44
- | "suggest"
45
- | "comment"
46
- | "view"
47
- | "candidate"
48
- | "preserve-only"
49
- | "blocked-import";
50
-
51
- export interface ScopeRailSegment {
52
- /** Identifier the chrome uses to sync with the Workflow rail tab. */
53
- scopeId: string;
54
- /** Visual+accessibility posture keyed off the scope mode or block reason. */
55
- posture: ScopeRailPosture;
56
- /** Human label; empty string when none was supplied by the host. */
57
- label: string;
58
- /** Runtime offsets (inclusive from, exclusive to) this segment spans on the active story. */
59
- fromOffset: number;
60
- toOffset: number;
61
- /** Story the segment sits on. */
62
- storyTarget: EditorStoryTarget;
63
- /** Page index the segment renders on (may span multiple pages; emitted per page). */
64
- pageIndex: number;
65
- /** Section index derived from the page graph. */
66
- sectionIndex: number;
67
- /** True when the scope is the active work item. */
68
- isActiveWorkItem: boolean;
69
- /**
70
- * Body-tint rect in overlay-space pixels, populated when the render kernel
71
- * is available. Chrome consumers read this directly instead of
72
- * re-projecting per render via the overlay projector. `null` when the
73
- * segment is produced without a kernel (e.g., in tests or before the
74
- * facet is bound to a page graph) — consumers fall back to per-render
75
- * anchor resolution in that case.
76
- */
77
- bodyTintRect: RenderFrameRect | null;
78
- }
79
-
80
- // ---------------------------------------------------------------------------
81
- // Collector input
82
- // ---------------------------------------------------------------------------
83
-
84
- export interface CollectScopeRailSegmentsInput {
85
- scopes: readonly WorkflowScope[] | undefined;
86
- candidates?: readonly WorkflowCandidateRange[];
87
- blockedReasons?: readonly WorkflowBlockedCommandReason[];
88
- lockedZones?: readonly WorkflowLockedZone[];
89
- activeWorkItemScopeIds?: readonly string[];
90
- /** Active story scopes render on; segments for other stories are skipped. */
91
- activeStory?: EditorStoryTarget;
92
- pageGraph: RuntimePageGraph;
93
- }
61
+ AttachScopeCardModelInput,
62
+ BuildExternalResolutionsInput,
63
+ BuildExternalResolutionsResult,
64
+ CollectScopeRailSegmentsInput,
65
+ ScopeRailPosture,
66
+ ScopeRailSegment,
67
+ } from "./types.ts";
68
+
69
+ // Re-export the type surface so consumers that import directly from
70
+ // `./compose.ts` (the historical home) keep compiling. The declarations
71
+ // live in `./types.ts`.
72
+ export type {
73
+ AttachScopeCardModelInput,
74
+ BuildExternalResolutionsInput,
75
+ BuildExternalResolutionsResult,
76
+ CollectScopeRailSegmentsInput,
77
+ ScopeRailPosture,
78
+ ScopeRailSegment,
79
+ };
94
80
 
95
81
  // ---------------------------------------------------------------------------
96
82
  // Entry point
@@ -293,69 +279,7 @@ function resolveScopePosture(scope: WorkflowScope): ScopeRailPosture {
293
279
  // ---------------------------------------------------------------------------
294
280
  // Scope card projection (P1b — consumed by ref.layout.getAllScopeCardModels)
295
281
  // ---------------------------------------------------------------------------
296
-
297
- export interface AttachScopeCardModelInput {
298
- /**
299
- * Segments produced by `collectScopeRailSegments`. The card model
300
- * keys off segments so per-scope card state stays aligned with the
301
- * rail stripe rendering.
302
- */
303
- segments: readonly ScopeRailSegment[];
304
- /**
305
- * Original workflow scopes — used to resolve `workItemId` for each
306
- * segment (the segment shape predates workItemId passthrough).
307
- * Optional; when absent, cards drop `workItemId` and issue matching
308
- * falls back to scope-id only.
309
- */
310
- scopes?: readonly WorkflowScope[];
311
- /**
312
- * Workflow metadata markup from `WorkflowMarkupSnapshot.metadata`.
313
- * Entries with `metadataId === ISSUE_METADATA_ID` that match a
314
- * segment's `workItemId` or `scopeId` attach as the card's issue.
315
- */
316
- metadata?: readonly WorkflowMetadataMarkup[];
317
- /**
318
- * Optional anchor index used to resolve each card's
319
- * `primaryAnchorRect`. When omitted, cards are produced without
320
- * rects — chrome consumers fall back to on-render positioning.
321
- */
322
- anchorIndex?: RenderAnchorIndex | null;
323
- /**
324
- * R3 — suggestion snapshot. Groups whose `issueId` matches the
325
- * scope's issue attach as `ScopeCardModel.suggestionGroups`; their
326
- * ids land in `suggestionGroupIds` as a convenience for consumers
327
- * that want a flat lookup.
328
- */
329
- suggestions?: SuggestionsSnapshot | null;
330
- /**
331
- * K1-light — review-action markup. Entries with
332
- * `metadataId === REVIEW_ACTION_METADATA_ID` whose coerced value's
333
- * `issueId` matches the scope's issue attach newest-first as
334
- * `ScopeCardModel.reviewActions`.
335
- */
336
- reviewActionMetadata?: readonly WorkflowMetadataMarkup[];
337
- /**
338
- * K2 — candidate ranges. Any entry with `source: "ai"` whose
339
- * offset range overlaps the segment flips `agentPending` to true.
340
- */
341
- candidates?: readonly WorkflowCandidateRange[];
342
- /**
343
- * Pre-resolved external metadata values, keyed by entryId. When an
344
- * entry in `metadata` or `reviewActionMetadata` has
345
- * `metadataPersistence === "external"` and its inline `value` is
346
- * undefined, this map supplies the resolved value (fetched by the caller
347
- * via `ScopeMetadataResolver.resolve`).
348
- *
349
- * Entries absent from the map render as if the metadata had no value —
350
- * the card still shows the scope but drops the issue row, consistent with
351
- * how malformed metadata is handled today.
352
- *
353
- * NOTE: The facet's `getAllScopeCardModels()` does NOT populate this.
354
- * Callers that need resolved values build the map via
355
- * `buildExternalResolutions()` and call `attachScopeCardModel()` directly.
356
- */
357
- externalResolutions?: ReadonlyMap<string, { value: Record<string, unknown>; version?: number }>;
358
- }
282
+ // `AttachScopeCardModelInput` lives in `./types.ts` (re-exported above).
359
283
 
360
284
  /**
361
285
  * Project rail segments into per-scope `ScopeCardModel` values.
@@ -570,28 +494,8 @@ function coerceIssueValue(
570
494
  // buildExternalResolutions — caller utility for pre-resolving external refs
571
495
  // ---------------------------------------------------------------------------
572
496
 
573
- /**
574
- * Structured result from `buildExternalResolutions`. Callers that previously
575
- * consumed the return value as a `Map` directly must now destructure `.resolutions`.
576
- */
577
- export interface BuildExternalResolutionsResult {
578
- /**
579
- * Resolved values keyed by `entryId`. Suitable for passing into
580
- * `AttachScopeCardModelInput.externalResolutions`.
581
- */
582
- resolutions: Map<string, { value: Record<string, unknown>; version?: number }>;
583
- /**
584
- * Detected version mismatches. Non-empty only when the caller passes
585
- * `detectConflicts: true`. Each record includes both sides' value +
586
- * version so the caller can emit a `metadata_conflict_detected` event.
587
- */
588
- conflicts: Array<{
589
- scopeId?: string;
590
- entryId?: string;
591
- embedded: { value?: Record<string, unknown>; version?: number } | null;
592
- external: { value?: Record<string, unknown>; version?: number } | null;
593
- }>;
594
- }
497
+ // `BuildExternalResolutionsResult` + `BuildExternalResolutionsInput`
498
+ // live in `./types.ts` (re-exported above).
595
499
 
596
500
  /**
597
501
  * Pre-resolve every external-mode metadata entry's value via the supplied
@@ -615,18 +519,9 @@ export interface BuildExternalResolutionsResult {
615
519
  * The layout facet's `getAllScopeCardModels()` does NOT call this — it is a
616
520
  * React-layer concern where async is normal.
617
521
  */
618
- export async function buildExternalResolutions(input: {
619
- metadata: readonly WorkflowMetadataMarkup[];
620
- reviewActionMetadata?: readonly WorkflowMetadataMarkup[];
621
- resolver: ScopeMetadataResolver;
622
- /**
623
- * When `true`, the helper compares each external entry's embedded
624
- * `metadataVersion` against the resolver-returned version and records a
625
- * conflict for every mismatch. Absent / `false` → `conflicts` is always
626
- * empty (backwards-compatible default).
627
- */
628
- detectConflicts?: boolean;
629
- }): Promise<BuildExternalResolutionsResult> {
522
+ export async function buildExternalResolutions(
523
+ input: BuildExternalResolutionsInput,
524
+ ): Promise<BuildExternalResolutionsResult> {
630
525
  const externalEntries = [
631
526
  ...input.metadata,
632
527
  ...(input.reviewActionMetadata ?? []),
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Scope-rail public types (declarations).
3
+ *
4
+ * Physical home for the rail shape contracts. `./compose.ts` imports
5
+ * from here and re-exports for backward compatibility with consumers
6
+ * that import directly from the composer. Refactor/06 Slice 1 created
7
+ * the file as a re-export facade; Slice-3 cleanup migrated the
8
+ * declarations so the split is real.
9
+ */
10
+
11
+ import type {
12
+ EditorStoryTarget,
13
+ ScopeCardModel,
14
+ ScopeMetadataResolver,
15
+ SuggestionsSnapshot,
16
+ WorkflowBlockedCommandReason,
17
+ WorkflowCandidateRange,
18
+ WorkflowLockedZone,
19
+ WorkflowMetadataMarkup,
20
+ WorkflowScope,
21
+ } from "../../../api/public-types.ts";
22
+ import type { RuntimePageGraph } from "../../layout/page-graph.ts";
23
+ import type {
24
+ RenderAnchorIndex,
25
+ RenderFrameRect,
26
+ } from "../../render/render-frame-types.ts";
27
+
28
+ /**
29
+ * Visual+accessibility posture keyed off the scope mode or block reason.
30
+ */
31
+ export type ScopeRailPosture =
32
+ | "edit"
33
+ | "suggest"
34
+ | "comment"
35
+ | "view"
36
+ | "candidate"
37
+ | "preserve-only"
38
+ | "blocked-import";
39
+
40
+ export interface ScopeRailSegment {
41
+ /** Identifier the chrome uses to sync with the Workflow rail tab. */
42
+ scopeId: string;
43
+ /** Visual+accessibility posture keyed off the scope mode or block reason. */
44
+ posture: ScopeRailPosture;
45
+ /** Human label; empty string when none was supplied by the host. */
46
+ label: string;
47
+ /** Runtime offsets (inclusive from, exclusive to) this segment spans on the active story. */
48
+ fromOffset: number;
49
+ toOffset: number;
50
+ /** Story the segment sits on. */
51
+ storyTarget: EditorStoryTarget;
52
+ /** Page index the segment renders on (may span multiple pages; emitted per page). */
53
+ pageIndex: number;
54
+ /** Section index derived from the page graph. */
55
+ sectionIndex: number;
56
+ /** True when the scope is the active work item. */
57
+ isActiveWorkItem: boolean;
58
+ /**
59
+ * Body-tint rect in overlay-space pixels, populated when the render kernel
60
+ * is available. Chrome consumers read this directly instead of
61
+ * re-projecting per render via the overlay projector. `null` when the
62
+ * segment is produced without a kernel (e.g., in tests or before the
63
+ * facet is bound to a page graph) — consumers fall back to per-render
64
+ * anchor resolution in that case.
65
+ */
66
+ bodyTintRect: RenderFrameRect | null;
67
+ }
68
+
69
+ export interface CollectScopeRailSegmentsInput {
70
+ scopes: readonly WorkflowScope[] | undefined;
71
+ candidates?: readonly WorkflowCandidateRange[];
72
+ blockedReasons?: readonly WorkflowBlockedCommandReason[];
73
+ lockedZones?: readonly WorkflowLockedZone[];
74
+ activeWorkItemScopeIds?: readonly string[];
75
+ /** Active story scopes render on; segments for other stories are skipped. */
76
+ activeStory?: EditorStoryTarget;
77
+ pageGraph: RuntimePageGraph;
78
+ }
79
+
80
+ export interface AttachScopeCardModelInput {
81
+ /**
82
+ * Segments produced by `collectScopeRailSegments`. The card model
83
+ * keys off segments so per-scope card state stays aligned with the
84
+ * rail stripe rendering.
85
+ */
86
+ segments: readonly ScopeRailSegment[];
87
+ /**
88
+ * Original workflow scopes — used to resolve `workItemId` for each
89
+ * segment (the segment shape predates workItemId passthrough).
90
+ * Optional; when absent, cards drop `workItemId` and issue matching
91
+ * falls back to scope-id only.
92
+ */
93
+ scopes?: readonly WorkflowScope[];
94
+ /**
95
+ * Workflow metadata markup from `WorkflowMarkupSnapshot.metadata`.
96
+ * Entries with `metadataId === ISSUE_METADATA_ID` that match a
97
+ * segment's `workItemId` or `scopeId` attach as the card's issue.
98
+ */
99
+ metadata?: readonly WorkflowMetadataMarkup[];
100
+ /**
101
+ * Optional anchor index used to resolve each card's
102
+ * `primaryAnchorRect`. When omitted, cards are produced without
103
+ * rects — chrome consumers fall back to on-render positioning.
104
+ */
105
+ anchorIndex?: RenderAnchorIndex | null;
106
+ /**
107
+ * R3 — suggestion snapshot. Groups whose `issueId` matches the
108
+ * scope's issue attach as `ScopeCardModel.suggestionGroups`; their
109
+ * ids land in `suggestionGroupIds` as a convenience for consumers
110
+ * that want a flat lookup.
111
+ */
112
+ suggestions?: SuggestionsSnapshot | null;
113
+ /**
114
+ * K1-light — review-action markup. Entries with
115
+ * `metadataId === REVIEW_ACTION_METADATA_ID` whose coerced value's
116
+ * `issueId` matches the scope's issue attach newest-first as
117
+ * `ScopeCardModel.reviewActions`.
118
+ */
119
+ reviewActionMetadata?: readonly WorkflowMetadataMarkup[];
120
+ /**
121
+ * K2 — candidate ranges. Any entry with `source: "ai"` whose
122
+ * offset range overlaps the segment flips `agentPending` to true.
123
+ */
124
+ candidates?: readonly WorkflowCandidateRange[];
125
+ /**
126
+ * Pre-resolved external metadata values, keyed by entryId. When an
127
+ * entry in `metadata` or `reviewActionMetadata` has
128
+ * `metadataPersistence === "external"` and its inline `value` is
129
+ * undefined, this map supplies the resolved value (fetched by the caller
130
+ * via `ScopeMetadataResolver.resolve`).
131
+ *
132
+ * Entries absent from the map render as if the metadata had no value —
133
+ * the card still shows the scope but drops the issue row, consistent with
134
+ * how malformed metadata is handled today.
135
+ *
136
+ * NOTE: The facet's `getAllScopeCardModels()` does NOT populate this.
137
+ * Callers that need resolved values build the map via
138
+ * `buildExternalResolutions()` and call `attachScopeCardModel()` directly.
139
+ */
140
+ externalResolutions?: ReadonlyMap<string, { value: Record<string, unknown>; version?: number }>;
141
+ }
142
+
143
+ /**
144
+ * Structured result from `buildExternalResolutions`. Callers that previously
145
+ * consumed the return value as a `Map` directly must now destructure `.resolutions`.
146
+ */
147
+ export interface BuildExternalResolutionsResult {
148
+ /**
149
+ * Resolved values keyed by `entryId`. Suitable for passing into
150
+ * `AttachScopeCardModelInput.externalResolutions`.
151
+ */
152
+ resolutions: Map<string, { value: Record<string, unknown>; version?: number }>;
153
+ /**
154
+ * Detected version mismatches. Non-empty only when the caller passes
155
+ * `detectConflicts: true`. Each record includes both sides' value +
156
+ * version so the caller can emit a `metadata_conflict_detected` event.
157
+ */
158
+ conflicts: Array<{
159
+ scopeId?: string;
160
+ entryId?: string;
161
+ embedded: { value?: Record<string, unknown>; version?: number } | null;
162
+ external: { value?: Record<string, unknown>; version?: number } | null;
163
+ }>;
164
+ }
165
+
166
+ export interface BuildExternalResolutionsInput {
167
+ metadata: readonly WorkflowMetadataMarkup[];
168
+ reviewActionMetadata?: readonly WorkflowMetadataMarkup[];
169
+ resolver: ScopeMetadataResolver;
170
+ /**
171
+ * When `true`, the helper compares each external entry's embedded
172
+ * `metadataVersion` against the resolver-returned version and records a
173
+ * conflict for every mismatch. Absent / `false` → `conflicts` is always
174
+ * empty (backwards-compatible default).
175
+ */
176
+ detectConflicts?: boolean;
177
+ }
178
+
179
+
180
+ /**
181
+ * Layer-06-owned workflow rail / scope-card facet. Implemented by the
182
+ * workflow coordinator (see `../coordinator.ts`). UI consumers receive
183
+ * this via `runtime.workflow` and use it in place of the deprecated
184
+ * layout-facet rail methods.
185
+ *
186
+ * Layer-06 Slice 4 (rail-seam inversion) made this the canonical seam
187
+ * for scope-rail + scope-card composition. The layout facet no longer
188
+ * exposes these methods.
189
+ */
190
+ export interface WorkflowFacet {
191
+ /** Segments for a specific page index. */
192
+ getRailSegments(pageIndex: number): readonly ScopeRailSegment[];
193
+ /** All segments across all pages. */
194
+ getAllRailSegments(): readonly ScopeRailSegment[];
195
+ /** Full scope-card models with metadata + suggestions attached. */
196
+ getAllScopeCardModels(): readonly ScopeCardModel[];
197
+ }
198
+
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Layer 06 — Scope-rail composer (null-input wrapper).
3
+ *
4
+ * Thin wrapper over `collectScopeRailSegments` in `./rail/compose.ts`.
5
+ * Accepts a possibly-null workflow input + a page graph, returns
6
+ * `ScopeRailSegment[]`. Returns `[]` when the caller has no overlay
7
+ * yet so downstream iteration never null-checks.
8
+ *
9
+ * History: originally parked in `src/runtime/geometry/project-anchors.ts`
10
+ * by refactor/05 Slice 2b as a transitional home. Moved here by
11
+ * refactor/06 (post-CLOSURE additive) per architecture 06's
12
+ * "Code that lives here" table — L06 is the canonical owner of scope-
13
+ * rail composition, and this is the null-input boundary.
14
+ *
15
+ * W9 purity: imports only sibling `./rail/compose.ts`.
16
+ */
17
+
18
+ import type { RuntimePageGraph } from "../layout/page-graph.ts";
19
+ import {
20
+ collectScopeRailSegments,
21
+ type CollectScopeRailSegmentsInput,
22
+ type ScopeRailSegment,
23
+ } from "./rail/compose.ts";
24
+
25
+ export function collectScopeRailSegmentsForQuery(
26
+ input:
27
+ | Omit<CollectScopeRailSegmentsInput, "pageGraph">
28
+ | null
29
+ | undefined,
30
+ graph: RuntimePageGraph,
31
+ ): ScopeRailSegment[] {
32
+ if (!input) {
33
+ // No overlay / no workflow input is a legitimate state — documents
34
+ // open without an overlay until the host calls `setWorkflowOverlay`
35
+ // or `addScope`. Callers iterate over an empty array in that case.
36
+ return [];
37
+ }
38
+ return collectScopeRailSegments({ ...input, pageGraph: graph });
39
+ }
@@ -3,9 +3,9 @@ import type {
3
3
  DocumentRootNode,
4
4
  InlineNode,
5
5
  ParagraphNode,
6
- } from "../model/canonical-document.ts";
7
- import type { CanonicalDocumentEnvelope } from "../core/state/editor-state.ts";
8
- import type { EditorAnchorProjection } from "../api/public-types.ts";
6
+ } from "../../model/canonical-document.ts";
7
+ import type { CanonicalDocumentEnvelope } from "../../core/state/editor-state.ts";
8
+ import type { EditorAnchorProjection } from "../../api/public-types.ts";
9
9
 
10
10
  export interface ResolvedScopeLocation {
11
11
  scopeId: string;