@beyondwork/docx-react-component 1.0.105 → 1.0.108

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/package.json +19 -5
  2. package/src/api/geometry-overlay-rects.ts +5 -0
  3. package/src/api/package-version.ts +1 -1
  4. package/src/api/page-anchor-id.ts +5 -0
  5. package/src/api/public-types.ts +16 -9
  6. package/src/api/table-node-specs.ts +6 -0
  7. package/src/api/v3/_create.ts +10 -2
  8. package/src/api/v3/_page-anchor-id.ts +52 -0
  9. package/src/api/v3/_runtime-handle.ts +92 -1
  10. package/src/api/v3/ai/_audit-reference.ts +28 -0
  11. package/src/api/v3/ai/_audit-time.ts +5 -0
  12. package/src/api/v3/ai/_pe2-evidence.ts +310 -6
  13. package/src/api/v3/ai/attach.ts +29 -4
  14. package/src/api/v3/ai/bundle.ts +6 -2
  15. package/src/api/v3/ai/inspect.ts +6 -2
  16. package/src/api/v3/ai/replacement.ts +112 -18
  17. package/src/api/v3/ai/resolve.ts +2 -2
  18. package/src/api/v3/ai/review.ts +177 -3
  19. package/src/api/v3/index.ts +8 -0
  20. package/src/api/v3/runtime/collab.ts +462 -0
  21. package/src/api/v3/runtime/document.ts +503 -20
  22. package/src/api/v3/runtime/geometry.ts +97 -0
  23. package/src/api/v3/runtime/layout.ts +744 -0
  24. package/src/api/v3/runtime/perf-probe.ts +14 -0
  25. package/src/api/v3/runtime/viewport.ts +9 -8
  26. package/src/api/v3/ui/_types.ts +202 -55
  27. package/src/api/v3/ui/chrome-preset-model.ts +5 -5
  28. package/src/api/v3/ui/debug.ts +115 -2
  29. package/src/api/v3/ui/index.ts +17 -0
  30. package/src/api/v3/ui/overlays.ts +0 -8
  31. package/src/api/v3/ui/surface.ts +56 -0
  32. package/src/api/v3/ui/viewport.ts +119 -9
  33. package/src/core/commands/image-commands.ts +1 -0
  34. package/src/core/commands/index.ts +6 -0
  35. package/src/core/schema/text-schema.ts +43 -5
  36. package/src/core/selection/mapping.ts +8 -1
  37. package/src/core/selection/review-anchors.ts +5 -1
  38. package/src/core/state/text-transaction.ts +8 -2
  39. package/src/io/export/serialize-revisions.ts +149 -1
  40. package/src/io/normalize/normalize-text.ts +6 -0
  41. package/src/io/ooxml/parse-bookmark-references.ts +55 -0
  42. package/src/io/ooxml/parse-fields.ts +24 -2
  43. package/src/io/ooxml/parse-headers-footers.ts +38 -5
  44. package/src/io/ooxml/parse-main-document.ts +153 -9
  45. package/src/io/ooxml/parse-numbering.ts +20 -0
  46. package/src/io/ooxml/parse-revisions.ts +19 -8
  47. package/src/io/opc/package-reader.ts +98 -8
  48. package/src/model/anchor.ts +4 -3
  49. package/src/model/canonical-document.ts +220 -2
  50. package/src/model/canonical-hash.ts +221 -0
  51. package/src/model/canonical-layout-inputs.ts +245 -6
  52. package/src/model/layout/index.ts +1 -0
  53. package/src/model/layout/page-graph-types.ts +147 -1
  54. package/src/model/review/revision-types.ts +14 -3
  55. package/src/preservation/store.ts +20 -4
  56. package/src/review/README.md +1 -1
  57. package/src/review/store/revision-actions.ts +14 -2
  58. package/src/runtime/collab/event-types.ts +67 -1
  59. package/src/runtime/collab/runtime-collab-sync.ts +177 -5
  60. package/src/runtime/diagnostics/layout-guard-warning.ts +18 -0
  61. package/src/runtime/document-heading-outline.ts +147 -0
  62. package/src/runtime/document-navigation.ts +8 -243
  63. package/src/runtime/document-runtime.ts +279 -115
  64. package/src/runtime/edit-dispatch/dispatch-text-command.ts +11 -0
  65. package/src/runtime/formatting/layout-inputs.ts +38 -5
  66. package/src/runtime/formatting/numbering/geometry.ts +28 -2
  67. package/src/runtime/geometry/adjacent-geometry-intake.ts +835 -0
  68. package/src/runtime/geometry/caret-geometry.ts +5 -6
  69. package/src/runtime/geometry/geometry-facet.ts +60 -10
  70. package/src/runtime/geometry/geometry-index.ts +661 -16
  71. package/src/runtime/geometry/geometry-types.ts +59 -0
  72. package/src/runtime/geometry/hit-test.ts +11 -1
  73. package/src/runtime/geometry/overlay-rects.ts +5 -3
  74. package/src/runtime/geometry/project-anchors.ts +1 -1
  75. package/src/runtime/geometry/word-layout-v2-line-intake.ts +323 -0
  76. package/src/runtime/layout/index.ts +6 -0
  77. package/src/runtime/layout/layout-engine-instance.ts +6 -1
  78. package/src/runtime/layout/layout-engine-version.ts +188 -16
  79. package/src/runtime/layout/layout-facet-types.ts +6 -0
  80. package/src/runtime/layout/page-graph.ts +23 -4
  81. package/src/runtime/layout/paginated-layout-engine.ts +149 -15
  82. package/src/runtime/layout/project-block-fragments.ts +351 -14
  83. package/src/runtime/layout/public-facet.ts +162 -24
  84. package/src/runtime/layout/table-row-continuation-contract.ts +107 -0
  85. package/src/runtime/layout/table-row-split.ts +92 -35
  86. package/src/runtime/prerender/cache-envelope.ts +2 -2
  87. package/src/runtime/prerender/cache-key.ts +5 -4
  88. package/src/runtime/prerender/customxml-cache.ts +0 -1
  89. package/src/runtime/render/render-kernel.ts +1 -1
  90. package/src/runtime/revision-runtime.ts +112 -10
  91. package/src/runtime/scopes/_scope-dependencies.ts +1 -0
  92. package/src/runtime/scopes/action-validation.ts +22 -2
  93. package/src/runtime/scopes/capabilities.ts +316 -0
  94. package/src/runtime/scopes/compile-scope-bundle.ts +14 -0
  95. package/src/runtime/scopes/compiler-service.ts +108 -4
  96. package/src/runtime/scopes/content-control-evidence.ts +79 -0
  97. package/src/runtime/scopes/create-issue.ts +5 -5
  98. package/src/runtime/scopes/evidence.ts +91 -0
  99. package/src/runtime/scopes/formatting/apply.ts +2 -0
  100. package/src/runtime/scopes/geometry-evidence.ts +130 -0
  101. package/src/runtime/scopes/index.ts +54 -0
  102. package/src/runtime/scopes/issue-lifecycle.ts +224 -0
  103. package/src/runtime/scopes/layout-evidence.ts +374 -0
  104. package/src/runtime/scopes/multi-paragraph-refusal.ts +37 -0
  105. package/src/runtime/scopes/preservation-boundary.ts +7 -1
  106. package/src/runtime/scopes/replacement/apply.ts +97 -34
  107. package/src/runtime/scopes/scope-kinds/paragraph.ts +108 -12
  108. package/src/runtime/scopes/semantic-scope-types.ts +242 -3
  109. package/src/runtime/scopes/visualization.ts +28 -0
  110. package/src/runtime/surface-projection.ts +44 -5
  111. package/src/runtime/telemetry/perf-probe.ts +216 -0
  112. package/src/runtime/virtualized-rendering.ts +36 -1
  113. package/src/runtime/workflow/ai-issue-lifecycle.ts +253 -0
  114. package/src/runtime/workflow/coordinator.ts +39 -11
  115. package/src/runtime/workflow/derived-scope-resolver.ts +63 -9
  116. package/src/runtime/workflow/index.ts +4 -0
  117. package/src/runtime/workflow/overlay-lane-types.ts +58 -0
  118. package/src/runtime/workflow/overlay-lanes.ts +386 -0
  119. package/src/runtime/workflow/overlay-store.ts +2 -2
  120. package/src/runtime/workflow/redline-posture-calibration.ts +257 -0
  121. package/src/runtime/workflow/word-field-matrix-calibration.ts +231 -0
  122. package/src/session/_sync-legacy.ts +17 -27
  123. package/src/session/import/loader.ts +6 -4
  124. package/src/session/import/source-package-evidence.ts +186 -2
  125. package/src/session/index.ts +5 -6
  126. package/src/session/session.ts +30 -56
  127. package/src/session/types.ts +8 -13
  128. package/src/shell/session-bootstrap.ts +155 -81
  129. package/src/ui/WordReviewEditor.tsx +520 -12
  130. package/src/ui/editor-shell-view.tsx +14 -4
  131. package/src/ui/editor-surface-controller.tsx +5 -3
  132. package/src/ui/headless/selection-tool-resolver.ts +1 -2
  133. package/src/ui/presence-overlay-lane.ts +130 -0
  134. package/src/ui/ui-controller-factory.ts +17 -0
  135. package/src/ui-tailwind/chrome/build-context-menu-entries.ts +5 -1
  136. package/src/ui-tailwind/chrome/editor-action-registry.ts +105 -5
  137. package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +7 -0
  138. package/src/ui-tailwind/chrome/layer-debug-contracts.ts +208 -0
  139. package/src/ui-tailwind/chrome/resolve-target-kind.ts +13 -0
  140. package/src/ui-tailwind/chrome/tw-alert-banner.tsx +11 -3
  141. package/src/ui-tailwind/chrome/tw-command-palette.tsx +36 -6
  142. package/src/ui-tailwind/chrome/tw-context-menu.tsx +6 -1
  143. package/src/ui-tailwind/chrome/tw-display-mode-selector.tsx +42 -109
  144. package/src/ui-tailwind/chrome/tw-inline-find-bar.tsx +26 -6
  145. package/src/ui-tailwind/chrome/tw-navigation-command-bar.tsx +328 -0
  146. package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +8 -4
  147. package/src/ui-tailwind/chrome/tw-runtime-repl-dialog.tsx +129 -1
  148. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +19 -5
  149. package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +5 -1
  150. package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +28 -12
  151. package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +30 -3
  152. package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +116 -10
  153. package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +223 -94
  154. package/src/ui-tailwind/chrome-overlay/tw-presence-overlay-lane.tsx +157 -0
  155. package/src/ui-tailwind/chrome-overlay/tw-review-overlay-lane-markers.tsx +259 -0
  156. package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +5 -2
  157. package/src/ui-tailwind/chrome-overlay/tw-substrate-overlay-lanes.tsx +314 -0
  158. package/src/ui-tailwind/debug/README.md +4 -1
  159. package/src/ui-tailwind/debug/layer11-consumer-readiness.ts +272 -0
  160. package/src/ui-tailwind/debug/layer11-word-field-matrix-evidence.ts +160 -0
  161. package/src/ui-tailwind/editor-surface/perf-probe.ts +14 -215
  162. package/src/ui-tailwind/editor-surface/pm-decorations.ts +42 -0
  163. package/src/ui-tailwind/editor-surface/pm-position-map.ts +38 -2
  164. package/src/ui-tailwind/editor-surface/pm-schema.ts +14 -4
  165. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +34 -5
  166. package/src/ui-tailwind/editor-surface/runtime-decoration-plugin.ts +9 -19
  167. package/src/ui-tailwind/editor-surface/surface-build-keys.ts +2 -2
  168. package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +145 -0
  169. package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +16 -11
  170. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +8 -10
  171. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +3 -0
  172. package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +4 -2
  173. package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +60 -20
  174. package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +16 -11
  175. package/src/ui-tailwind/review/tw-health-panel.tsx +36 -17
  176. package/src/ui-tailwind/review/tw-review-rail.tsx +7 -4
  177. package/src/ui-tailwind/review-workspace/diagnostics-visibility.ts +44 -0
  178. package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +11 -0
  179. package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +16 -1
  180. package/src/ui-tailwind/review-workspace/types.ts +26 -12
  181. package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +40 -11
  182. package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +2 -1
  183. package/src/ui-tailwind/review-workspace/use-page-markers.ts +15 -26
  184. package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +35 -18
  185. package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +41 -32
  186. package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +2 -1
  187. package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +2 -1
  188. package/src/ui-tailwind/status/tw-status-bar.tsx +6 -5
  189. package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +52 -80
  190. package/src/ui-tailwind/toolbar/tw-shell-header.tsx +12 -48
  191. package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +9 -4
  192. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +328 -361
  193. package/src/ui-tailwind/tw-review-workspace.tsx +152 -286
