@beyondwork/docx-react-component 1.0.104 → 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 +1 -1
- package/src/api/public-types.ts +3 -0
- package/src/api/v3/_create.ts +9 -2
- package/src/api/v3/ai/_audit-reference.ts +28 -0
- package/src/api/v3/ai/_pe2-evidence.ts +419 -0
- package/src/api/v3/ai/attach.ts +22 -2
- package/src/api/v3/ai/bundle.ts +18 -6
- package/src/api/v3/ai/inspect.ts +12 -2
- package/src/api/v3/ai/replacement.ts +124 -0
- package/src/api/v3/index.ts +7 -0
- package/src/api/v3/ui/_types.ts +139 -0
- package/src/api/v3/ui/index.ts +9 -0
- package/src/api/v3/ui/overlays.ts +104 -0
- package/src/api/v3/ui/viewport.ts +97 -0
- package/src/model/layout/index.ts +3 -0
- package/src/model/layout/page-graph-types.ts +118 -0
- package/src/model/layout/runtime-page-graph-types.ts +13 -0
- package/src/runtime/document-runtime.ts +39 -18
- package/src/runtime/event-refresh-hints.ts +33 -6
- package/src/runtime/geometry/geometry-facet.ts +9 -1
- package/src/runtime/geometry/geometry-index.ts +461 -10
- package/src/runtime/geometry/geometry-types.ts +6 -0
- package/src/runtime/geometry/object-handles.ts +7 -4
- package/src/runtime/layout/layout-engine-instance.ts +2 -0
- package/src/runtime/layout/layout-engine-version.ts +36 -1
- package/src/runtime/layout/page-graph.ts +697 -10
- package/src/runtime/layout/paginated-layout-engine.ts +10 -0
- package/src/runtime/layout/project-block-fragments.ts +187 -8
- package/src/runtime/layout/public-facet.ts +236 -0
- package/src/runtime/prerender/graph-canonicalize.ts +14 -0
- package/src/runtime/workflow/index.ts +1 -0
- package/src/runtime/workflow/overlay-lanes.ts +228 -0
- package/src/ui/presence-overlay-lane.ts +131 -0
- package/src/ui/ui-controller-factory.ts +21 -0
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.
|
|
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": [
|
package/src/api/public-types.ts
CHANGED
|
@@ -177,9 +177,11 @@ export type {
|
|
|
177
177
|
PublicBlockMeasurement,
|
|
178
178
|
PublicFieldDirtinessReport,
|
|
179
179
|
PublicLineBox,
|
|
180
|
+
PublicLayoutDivergence,
|
|
180
181
|
PublicMeasurementFidelity,
|
|
181
182
|
PublicNoteAllocation,
|
|
182
183
|
PublicPageAnchor,
|
|
184
|
+
PublicPageFrame,
|
|
183
185
|
PublicPageNode,
|
|
184
186
|
PublicPageRegion,
|
|
185
187
|
PublicPageRegions,
|
|
@@ -190,6 +192,7 @@ export type {
|
|
|
190
192
|
PublicResolvedParagraphFormatting,
|
|
191
193
|
PublicResolvedRunFormatting,
|
|
192
194
|
PublicSectionNode,
|
|
195
|
+
PublicTwipsRect,
|
|
193
196
|
// R0.5: named page-format + margin-preset catalogs
|
|
194
197
|
PageFormatDefinition,
|
|
195
198
|
ActivePageFormat,
|
package/src/api/v3/_create.ts
CHANGED
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 09 PE2 evidence projection.
|
|
3
|
+
*
|
|
4
|
+
* The AI API should not leak the full runtime geometry index. Agents need a
|
|
5
|
+
* small, JSON-stable read model that says whether PE2 geometry evidence is
|
|
6
|
+
* available and, for scope reads, whether a replacement envelope exists for
|
|
7
|
+
* the requested scope.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { RuntimeApiHandle } from "../_runtime-handle.ts";
|
|
11
|
+
import type { ScopeHandle } from "../../../runtime/scopes/index.ts";
|
|
12
|
+
import type {
|
|
13
|
+
GeometryIndexCoverage,
|
|
14
|
+
GeometryPrecision,
|
|
15
|
+
GeometryRehydrationStatus,
|
|
16
|
+
GeometryReplacementEnvelopeEntry,
|
|
17
|
+
GeometrySourceIdentity,
|
|
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";
|
|
25
|
+
|
|
26
|
+
export interface AiPe2GeometryCoverageEvidence {
|
|
27
|
+
readonly status: GeometryRehydrationStatus;
|
|
28
|
+
readonly pageCount: number;
|
|
29
|
+
readonly regionCount: number;
|
|
30
|
+
readonly sliceCount: number;
|
|
31
|
+
readonly lineCount: number;
|
|
32
|
+
readonly anchorCount: number;
|
|
33
|
+
readonly hitTargetCount: number;
|
|
34
|
+
readonly semanticEntryCount: number;
|
|
35
|
+
readonly replacementEnvelopeCount: number;
|
|
36
|
+
readonly objectHandleCount: number;
|
|
37
|
+
readonly precision: {
|
|
38
|
+
readonly exact: number;
|
|
39
|
+
readonly "within-tolerance": number;
|
|
40
|
+
readonly heuristic: number;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface AiPe2DocumentEvidence {
|
|
45
|
+
readonly geometry: AiPe2GeometryCoverageEvidence;
|
|
46
|
+
readonly layout: AiPe2LayoutEvidence;
|
|
47
|
+
readonly oracle: AiPe2OracleEvidence;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface AiPe2ScopeReplacementEnvelopeEvidence {
|
|
51
|
+
readonly status: GeometryRehydrationStatus;
|
|
52
|
+
readonly precision: GeometryPrecision;
|
|
53
|
+
readonly rectCount: number;
|
|
54
|
+
readonly pageIds?: readonly string[];
|
|
55
|
+
readonly sourceIdentity?: GeometrySourceIdentity;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface AiPe2ScopeEvidence {
|
|
59
|
+
readonly geometry: {
|
|
60
|
+
readonly coverage: AiPe2GeometryCoverageEvidence;
|
|
61
|
+
readonly replacementEnvelope?: AiPe2ScopeReplacementEnvelopeEvidence;
|
|
62
|
+
readonly reason?: "geometry-index-unavailable" | "scope-envelope-not-found";
|
|
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;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function copyCoverage(coverage: GeometryIndexCoverage): AiPe2GeometryCoverageEvidence {
|
|
119
|
+
return {
|
|
120
|
+
status: coverage.status,
|
|
121
|
+
pageCount: coverage.pageCount,
|
|
122
|
+
regionCount: coverage.regionCount,
|
|
123
|
+
sliceCount: coverage.sliceCount,
|
|
124
|
+
lineCount: coverage.lineCount,
|
|
125
|
+
anchorCount: coverage.anchorCount,
|
|
126
|
+
hitTargetCount: coverage.hitTargetCount,
|
|
127
|
+
semanticEntryCount: coverage.semanticEntryCount,
|
|
128
|
+
replacementEnvelopeCount: coverage.replacementEnvelopeCount,
|
|
129
|
+
objectHandleCount: coverage.objectHandleCount,
|
|
130
|
+
precision: {
|
|
131
|
+
exact: coverage.precision.exact,
|
|
132
|
+
"within-tolerance": coverage.precision["within-tolerance"],
|
|
133
|
+
heuristic: coverage.precision.heuristic,
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function copyEnvelope(
|
|
139
|
+
envelope: GeometryReplacementEnvelopeEntry,
|
|
140
|
+
): AiPe2ScopeReplacementEnvelopeEvidence {
|
|
141
|
+
return {
|
|
142
|
+
status: envelope.status,
|
|
143
|
+
precision: envelope.precision,
|
|
144
|
+
rectCount: envelope.rects.length,
|
|
145
|
+
...(envelope.pageIds ? { pageIds: [...envelope.pageIds] } : {}),
|
|
146
|
+
...(envelope.sourceIdentity ? { sourceIdentity: { ...envelope.sourceIdentity } } : {}),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const UNAVAILABLE_COVERAGE: AiPe2GeometryCoverageEvidence = {
|
|
151
|
+
status: "unavailable",
|
|
152
|
+
pageCount: 0,
|
|
153
|
+
regionCount: 0,
|
|
154
|
+
sliceCount: 0,
|
|
155
|
+
lineCount: 0,
|
|
156
|
+
anchorCount: 0,
|
|
157
|
+
hitTargetCount: 0,
|
|
158
|
+
semanticEntryCount: 0,
|
|
159
|
+
replacementEnvelopeCount: 0,
|
|
160
|
+
objectHandleCount: 0,
|
|
161
|
+
precision: { exact: 0, "within-tolerance": 0, heuristic: 0 },
|
|
162
|
+
};
|
|
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
|
+
|
|
351
|
+
export function projectDocumentPe2Evidence(
|
|
352
|
+
runtime: RuntimeApiHandle,
|
|
353
|
+
options?: AiPe2EvidenceOptions,
|
|
354
|
+
): AiPe2DocumentEvidence {
|
|
355
|
+
const layout = projectLayoutEvidence(runtime);
|
|
356
|
+
const geometry = runtime.geometry
|
|
357
|
+
? copyCoverage(runtime.geometry.getGeometryCoverage())
|
|
358
|
+
: UNAVAILABLE_COVERAGE;
|
|
359
|
+
return {
|
|
360
|
+
geometry,
|
|
361
|
+
layout,
|
|
362
|
+
oracle: projectOracleEvidence(runtime, options, { pageIds: layout.pageIds }),
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export function projectScopePe2Evidence(
|
|
367
|
+
runtime: RuntimeApiHandle,
|
|
368
|
+
handle: ScopeHandle,
|
|
369
|
+
options?: AiPe2EvidenceOptions,
|
|
370
|
+
): AiPe2ScopeEvidence {
|
|
371
|
+
const { scopeId } = handle;
|
|
372
|
+
if (!runtime.geometry) {
|
|
373
|
+
const layout = projectLayoutEvidence(runtime, []);
|
|
374
|
+
return {
|
|
375
|
+
geometry: {
|
|
376
|
+
coverage: UNAVAILABLE_COVERAGE,
|
|
377
|
+
reason: "geometry-index-unavailable",
|
|
378
|
+
},
|
|
379
|
+
layout,
|
|
380
|
+
oracle: projectOracleEvidence(runtime, options, { scopeId, pageIds: layout.pageIds }),
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
const coverage = copyCoverage(runtime.geometry.getGeometryCoverage());
|
|
384
|
+
const index = runtime.geometry.getGeometryIndex();
|
|
385
|
+
if (!index) {
|
|
386
|
+
const layout = projectLayoutEvidence(runtime, []);
|
|
387
|
+
return {
|
|
388
|
+
geometry: {
|
|
389
|
+
coverage,
|
|
390
|
+
reason: "geometry-index-unavailable",
|
|
391
|
+
},
|
|
392
|
+
layout,
|
|
393
|
+
oracle: projectOracleEvidence(runtime, options, { scopeId, pageIds: layout.pageIds }),
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const envelope = findReplacementEnvelopeForHandle(index.replacementEnvelopes, handle);
|
|
398
|
+
if (!envelope) {
|
|
399
|
+
const layout = projectLayoutEvidence(runtime, []);
|
|
400
|
+
return {
|
|
401
|
+
geometry: {
|
|
402
|
+
coverage,
|
|
403
|
+
reason: "scope-envelope-not-found",
|
|
404
|
+
},
|
|
405
|
+
layout,
|
|
406
|
+
oracle: projectOracleEvidence(runtime, options, { scopeId, pageIds: layout.pageIds }),
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const layout = projectLayoutEvidence(runtime, envelope.pageIds);
|
|
411
|
+
return {
|
|
412
|
+
geometry: {
|
|
413
|
+
coverage,
|
|
414
|
+
replacementEnvelope: copyEnvelope(envelope),
|
|
415
|
+
},
|
|
416
|
+
layout,
|
|
417
|
+
oracle: projectOracleEvidence(runtime, options, { scopeId, pageIds: layout.pageIds }),
|
|
418
|
+
};
|
|
419
|
+
}
|
package/src/api/v3/ai/attach.ts
CHANGED
|
@@ -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;
|
package/src/api/v3/ai/bundle.ts
CHANGED
|
@@ -24,6 +24,11 @@ import {
|
|
|
24
24
|
type SemanticScope,
|
|
25
25
|
} from "../../../runtime/scopes/index.ts";
|
|
26
26
|
import type { ApiV3FnMetadata } from "../_layer-metadata.ts";
|
|
27
|
+
import {
|
|
28
|
+
projectScopePe2Evidence,
|
|
29
|
+
type AiPe2EvidenceOptions,
|
|
30
|
+
type AiPe2ScopeEvidence,
|
|
31
|
+
} from "./_pe2-evidence.ts";
|
|
27
32
|
|
|
28
33
|
/**
|
|
29
34
|
* Handle-shaped input (architecture A3 — scope-handle-first targeting).
|
|
@@ -42,8 +47,9 @@ export interface GetScopeBundleInput {
|
|
|
42
47
|
readonly nowUtc: string;
|
|
43
48
|
}
|
|
44
49
|
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
export type ScopeBundle = RuntimeScopeBundle & {
|
|
51
|
+
readonly pe2Evidence: AiPe2ScopeEvidence;
|
|
52
|
+
};
|
|
47
53
|
|
|
48
54
|
export interface ScopeBundleNotFound {
|
|
49
55
|
readonly notFound: true;
|
|
@@ -91,14 +97,17 @@ export const getScopeBundleMetadata: ApiV3FnMetadata = {
|
|
|
91
97
|
boundedScope: "scope",
|
|
92
98
|
auditCategory: "scope-bundle",
|
|
93
99
|
contextPromptShape:
|
|
94
|
-
"Bundle content + formatting + layout + geometry + workflow + replaceability for prompt context.",
|
|
100
|
+
"Bundle content + formatting + layout + geometry + workflow + replaceability + PE2 geometry coverage/envelope evidence for prompt context.",
|
|
95
101
|
},
|
|
96
102
|
stateClass: "A-canonical",
|
|
97
103
|
persistsTo: "canonical",
|
|
98
104
|
rwdReference: "§AI API § ai.getScopeBundle",
|
|
99
105
|
};
|
|
100
106
|
|
|
101
|
-
export function createBundleFamily(
|
|
107
|
+
export function createBundleFamily(
|
|
108
|
+
runtime: RuntimeApiHandle,
|
|
109
|
+
pe2Evidence?: AiPe2EvidenceOptions,
|
|
110
|
+
) {
|
|
102
111
|
const compiler = createScopeCompilerService(runtime);
|
|
103
112
|
return {
|
|
104
113
|
getScope(input: GetScopeInput): SemanticScope | null {
|
|
@@ -110,7 +119,7 @@ export function createBundleFamily(runtime: RuntimeApiHandle) {
|
|
|
110
119
|
return compiled?.scope ?? null;
|
|
111
120
|
},
|
|
112
121
|
|
|
113
|
-
getScopeBundle(input: GetScopeBundleInput):
|
|
122
|
+
getScopeBundle(input: GetScopeBundleInput): ScopeBundle | ScopeBundleNotFound {
|
|
114
123
|
// @endStateApi — live-with-adapter. Routes through the compiler-
|
|
115
124
|
// service facade.
|
|
116
125
|
//
|
|
@@ -126,7 +135,10 @@ export function createBundleFamily(runtime: RuntimeApiHandle) {
|
|
|
126
135
|
reason: "no scope with this id in canonical document or review store",
|
|
127
136
|
};
|
|
128
137
|
}
|
|
129
|
-
return
|
|
138
|
+
return {
|
|
139
|
+
...bundle,
|
|
140
|
+
pe2Evidence: projectScopePe2Evidence(runtime, input.handle, pe2Evidence),
|
|
141
|
+
};
|
|
130
142
|
},
|
|
131
143
|
};
|
|
132
144
|
}
|