@beyondwork/docx-react-component 1.0.105 → 1.0.106

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@beyondwork/docx-react-component",
3
3
  "publisher": "beyondwork",
4
- "version": "1.0.105",
4
+ "version": "1.0.106",
5
5
  "description": "Embeddable React Word (docx) editor with review, comments, tracked changes, and round-trip OOXML fidelity.",
6
6
  "type": "module",
7
7
  "sideEffects": [
@@ -41,6 +41,7 @@ import { createReviewFamily as createAiReviewFamily } from "./ai/review.ts";
41
41
  import { createEvaluateFamily } from "./ai/evaluate.ts";
42
42
  import { createStatsFamily } from "./ai/stats.ts";
43
43
  import { createOutlineFamily } from "./ai/outline.ts";
44
+ import type { AiPe2EvidenceOptions } from "./ai/_pe2-evidence.ts";
44
45
 
45
46
  import { createUiApi } from "./ui/_create.ts";
46
47
  import type { ApiV3Ui, UiControllerFactory } from "./ui/_types.ts";
@@ -108,6 +109,12 @@ export interface ApiV3 {
108
109
  */
109
110
  export interface CreateApiV3Opts {
110
111
  readonly ui?: UiControllerFactory;
112
+ /**
113
+ * Optional PE2 evidence bridge. Hosts/debug services that already have
114
+ * truth-oracle run metadata can inject it here; omitted means AI reads
115
+ * report `pe2Evidence.oracle.status: "not-wired"`.
116
+ */
117
+ readonly pe2Evidence?: AiPe2EvidenceOptions;
111
118
  }
112
119
 
113
120
  /**
@@ -119,9 +126,9 @@ export interface CreateApiV3Opts {
119
126
  */
120
127
  export function createApiV3(handle: RuntimeApiHandle, opts?: CreateApiV3Opts): ApiV3 {
121
128
  const ai: ApiV3Ai = {
122
- ...createInspectFamily(handle),
129
+ ...createInspectFamily(handle, opts?.pe2Evidence),
123
130
  ...createResolveFamily(handle),
124
- ...createBundleFamily(handle),
131
+ ...createBundleFamily(handle, opts?.pe2Evidence),
125
132
  ...createReplacementFamily(handle),
126
133
  ...createAttachFamily(handle),
127
134
  ...createExportFamily(handle),
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Compact AI-facing pointer to an emitted ScopeActionAudit.
3
+ *
4
+ * The full audit bundle remains on the `scope` telemetry channel. Mutation
5
+ * return values expose only enough provenance for agents to cite the action
6
+ * and correlate it with telemetry.
7
+ */
8
+
9
+ import type { ScopeActionAudit } from "../../../runtime/scopes/index.ts";
10
+
11
+ export interface AiActionAuditReference {
12
+ readonly actionId: string;
13
+ readonly actorId: string;
14
+ readonly origin: ScopeActionAudit["origin"];
15
+ readonly emittedAtUtc: string;
16
+ }
17
+
18
+ export function projectAuditReference(
19
+ audit: ScopeActionAudit | null | undefined,
20
+ ): AiActionAuditReference | undefined {
21
+ if (!audit) return undefined;
22
+ return {
23
+ actionId: audit.actionId,
24
+ actorId: audit.actorId,
25
+ origin: audit.origin,
26
+ emittedAtUtc: audit.emittedAtUtc,
27
+ };
28
+ }
@@ -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,58 @@ 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
+ }
77
+
78
+ export interface AiPe2LayoutEvidence {
79
+ readonly status: "realized" | "unavailable";
80
+ readonly pageCount: number;
81
+ readonly pageIds: readonly string[];
82
+ readonly pagesWithDivergences: readonly string[];
83
+ readonly divergenceIds: readonly string[];
84
+ readonly divergences: readonly AiPe2LayoutDivergenceEvidence[];
85
+ readonly reason?: "scope-page-evidence-not-found";
86
+ }
87
+
88
+ export type AiPe2OracleVerdict =
89
+ | "match"
90
+ | "divergent"
91
+ | "blocked"
92
+ | "oracle-incomplete"
93
+ | "runtime-projection-not-wired"
94
+ | "not-compared";
95
+
96
+ export interface AiPe2OracleEvidence {
97
+ readonly status: "available" | "not-wired";
98
+ readonly runIds: readonly string[];
99
+ readonly divergenceIds: readonly string[];
100
+ readonly verdict?: AiPe2OracleVerdict;
101
+ readonly reason?: "truth-adapter-unavailable" | "truth-adapter-error";
102
+ }
103
+
104
+ export interface AiPe2OracleEvidenceProviderInput {
105
+ readonly documentId: string;
106
+ readonly scopeId?: string;
107
+ readonly pageIds: readonly string[];
108
+ }
109
+
110
+ export type AiPe2OracleEvidenceProvider = (
111
+ input: AiPe2OracleEvidenceProviderInput,
112
+ ) => AiPe2OracleEvidence | null | undefined;
113
+
114
+ export interface AiPe2EvidenceOptions {
115
+ readonly oracle?: AiPe2OracleEvidenceProvider;
55
116
  }
56
117
 
57
118
  function copyCoverage(coverage: GeometryIndexCoverage): AiPe2GeometryCoverageEvidence {
@@ -100,54 +161,259 @@ const UNAVAILABLE_COVERAGE: AiPe2GeometryCoverageEvidence = {
100
161
  precision: { exact: 0, "within-tolerance": 0, heuristic: 0 },
101
162
  };
102
163
 
164
+ function copyLayoutDivergence(
165
+ divergence: PublicLayoutDivergence,
166
+ ): AiPe2LayoutDivergenceEvidence {
167
+ return {
168
+ divergenceId: divergence.divergenceId,
169
+ kind: divergence.kind,
170
+ source: divergence.source,
171
+ severity: divergence.severity,
172
+ message: divergence.message,
173
+ ...(divergence.regionKinds ? { regionKinds: [...divergence.regionKinds] } : {}),
174
+ ...(divergence.fragmentIds ? { fragmentIds: [...divergence.fragmentIds] } : {}),
175
+ };
176
+ }
177
+
178
+ function projectLayoutEvidence(
179
+ runtime: RuntimeApiHandle,
180
+ pageIds?: readonly string[],
181
+ ): AiPe2LayoutEvidence {
182
+ if (typeof runtime.layout?.getPageCount !== "function") {
183
+ return {
184
+ status: "unavailable",
185
+ pageCount: 0,
186
+ pageIds: [],
187
+ pagesWithDivergences: [],
188
+ divergenceIds: [],
189
+ divergences: [],
190
+ };
191
+ }
192
+ const pageCount = runtime.layout.getPageCount();
193
+ const selectedPageIds = pageIds ? new Set(pageIds) : null;
194
+ const pageIdOut: string[] = [];
195
+ const pagesWithDivergences: string[] = [];
196
+ const divergenceIds = new Set<string>();
197
+ const divergencesById = new Map<string, AiPe2LayoutDivergenceEvidence>();
198
+
199
+ for (let pageIndex = 0; pageIndex < pageCount; pageIndex += 1) {
200
+ const page = runtime.layout.getPage(pageIndex);
201
+ if (!page) continue;
202
+ if (selectedPageIds && !selectedPageIds.has(page.pageId)) continue;
203
+ pageIdOut.push(page.pageId);
204
+
205
+ for (const divergenceId of page.frame?.divergenceIds ?? []) {
206
+ divergenceIds.add(divergenceId);
207
+ }
208
+ for (const divergence of page.divergences ?? []) {
209
+ divergenceIds.add(divergence.divergenceId);
210
+ divergencesById.set(divergence.divergenceId, copyLayoutDivergence(divergence));
211
+ }
212
+ if ((page.frame?.divergenceIds.length ?? 0) > 0 || (page.divergences?.length ?? 0) > 0) {
213
+ pagesWithDivergences.push(page.pageId);
214
+ }
215
+ }
216
+
217
+ return {
218
+ status: pageIdOut.length > 0 ? "realized" : "unavailable",
219
+ pageCount: pageIdOut.length,
220
+ pageIds: pageIdOut,
221
+ pagesWithDivergences,
222
+ divergenceIds: [...divergenceIds],
223
+ divergences: [...divergencesById.values()],
224
+ ...(selectedPageIds && pageIdOut.length === 0
225
+ ? { reason: "scope-page-evidence-not-found" as const }
226
+ : {}),
227
+ };
228
+ }
229
+
230
+ function copyOracleEvidence(evidence: AiPe2OracleEvidence): AiPe2OracleEvidence {
231
+ return {
232
+ status: evidence.status,
233
+ runIds: [...evidence.runIds],
234
+ divergenceIds: [...evidence.divergenceIds],
235
+ ...(evidence.verdict ? { verdict: evidence.verdict } : {}),
236
+ ...(evidence.reason ? { reason: evidence.reason } : {}),
237
+ };
238
+ }
239
+
240
+ function canonicalStoryKeyForHandle(handle: ScopeHandle): string {
241
+ const target = handle.storyTarget;
242
+ switch (target.kind) {
243
+ case "main":
244
+ return MAIN_STORY_KEY;
245
+ case "header":
246
+ return createHeaderFooterStoryKey({
247
+ kind: "header",
248
+ relationshipId: target.relationshipId,
249
+ variant: target.variant,
250
+ ...(target.sectionIndex !== undefined ? { sectionIndex: target.sectionIndex } : {}),
251
+ });
252
+ case "footer":
253
+ return createHeaderFooterStoryKey({
254
+ kind: "footer",
255
+ relationshipId: target.relationshipId,
256
+ variant: target.variant,
257
+ ...(target.sectionIndex !== undefined ? { sectionIndex: target.sectionIndex } : {}),
258
+ });
259
+ case "footnote":
260
+ return createNoteStoryKey("footnote", target.noteId);
261
+ case "endnote":
262
+ return createNoteStoryKey("endnote", target.noteId);
263
+ }
264
+ }
265
+
266
+ function semanticMainBlockPath(handle: ScopeHandle): string | null {
267
+ const path = handle.semanticPath;
268
+ if (path[0] !== "body") return null;
269
+ if (path[1] === "paragraph" || path[1] === "heading" || path[1] === "list-item") {
270
+ const blockIndex = path[path.length - 1];
271
+ return typeof blockIndex === "string" && /^\d+$/u.test(blockIndex)
272
+ ? `${MAIN_STORY_KEY}/block[${blockIndex}]`
273
+ : null;
274
+ }
275
+ if (path[1] === "table" && typeof path[2] === "string" && /^\d+$/u.test(path[2])) {
276
+ return `${MAIN_STORY_KEY}/block[${path[2]}]`;
277
+ }
278
+ return null;
279
+ }
280
+
281
+ function scoreEnvelopeForHandle(
282
+ envelope: GeometryReplacementEnvelopeEntry,
283
+ handle: ScopeHandle,
284
+ storyKey: string,
285
+ ): number {
286
+ if (envelope.scopeId !== handle.scopeId) return -1;
287
+ const source = envelope.sourceIdentity;
288
+ if (!source) return 0;
289
+
290
+ let score = 1;
291
+ if (source.scopeId === handle.scopeId) score += 2;
292
+ if (source.storyKey === storyKey) score += 8;
293
+ if (source.scopeKey === `${storyKey}:scope:${handle.scopeId}` ||
294
+ source.scopeKey?.startsWith(`${storyKey}:scope:${handle.scopeId}:`)) {
295
+ score += 4;
296
+ }
297
+
298
+ const blockPath = semanticMainBlockPath(handle);
299
+ if (blockPath && source.blockPath === blockPath) score += 2;
300
+
301
+ return score;
302
+ }
303
+
304
+ function findReplacementEnvelopeForHandle(
305
+ envelopes: readonly GeometryReplacementEnvelopeEntry[],
306
+ handle: ScopeHandle,
307
+ ): GeometryReplacementEnvelopeEntry | undefined {
308
+ const storyKey = canonicalStoryKeyForHandle(handle);
309
+ let best: GeometryReplacementEnvelopeEntry | undefined;
310
+ let bestScore = -1;
311
+ for (const envelope of envelopes) {
312
+ const score = scoreEnvelopeForHandle(envelope, handle, storyKey);
313
+ if (score > bestScore) {
314
+ best = envelope;
315
+ bestScore = score;
316
+ }
317
+ }
318
+ return bestScore >= 0 ? best : undefined;
319
+ }
320
+
321
+ function projectOracleEvidence(
322
+ runtime: RuntimeApiHandle,
323
+ options: AiPe2EvidenceOptions | undefined,
324
+ input: Omit<AiPe2OracleEvidenceProviderInput, "documentId">,
325
+ ): AiPe2OracleEvidence {
326
+ const provider = options?.oracle;
327
+ if (provider) {
328
+ try {
329
+ const evidence = provider({
330
+ documentId: runtime.getSessionState().documentId,
331
+ ...input,
332
+ });
333
+ if (evidence) return copyOracleEvidence(evidence);
334
+ } catch {
335
+ return {
336
+ status: "not-wired",
337
+ runIds: [],
338
+ divergenceIds: [],
339
+ reason: "truth-adapter-error",
340
+ };
341
+ }
342
+ }
343
+ return {
344
+ status: "not-wired",
345
+ runIds: [],
346
+ divergenceIds: [],
347
+ reason: "truth-adapter-unavailable",
348
+ };
349
+ }
350
+
103
351
  export function projectDocumentPe2Evidence(
104
352
  runtime: RuntimeApiHandle,
353
+ options?: AiPe2EvidenceOptions,
105
354
  ): AiPe2DocumentEvidence {
106
- if (!runtime.geometry) {
107
- return { geometry: UNAVAILABLE_COVERAGE };
108
- }
355
+ const layout = projectLayoutEvidence(runtime);
356
+ const geometry = runtime.geometry
357
+ ? copyCoverage(runtime.geometry.getGeometryCoverage())
358
+ : UNAVAILABLE_COVERAGE;
109
359
  return {
110
- geometry: copyCoverage(runtime.geometry.getGeometryCoverage()),
360
+ geometry,
361
+ layout,
362
+ oracle: projectOracleEvidence(runtime, options, { pageIds: layout.pageIds }),
111
363
  };
112
364
  }
113
365
 
114
366
  export function projectScopePe2Evidence(
115
367
  runtime: RuntimeApiHandle,
116
- scopeId: string,
368
+ handle: ScopeHandle,
369
+ options?: AiPe2EvidenceOptions,
117
370
  ): AiPe2ScopeEvidence {
371
+ const { scopeId } = handle;
118
372
  if (!runtime.geometry) {
373
+ const layout = projectLayoutEvidence(runtime, []);
119
374
  return {
120
375
  geometry: {
121
376
  coverage: UNAVAILABLE_COVERAGE,
122
377
  reason: "geometry-index-unavailable",
123
378
  },
379
+ layout,
380
+ oracle: projectOracleEvidence(runtime, options, { scopeId, pageIds: layout.pageIds }),
124
381
  };
125
382
  }
126
383
  const coverage = copyCoverage(runtime.geometry.getGeometryCoverage());
127
384
  const index = runtime.geometry.getGeometryIndex();
128
385
  if (!index) {
386
+ const layout = projectLayoutEvidence(runtime, []);
129
387
  return {
130
388
  geometry: {
131
389
  coverage,
132
390
  reason: "geometry-index-unavailable",
133
391
  },
392
+ layout,
393
+ oracle: projectOracleEvidence(runtime, options, { scopeId, pageIds: layout.pageIds }),
134
394
  };
135
395
  }
136
396
 
137
- const envelope = index.replacementEnvelopes.find((entry) => entry.scopeId === scopeId);
397
+ const envelope = findReplacementEnvelopeForHandle(index.replacementEnvelopes, handle);
138
398
  if (!envelope) {
399
+ const layout = projectLayoutEvidence(runtime, []);
139
400
  return {
140
401
  geometry: {
141
402
  coverage,
142
403
  reason: "scope-envelope-not-found",
143
404
  },
405
+ layout,
406
+ oracle: projectOracleEvidence(runtime, options, { scopeId, pageIds: layout.pageIds }),
144
407
  };
145
408
  }
146
409
 
410
+ const layout = projectLayoutEvidence(runtime, envelope.pageIds);
147
411
  return {
148
412
  geometry: {
149
413
  coverage,
150
414
  replacementEnvelope: copyEnvelope(envelope),
151
415
  },
416
+ layout,
417
+ oracle: projectOracleEvidence(runtime, options, { scopeId, pageIds: layout.pageIds }),
152
418
  };
153
419
  }
@@ -37,15 +37,22 @@ 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";
40
44
 
41
45
  export interface AttachExplanationInput {
42
46
  readonly scopeId: string;
43
47
  readonly explanation: string;
48
+ readonly actorId?: string;
49
+ readonly origin?: "ui" | "agent" | "host";
44
50
  }
45
51
 
46
52
  export interface AttachExplanationResult {
47
53
  readonly explanationId: string;
48
54
  readonly attached: boolean;
55
+ readonly auditReference?: AiActionAuditReference;
49
56
  /**
50
57
  * Present when `attached: false`. Mirrors the primitive's refusal
51
58
  * reason (`scope-not-resolvable:<scopeId>` post-coord-06 §13c;
@@ -85,11 +92,14 @@ export interface CreateIssueInput {
85
92
  readonly scopeId: string;
86
93
  readonly summary: string;
87
94
  readonly severity?: "info" | "warning" | "error";
95
+ readonly actorId?: string;
96
+ readonly origin?: "ui" | "agent" | "host";
88
97
  }
89
98
 
90
99
  export interface CreateIssueResult {
91
100
  readonly issueId: string;
92
101
  readonly created: boolean;
102
+ readonly auditReference?: AiActionAuditReference;
93
103
  readonly reason?: string;
94
104
  }
95
105
 
@@ -141,10 +151,13 @@ export function createAttachFamily(runtime: RuntimeApiHandle) {
141
151
  explanation: input.explanation,
142
152
  explanationId,
143
153
  });
154
+ let auditReference: AiActionAuditReference | undefined;
144
155
  if (primitiveResult.attached && preScope) {
145
- emitScopeMetadataAudit({
156
+ const audit = emitScopeMetadataAudit({
146
157
  runtime,
147
158
  actionId: attachExplanationMetadata.name,
159
+ ...(input.actorId ? { actorId: input.actorId } : {}),
160
+ ...(input.origin ? { origin: input.origin } : {}),
148
161
  scopeId: input.scopeId,
149
162
  targetScopeSnapshot: preScope,
150
163
  proposedContent: {
@@ -159,6 +172,7 @@ export function createAttachFamily(runtime: RuntimeApiHandle) {
159
172
  emittedAtUtc: new Date(0).toISOString(),
160
173
  documentHashBefore,
161
174
  });
175
+ auditReference = projectAuditReference(audit);
162
176
  }
163
177
  emitUxResponse(runtime, {
164
178
  apiFn: attachExplanationMetadata.name,
@@ -170,6 +184,7 @@ export function createAttachFamily(runtime: RuntimeApiHandle) {
170
184
  return {
171
185
  explanationId: primitiveResult.explanationId,
172
186
  attached: primitiveResult.attached,
187
+ ...(auditReference ? { auditReference } : {}),
173
188
  // §1.17 — surface primitive's reason on refusal for symmetry
174
189
  // with CreateIssueResult. The primitive returns `reason` only
175
190
  // when `attached: false`; passthrough preserves that contract.
@@ -197,10 +212,13 @@ export function createAttachFamily(runtime: RuntimeApiHandle) {
197
212
  ...(input.severity ? { severity: input.severity } : {}),
198
213
  issueId,
199
214
  });
215
+ let auditReference: AiActionAuditReference | undefined;
200
216
  if (primitiveResult.created && preScope) {
201
- emitScopeMetadataAudit({
217
+ const audit = emitScopeMetadataAudit({
202
218
  runtime,
203
219
  actionId: createIssueMetadata.name,
220
+ ...(input.actorId ? { actorId: input.actorId } : {}),
221
+ ...(input.origin ? { origin: input.origin } : {}),
204
222
  scopeId: input.scopeId,
205
223
  targetScopeSnapshot: preScope,
206
224
  proposedContent: {
@@ -216,6 +234,7 @@ export function createAttachFamily(runtime: RuntimeApiHandle) {
216
234
  emittedAtUtc: new Date(0).toISOString(),
217
235
  documentHashBefore,
218
236
  });
237
+ auditReference = projectAuditReference(audit);
219
238
  }
220
239
  emitUxResponse(runtime, {
221
240
  apiFn: createIssueMetadata.name,
@@ -227,6 +246,7 @@ export function createAttachFamily(runtime: RuntimeApiHandle) {
227
246
  const out: CreateIssueResult = {
228
247
  issueId: primitiveResult.issueId,
229
248
  created: primitiveResult.created,
249
+ ...(auditReference ? { auditReference } : {}),
230
250
  ...(primitiveResult.created ? {} : { reason: primitiveResult.reason }),
231
251
  };
232
252
  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
 
@@ -33,6 +33,10 @@ import type {
33
33
  } from "../../../runtime/scopes/index.ts";
34
34
  import type { AIAction } from "../../../runtime/workflow/ai-action-policy.ts";
35
35
  import type { TextFormattingDirective } from "../../public-types.ts";
36
+ import {
37
+ projectAuditReference,
38
+ type AiActionAuditReference,
39
+ } from "./_audit-reference.ts";
36
40
 
37
41
  export interface ReplacementProposalInput {
38
42
  readonly targetScopeId: string;
@@ -125,6 +129,7 @@ export interface ApplyResult {
125
129
  readonly blockers?: readonly string[];
126
130
  readonly blockerDetails?: readonly ActionBlockerDetail[];
127
131
  readonly auditHint?: string;
132
+ readonly auditReference?: AiActionAuditReference;
128
133
  /**
129
134
  * Gap A (post-Slice-7 integration) — revision IDs authored during
130
135
  * the apply. Populated for suggest-mode (tracked insert + delete);
@@ -488,6 +493,9 @@ export function createReplacementFamily(runtime: RuntimeApiHandle) {
488
493
  : {}),
489
494
  ...(blockerDetails ? { blockerDetails } : {}),
490
495
  ...(result.audit ? { auditHint: result.audit.actionId } : {}),
496
+ ...(result.audit
497
+ ? { auditReference: projectAuditReference(result.audit) }
498
+ : {}),
491
499
  authoredRevisionIds: result.authoredRevisionIds,
492
500
  };
493
501
  },
@@ -533,6 +541,9 @@ export function createReplacementFamily(runtime: RuntimeApiHandle) {
533
541
  : {}),
534
542
  ...(blockerDetails ? { blockerDetails } : {}),
535
543
  ...(result.audit ? { auditHint: result.audit.actionId } : {}),
544
+ ...(result.audit
545
+ ? { auditReference: projectAuditReference(result.audit) }
546
+ : {}),
536
547
  authoredRevisionIds: result.authoredRevisionIds,
537
548
  };
538
549
  },
@@ -14,6 +14,13 @@
14
14
 
15
15
  export { createApiV3 } from "./_create.ts";
16
16
  export type { ApiV3, CreateApiV3Opts } from "./_create.ts";
17
+ export type {
18
+ AiPe2EvidenceOptions,
19
+ AiPe2OracleEvidence,
20
+ AiPe2OracleEvidenceProvider,
21
+ AiPe2OracleEvidenceProviderInput,
22
+ AiPe2OracleVerdict,
23
+ } from "./ai/_pe2-evidence.ts";
17
24
 
18
25
  export type {
19
26
  ApiStatus,