@@ -37,10 +37,12 @@ import type {
37
37
  WorkflowMetadataEntry,
38
38
  WorkflowMetadataSnapshot,
39
39
  WorkflowOverlay,
40
+ WorkflowEventOrigin,
40
41
  } from "./_scope-dependencies.ts";
41
42
  import type { CanonicalDocumentEnvelope } from "../../core/state/editor-state.ts";
42
43
  import type { TelemetryBus } from "../debug/telemetry-bus.ts";
43
44
  import type { AIAction } from "../workflow/ai-action-policy.ts";
45
+ import type { ScopeGeometryEvidenceProvider } from "./geometry-evidence.ts";
44
46
 
45
47
  import {
46
48
  buildParagraphIndexMap,
@@ -49,6 +51,12 @@ import {
49
51
  } from "./compile-scope.ts";
50
52
  import { compileScopeBundleById } from "./compile-scope-bundle.ts";
51
53
  import { enumerateScopes, type EnumeratedScope } from "./enumerate-scopes.ts";
54
+ import {
55
+ collectTopLevelTableBlockIdsFromRenderSnapshot,
56
+ createRuntimeTableFrameLayoutEvidenceProvider,
57
+ type ScopeRuntimeLayoutEvidenceSource,
58
+ type ScopeRuntimeRenderSnapshotLike,
59
+ } from "./layout-evidence.ts";
52
60
  import {
53
61
  attachExplanation,
54
62
  type AttachExplanationResult,
@@ -59,6 +67,12 @@ import {
59
67
  type IssueSeverity,
60
68
  type IssueStatus,
61
69
  } from "./create-issue.ts";
70
+ import {
71
+ resolveIssueLifecycleTarget,
72
+ transitionScopeIssueLifecycle,
73
+ type IssueLifecycleAction,
74
+ type TransitionScopeIssueLifecycleResult,
75
+ } from "./issue-lifecycle.ts";
62
76
  import {
63
77
  applyScopeReplacement,
64
78
  type ApplyScopeReplacementResult,
@@ -69,12 +83,12 @@ import {
69
83
  } from "./formatting/apply.ts";
70
84
  import { proposeReplacement } from "./replacement/propose.ts";
71
85
  import type {
72
- ReplacementOperationKind,
73
86
  ReplacementPreservePolicy,
74
87
  ReplacementScope,
75
88
  RuntimeOperationPlan,
76
89
  ScopeFormattingAction,
77
90
  ScopeFormattingScope,
91
+ ScopeReplacementOperationKind,
78
92
  ScopeBundle,
79
93
  ScopeHandle,
80
94
  SemanticScope,
@@ -98,10 +112,16 @@ export interface CompilerServiceRuntime {
98
112
  getInteractionGuardSnapshot(): InteractionGuardSnapshot;
99
113
  getCompatibilityReport(): CompatibilityReport;
100
114
  getWorkflowMetadataSnapshot(): WorkflowMetadataSnapshot;
101
- setWorkflowMetadataEntries(entries: readonly WorkflowMetadataEntry[]): void;
115
+ setWorkflowMetadataEntries(
116
+ entries: readonly WorkflowMetadataEntry[],
117
+ origin?: WorkflowEventOrigin,
118
+ ): void;
119
+ getRenderSnapshot?(): ScopeRuntimeRenderSnapshotLike;
102
120
  getSessionState(): ScopeSessionState;
103
121
  applyScopeReplacement(plan: RuntimeOperationPlan): void;
104
122
  applyScopeFormatting(plan: RuntimeOperationPlan): boolean;
123
+ readonly geometry?: ScopeGeometryEvidenceProvider;
124
+ readonly layout?: ScopeRuntimeLayoutEvidenceSource;
105
125
  debug?: { bus: TelemetryBus };
106
126
  }
107
127
 
@@ -113,7 +133,7 @@ export interface CompileScopeByIdResult {
113
133
 
114
134
  export interface ApplyReplacementRequest {
115
135
  readonly targetScopeId: string;
116
- readonly operation: ReplacementOperationKind;
136
+ readonly operation: ScopeReplacementOperationKind;
117
137
  /**
118
138
  * Flat text payload. Shorthand for
119
139
  * `proposedContent: {kind: "text", text}`. Ignored when
@@ -165,6 +185,14 @@ export interface CreateIssueRequest {
165
185
  readonly status?: IssueStatus;
166
186
  }
167
187
 
188
+ export interface TransitionIssueLifecycleRequest {
189
+ readonly issueId: string;
190
+ readonly action: IssueLifecycleAction;
191
+ readonly actorId: string;
192
+ readonly origin: "ui" | "agent" | "host";
193
+ readonly emittedAtUtc: string;
194
+ }
195
+
168
196
  export interface ScopeCompilerService {
169
197
  /**
170
198
  * Enumerate + compile every live scope in the document. Per-call the
@@ -197,7 +225,7 @@ export interface ScopeCompilerService {
197
225
  buildReplacementScope(
198
226
  targetHandle: ScopeHandle,
199
227
  input: {
200
- readonly operation: ReplacementOperationKind;
228
+ readonly operation: ScopeReplacementOperationKind;
201
229
  readonly proposedText?: string;
202
230
  readonly formatting?: ReplacementScope["formatting"];
203
231
  readonly preserve?: ReplacementPreservePolicy;
@@ -238,6 +266,17 @@ export interface ScopeCompilerService {
238
266
  * overlay-only constraint as `attachExplanation`.
239
267
  */
240
268
  createIssue(request: CreateIssueRequest): CreateIssueResult;
269
+
270
+ /**
271
+ * Resolve/reopen an existing `ai.issue` metadata entry through the L06
272
+ * durable lifecycle substrate, but only after its scope target still compiles
273
+ * through Layer 08. This is intentionally not a public L09 API yet; it is the
274
+ * scope/evidence join that L09 will consume when `ai.resolveIssue` /
275
+ * `ai.reopenIssue` graduate.
276
+ */
277
+ transitionIssueLifecycle(
278
+ request: TransitionIssueLifecycleRequest,
279
+ ): TransitionScopeIssueLifecycleResult;
241
280
  }
242
281
 
243
282
  /**
@@ -324,12 +363,24 @@ export function createScopeCompilerService(
324
363
  // operations go through `attachScopeMetadata` via this same
325
364
  // runtime surface, so the snapshot is always fresh here.
326
365
  const workflowMetadataEntries = runtime.getWorkflowMetadataSnapshot().entries;
366
+ const layout =
367
+ runtime.layout
368
+ ? createRuntimeTableFrameLayoutEvidenceProvider({
369
+ layout: runtime.layout,
370
+ tableBlockIdsByBlockIndex:
371
+ collectTopLevelTableBlockIdsFromRenderSnapshot(
372
+ runtime.getRenderSnapshot?.(),
373
+ ),
374
+ })
375
+ : undefined;
327
376
  return compileScopeBundleById(scopeId, {
328
377
  document,
329
378
  ...(overlay ? { overlay } : {}),
330
379
  nowUtc,
331
380
  catalog: document.styles,
332
381
  workflowMetadataEntries,
382
+ ...(runtime.geometry ? { geometry: runtime.geometry } : {}),
383
+ ...(layout ? { layout } : {}),
333
384
  });
334
385
  },
335
386
 
@@ -361,6 +412,7 @@ export function createScopeCompilerService(
361
412
  reason: "scope-not-resolvable",
362
413
  validation: {
363
414
  safe: false,
415
+ posture: "hard-refusal",
364
416
  blockedReasons: Object.freeze([
365
417
  `scope-not-resolvable:${request.targetScopeId}`,
366
418
  ]),
@@ -400,6 +452,7 @@ export function createScopeCompilerService(
400
452
  runtime.getInteractionGuardSnapshot(),
401
453
  getCompatibilityReport: () => runtime.getCompatibilityReport(),
402
454
  applyScopeReplacement: (plan) => runtime.applyScopeReplacement(plan),
455
+ verifyReadback: true,
403
456
  },
404
457
  proposed,
405
458
  ...(request.actionId ? { actionId: request.actionId } : {}),
@@ -418,6 +471,7 @@ export function createScopeCompilerService(
418
471
  reason: "scope-not-resolvable",
419
472
  validation: {
420
473
  safe: false,
474
+ posture: "hard-refusal",
421
475
  blockedReasons: Object.freeze([
422
476
  `scope-not-resolvable:${request.targetScopeId}`,
423
477
  ]),
@@ -498,5 +552,55 @@ export function createScopeCompilerService(
498
552
  },
499
553
  );
500
554
  },
555
+
556
+ transitionIssueLifecycle(
557
+ request: TransitionIssueLifecycleRequest,
558
+ ): TransitionScopeIssueLifecycleResult {
559
+ const target = resolveIssueLifecycleTarget(
560
+ runtime.getWorkflowMetadataSnapshot(),
561
+ request.issueId,
562
+ );
563
+ if (!target) {
564
+ const reason = `issue-not-found:${request.issueId}`;
565
+ return {
566
+ transitioned: false,
567
+ issueId: request.issueId,
568
+ reason,
569
+ blockers: Object.freeze([reason]),
570
+ };
571
+ }
572
+
573
+ const compiled = this.compileScopeById(target.scopeId);
574
+ if (!compiled) {
575
+ const reason = `scope-not-resolvable:${target.scopeId}`;
576
+ return {
577
+ transitioned: false,
578
+ issueId: target.issueId,
579
+ reason,
580
+ blockers: Object.freeze([reason]),
581
+ scopeId: target.scopeId,
582
+ };
583
+ }
584
+
585
+ const documentBefore = runtime.getCanonicalDocument();
586
+ const result = transitionScopeIssueLifecycle({
587
+ runtime: {
588
+ getCanonicalDocument: () => runtime.getCanonicalDocument(),
589
+ getWorkflowMetadataSnapshot: () =>
590
+ runtime.getWorkflowMetadataSnapshot(),
591
+ setWorkflowMetadataEntries: (entries, origin) =>
592
+ runtime.setWorkflowMetadataEntries([...entries], origin),
593
+ },
594
+ documentBefore,
595
+ targetScopeSnapshot: compiled.scope,
596
+ issueId: target.issueId,
597
+ action: request.action,
598
+ actorId: request.actorId,
599
+ origin: request.origin,
600
+ emittedAtUtc: request.emittedAtUtc,
601
+ ...(runtime.debug?.bus ? { bus: runtime.debug.bus } : {}),
602
+ });
603
+ return result;
604
+ },
501
605
  };
502
606
  }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Content-control / SDT evidence for scope bundles and preservation checks.
3
+ *
4
+ * SDTs are package-backed wrappers, not L08 scope truth. This helper only
5
+ * reports overlap with a scope range so capability and validation surfaces can
6
+ * stay preserve-first until L02/L04 expose richer source/layout refs.
7
+ */
8
+
9
+ import type {
10
+ CanonicalDocument,
11
+ DocumentRootNode,
12
+ SdtNode,
13
+ } from "../../model/canonical-document.ts";
14
+ import type { CanonicalDocumentEnvelope } from "../../core/state/editor-state.ts";
15
+
16
+ import { computeBlockPositions, type ScopePositionRange } from "./position-map.ts";
17
+ import { rangesOverlap } from "./scope-range.ts";
18
+ import type {
19
+ ScopeContentControlEvidence,
20
+ ScopeContentControlEvidenceEntry,
21
+ } from "./semantic-scope-types.ts";
22
+
23
+ function documentRoot(
24
+ document: Pick<CanonicalDocument, "content"> | CanonicalDocumentEnvelope,
25
+ ): DocumentRootNode {
26
+ const envelope = document as CanonicalDocumentEnvelope;
27
+ return "content" in envelope
28
+ ? (envelope.content as DocumentRootNode)
29
+ : (document as unknown as DocumentRootNode);
30
+ }
31
+
32
+ function entryForSdt(
33
+ blockIndex: number,
34
+ sdt: SdtNode,
35
+ ): ScopeContentControlEvidenceEntry {
36
+ const typePart = sdt.properties.sdtType ?? "unknown";
37
+ return {
38
+ evidenceId: `sdt:${blockIndex}:${typePart}`,
39
+ blockIndex,
40
+ ...(sdt.properties.sdtType ? { sdtType: sdt.properties.sdtType } : {}),
41
+ ...(sdt.properties.alias ? { alias: sdt.properties.alias } : {}),
42
+ ...(sdt.properties.tag ? { tag: sdt.properties.tag } : {}),
43
+ ...(sdt.properties.lock ? { lock: sdt.properties.lock } : {}),
44
+ };
45
+ }
46
+
47
+ export function findContentControlsIntersectingRange(
48
+ document: Pick<CanonicalDocument, "content"> | CanonicalDocumentEnvelope,
49
+ range: ScopePositionRange | null,
50
+ ): readonly ScopeContentControlEvidenceEntry[] {
51
+ if (!range) return Object.freeze([]);
52
+
53
+ const root = documentRoot(document);
54
+ const blockRanges = computeBlockPositions(document);
55
+ const entries: ScopeContentControlEvidenceEntry[] = [];
56
+
57
+ for (const blockRange of blockRanges) {
58
+ const block = root.children[blockRange.blockIndex];
59
+ if (!block || block.type !== "sdt") continue;
60
+ if (!rangesOverlap(range, { from: blockRange.from, to: blockRange.to })) {
61
+ continue;
62
+ }
63
+ entries.push(entryForSdt(blockRange.blockIndex, block));
64
+ }
65
+
66
+ return Object.freeze(entries);
67
+ }
68
+
69
+ export function deriveScopeContentControlEvidence(
70
+ document: Pick<CanonicalDocument, "content"> | CanonicalDocumentEnvelope,
71
+ range: ScopePositionRange | null,
72
+ ): ScopeContentControlEvidence {
73
+ const entries = findContentControlsIntersectingRange(document, range);
74
+ return {
75
+ status: entries.length > 0 ? "present" : "none",
76
+ count: entries.length,
77
+ entries,
78
+ };
79
+ }
@@ -9,10 +9,9 @@
9
9
  * Issues are metadata records rather than a dedicated overlay section
10
10
  * in this slice — matches the Slice-6 plan's "issue store is a new
11
11
  * section on the workflow overlay" intent without requiring an
12
- * overlay-schema minor bump. When CLM workblocks need richer lifecycle
13
- * (resolve/reopen transitions, assigned owners), a follow-up sub-slice
14
- * promotes issues to a first-class overlay kind and the storage
15
- * migrates — the metadataId stays stable so callers don't break.
12
+ * overlay-schema minor bump. Layer 06 owns the durable lifecycle substrate for
13
+ * the stable metadataId; L08/L09 still own scope/API shaped resolve/reopen
14
+ * exposure.
16
15
  *
17
16
  * Scope coverage (coord-06 §13c shipped 2026-04-23): both overlay
18
17
  * (workflow) scopes AND derived paragraph / heading / list-item
@@ -28,9 +27,10 @@ import type {
28
27
  MetadataWriterRuntime,
29
28
  } from "../workflow/metadata-writer.ts";
30
29
  import { attachScopeMetadata } from "../workflow/metadata-writer.ts";
30
+ import { AI_ISSUE_METADATA_ID } from "../workflow/ai-issue-lifecycle.ts";
31
31
 
32
32
  /** Stable metadataId for AI-authored issues. */
33
- export const AI_ISSUE_METADATA_ID = "ai.issue" as const;
33
+ export { AI_ISSUE_METADATA_ID };
34
34
 
35
35
  export type IssueSeverity = "info" | "warning" | "error";
36
36
  export type IssueStatus = "open" | "resolved";
@@ -24,10 +24,21 @@ import type {
24
24
  } from "./_scope-dependencies.ts";
25
25
 
26
26
  import { AI_EXPLANATION_METADATA_ID } from "./attach-explanation.ts";
27
+ import { deriveScopeCapabilities } from "./capabilities.ts";
28
+ import { deriveScopeContentControlEvidence } from "./content-control-evidence.ts";
27
29
  import { AI_ISSUE_METADATA_ID } from "./create-issue.ts";
28
30
  import type { EnumeratedScope } from "./enumerate-scopes.ts";
31
+ import {
32
+ deriveScopeGeometryEvidence,
33
+ type ScopeGeometryEvidenceProvider,
34
+ } from "./geometry-evidence.ts";
35
+ import {
36
+ deriveScopeLayoutEvidence,
37
+ type ScopeLayoutEvidenceProvider,
38
+ } from "./layout-evidence.ts";
29
39
  import { buildScopePositionMap, type ScopePositionRange } from "./position-map.ts";
30
40
  import { rangesOverlap, resolveScopeRange } from "./scope-range.ts";
41
+ import { deriveScopeVisualization } from "./visualization.ts";
31
42
  import type {
32
43
  AIExplanationSummary,
33
44
  AIIssueSummary,
@@ -86,6 +97,16 @@ export interface EvidenceInputs {
86
97
  * `runtime.getWorkflowMetadataSnapshot().entries` through here.
87
98
  */
88
99
  readonly workflowMetadataEntries?: readonly WorkflowMetadataEntry[];
100
+ /**
101
+ * Layer-05 geometry facet subset. When present, evidence includes the
102
+ * current replacement envelope or an explicit requires-rehydration status.
103
+ */
104
+ readonly geometry?: ScopeGeometryEvidenceProvider;
105
+ /**
106
+ * Optional lower-layer layout evidence seam. Missing provider or missing
107
+ * rows are surfaced explicitly in `ScopeBundleEvidence.layout`.
108
+ */
109
+ readonly layout?: ScopeLayoutEvidenceProvider;
89
110
  }
90
111
 
91
112
  function normalizeSeverity(raw: unknown): AIIssueSummary["severity"] {
@@ -98,6 +119,38 @@ function normalizeStatus(raw: unknown): AIIssueSummary["status"] {
98
119
  return "open";
99
120
  }
100
121
 
122
+ function projectIssueTransition(raw: unknown): AIIssueSummary["lastTransition"] | undefined {
123
+ const value = raw as
124
+ | {
125
+ action?: unknown;
126
+ actorId?: unknown;
127
+ at?: unknown;
128
+ origin?: unknown;
129
+ fromStatus?: unknown;
130
+ toStatus?: unknown;
131
+ }
132
+ | undefined;
133
+ if (!value || typeof value !== "object") return undefined;
134
+ if (value.action !== "resolve" && value.action !== "reopen") return undefined;
135
+ if (typeof value.actorId !== "string") return undefined;
136
+ if (typeof value.at !== "string") return undefined;
137
+ if (typeof value.origin !== "string") return undefined;
138
+ if (value.fromStatus !== "open" && value.fromStatus !== "resolved") {
139
+ return undefined;
140
+ }
141
+ if (value.toStatus !== "open" && value.toStatus !== "resolved") {
142
+ return undefined;
143
+ }
144
+ return {
145
+ action: value.action,
146
+ actorId: value.actorId,
147
+ at: value.at,
148
+ origin: value.origin,
149
+ fromStatus: value.fromStatus,
150
+ toStatus: value.toStatus,
151
+ };
152
+ }
153
+
101
154
  function projectAIExplanation(
102
155
  entry: WorkflowMetadataEntry,
103
156
  ): AIExplanationSummary | null {
@@ -127,9 +180,18 @@ function projectAIIssue(
127
180
  severity?: unknown;
128
181
  status?: unknown;
129
182
  createdAtUtc?: string;
183
+ statusUpdatedAtUtc?: string;
184
+ resolvedAtUtc?: string;
185
+ resolvedBy?: string;
186
+ reopenedAtUtc?: string;
187
+ reopenedBy?: string;
188
+ lifecycle?: unknown[];
130
189
  }
131
190
  | undefined;
132
191
  if (!value || typeof value.summary !== "string") return null;
192
+ const lastTransition = Array.isArray(value.lifecycle)
193
+ ? projectIssueTransition(value.lifecycle[value.lifecycle.length - 1])
194
+ : undefined;
133
195
  return {
134
196
  issueId:
135
197
  typeof value.issueId === "string" && value.issueId.length > 0
@@ -141,6 +203,22 @@ function projectAIIssue(
141
203
  ...(typeof value.createdAtUtc === "string"
142
204
  ? { createdAtUtc: value.createdAtUtc }
143
205
  : {}),
206
+ ...(typeof value.statusUpdatedAtUtc === "string"
207
+ ? { statusUpdatedAtUtc: value.statusUpdatedAtUtc }
208
+ : {}),
209
+ ...(typeof value.resolvedAtUtc === "string"
210
+ ? { resolvedAtUtc: value.resolvedAtUtc }
211
+ : {}),
212
+ ...(typeof value.resolvedBy === "string"
213
+ ? { resolvedBy: value.resolvedBy }
214
+ : {}),
215
+ ...(typeof value.reopenedAtUtc === "string"
216
+ ? { reopenedAtUtc: value.reopenedAtUtc }
217
+ : {}),
218
+ ...(typeof value.reopenedBy === "string"
219
+ ? { reopenedBy: value.reopenedBy }
220
+ : {}),
221
+ ...(lastTransition ? { lastTransition } : {}),
144
222
  };
145
223
  }
146
224
 
@@ -221,11 +299,24 @@ export function composeEvidence(inputs: EvidenceInputs): ScopeBundleEvidence {
221
299
  aiExplanations.sort((a, b) => a.explanationId.localeCompare(b.explanationId));
222
300
  aiIssues.sort((a, b) => a.issueId.localeCompare(b.issueId));
223
301
 
302
+ const layout = deriveScopeLayoutEvidence(scope.handle.scopeId, inputs.layout);
303
+ const geometry = deriveScopeGeometryEvidence(scope.handle.scopeId, inputs.geometry);
304
+ const contentControls = deriveScopeContentControlEvidence(document, selfRange);
305
+
224
306
  return {
225
307
  formattingSummary: formattingSummaryOf(scope),
226
308
  reviewItemIds,
227
309
  overlappingWorkflowScopeIds,
228
310
  compatibilityFlags,
311
+ layout,
312
+ geometry,
313
+ visualization: deriveScopeVisualization(scope),
314
+ contentControls,
315
+ capabilities: deriveScopeCapabilities(scope, {
316
+ layout,
317
+ geometry,
318
+ contentControls,
319
+ }),
229
320
  ...(inputs.workflowMetadataEntries
230
321
  ? { aiExplanations, aiIssues }
231
322
  : {}),
@@ -156,6 +156,7 @@ export function applyScopeFormatting(
156
156
  if (!resolvedScope || !resolvedEnumerated) {
157
157
  const validation: ValidationResult = {
158
158
  safe: false,
159
+ posture: "hard-refusal",
159
160
  blockedReasons: Object.freeze([
160
161
  `scope-not-resolvable:${proposed.targetHandle.scopeId}`,
161
162
  ]),
@@ -211,6 +212,7 @@ export function applyScopeFormatting(
211
212
  : `compile-refused:${resolvedScope.kind}:formatting-not-implemented`;
212
213
  const refused: ValidationResult = {
213
214
  safe: false,
215
+ posture: "hard-refusal",
214
216
  blockedReasons: Object.freeze([blocker]),
215
217
  warnings: verdict.warnings,
216
218
  };
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Scope geometry evidence projection.
3
+ *
4
+ * Layer 08 consumes the Layer 05 replacement-envelope seam when it is wired,
5
+ * but it does not compute geometry itself. Cold or missing geometry remains
6
+ * explicit evidence, not a synthesized rectangle.
7
+ */
8
+
9
+ import type {
10
+ ScopeGeometryEvidence,
11
+ ScopeGeometryEvidencePrecision,
12
+ ScopeGeometryEvidenceRect,
13
+ ScopeLayoutContinuationEvidence,
14
+ } from "./semantic-scope-types.ts";
15
+
16
+ type GeometrySpace = ScopeGeometryEvidenceRect["space"];
17
+
18
+ interface EnvelopeRectLike {
19
+ readonly leftPx: number;
20
+ readonly topPx: number;
21
+ readonly widthPx: number;
22
+ readonly heightPx: number;
23
+ readonly space: GeometrySpace;
24
+ readonly precision?: ScopeGeometryEvidencePrecision;
25
+ }
26
+
27
+ interface EnvelopeLike {
28
+ readonly scopeRects: readonly EnvelopeRectLike[];
29
+ readonly pageIds?: readonly string[];
30
+ readonly continuation?: ScopeLayoutContinuationEvidence;
31
+ readonly attachPoint: {
32
+ readonly xPx: number;
33
+ readonly yPx: number;
34
+ readonly space: GeometrySpace;
35
+ };
36
+ readonly confidence: "exact" | "medium" | "detached";
37
+ readonly linesCrossed: number;
38
+ readonly rehydrationStatus?: "realized" | "requires-rehydration" | "unavailable";
39
+ readonly precision?: ScopeGeometryEvidencePrecision;
40
+ readonly sourceIdentity?: {
41
+ readonly storyKey?: string;
42
+ readonly blockPath?: string;
43
+ readonly tableKey?: string;
44
+ readonly rowKey?: string;
45
+ readonly cellKey?: string;
46
+ readonly scopeKey?: string;
47
+ readonly scopeId?: string;
48
+ readonly objectKey?: string;
49
+ readonly inlinePath?: string;
50
+ readonly objectKind?: string;
51
+ readonly editPosture?: string;
52
+ readonly joinKind?: string;
53
+ };
54
+ }
55
+
56
+ export interface ScopeGeometryEvidenceProvider {
57
+ getReplacementEnvelope(scopeId: string): EnvelopeLike | null;
58
+ }
59
+
60
+ function mapRect(rect: EnvelopeRectLike): ScopeGeometryEvidenceRect {
61
+ return {
62
+ x: rect.leftPx,
63
+ y: rect.topPx,
64
+ width: rect.widthPx,
65
+ height: rect.heightPx,
66
+ space: rect.space,
67
+ ...(rect.precision ? { precision: rect.precision } : {}),
68
+ };
69
+ }
70
+
71
+ export function deriveScopeGeometryEvidence(
72
+ scopeId: string,
73
+ provider?: ScopeGeometryEvidenceProvider,
74
+ ): ScopeGeometryEvidence {
75
+ if (!provider) {
76
+ return {
77
+ status: "unavailable",
78
+ requiresRehydration: false,
79
+ reason: "geometry-facet-unavailable",
80
+ };
81
+ }
82
+
83
+ const envelope = provider.getReplacementEnvelope(scopeId);
84
+ if (!envelope) {
85
+ return {
86
+ status: "requires-rehydration",
87
+ requiresRehydration: true,
88
+ reason: "replacement-envelope-unavailable",
89
+ };
90
+ }
91
+
92
+ if (envelope.rehydrationStatus === "unavailable") {
93
+ return {
94
+ status: "unavailable",
95
+ requiresRehydration: false,
96
+ reason: "replacement-envelope-unavailable",
97
+ ...(envelope.pageIds ? { pageIds: Object.freeze([...envelope.pageIds]) } : {}),
98
+ ...(envelope.continuation
99
+ ? { continuationState: { ...envelope.continuation } }
100
+ : {}),
101
+ ...(envelope.sourceIdentity
102
+ ? { sourceIdentity: { ...envelope.sourceIdentity } }
103
+ : {}),
104
+ };
105
+ }
106
+
107
+ const requiresRehydration =
108
+ envelope.rehydrationStatus === "requires-rehydration";
109
+ return {
110
+ status: requiresRehydration ? "requires-rehydration" : "available",
111
+ requiresRehydration,
112
+ ...(requiresRehydration ? { reason: "replacement-envelope-requires-rehydration" } : {}),
113
+ ...(envelope.pageIds ? { pageIds: Object.freeze([...envelope.pageIds]) } : {}),
114
+ confidence: envelope.confidence,
115
+ ...(envelope.precision ? { precision: envelope.precision } : {}),
116
+ rects: Object.freeze(envelope.scopeRects.map(mapRect)),
117
+ attachPoint: {
118
+ x: envelope.attachPoint.xPx,
119
+ y: envelope.attachPoint.yPx,
120
+ space: envelope.attachPoint.space,
121
+ },
122
+ linesCrossed: envelope.linesCrossed,
123
+ ...(envelope.continuation
124
+ ? { continuationState: { ...envelope.continuation } }
125
+ : {}),
126
+ ...(envelope.sourceIdentity
127
+ ? { sourceIdentity: { ...envelope.sourceIdentity } }
128
+ : {}),
129
+ };
130
+ }