@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
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  import type { RuntimeApiHandle } from "../_runtime-handle.ts";
11
+ import type { ScopeHandle } from "../../../runtime/scopes/index.ts";
11
12
  import type {
12
13
  GeometryIndexCoverage,
13
14
  GeometryPrecision,
@@ -15,6 +16,12 @@ import type {
15
16
  GeometryReplacementEnvelopeEntry,
16
17
  GeometrySourceIdentity,
17
18
  } from "../../../runtime/geometry/index.ts";
19
+ import type { PublicLayoutDivergence } from "../../../runtime/layout/public-facet.ts";
20
+ import {
21
+ createHeaderFooterStoryKey,
22
+ createNoteStoryKey,
23
+ MAIN_STORY_KEY,
24
+ } from "../../../model/canonical-layout-inputs.ts";
18
25
 
19
26
  export interface AiPe2GeometryCoverageEvidence {
20
27
  readonly status: GeometryRehydrationStatus;
@@ -36,6 +43,8 @@ export interface AiPe2GeometryCoverageEvidence {
36
43
 
37
44
  export interface AiPe2DocumentEvidence {
38
45
  readonly geometry: AiPe2GeometryCoverageEvidence;
46
+ readonly layout: AiPe2LayoutEvidence;
47
+ readonly oracle: AiPe2OracleEvidence;
39
48
  }
40
49
 
41
50
  export interface AiPe2ScopeReplacementEnvelopeEvidence {
@@ -52,6 +61,72 @@ export interface AiPe2ScopeEvidence {
52
61
  readonly replacementEnvelope?: AiPe2ScopeReplacementEnvelopeEvidence;
53
62
  readonly reason?: "geometry-index-unavailable" | "scope-envelope-not-found";
54
63
  };
64
+ readonly layout: AiPe2LayoutEvidence;
65
+ readonly oracle: AiPe2OracleEvidence;
66
+ }
67
+
68
+ export interface AiPe2LayoutDivergenceEvidence {
69
+ readonly divergenceId: string;
70
+ readonly kind: string;
71
+ readonly source: string;
72
+ readonly severity: string;
73
+ readonly message: string;
74
+ readonly regionKinds?: readonly string[];
75
+ readonly fragmentIds?: readonly string[];
76
+ readonly objectIds?: readonly string[];
77
+ }
78
+
79
+ export interface AiPe2LayoutEvidence {
80
+ readonly status: "realized" | "unavailable";
81
+ readonly pageCount: number;
82
+ readonly pageIds: readonly string[];
83
+ readonly pagesWithDivergences: readonly string[];
84
+ readonly divergenceIds: readonly string[];
85
+ readonly divergences: readonly AiPe2LayoutDivergenceEvidence[];
86
+ readonly reason?: "scope-page-evidence-not-found";
87
+ }
88
+
89
+ export type AiPe2OracleVerdict =
90
+ | "match"
91
+ | "divergent"
92
+ | "blocked"
93
+ | "oracle-incomplete"
94
+ | "runtime-projection-not-wired"
95
+ | "not-compared";
96
+
97
+ export interface AiPe2GraphOracleReference {
98
+ readonly mode: "static" | "live";
99
+ readonly cacheKey: string;
100
+ readonly lane?: string;
101
+ readonly docId?: string;
102
+ readonly pageCount?: number;
103
+ readonly paragraphCount?: number;
104
+ readonly pdfSha256?: string;
105
+ readonly sourceSha256?: string;
106
+ readonly backendIdentityTag?: string;
107
+ }
108
+
109
+ export interface AiPe2OracleEvidence {
110
+ readonly status: "available" | "not-wired";
111
+ readonly runIds: readonly string[];
112
+ readonly divergenceIds: readonly string[];
113
+ readonly graphOracleReferences?: readonly AiPe2GraphOracleReference[];
114
+ readonly verdict?: AiPe2OracleVerdict;
115
+ readonly reason?: "truth-adapter-unavailable" | "truth-adapter-error";
116
+ }
117
+
118
+ export interface AiPe2OracleEvidenceProviderInput {
119
+ readonly documentId: string;
120
+ readonly scopeId?: string;
121
+ readonly pageIds: readonly string[];
122
+ }
123
+
124
+ export type AiPe2OracleEvidenceProvider = (
125
+ input: AiPe2OracleEvidenceProviderInput,
126
+ ) => AiPe2OracleEvidence | null | undefined;
127
+
128
+ export interface AiPe2EvidenceOptions {
129
+ readonly oracle?: AiPe2OracleEvidenceProvider;
55
130
  }
56
131
 
57
132
  function copyCoverage(coverage: GeometryIndexCoverage): AiPe2GeometryCoverageEvidence {
@@ -100,54 +175,283 @@ const UNAVAILABLE_COVERAGE: AiPe2GeometryCoverageEvidence = {
100
175
  precision: { exact: 0, "within-tolerance": 0, heuristic: 0 },
101
176
  };
102
177
 
178
+ function copyLayoutDivergence(
179
+ divergence: PublicLayoutDivergence,
180
+ ): AiPe2LayoutDivergenceEvidence {
181
+ return {
182
+ divergenceId: divergence.divergenceId,
183
+ kind: divergence.kind,
184
+ source: divergence.source,
185
+ severity: divergence.severity,
186
+ message: divergence.message,
187
+ ...(divergence.regionKinds ? { regionKinds: [...divergence.regionKinds] } : {}),
188
+ ...(divergence.fragmentIds ? { fragmentIds: [...divergence.fragmentIds] } : {}),
189
+ ...(divergence.objectIds ? { objectIds: [...divergence.objectIds] } : {}),
190
+ };
191
+ }
192
+
193
+ function copyGraphOracleReference(
194
+ reference: AiPe2GraphOracleReference,
195
+ ): AiPe2GraphOracleReference {
196
+ return {
197
+ mode: reference.mode,
198
+ cacheKey: reference.cacheKey,
199
+ ...(reference.lane ? { lane: reference.lane } : {}),
200
+ ...(reference.docId ? { docId: reference.docId } : {}),
201
+ ...(reference.pageCount !== undefined ? { pageCount: reference.pageCount } : {}),
202
+ ...(reference.paragraphCount !== undefined
203
+ ? { paragraphCount: reference.paragraphCount }
204
+ : {}),
205
+ ...(reference.pdfSha256 ? { pdfSha256: reference.pdfSha256 } : {}),
206
+ ...(reference.sourceSha256 ? { sourceSha256: reference.sourceSha256 } : {}),
207
+ ...(reference.backendIdentityTag
208
+ ? { backendIdentityTag: reference.backendIdentityTag }
209
+ : {}),
210
+ };
211
+ }
212
+
213
+ function projectLayoutEvidence(
214
+ runtime: RuntimeApiHandle,
215
+ pageIds?: readonly string[],
216
+ ): AiPe2LayoutEvidence {
217
+ if (typeof runtime.layout?.getPageCount !== "function") {
218
+ return {
219
+ status: "unavailable",
220
+ pageCount: 0,
221
+ pageIds: [],
222
+ pagesWithDivergences: [],
223
+ divergenceIds: [],
224
+ divergences: [],
225
+ };
226
+ }
227
+ const pageCount = runtime.layout.getPageCount();
228
+ const selectedPageIds = pageIds ? new Set(pageIds) : null;
229
+ const pageIdOut: string[] = [];
230
+ const pagesWithDivergences: string[] = [];
231
+ const divergenceIds = new Set<string>();
232
+ const divergencesById = new Map<string, AiPe2LayoutDivergenceEvidence>();
233
+
234
+ for (let pageIndex = 0; pageIndex < pageCount; pageIndex += 1) {
235
+ const page = runtime.layout.getPage(pageIndex);
236
+ if (!page) continue;
237
+ if (selectedPageIds && !selectedPageIds.has(page.pageId)) continue;
238
+ pageIdOut.push(page.pageId);
239
+
240
+ for (const divergenceId of page.frame?.divergenceIds ?? []) {
241
+ divergenceIds.add(divergenceId);
242
+ }
243
+ for (const divergence of page.divergences ?? []) {
244
+ divergenceIds.add(divergence.divergenceId);
245
+ divergencesById.set(divergence.divergenceId, copyLayoutDivergence(divergence));
246
+ }
247
+ if ((page.frame?.divergenceIds.length ?? 0) > 0 || (page.divergences?.length ?? 0) > 0) {
248
+ pagesWithDivergences.push(page.pageId);
249
+ }
250
+ }
251
+
252
+ return {
253
+ status: pageIdOut.length > 0 ? "realized" : "unavailable",
254
+ pageCount: pageIdOut.length,
255
+ pageIds: pageIdOut,
256
+ pagesWithDivergences,
257
+ divergenceIds: [...divergenceIds],
258
+ divergences: [...divergencesById.values()],
259
+ ...(selectedPageIds && pageIdOut.length === 0
260
+ ? { reason: "scope-page-evidence-not-found" as const }
261
+ : {}),
262
+ };
263
+ }
264
+
265
+ function copyOracleEvidence(evidence: AiPe2OracleEvidence): AiPe2OracleEvidence {
266
+ return {
267
+ status: evidence.status,
268
+ runIds: [...evidence.runIds],
269
+ divergenceIds: [...evidence.divergenceIds],
270
+ ...(evidence.graphOracleReferences
271
+ ? { graphOracleReferences: evidence.graphOracleReferences.map(copyGraphOracleReference) }
272
+ : {}),
273
+ ...(evidence.verdict ? { verdict: evidence.verdict } : {}),
274
+ ...(evidence.reason ? { reason: evidence.reason } : {}),
275
+ };
276
+ }
277
+
278
+ function canonicalStoryKeyForHandle(handle: ScopeHandle): string {
279
+ const target = handle.storyTarget;
280
+ switch (target.kind) {
281
+ case "main":
282
+ return MAIN_STORY_KEY;
283
+ case "header":
284
+ return createHeaderFooterStoryKey({
285
+ kind: "header",
286
+ relationshipId: target.relationshipId,
287
+ variant: target.variant,
288
+ ...(target.sectionIndex !== undefined ? { sectionIndex: target.sectionIndex } : {}),
289
+ });
290
+ case "footer":
291
+ return createHeaderFooterStoryKey({
292
+ kind: "footer",
293
+ relationshipId: target.relationshipId,
294
+ variant: target.variant,
295
+ ...(target.sectionIndex !== undefined ? { sectionIndex: target.sectionIndex } : {}),
296
+ });
297
+ case "footnote":
298
+ return createNoteStoryKey("footnote", target.noteId);
299
+ case "endnote":
300
+ return createNoteStoryKey("endnote", target.noteId);
301
+ }
302
+ }
303
+
304
+ function semanticMainBlockPath(handle: ScopeHandle): string | null {
305
+ const path = handle.semanticPath;
306
+ if (path[0] !== "body") return null;
307
+ if (path[1] === "paragraph" || path[1] === "heading" || path[1] === "list-item") {
308
+ const blockIndex = path[path.length - 1];
309
+ return typeof blockIndex === "string" && /^\d+$/u.test(blockIndex)
310
+ ? `${MAIN_STORY_KEY}/block[${blockIndex}]`
311
+ : null;
312
+ }
313
+ if (path[1] === "table" && typeof path[2] === "string" && /^\d+$/u.test(path[2])) {
314
+ return `${MAIN_STORY_KEY}/block[${path[2]}]`;
315
+ }
316
+ return null;
317
+ }
318
+
319
+ function scoreEnvelopeForHandle(
320
+ envelope: GeometryReplacementEnvelopeEntry,
321
+ handle: ScopeHandle,
322
+ storyKey: string,
323
+ ): number {
324
+ if (envelope.scopeId !== handle.scopeId) return -1;
325
+ const source = envelope.sourceIdentity;
326
+ if (!source) return 0;
327
+
328
+ let score = 1;
329
+ if (source.scopeId === handle.scopeId) score += 2;
330
+ if (source.storyKey === storyKey) score += 8;
331
+ if (source.scopeKey === `${storyKey}:scope:${handle.scopeId}` ||
332
+ source.scopeKey?.startsWith(`${storyKey}:scope:${handle.scopeId}:`)) {
333
+ score += 4;
334
+ }
335
+
336
+ const blockPath = semanticMainBlockPath(handle);
337
+ if (blockPath && source.blockPath === blockPath) score += 2;
338
+
339
+ return score;
340
+ }
341
+
342
+ function findReplacementEnvelopeForHandle(
343
+ envelopes: readonly GeometryReplacementEnvelopeEntry[],
344
+ handle: ScopeHandle,
345
+ ): GeometryReplacementEnvelopeEntry | undefined {
346
+ const storyKey = canonicalStoryKeyForHandle(handle);
347
+ let best: GeometryReplacementEnvelopeEntry | undefined;
348
+ let bestScore = -1;
349
+ for (const envelope of envelopes) {
350
+ const score = scoreEnvelopeForHandle(envelope, handle, storyKey);
351
+ if (score > bestScore) {
352
+ best = envelope;
353
+ bestScore = score;
354
+ }
355
+ }
356
+ return bestScore >= 0 ? best : undefined;
357
+ }
358
+
359
+ function projectOracleEvidence(
360
+ runtime: RuntimeApiHandle,
361
+ options: AiPe2EvidenceOptions | undefined,
362
+ input: Omit<AiPe2OracleEvidenceProviderInput, "documentId">,
363
+ ): AiPe2OracleEvidence {
364
+ const provider = options?.oracle;
365
+ if (provider) {
366
+ try {
367
+ const evidence = provider({
368
+ documentId: runtime.getSessionState().documentId,
369
+ ...input,
370
+ });
371
+ if (evidence) return copyOracleEvidence(evidence);
372
+ } catch {
373
+ return {
374
+ status: "not-wired",
375
+ runIds: [],
376
+ divergenceIds: [],
377
+ reason: "truth-adapter-error",
378
+ };
379
+ }
380
+ }
381
+ return {
382
+ status: "not-wired",
383
+ runIds: [],
384
+ divergenceIds: [],
385
+ reason: "truth-adapter-unavailable",
386
+ };
387
+ }
388
+
103
389
  export function projectDocumentPe2Evidence(
104
390
  runtime: RuntimeApiHandle,
391
+ options?: AiPe2EvidenceOptions,
105
392
  ): AiPe2DocumentEvidence {
106
- if (!runtime.geometry) {
107
- return { geometry: UNAVAILABLE_COVERAGE };
108
- }
393
+ const layout = projectLayoutEvidence(runtime);
394
+ const geometry = runtime.geometry
395
+ ? copyCoverage(runtime.geometry.getGeometryCoverage())
396
+ : UNAVAILABLE_COVERAGE;
109
397
  return {
110
- geometry: copyCoverage(runtime.geometry.getGeometryCoverage()),
398
+ geometry,
399
+ layout,
400
+ oracle: projectOracleEvidence(runtime, options, { pageIds: layout.pageIds }),
111
401
  };
112
402
  }
113
403
 
114
404
  export function projectScopePe2Evidence(
115
405
  runtime: RuntimeApiHandle,
116
- scopeId: string,
406
+ handle: ScopeHandle,
407
+ options?: AiPe2EvidenceOptions,
117
408
  ): AiPe2ScopeEvidence {
409
+ const { scopeId } = handle;
118
410
  if (!runtime.geometry) {
411
+ const layout = projectLayoutEvidence(runtime, []);
119
412
  return {
120
413
  geometry: {
121
414
  coverage: UNAVAILABLE_COVERAGE,
122
415
  reason: "geometry-index-unavailable",
123
416
  },
417
+ layout,
418
+ oracle: projectOracleEvidence(runtime, options, { scopeId, pageIds: layout.pageIds }),
124
419
  };
125
420
  }
126
421
  const coverage = copyCoverage(runtime.geometry.getGeometryCoverage());
127
422
  const index = runtime.geometry.getGeometryIndex();
128
423
  if (!index) {
424
+ const layout = projectLayoutEvidence(runtime, []);
129
425
  return {
130
426
  geometry: {
131
427
  coverage,
132
428
  reason: "geometry-index-unavailable",
133
429
  },
430
+ layout,
431
+ oracle: projectOracleEvidence(runtime, options, { scopeId, pageIds: layout.pageIds }),
134
432
  };
135
433
  }
136
434
 
137
- const envelope = index.replacementEnvelopes.find((entry) => entry.scopeId === scopeId);
435
+ const envelope = findReplacementEnvelopeForHandle(index.replacementEnvelopes, handle);
138
436
  if (!envelope) {
437
+ const layout = projectLayoutEvidence(runtime, []);
139
438
  return {
140
439
  geometry: {
141
440
  coverage,
142
441
  reason: "scope-envelope-not-found",
143
442
  },
443
+ layout,
444
+ oracle: projectOracleEvidence(runtime, options, { scopeId, pageIds: layout.pageIds }),
144
445
  };
145
446
  }
146
447
 
448
+ const layout = projectLayoutEvidence(runtime, envelope.pageIds);
147
449
  return {
148
450
  geometry: {
149
451
  coverage,
150
452
  replacementEnvelope: copyEnvelope(envelope),
151
453
  },
454
+ layout,
455
+ oracle: projectOracleEvidence(runtime, options, { scopeId, pageIds: layout.pageIds }),
152
456
  };
153
457
  }
@@ -37,15 +37,23 @@ import {
37
37
  emitScopeMetadataAudit,
38
38
  snapshotDocumentHash,
39
39
  } from "./_metadata-audit.ts";
40
+ import {
41
+ projectAuditReference,
42
+ type AiActionAuditReference,
43
+ } from "./_audit-reference.ts";
44
+ import { currentAuditTimestamp } from "./_audit-time.ts";
40
45
 
41
46
  export interface AttachExplanationInput {
42
47
  readonly scopeId: string;
43
48
  readonly explanation: string;
49
+ readonly actorId?: string;
50
+ readonly origin?: "ui" | "agent" | "host";
44
51
  }
45
52
 
46
53
  export interface AttachExplanationResult {
47
54
  readonly explanationId: string;
48
55
  readonly attached: boolean;
56
+ readonly auditReference?: AiActionAuditReference;
49
57
  /**
50
58
  * Present when `attached: false`. Mirrors the primitive's refusal
51
59
  * reason (`scope-not-resolvable:<scopeId>` post-coord-06 §13c;
@@ -85,11 +93,14 @@ export interface CreateIssueInput {
85
93
  readonly scopeId: string;
86
94
  readonly summary: string;
87
95
  readonly severity?: "info" | "warning" | "error";
96
+ readonly actorId?: string;
97
+ readonly origin?: "ui" | "agent" | "host";
88
98
  }
89
99
 
90
100
  export interface CreateIssueResult {
91
101
  readonly issueId: string;
92
102
  readonly created: boolean;
103
+ readonly auditReference?: AiActionAuditReference;
93
104
  readonly reason?: string;
94
105
  }
95
106
 
@@ -136,15 +147,20 @@ export function createAttachFamily(runtime: RuntimeApiHandle) {
136
147
  );
137
148
  const preScope = captureScopeSnapshot(runtime, input.scopeId);
138
149
  const documentHashBefore = snapshotDocumentHash(runtime);
150
+ const emittedAtUtc = currentAuditTimestamp(runtime);
139
151
  const primitiveResult = compiler.attachExplanation({
140
152
  scopeId: input.scopeId,
141
153
  explanation: input.explanation,
142
154
  explanationId,
155
+ createdAtUtc: emittedAtUtc,
143
156
  });
157
+ let auditReference: AiActionAuditReference | undefined;
144
158
  if (primitiveResult.attached && preScope) {
145
- emitScopeMetadataAudit({
159
+ const audit = emitScopeMetadataAudit({
146
160
  runtime,
147
161
  actionId: attachExplanationMetadata.name,
162
+ ...(input.actorId ? { actorId: input.actorId } : {}),
163
+ ...(input.origin ? { origin: input.origin } : {}),
148
164
  scopeId: input.scopeId,
149
165
  targetScopeSnapshot: preScope,
150
166
  proposedContent: {
@@ -156,9 +172,10 @@ export function createAttachFamily(runtime: RuntimeApiHandle) {
156
172
  },
157
173
  compiledOperationKind: "metadata-attach-explanation",
158
174
  compiledOperationSummary: `attach explanation ${primitiveResult.explanationId} to scope ${input.scopeId}`,
159
- emittedAtUtc: new Date(0).toISOString(),
175
+ emittedAtUtc,
160
176
  documentHashBefore,
161
177
  });
178
+ auditReference = projectAuditReference(audit);
162
179
  }
163
180
  emitUxResponse(runtime, {
164
181
  apiFn: attachExplanationMetadata.name,
@@ -170,6 +187,7 @@ export function createAttachFamily(runtime: RuntimeApiHandle) {
170
187
  return {
171
188
  explanationId: primitiveResult.explanationId,
172
189
  attached: primitiveResult.attached,
190
+ ...(auditReference ? { auditReference } : {}),
173
191
  // §1.17 — surface primitive's reason on refusal for symmetry
174
192
  // with CreateIssueResult. The primitive returns `reason` only
175
193
  // when `attached: false`; passthrough preserves that contract.
@@ -191,16 +209,21 @@ export function createAttachFamily(runtime: RuntimeApiHandle) {
191
209
  );
192
210
  const preScope = captureScopeSnapshot(runtime, input.scopeId);
193
211
  const documentHashBefore = snapshotDocumentHash(runtime);
212
+ const emittedAtUtc = currentAuditTimestamp(runtime);
194
213
  const primitiveResult = compiler.createIssue({
195
214
  scopeId: input.scopeId,
196
215
  summary: input.summary,
197
216
  ...(input.severity ? { severity: input.severity } : {}),
198
217
  issueId,
218
+ createdAtUtc: emittedAtUtc,
199
219
  });
220
+ let auditReference: AiActionAuditReference | undefined;
200
221
  if (primitiveResult.created && preScope) {
201
- emitScopeMetadataAudit({
222
+ const audit = emitScopeMetadataAudit({
202
223
  runtime,
203
224
  actionId: createIssueMetadata.name,
225
+ ...(input.actorId ? { actorId: input.actorId } : {}),
226
+ ...(input.origin ? { origin: input.origin } : {}),
204
227
  scopeId: input.scopeId,
205
228
  targetScopeSnapshot: preScope,
206
229
  proposedContent: {
@@ -213,9 +236,10 @@ export function createAttachFamily(runtime: RuntimeApiHandle) {
213
236
  },
214
237
  compiledOperationKind: "metadata-attach-issue",
215
238
  compiledOperationSummary: `create issue ${primitiveResult.issueId} on scope ${input.scopeId}`,
216
- emittedAtUtc: new Date(0).toISOString(),
239
+ emittedAtUtc,
217
240
  documentHashBefore,
218
241
  });
242
+ auditReference = projectAuditReference(audit);
219
243
  }
220
244
  emitUxResponse(runtime, {
221
245
  apiFn: createIssueMetadata.name,
@@ -227,6 +251,7 @@ export function createAttachFamily(runtime: RuntimeApiHandle) {
227
251
  const out: CreateIssueResult = {
228
252
  issueId: primitiveResult.issueId,
229
253
  created: primitiveResult.created,
254
+ ...(auditReference ? { auditReference } : {}),
230
255
  ...(primitiveResult.created ? {} : { reason: primitiveResult.reason }),
231
256
  };
232
257
  return out;
@@ -26,6 +26,7 @@ import {
26
26
  import type { ApiV3FnMetadata } from "../_layer-metadata.ts";
27
27
  import {
28
28
  projectScopePe2Evidence,
29
+ type AiPe2EvidenceOptions,
29
30
  type AiPe2ScopeEvidence,
30
31
  } from "./_pe2-evidence.ts";
31
32
 
@@ -103,7 +104,10 @@ export const getScopeBundleMetadata: ApiV3FnMetadata = {
103
104
  rwdReference: "§AI API § ai.getScopeBundle",
104
105
  };
105
106
 
106
- export function createBundleFamily(runtime: RuntimeApiHandle) {
107
+ export function createBundleFamily(
108
+ runtime: RuntimeApiHandle,
109
+ pe2Evidence?: AiPe2EvidenceOptions,
110
+ ) {
107
111
  const compiler = createScopeCompilerService(runtime);
108
112
  return {
109
113
  getScope(input: GetScopeInput): SemanticScope | null {
@@ -133,7 +137,7 @@ export function createBundleFamily(runtime: RuntimeApiHandle) {
133
137
  }
134
138
  return {
135
139
  ...bundle,
136
- pe2Evidence: projectScopePe2Evidence(runtime, scopeId),
140
+ pe2Evidence: projectScopePe2Evidence(runtime, input.handle, pe2Evidence),
137
141
  };
138
142
  },
139
143
  };
@@ -18,6 +18,7 @@ import {
18
18
  import type { ApiV3FnMetadata } from "../_layer-metadata.ts";
19
19
  import {
20
20
  projectDocumentPe2Evidence,
21
+ type AiPe2EvidenceOptions,
21
22
  type AiPe2DocumentEvidence,
22
23
  } from "./_pe2-evidence.ts";
23
24
 
@@ -84,7 +85,10 @@ function buildKindDistribution(
84
85
  return out;
85
86
  }
86
87
 
87
- export function createInspectFamily(runtime: RuntimeApiHandle) {
88
+ export function createInspectFamily(
89
+ runtime: RuntimeApiHandle,
90
+ pe2Evidence?: AiPe2EvidenceOptions,
91
+ ) {
88
92
  const compiler = createScopeCompilerService(runtime);
89
93
  return {
90
94
  inspectDocument(): InspectDocumentResult {
@@ -102,7 +106,7 @@ export function createInspectFamily(runtime: RuntimeApiHandle) {
102
106
  scopeCount: scopes.length,
103
107
  semanticSummary: summary,
104
108
  kindDistribution,
105
- pe2Evidence: projectDocumentPe2Evidence(runtime),
109
+ pe2Evidence: projectDocumentPe2Evidence(runtime, pe2Evidence),
106
110
  };
107
111
  },
108
112