@beyondwork/docx-react-component 1.0.103 → 1.0.105

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 (45) hide show
  1. package/package.json +1 -1
  2. package/src/api/public-types.ts +66 -1
  3. package/src/api/v3/_runtime-handle.ts +2 -0
  4. package/src/api/v3/ai/_pe2-evidence.ts +153 -0
  5. package/src/api/v3/ai/bundle.ts +13 -5
  6. package/src/api/v3/ai/inspect.ts +7 -1
  7. package/src/api/v3/ai/outline.ts +2 -7
  8. package/src/api/v3/ai/replacement.ts +113 -0
  9. package/src/api/v3/runtime/geometry.ts +79 -0
  10. package/src/api/v3/ui/_types.ts +86 -0
  11. package/src/api/v3/ui/index.ts +5 -0
  12. package/src/api/v3/ui/overlays.ts +104 -0
  13. package/src/io/ooxml/parse-drawing.ts +99 -1
  14. package/src/io/ooxml/parse-fields.ts +27 -6
  15. package/src/io/ooxml/parse-shapes.ts +130 -0
  16. package/src/model/canonical-document.ts +34 -3
  17. package/src/model/canonical-layout-inputs.ts +979 -0
  18. package/src/model/layout/index.ts +9 -0
  19. package/src/model/layout/page-graph-types.ts +150 -0
  20. package/src/model/layout/runtime-page-graph-types.ts +23 -0
  21. package/src/runtime/collab/runtime-collab-sync.ts +3 -3
  22. package/src/runtime/debug/build-debug-inspector-snapshot.ts +17 -4
  23. package/src/runtime/document-runtime.ts +30 -14
  24. package/src/runtime/event-refresh-hints.ts +35 -5
  25. package/src/runtime/formatting/formatting-context.ts +110 -9
  26. package/src/runtime/formatting/index.ts +2 -0
  27. package/src/runtime/formatting/layout-inputs.ts +67 -3
  28. package/src/runtime/geometry/caret-geometry.ts +82 -10
  29. package/src/runtime/geometry/geometry-facet.ts +44 -0
  30. package/src/runtime/geometry/geometry-index.ts +1268 -0
  31. package/src/runtime/geometry/geometry-types.ts +227 -1
  32. package/src/runtime/geometry/index.ts +26 -0
  33. package/src/runtime/geometry/inert-geometry-facet.ts +3 -0
  34. package/src/runtime/geometry/object-handles.ts +7 -4
  35. package/src/runtime/geometry/replacement-envelope.ts +41 -2
  36. package/src/runtime/layout/layout-engine-instance.ts +2 -0
  37. package/src/runtime/layout/layout-engine-version.ts +44 -1
  38. package/src/runtime/layout/page-graph.ts +877 -2
  39. package/src/runtime/layout/project-block-fragments.ts +101 -1
  40. package/src/runtime/layout/public-facet.ts +152 -0
  41. package/src/runtime/prerender/graph-canonicalize.ts +44 -0
  42. package/src/runtime/surface-projection.ts +43 -3
  43. package/src/runtime/workflow/coordinator.ts +57 -11
  44. package/src/ui/ui-controller-factory.ts +11 -0
  45. package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +3 -0
@@ -24,7 +24,10 @@
24
24
  */
25
25
 
26
26
  import type { EditorStoryTarget } from "../../api/public-types";
27
- import type { PublicPageRegion } from "../layout/public-facet.ts";
27
+ import type {
28
+ PublicMeasurementFidelity,
29
+ PublicPageRegion,
30
+ } from "../layout/public-facet.ts";
28
31
 
29
32
  // ---------------------------------------------------------------------------
30
33
  // G5 · Coordinate space tags
@@ -75,6 +78,11 @@ export type GeometrySpace = "twips" | "frame" | "overlay";
75
78
  */
76
79
  export type GeometryPrecision = "exact" | "within-tolerance" | "heuristic";
77
80
 
81
+ export type GeometryRehydrationStatus =
82
+ | "realized"
83
+ | "requires-rehydration"
84
+ | "unavailable";
85
+
78
86
  // ---------------------------------------------------------------------------
79
87
  // Core rect shape
80
88
  // ---------------------------------------------------------------------------
@@ -98,6 +106,206 @@ export interface GeometryRect {
98
106
  precision?: GeometryPrecision;
99
107
  }
100
108
 
109
+ // ---------------------------------------------------------------------------
110
+ // PE2 geometry index (Slice 1 · page-slice projection substrate)
111
+ // ---------------------------------------------------------------------------
112
+
113
+ export interface GeometryPrecisionCounts {
114
+ exact: number;
115
+ "within-tolerance": number;
116
+ heuristic: number;
117
+ }
118
+
119
+ export interface GeometryIndexCoverage {
120
+ status: GeometryRehydrationStatus;
121
+ pageCount: number;
122
+ regionCount: number;
123
+ sliceCount: number;
124
+ lineCount: number;
125
+ anchorCount: number;
126
+ hitTargetCount: number;
127
+ semanticEntryCount: number;
128
+ replacementEnvelopeCount: number;
129
+ objectHandleCount: number;
130
+ precision: GeometryPrecisionCounts;
131
+ }
132
+
133
+ export type GeometrySourceIdentityJoinKind = "direct" | "block-scoped";
134
+
135
+ /**
136
+ * Stable canonical identity joined onto projected geometry when the current
137
+ * substrate can prove the correspondence without consulting renderer state.
138
+ *
139
+ * `joinKind: "direct"` means the geometry node maps to the named canonical
140
+ * table/row/cell. `joinKind: "block-scoped"` means the geometry rect still
141
+ * belongs to the enclosing rendered block/line; object fields identify the
142
+ * canonical object carried by that block, not a true object bbox.
143
+ */
144
+ export interface GeometrySourceIdentity {
145
+ storyKey: string;
146
+ blockPath?: string;
147
+ tableKey?: string;
148
+ rowKey?: string;
149
+ cellKey?: string;
150
+ scopeKey?: string;
151
+ scopeId?: string;
152
+ objectKey?: string;
153
+ inlinePath?: string;
154
+ objectKind?: string;
155
+ editPosture?: string;
156
+ joinKind: GeometrySourceIdentityJoinKind;
157
+ }
158
+
159
+ export interface GeometryIndex {
160
+ /**
161
+ * Source adapter for this index. PE2's target input is L04 page slices; the
162
+ * current substrate projects the render frame because it is the runtime's
163
+ * already materialized page-slice view.
164
+ */
165
+ source: "render-frame-adapter";
166
+ revision: number;
167
+ measurementFidelity: PublicMeasurementFidelity;
168
+ activeStory: EditorStoryTarget;
169
+ pages: readonly GeometryIndexPage[];
170
+ regions: readonly GeometryIndexRegion[];
171
+ slices: readonly GeometryIndexSlice[];
172
+ lines: readonly GeometryIndexLine[];
173
+ anchors: readonly AnchorGeometry[];
174
+ hitTargets: readonly GeometryHitTarget[];
175
+ semanticEntries: readonly SemanticDisplayEntry[];
176
+ replacementEnvelopes: readonly GeometryReplacementEnvelopeEntry[];
177
+ objectHandles: readonly GeometryObjectHandleEntry[];
178
+ coverage: GeometryIndexCoverage;
179
+ }
180
+
181
+ export interface GeometryIndexPage {
182
+ pageId: string;
183
+ pageIndex: number;
184
+ rect: GeometryRect;
185
+ regionIds: readonly string[];
186
+ }
187
+
188
+ export interface GeometryIndexRegion {
189
+ regionId: string;
190
+ pageId: string;
191
+ pageIndex: number;
192
+ kind: PublicPageRegion["kind"];
193
+ ordinal: number;
194
+ rect: GeometryRect;
195
+ sliceIds: readonly string[];
196
+ }
197
+
198
+ export interface GeometryIndexSlice {
199
+ sliceId: string;
200
+ pageId: string;
201
+ pageIndex: number;
202
+ regionId: string;
203
+ regionKind: PublicPageRegion["kind"];
204
+ blockId: string;
205
+ fragmentId: string;
206
+ kind: "paragraph" | "table" | "opaque" | "image-float" | "synthetic";
207
+ rect: GeometryRect;
208
+ lineIds: readonly string[];
209
+ sourceIdentity?: GeometrySourceIdentity;
210
+ }
211
+
212
+ export interface GeometryIndexLine {
213
+ lineId: string;
214
+ pageId: string;
215
+ pageIndex: number;
216
+ regionId: string;
217
+ regionKind: PublicPageRegion["kind"];
218
+ blockId: string;
219
+ fragmentId: string;
220
+ lineIndex: number;
221
+ rect: GeometryRect;
222
+ /** Baseline offset from the line rect's top, in frame pixels. */
223
+ baseline?: number;
224
+ baselinePrecision?: GeometryPrecision;
225
+ anchorIds: readonly string[];
226
+ }
227
+
228
+ export interface AnchorGeometry {
229
+ anchorId: string;
230
+ pageId: string;
231
+ pageIndex: number;
232
+ regionId: string;
233
+ regionKind: PublicPageRegion["kind"];
234
+ blockId?: string;
235
+ fragmentId?: string;
236
+ lineId?: string;
237
+ runtimeOffset?: number;
238
+ rect: GeometryRect;
239
+ precision: GeometryPrecision;
240
+ sourceIdentity?: GeometrySourceIdentity;
241
+ }
242
+
243
+ export interface GeometryHitTarget {
244
+ targetId: string;
245
+ pageId: string;
246
+ pageIndex: number;
247
+ regionId: string;
248
+ regionKind: PublicPageRegion["kind"];
249
+ blockId: string;
250
+ fragmentId: string;
251
+ lineIndex: number;
252
+ rect: GeometryRect;
253
+ precision: GeometryPrecision;
254
+ }
255
+
256
+ export type SemanticDisplayEntryKind =
257
+ | "text-line"
258
+ | "numbering-marker"
259
+ | "table-frame"
260
+ | "table-row"
261
+ | "table-cell"
262
+ | "toc-leader"
263
+ | "toc-page-label"
264
+ | "field-result"
265
+ | "inline-object"
266
+ | "floating-object"
267
+ | "placeholder"
268
+ | "background"
269
+ | "border"
270
+ | "debug-classification";
271
+
272
+ export interface SemanticDisplayEntry {
273
+ entryId: string;
274
+ kind: SemanticDisplayEntryKind;
275
+ pageId: string;
276
+ pageIndex: number;
277
+ regionId?: string;
278
+ regionKind?: PublicPageRegion["kind"];
279
+ sliceId?: string;
280
+ lineId?: string;
281
+ blockId?: string;
282
+ fragmentId?: string;
283
+ rowIndex?: number;
284
+ columnIndex?: number;
285
+ rect: GeometryRect;
286
+ status: GeometryRehydrationStatus;
287
+ precision: GeometryPrecision;
288
+ sourceIdentity?: GeometrySourceIdentity;
289
+ }
290
+
291
+ export interface GeometryReplacementEnvelopeEntry {
292
+ scopeId: string;
293
+ pageIds?: readonly string[];
294
+ rects: readonly GeometryRect[];
295
+ status: GeometryRehydrationStatus;
296
+ precision: GeometryPrecision;
297
+ sourceIdentity?: GeometrySourceIdentity;
298
+ }
299
+
300
+ export interface GeometryObjectHandleEntry {
301
+ objectId: string;
302
+ pageIds?: readonly string[];
303
+ rects: readonly GeometryRect[];
304
+ status: GeometryRehydrationStatus;
305
+ precision: GeometryPrecision;
306
+ sourceIdentity?: GeometrySourceIdentity;
307
+ }
308
+
101
309
  // ---------------------------------------------------------------------------
102
310
  // Per-granularity geometry nodes (read models; Slice 2+ populates them)
103
311
  // ---------------------------------------------------------------------------
@@ -200,6 +408,14 @@ export interface AnchorQuery {
200
408
 
201
409
  export type EnvelopeConfidence = "exact" | "medium" | "detached";
202
410
 
411
+ export interface EnvelopeContinuationState {
412
+ pageIds: readonly string[];
413
+ pageCount: number;
414
+ crossesPageBoundary: boolean;
415
+ continuedFromPreviousPage: boolean;
416
+ continuesToNextPage: boolean;
417
+ }
418
+
203
419
  export interface EnvelopeBundle {
204
420
  /**
205
421
  * Rect coverage for the resolved scope. Slice-5 substrate produces
@@ -211,6 +427,10 @@ export interface EnvelopeBundle {
211
427
  * walk if the count is lower than expected.
212
428
  */
213
429
  scopeRects: readonly GeometryRect[];
430
+ /** Page ids whose projected page frames intersect `scopeRects`. */
431
+ pageIds: readonly string[];
432
+ /** Continuation metadata for multi-page / partial-page replacement scopes. */
433
+ continuation: EnvelopeContinuationState;
214
434
  /** Anchor point consumers attach chrome to (top-left of first rect). */
215
435
  attachPoint: { xPx: number; yPx: number; space: GeometrySpace };
216
436
  /**
@@ -227,6 +447,12 @@ export interface EnvelopeBundle {
227
447
  * layer-05 closure.
228
448
  */
229
449
  linesCrossed: number;
450
+ /**
451
+ * Realized for live range scopes. Detached scopes are projected from a
452
+ * last-known range and are marked `requires-rehydration` so callers do not
453
+ * mistake the geometry for current document truth.
454
+ */
455
+ rehydrationStatus: GeometryRehydrationStatus;
230
456
  /**
231
457
  * Precision tag. `"exact"` when the envelope collapsed to a caret rect
232
458
  * (single anchor position); `"within-tolerance"` when the envelope is
@@ -13,7 +13,24 @@
13
13
 
14
14
  export type {
15
15
  GeometrySpace,
16
+ GeometryPrecision,
16
17
  GeometryRect,
18
+ GeometryRehydrationStatus,
19
+ GeometryPrecisionCounts,
20
+ GeometrySourceIdentityJoinKind,
21
+ GeometrySourceIdentity,
22
+ GeometryIndexCoverage,
23
+ GeometryIndex,
24
+ GeometryIndexPage,
25
+ GeometryIndexRegion,
26
+ GeometryIndexSlice,
27
+ GeometryIndexLine,
28
+ AnchorGeometry,
29
+ GeometryHitTarget,
30
+ SemanticDisplayEntryKind,
31
+ SemanticDisplayEntry,
32
+ GeometryReplacementEnvelopeEntry,
33
+ GeometryObjectHandleEntry,
17
34
  PageGeometry,
18
35
  BlockGeometry,
19
36
  LineGeometry,
@@ -24,11 +41,20 @@ export type {
24
41
  AnchorQueryKind,
25
42
  AnchorQuery,
26
43
  EnvelopeConfidence,
44
+ EnvelopeContinuationState,
27
45
  EnvelopeBundle,
28
46
  Viewport,
29
47
  ViewportListener,
30
48
  } from "./geometry-types.ts";
31
49
 
50
+ export {
51
+ createUnavailableGeometryCoverage,
52
+ projectGeometryIndexFromFrame,
53
+ summarizeGeometryCoverageFromFrame,
54
+ } from "./geometry-index.ts";
55
+
56
+ export type { GeometryIndexProjectionOptions } from "./geometry-index.ts";
57
+
32
58
  export type {
33
59
  GeometryFacet,
34
60
  CreateGeometryFacetInput,
@@ -10,6 +10,7 @@
10
10
 
11
11
  import type { GeometryFacet } from "./geometry-facet.ts";
12
12
  import type { Viewport } from "./geometry-types.ts";
13
+ import { createUnavailableGeometryCoverage } from "./geometry-index.ts";
13
14
 
14
15
  const INERT_VIEWPORT: Viewport = Object.freeze({
15
16
  scrollLeftPx: 0,
@@ -20,6 +21,8 @@ const INERT_VIEWPORT: Viewport = Object.freeze({
20
21
 
21
22
  export function createInertGeometryFacet(): GeometryFacet {
22
23
  return {
24
+ getGeometryIndex: () => null,
25
+ getGeometryCoverage: () => createUnavailableGeometryCoverage(),
23
26
  hitTest: () => null,
24
27
  getAnchorRects: () => [],
25
28
  getAnchor: () => null,
@@ -27,7 +27,7 @@
27
27
  */
28
28
 
29
29
  import type { RenderFrame, RenderFrameRect } from "../render/index.ts";
30
- import type { GeometryRect } from "./geometry-types.ts";
30
+ import type { GeometryPrecision, GeometryRect } from "./geometry-types.ts";
31
31
 
32
32
  const ROTATE_HANDLE_OFFSET_PX = 20;
33
33
 
@@ -38,10 +38,13 @@ export function resolveObjectHandles(
38
38
  if (!frame) return [];
39
39
  const bbox = frame.anchorIndex.byObjectId(objectId);
40
40
  if (!bbox) return [];
41
- return buildHandles(bbox);
41
+ return buildObjectHandleRectsFromRect(bbox);
42
42
  }
43
43
 
44
- function buildHandles(bbox: RenderFrameRect): readonly GeometryRect[] {
44
+ export function buildObjectHandleRectsFromRect(
45
+ bbox: RenderFrameRect,
46
+ precision: GeometryPrecision = "heuristic",
47
+ ): readonly GeometryRect[] {
45
48
  const { leftPx, topPx, widthPx, heightPx } = bbox;
46
49
  const right = leftPx + widthPx;
47
50
  const bottom = topPx + heightPx;
@@ -61,7 +64,7 @@ function buildHandles(bbox: RenderFrameRect): readonly GeometryRect[] {
61
64
  widthPx: 0,
62
65
  heightPx: 0,
63
66
  space: "frame",
64
- precision: "heuristic",
67
+ precision,
65
68
  });
66
69
  return [
67
70
  point(leftPx, topPx), // 0 top-left
@@ -75,7 +75,7 @@ export function resolveReplacementEnvelope(
75
75
  if (!Number.isFinite(from) || !Number.isFinite(to)) return null;
76
76
  const rects = resolveSelectionRects(frame, { from, to, story });
77
77
  if (rects.length === 0) return null;
78
- return buildBundle(rects, "exact");
78
+ return buildBundle(frame, rects, "exact");
79
79
  }
80
80
 
81
81
  // Detached: project the last-known range and tag confidence as such.
@@ -83,10 +83,11 @@ export function resolveReplacementEnvelope(
83
83
  if (!Number.isFinite(from) || !Number.isFinite(to)) return null;
84
84
  const rects = resolveSelectionRects(frame, { from, to, story });
85
85
  if (rects.length === 0) return null;
86
- return buildBundle(rects, "detached");
86
+ return buildBundle(frame, rects, "detached");
87
87
  }
88
88
 
89
89
  function buildBundle(
90
+ frame: RenderFrame,
90
91
  rects: readonly GeometryRect[],
91
92
  confidence: EnvelopeBundle["confidence"],
92
93
  ): EnvelopeBundle {
@@ -104,8 +105,17 @@ function buildBundle(
104
105
  const rectPrecision = coarsestRectPrecision(rects);
105
106
  const envelopePrecision: EnvelopeBundle["precision"] =
106
107
  confidence === "detached" ? "heuristic" : rectPrecision;
108
+ const pageIds = resolveIntersectingPageIds(frame, rects);
107
109
  return {
108
110
  scopeRects: rects,
111
+ pageIds,
112
+ continuation: {
113
+ pageIds,
114
+ pageCount: pageIds.length,
115
+ crossesPageBoundary: pageIds.length > 1,
116
+ continuedFromPreviousPage: false,
117
+ continuesToNextPage: false,
118
+ },
109
119
  attachPoint: {
110
120
  xPx: first.leftPx,
111
121
  yPx: first.topPx,
@@ -113,10 +123,39 @@ function buildBundle(
113
123
  },
114
124
  confidence,
115
125
  linesCrossed: rects.length,
126
+ rehydrationStatus:
127
+ confidence === "detached" ? "requires-rehydration" : "realized",
116
128
  precision: envelopePrecision,
117
129
  };
118
130
  }
119
131
 
132
+ function resolveIntersectingPageIds(
133
+ frame: RenderFrame,
134
+ rects: readonly GeometryRect[],
135
+ ): readonly string[] {
136
+ if (!Array.isArray(frame.pages)) return [];
137
+ const ids: string[] = [];
138
+ for (const page of frame.pages) {
139
+ if (rects.some((rect) => intersects(rect, page.frame))) {
140
+ ids.push(page.page.pageId);
141
+ }
142
+ }
143
+ return ids;
144
+ }
145
+
146
+ function intersects(rect: GeometryRect, page: { leftPx: number; topPx: number; widthPx: number; heightPx: number }): boolean {
147
+ const rectRight = rect.leftPx + rect.widthPx;
148
+ const rectBottom = rect.topPx + rect.heightPx;
149
+ const pageRight = page.leftPx + page.widthPx;
150
+ const pageBottom = page.topPx + page.heightPx;
151
+ return (
152
+ rect.leftPx <= pageRight &&
153
+ rectRight >= page.leftPx &&
154
+ rect.topPx <= pageBottom &&
155
+ rectBottom >= page.topPx
156
+ );
157
+ }
158
+
120
159
  function coarsestRectPrecision(
121
160
  rects: readonly GeometryRect[],
122
161
  ): "exact" | "within-tolerance" | "heuristic" {
@@ -490,6 +490,7 @@ export function createLayoutEngine(
490
490
  fragmentsByPageIndex,
491
491
  lineBoxesByPageIndex,
492
492
  noteAllocationsByPageIndex: pageStack.noteAllocationsByPageIndex,
493
+ subParts: document.subParts,
493
494
  });
494
495
 
495
496
  // Field dirtiness diff from previous graph
@@ -669,6 +670,7 @@ export function createLayoutEngine(
669
670
  fragmentsByPageIndex: freshFragmentsByPageIndex,
670
671
  lineBoxesByPageIndex: freshLineBoxesByPageIndex,
671
672
  noteAllocationsByPageIndex: freshResult.noteAllocationsByPageIndex,
673
+ subParts: document.subParts,
672
674
  });
673
675
  const freshNodes = freshGraph.pages;
674
676
 
@@ -1031,8 +1031,51 @@
1031
1031
  * content instead of checking only top-level paragraphs. This honors
1032
1032
  * `<w:br w:type="page"/>` inside cover-page SDTs such as the CCEP SOW
1033
1033
  * template, changing page assignment from the v61 cache shape.
1034
+ *
1035
+ * 63 — PE2 geometry-projection substrate (Layer 05). Adds the new
1036
+ * geometry-index module (`src/runtime/geometry/geometry-index.ts`,
1037
+ * `geometry-facet.ts`, `caret-geometry.ts`, `replacement-envelope.ts`,
1038
+ * `inert-geometry-facet.ts`, `geometry-types.ts`, `index.ts`) and
1039
+ * advances the geometry projections that downstream caches consume.
1040
+ * Persisted layout caches keyed on the v62 geometry shape must
1041
+ * re-derive. Shipped via pe2 commits `957069161` + `1f36767d7`.
1042
+ *
1043
+ * 64 — PE2 Slice 2 page-frame graph substrate (Layer 04). `RuntimePageNode`
1044
+ * built by L04 now carries a twips-only `RuntimePageFrame` payload, explicit
1045
+ * `rectTwips` on resolved page regions, and typed layout divergence lists.
1046
+ * Existing `regions` remain the compatibility surface, but cache envelopes
1047
+ * from v63 invalidate because the page graph payload shape changed.
1048
+ * Shipped via pe2 commit `24a316af2`.
1049
+ *
1050
+ * 65 — PE2 Slice 2 page-local story instances (Layer 04). `RuntimePageFrame`
1051
+ * now carries stable header/footer `pageLocalStories` records with story
1052
+ * keys, variants, relationship ids, measured frame heights, and empty
1053
+ * field/object ledgers for later Slice 2/4 population. Cache envelopes
1054
+ * from v64 invalidate because the page-frame payload shape changed again.
1055
+ * Shipped via pe2 commit `06fe6f692`.
1056
+ *
1057
+ * 66 — PE2 Slice 2 page-local field ledgers (Layer 04). Page graph
1058
+ * construction now walks canonical header/footer subparts for each
1059
+ * page-local story instance and records resolved PAGE / NUMPAGES /
1060
+ * SECTIONPAGES display text in the story's `resolvedFields` ledger.
1061
+ * Cache envelopes from v65 invalidate because page-frame story payloads
1062
+ * now carry field-resolution data. Shipped via pe2 commit `a3a42bec9`.
1063
+ *
1064
+ * 67 — PE2 Slice 2 page-local object ledgers (Layer 04). Header/footer
1065
+ * page-local story instances now record canonical image/drawing/preserve-only
1066
+ * objects as twips/plain anchored-object ledger rows and emit typed
1067
+ * unsupported-wrap / preserve-only-placeholder divergences. Cache envelopes
1068
+ * from v66 invalidate because page-frame story payloads and divergence ids
1069
+ * can change. Shipped via pe2 commit `7d8bb94ac`.
1070
+ *
1071
+ * 68 — PE2 Slice 3 typed continuation cursors (Layer 04). Paragraph and
1072
+ * table slice fragments now carry a twips/plain continuation cursor with
1073
+ * sequence position, line/row range, continuation direction, repeated
1074
+ * table header rows, and vertical-merge carry metadata. Cache envelopes
1075
+ * from v67 invalidate because fragment payloads can now include
1076
+ * continuation state. Shipped via pe2 commit `33fbf45ac`.
1034
1077
  */
1035
- export const LAYOUT_ENGINE_VERSION = 62 as const;
1078
+ export const LAYOUT_ENGINE_VERSION = 68 as const;
1036
1079
 
1037
1080
  /**
1038
1081
  * Serialization schema version for the LayCache payload (the cache envelope