@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.
- package/package.json +19 -5
- package/src/api/geometry-overlay-rects.ts +5 -0
- package/src/api/package-version.ts +1 -1
- package/src/api/page-anchor-id.ts +5 -0
- package/src/api/public-types.ts +16 -9
- package/src/api/table-node-specs.ts +6 -0
- package/src/api/v3/_create.ts +10 -2
- package/src/api/v3/_page-anchor-id.ts +52 -0
- package/src/api/v3/_runtime-handle.ts +92 -1
- package/src/api/v3/ai/_audit-reference.ts +28 -0
- package/src/api/v3/ai/_audit-time.ts +5 -0
- package/src/api/v3/ai/_pe2-evidence.ts +310 -6
- package/src/api/v3/ai/attach.ts +29 -4
- package/src/api/v3/ai/bundle.ts +6 -2
- package/src/api/v3/ai/inspect.ts +6 -2
- package/src/api/v3/ai/replacement.ts +112 -18
- package/src/api/v3/ai/resolve.ts +2 -2
- package/src/api/v3/ai/review.ts +177 -3
- package/src/api/v3/index.ts +8 -0
- package/src/api/v3/runtime/collab.ts +462 -0
- package/src/api/v3/runtime/document.ts +503 -20
- package/src/api/v3/runtime/geometry.ts +97 -0
- package/src/api/v3/runtime/layout.ts +744 -0
- package/src/api/v3/runtime/perf-probe.ts +14 -0
- package/src/api/v3/runtime/viewport.ts +9 -8
- package/src/api/v3/ui/_types.ts +202 -55
- package/src/api/v3/ui/chrome-preset-model.ts +5 -5
- package/src/api/v3/ui/debug.ts +115 -2
- package/src/api/v3/ui/index.ts +17 -0
- package/src/api/v3/ui/overlays.ts +0 -8
- package/src/api/v3/ui/surface.ts +56 -0
- package/src/api/v3/ui/viewport.ts +119 -9
- package/src/core/commands/image-commands.ts +1 -0
- package/src/core/commands/index.ts +6 -0
- package/src/core/schema/text-schema.ts +43 -5
- package/src/core/selection/mapping.ts +8 -1
- package/src/core/selection/review-anchors.ts +5 -1
- package/src/core/state/text-transaction.ts +8 -2
- package/src/io/export/serialize-revisions.ts +149 -1
- package/src/io/normalize/normalize-text.ts +6 -0
- package/src/io/ooxml/parse-bookmark-references.ts +55 -0
- package/src/io/ooxml/parse-fields.ts +24 -2
- package/src/io/ooxml/parse-headers-footers.ts +38 -5
- package/src/io/ooxml/parse-main-document.ts +153 -9
- package/src/io/ooxml/parse-numbering.ts +20 -0
- package/src/io/ooxml/parse-revisions.ts +19 -8
- package/src/io/opc/package-reader.ts +98 -8
- package/src/model/anchor.ts +4 -3
- package/src/model/canonical-document.ts +220 -2
- package/src/model/canonical-hash.ts +221 -0
- package/src/model/canonical-layout-inputs.ts +245 -6
- package/src/model/layout/index.ts +1 -0
- package/src/model/layout/page-graph-types.ts +147 -1
- package/src/model/review/revision-types.ts +14 -3
- package/src/preservation/store.ts +20 -4
- package/src/review/README.md +1 -1
- package/src/review/store/revision-actions.ts +14 -2
- package/src/runtime/collab/event-types.ts +67 -1
- package/src/runtime/collab/runtime-collab-sync.ts +177 -5
- package/src/runtime/diagnostics/layout-guard-warning.ts +18 -0
- package/src/runtime/document-heading-outline.ts +147 -0
- package/src/runtime/document-navigation.ts +8 -243
- package/src/runtime/document-runtime.ts +279 -115
- package/src/runtime/edit-dispatch/dispatch-text-command.ts +11 -0
- package/src/runtime/formatting/layout-inputs.ts +38 -5
- package/src/runtime/formatting/numbering/geometry.ts +28 -2
- package/src/runtime/geometry/adjacent-geometry-intake.ts +835 -0
- package/src/runtime/geometry/caret-geometry.ts +5 -6
- package/src/runtime/geometry/geometry-facet.ts +60 -10
- package/src/runtime/geometry/geometry-index.ts +661 -16
- package/src/runtime/geometry/geometry-types.ts +59 -0
- package/src/runtime/geometry/hit-test.ts +11 -1
- package/src/runtime/geometry/overlay-rects.ts +5 -3
- package/src/runtime/geometry/project-anchors.ts +1 -1
- package/src/runtime/geometry/word-layout-v2-line-intake.ts +323 -0
- package/src/runtime/layout/index.ts +6 -0
- package/src/runtime/layout/layout-engine-instance.ts +6 -1
- package/src/runtime/layout/layout-engine-version.ts +188 -16
- package/src/runtime/layout/layout-facet-types.ts +6 -0
- package/src/runtime/layout/page-graph.ts +23 -4
- package/src/runtime/layout/paginated-layout-engine.ts +149 -15
- package/src/runtime/layout/project-block-fragments.ts +351 -14
- package/src/runtime/layout/public-facet.ts +162 -24
- package/src/runtime/layout/table-row-continuation-contract.ts +107 -0
- package/src/runtime/layout/table-row-split.ts +92 -35
- package/src/runtime/prerender/cache-envelope.ts +2 -2
- package/src/runtime/prerender/cache-key.ts +5 -4
- package/src/runtime/prerender/customxml-cache.ts +0 -1
- package/src/runtime/render/render-kernel.ts +1 -1
- package/src/runtime/revision-runtime.ts +112 -10
- package/src/runtime/scopes/_scope-dependencies.ts +1 -0
- package/src/runtime/scopes/action-validation.ts +22 -2
- package/src/runtime/scopes/capabilities.ts +316 -0
- package/src/runtime/scopes/compile-scope-bundle.ts +14 -0
- package/src/runtime/scopes/compiler-service.ts +108 -4
- package/src/runtime/scopes/content-control-evidence.ts +79 -0
- package/src/runtime/scopes/create-issue.ts +5 -5
- package/src/runtime/scopes/evidence.ts +91 -0
- package/src/runtime/scopes/formatting/apply.ts +2 -0
- package/src/runtime/scopes/geometry-evidence.ts +130 -0
- package/src/runtime/scopes/index.ts +54 -0
- package/src/runtime/scopes/issue-lifecycle.ts +224 -0
- package/src/runtime/scopes/layout-evidence.ts +374 -0
- package/src/runtime/scopes/multi-paragraph-refusal.ts +37 -0
- package/src/runtime/scopes/preservation-boundary.ts +7 -1
- package/src/runtime/scopes/replacement/apply.ts +97 -34
- package/src/runtime/scopes/scope-kinds/paragraph.ts +108 -12
- package/src/runtime/scopes/semantic-scope-types.ts +242 -3
- package/src/runtime/scopes/visualization.ts +28 -0
- package/src/runtime/surface-projection.ts +44 -5
- package/src/runtime/telemetry/perf-probe.ts +216 -0
- package/src/runtime/virtualized-rendering.ts +36 -1
- package/src/runtime/workflow/ai-issue-lifecycle.ts +253 -0
- package/src/runtime/workflow/coordinator.ts +39 -11
- package/src/runtime/workflow/derived-scope-resolver.ts +63 -9
- package/src/runtime/workflow/index.ts +4 -0
- package/src/runtime/workflow/overlay-lane-types.ts +58 -0
- package/src/runtime/workflow/overlay-lanes.ts +386 -0
- package/src/runtime/workflow/overlay-store.ts +2 -2
- package/src/runtime/workflow/redline-posture-calibration.ts +257 -0
- package/src/runtime/workflow/word-field-matrix-calibration.ts +231 -0
- package/src/session/_sync-legacy.ts +17 -27
- package/src/session/import/loader.ts +6 -4
- package/src/session/import/source-package-evidence.ts +186 -2
- package/src/session/index.ts +5 -6
- package/src/session/session.ts +30 -56
- package/src/session/types.ts +8 -13
- package/src/shell/session-bootstrap.ts +155 -81
- package/src/ui/WordReviewEditor.tsx +520 -12
- package/src/ui/editor-shell-view.tsx +14 -4
- package/src/ui/editor-surface-controller.tsx +5 -3
- package/src/ui/headless/selection-tool-resolver.ts +1 -2
- package/src/ui/presence-overlay-lane.ts +130 -0
- package/src/ui/ui-controller-factory.ts +17 -0
- package/src/ui-tailwind/chrome/build-context-menu-entries.ts +5 -1
- package/src/ui-tailwind/chrome/editor-action-registry.ts +105 -5
- package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +7 -0
- package/src/ui-tailwind/chrome/layer-debug-contracts.ts +208 -0
- package/src/ui-tailwind/chrome/resolve-target-kind.ts +13 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +11 -3
- package/src/ui-tailwind/chrome/tw-command-palette.tsx +36 -6
- package/src/ui-tailwind/chrome/tw-context-menu.tsx +6 -1
- package/src/ui-tailwind/chrome/tw-display-mode-selector.tsx +42 -109
- package/src/ui-tailwind/chrome/tw-inline-find-bar.tsx +26 -6
- package/src/ui-tailwind/chrome/tw-navigation-command-bar.tsx +328 -0
- package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +8 -4
- package/src/ui-tailwind/chrome/tw-runtime-repl-dialog.tsx +129 -1
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +19 -5
- package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +5 -1
- package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +28 -12
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +30 -3
- package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +116 -10
- package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +223 -94
- package/src/ui-tailwind/chrome-overlay/tw-presence-overlay-lane.tsx +157 -0
- package/src/ui-tailwind/chrome-overlay/tw-review-overlay-lane-markers.tsx +259 -0
- package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +5 -2
- package/src/ui-tailwind/chrome-overlay/tw-substrate-overlay-lanes.tsx +314 -0
- package/src/ui-tailwind/debug/README.md +4 -1
- package/src/ui-tailwind/debug/layer11-consumer-readiness.ts +272 -0
- package/src/ui-tailwind/debug/layer11-word-field-matrix-evidence.ts +160 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +14 -215
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +42 -0
- package/src/ui-tailwind/editor-surface/pm-position-map.ts +38 -2
- package/src/ui-tailwind/editor-surface/pm-schema.ts +14 -4
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +34 -5
- package/src/ui-tailwind/editor-surface/runtime-decoration-plugin.ts +9 -19
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +2 -2
- package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +145 -0
- package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +16 -11
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +8 -10
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +3 -0
- package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +4 -2
- package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +60 -20
- package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +16 -11
- package/src/ui-tailwind/review/tw-health-panel.tsx +36 -17
- package/src/ui-tailwind/review/tw-review-rail.tsx +7 -4
- package/src/ui-tailwind/review-workspace/diagnostics-visibility.ts +44 -0
- package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +11 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +16 -1
- package/src/ui-tailwind/review-workspace/types.ts +26 -12
- package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +40 -11
- package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +2 -1
- package/src/ui-tailwind/review-workspace/use-page-markers.ts +15 -26
- package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +35 -18
- package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +41 -32
- package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +2 -1
- package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +2 -1
- package/src/ui-tailwind/status/tw-status-bar.tsx +6 -5
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +52 -80
- package/src/ui-tailwind/toolbar/tw-shell-header.tsx +12 -48
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +9 -4
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +328 -361
- package/src/ui-tailwind/tw-review-workspace.tsx +152 -286
|
@@ -26,8 +26,24 @@ export type {
|
|
|
26
26
|
ReplacementOperationKind,
|
|
27
27
|
ReplacementPreservePolicy,
|
|
28
28
|
ReplacementScope,
|
|
29
|
+
ScopeReplacementOperationKind,
|
|
29
30
|
ScopeActionOperationKind,
|
|
30
31
|
ScopeActionProposal,
|
|
32
|
+
ScopeCapabilities,
|
|
33
|
+
ScopeCapabilityStatus,
|
|
34
|
+
ScopeCapabilityVerdict,
|
|
35
|
+
ScopeContentControlEvidence,
|
|
36
|
+
ScopeContentControlEvidenceEntry,
|
|
37
|
+
ScopeContentControlEvidenceStatus,
|
|
38
|
+
ScopeEvidenceAvailability,
|
|
39
|
+
ScopeGeometryEvidence,
|
|
40
|
+
ScopeGeometryEvidencePrecision,
|
|
41
|
+
ScopeGeometryEvidenceRect,
|
|
42
|
+
ScopeGeometryEvidenceStatus,
|
|
43
|
+
ScopeLayoutContinuationEvidence,
|
|
44
|
+
ScopeLayoutEvidence,
|
|
45
|
+
ScopeVisualizationClass,
|
|
46
|
+
ScopeVisualizationHint,
|
|
31
47
|
RuntimeOperationPlan,
|
|
32
48
|
RuntimeOperationStep,
|
|
33
49
|
RuntimeOperationStepKind,
|
|
@@ -35,6 +51,7 @@ export type {
|
|
|
35
51
|
ScopeFormattingAction,
|
|
36
52
|
ScopeFormattingClearTarget,
|
|
37
53
|
ScopeFormattingScope,
|
|
54
|
+
ScopeActionPosture,
|
|
38
55
|
ScopeBundle,
|
|
39
56
|
ScopeBundleEvidence,
|
|
40
57
|
ScopeBundleNeighborhood,
|
|
@@ -56,6 +73,33 @@ export type {
|
|
|
56
73
|
ValidationIssue,
|
|
57
74
|
ValidationResult,
|
|
58
75
|
} from "./semantic-scope-types.ts";
|
|
76
|
+
export { deriveScopeCapabilities } from "./capabilities.ts";
|
|
77
|
+
export type { ScopeCapabilityContext } from "./capabilities.ts";
|
|
78
|
+
export {
|
|
79
|
+
deriveScopeContentControlEvidence,
|
|
80
|
+
findContentControlsIntersectingRange,
|
|
81
|
+
} from "./content-control-evidence.ts";
|
|
82
|
+
export {
|
|
83
|
+
deriveScopeGeometryEvidence,
|
|
84
|
+
type ScopeGeometryEvidenceProvider,
|
|
85
|
+
} from "./geometry-evidence.ts";
|
|
86
|
+
export {
|
|
87
|
+
deriveScopeLayoutEvidence,
|
|
88
|
+
collectTopLevelTableBlockIdsFromRenderSnapshot,
|
|
89
|
+
createRuntimeTableFrameLayoutEvidenceProvider,
|
|
90
|
+
type RuntimeTableFrameLayoutEvidenceOptions,
|
|
91
|
+
type ScopeLayoutEvidenceEntry,
|
|
92
|
+
type ScopeLayoutEvidenceProvider,
|
|
93
|
+
type ScopeRuntimeLayoutEvidenceSource,
|
|
94
|
+
type ScopeRuntimeLayoutFragment,
|
|
95
|
+
type ScopeRuntimeRenderSnapshotLike,
|
|
96
|
+
} from "./layout-evidence.ts";
|
|
97
|
+
export {
|
|
98
|
+
MULTI_PARAGRAPH_REPLACEMENT_REFUSAL,
|
|
99
|
+
multiParagraphReplacementBlockers,
|
|
100
|
+
} from "./multi-paragraph-refusal.ts";
|
|
101
|
+
export type { MultiParagraphReplacementShape } from "./multi-paragraph-refusal.ts";
|
|
102
|
+
export { deriveScopeVisualization } from "./visualization.ts";
|
|
59
103
|
|
|
60
104
|
export {
|
|
61
105
|
buildParagraphIndexMap,
|
|
@@ -153,6 +197,15 @@ export {
|
|
|
153
197
|
type IssueSeverity,
|
|
154
198
|
type IssueStatus,
|
|
155
199
|
} from "./create-issue.ts";
|
|
200
|
+
export {
|
|
201
|
+
resolveIssueLifecycleTarget,
|
|
202
|
+
transitionScopeIssueLifecycle,
|
|
203
|
+
type IssueLifecycleAction,
|
|
204
|
+
type IssueLifecycleRuntime,
|
|
205
|
+
type IssueLifecycleTarget,
|
|
206
|
+
type TransitionScopeIssueLifecycleInputs,
|
|
207
|
+
type TransitionScopeIssueLifecycleResult,
|
|
208
|
+
} from "./issue-lifecycle.ts";
|
|
156
209
|
export {
|
|
157
210
|
createScopeCompilerService,
|
|
158
211
|
type ApplyFormattingRequest,
|
|
@@ -161,5 +214,6 @@ export {
|
|
|
161
214
|
type CompileScopeByIdResult,
|
|
162
215
|
type CompilerServiceRuntime,
|
|
163
216
|
type CreateIssueRequest,
|
|
217
|
+
type TransitionIssueLifecycleRequest,
|
|
164
218
|
type ScopeCompilerService,
|
|
165
219
|
} from "./compiler-service.ts";
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 08 issue lifecycle binding.
|
|
3
|
+
*
|
|
4
|
+
* Layer 06 owns durable `ai.issue` metadata status transitions. This module
|
|
5
|
+
* adds the scope-compiler binding that future L09 `resolveIssue` /
|
|
6
|
+
* `reopenIssue` APIs need: find the issue's scope, require that scope to still
|
|
7
|
+
* compile, preserve the existing metadata entry id, and emit scope-shaped audit
|
|
8
|
+
* evidence for the lifecycle transition.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { TelemetryBus } from "../debug/telemetry-bus.ts";
|
|
12
|
+
import {
|
|
13
|
+
projectAIIssueLifecycleReadback,
|
|
14
|
+
transitionAIIssueLifecycle,
|
|
15
|
+
type AIIssueLifecycleAction,
|
|
16
|
+
type AIIssueLifecycleAuditEntry,
|
|
17
|
+
type AIIssueStatus,
|
|
18
|
+
} from "../workflow/ai-issue-lifecycle.ts";
|
|
19
|
+
import type {
|
|
20
|
+
WorkflowEventOrigin,
|
|
21
|
+
WorkflowMetadataEntry,
|
|
22
|
+
WorkflowMetadataSnapshot,
|
|
23
|
+
} from "./_scope-dependencies.ts";
|
|
24
|
+
import type { CanonicalDocumentEnvelope } from "../../core/state/editor-state.ts";
|
|
25
|
+
import type {
|
|
26
|
+
ReplacementScope,
|
|
27
|
+
ScopeActionAudit,
|
|
28
|
+
SemanticScope,
|
|
29
|
+
ValidationResult,
|
|
30
|
+
} from "./semantic-scope-types.ts";
|
|
31
|
+
|
|
32
|
+
export type IssueLifecycleAction = AIIssueLifecycleAction;
|
|
33
|
+
|
|
34
|
+
export interface IssueLifecycleRuntime {
|
|
35
|
+
getCanonicalDocument(): CanonicalDocumentEnvelope;
|
|
36
|
+
getWorkflowMetadataSnapshot(): WorkflowMetadataSnapshot;
|
|
37
|
+
setWorkflowMetadataEntries(
|
|
38
|
+
entries: readonly WorkflowMetadataEntry[],
|
|
39
|
+
origin?: WorkflowEventOrigin,
|
|
40
|
+
): void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface IssueLifecycleTarget {
|
|
44
|
+
readonly issueId: string;
|
|
45
|
+
readonly entryId: string;
|
|
46
|
+
readonly scopeId: string;
|
|
47
|
+
readonly status: AIIssueStatus;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface TransitionScopeIssueLifecycleInputs {
|
|
51
|
+
readonly runtime: IssueLifecycleRuntime;
|
|
52
|
+
readonly documentBefore: CanonicalDocumentEnvelope;
|
|
53
|
+
readonly targetScopeSnapshot: SemanticScope;
|
|
54
|
+
readonly issueId: string;
|
|
55
|
+
readonly action: IssueLifecycleAction;
|
|
56
|
+
readonly actorId: string;
|
|
57
|
+
readonly origin: "ui" | "agent" | "host";
|
|
58
|
+
readonly emittedAtUtc: string;
|
|
59
|
+
readonly bus?: TelemetryBus;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type TransitionScopeIssueLifecycleResult =
|
|
63
|
+
| {
|
|
64
|
+
readonly transitioned: true;
|
|
65
|
+
readonly issueId: string;
|
|
66
|
+
readonly entryId: string;
|
|
67
|
+
readonly scopeId: string;
|
|
68
|
+
readonly fromStatus: AIIssueStatus;
|
|
69
|
+
readonly toStatus: AIIssueStatus;
|
|
70
|
+
readonly lifecycleAudit: AIIssueLifecycleAuditEntry;
|
|
71
|
+
readonly targetScopeSnapshot: SemanticScope;
|
|
72
|
+
readonly audit: ScopeActionAudit;
|
|
73
|
+
}
|
|
74
|
+
| {
|
|
75
|
+
readonly transitioned: false;
|
|
76
|
+
readonly issueId: string;
|
|
77
|
+
readonly reason: string;
|
|
78
|
+
readonly blockers: readonly string[];
|
|
79
|
+
readonly scopeId?: string;
|
|
80
|
+
readonly targetScopeSnapshot?: SemanticScope;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
function documentHash(doc: CanonicalDocumentEnvelope): string {
|
|
84
|
+
let textLength = 0;
|
|
85
|
+
for (const block of doc.content.children) {
|
|
86
|
+
if (block.type !== "paragraph") continue;
|
|
87
|
+
for (const child of block.children) {
|
|
88
|
+
if (child.type === "text") textLength += child.text.length;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return `blocks:${doc.content.children.length}|text:${textLength}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function freezeBlocker(reason: string): readonly string[] {
|
|
95
|
+
return Object.freeze([reason]);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function resolveIssueLifecycleTarget(
|
|
99
|
+
snapshot: WorkflowMetadataSnapshot,
|
|
100
|
+
issueIdOrEntryId: string,
|
|
101
|
+
): IssueLifecycleTarget | null {
|
|
102
|
+
const readback = projectAIIssueLifecycleReadback(snapshot.entries).find(
|
|
103
|
+
(issue) =>
|
|
104
|
+
issue.issueId === issueIdOrEntryId || issue.entryId === issueIdOrEntryId,
|
|
105
|
+
);
|
|
106
|
+
if (!readback || !readback.scopeId) return null;
|
|
107
|
+
return {
|
|
108
|
+
issueId: readback.issueId,
|
|
109
|
+
entryId: readback.entryId,
|
|
110
|
+
scopeId: readback.scopeId,
|
|
111
|
+
status: readback.status,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function buildLifecycleAudit(
|
|
116
|
+
inputs: TransitionScopeIssueLifecycleInputs,
|
|
117
|
+
transition: {
|
|
118
|
+
readonly issueId: string;
|
|
119
|
+
readonly entryId: string;
|
|
120
|
+
readonly fromStatus: AIIssueStatus;
|
|
121
|
+
readonly toStatus: AIIssueStatus;
|
|
122
|
+
readonly audit: AIIssueLifecycleAuditEntry;
|
|
123
|
+
},
|
|
124
|
+
): ScopeActionAudit {
|
|
125
|
+
const snapshot = inputs.targetScopeSnapshot;
|
|
126
|
+
const proposed: ReplacementScope = {
|
|
127
|
+
targetHandle: snapshot.handle,
|
|
128
|
+
operation: "annotate",
|
|
129
|
+
proposedContent: {
|
|
130
|
+
kind: "structured",
|
|
131
|
+
structured: {
|
|
132
|
+
metadataKind: "issue-lifecycle",
|
|
133
|
+
issueId: transition.issueId,
|
|
134
|
+
entryId: transition.entryId,
|
|
135
|
+
action: inputs.action,
|
|
136
|
+
fromStatus: transition.fromStatus,
|
|
137
|
+
toStatus: transition.toStatus,
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
proposedAtUtc: inputs.emittedAtUtc,
|
|
141
|
+
};
|
|
142
|
+
const validation: ValidationResult = {
|
|
143
|
+
safe: true,
|
|
144
|
+
posture: "supported",
|
|
145
|
+
blockedReasons: Object.freeze([]),
|
|
146
|
+
warnings: Object.freeze([]),
|
|
147
|
+
};
|
|
148
|
+
return {
|
|
149
|
+
actionId:
|
|
150
|
+
inputs.action === "resolve" ? "ai.resolveIssue" : "ai.reopenIssue",
|
|
151
|
+
actorId: inputs.actorId,
|
|
152
|
+
origin: inputs.origin,
|
|
153
|
+
documentHashBefore: documentHash(inputs.documentBefore),
|
|
154
|
+
documentHashAfter: documentHash(inputs.runtime.getCanonicalDocument()),
|
|
155
|
+
targetScopeSnapshot: snapshot,
|
|
156
|
+
proposed,
|
|
157
|
+
compiledOperations: Object.freeze([
|
|
158
|
+
{
|
|
159
|
+
kind:
|
|
160
|
+
inputs.action === "resolve"
|
|
161
|
+
? "metadata-issue-resolve"
|
|
162
|
+
: "metadata-issue-reopen",
|
|
163
|
+
summary: `${inputs.action} issue ${transition.issueId} on scope ${snapshot.handle.scopeId}`,
|
|
164
|
+
},
|
|
165
|
+
]),
|
|
166
|
+
validation,
|
|
167
|
+
emittedAtUtc: inputs.emittedAtUtc,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function transitionScopeIssueLifecycle(
|
|
172
|
+
inputs: TransitionScopeIssueLifecycleInputs,
|
|
173
|
+
): TransitionScopeIssueLifecycleResult {
|
|
174
|
+
const target = resolveIssueLifecycleTarget(
|
|
175
|
+
inputs.runtime.getWorkflowMetadataSnapshot(),
|
|
176
|
+
inputs.issueId,
|
|
177
|
+
);
|
|
178
|
+
if (!target) {
|
|
179
|
+
const reason = `issue-not-found:${inputs.issueId}`;
|
|
180
|
+
return {
|
|
181
|
+
transitioned: false,
|
|
182
|
+
issueId: inputs.issueId,
|
|
183
|
+
reason,
|
|
184
|
+
blockers: freezeBlocker(reason),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const transition = transitionAIIssueLifecycle(inputs.runtime, {
|
|
189
|
+
issueId: target.issueId,
|
|
190
|
+
action: inputs.action,
|
|
191
|
+
actorId: inputs.actorId,
|
|
192
|
+
at: inputs.emittedAtUtc,
|
|
193
|
+
origin: { source: inputs.origin, at: inputs.emittedAtUtc },
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
if (!transition.transitioned) {
|
|
197
|
+
const reason = `${transition.reason}:${transition.issueId}`;
|
|
198
|
+
return {
|
|
199
|
+
transitioned: false,
|
|
200
|
+
issueId: transition.issueId,
|
|
201
|
+
reason,
|
|
202
|
+
blockers: freezeBlocker(reason),
|
|
203
|
+
scopeId: target.scopeId,
|
|
204
|
+
targetScopeSnapshot: inputs.targetScopeSnapshot,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const audit = buildLifecycleAudit(inputs, transition);
|
|
209
|
+
inputs.bus?.emitLazy("scope", () => ({
|
|
210
|
+
type: "scope.action_audit",
|
|
211
|
+
payload: audit,
|
|
212
|
+
}));
|
|
213
|
+
return {
|
|
214
|
+
transitioned: true,
|
|
215
|
+
issueId: transition.issueId,
|
|
216
|
+
entryId: transition.entryId,
|
|
217
|
+
scopeId: target.scopeId,
|
|
218
|
+
fromStatus: transition.fromStatus,
|
|
219
|
+
toStatus: transition.toStatus,
|
|
220
|
+
lifecycleAudit: transition.audit,
|
|
221
|
+
targetScopeSnapshot: inputs.targetScopeSnapshot,
|
|
222
|
+
audit,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scope layout evidence projection.
|
|
3
|
+
*
|
|
4
|
+
* Layer 08 only consumes layout evidence supplied by lower layers. When the
|
|
5
|
+
* seam is absent or cold, the bundle reports that explicitly instead of
|
|
6
|
+
* deriving page slices or continuation state from canonical content.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
ScopeLayoutContinuationEvidence,
|
|
11
|
+
ScopeLayoutEvidence,
|
|
12
|
+
ScopeTableFrameEvidence,
|
|
13
|
+
ScopeTableFramePageEvidence,
|
|
14
|
+
} from "./semantic-scope-types.ts";
|
|
15
|
+
|
|
16
|
+
export interface ScopeLayoutEvidenceEntry {
|
|
17
|
+
readonly status?: ScopeLayoutEvidence["status"];
|
|
18
|
+
readonly completeness?: ScopeLayoutEvidence["completeness"];
|
|
19
|
+
readonly reason?: string;
|
|
20
|
+
readonly pageSliceIds?: readonly string[];
|
|
21
|
+
readonly layoutObjectIds?: readonly string[];
|
|
22
|
+
readonly continuationState?: ScopeLayoutContinuationEvidence;
|
|
23
|
+
readonly divergenceIds?: readonly string[];
|
|
24
|
+
readonly tableFrame?: ScopeTableFrameEvidence;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ScopeLayoutEvidenceProvider {
|
|
28
|
+
getScopeLayoutEvidence(scopeId: string): ScopeLayoutEvidenceEntry | null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ScopeRuntimeLayoutFragment {
|
|
32
|
+
readonly fragmentId: string;
|
|
33
|
+
readonly blockId: string;
|
|
34
|
+
readonly pageId: string;
|
|
35
|
+
readonly pageIndex: number;
|
|
36
|
+
readonly kind?: "whole" | "paragraph-slice" | "table-slice";
|
|
37
|
+
readonly tableRowRange?: {
|
|
38
|
+
readonly from: number;
|
|
39
|
+
readonly to: number;
|
|
40
|
+
readonly totalRows: number;
|
|
41
|
+
};
|
|
42
|
+
readonly continuation?: {
|
|
43
|
+
readonly kind: string;
|
|
44
|
+
readonly continuesFromPreviousPage?: boolean;
|
|
45
|
+
readonly continuesToNextPage?: boolean;
|
|
46
|
+
readonly repeatedHeaderRowIndexes?: readonly number[];
|
|
47
|
+
readonly splitRowCarry?: readonly {
|
|
48
|
+
readonly rowIndex: number;
|
|
49
|
+
readonly continuesFromPreviousPage: boolean;
|
|
50
|
+
readonly continuesToNextPage: boolean;
|
|
51
|
+
}[];
|
|
52
|
+
readonly verticalMergeCarry?: readonly {
|
|
53
|
+
readonly columnIndex: number;
|
|
54
|
+
readonly restartRowIndex: number;
|
|
55
|
+
}[];
|
|
56
|
+
};
|
|
57
|
+
readonly layoutObject?: {
|
|
58
|
+
readonly objectId?: string;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface ScopeRuntimeLayoutEvidenceSource {
|
|
63
|
+
getPageCount(): number;
|
|
64
|
+
getFragmentsForPage(pageIndex: number): readonly ScopeRuntimeLayoutFragment[];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface RuntimeTableFrameLayoutEvidenceOptions {
|
|
68
|
+
readonly layout: ScopeRuntimeLayoutEvidenceSource;
|
|
69
|
+
readonly tableBlockIdsByBlockIndex?: ReadonlyMap<number, string>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ScopeRuntimeRenderSnapshotLike {
|
|
73
|
+
readonly surface?: {
|
|
74
|
+
readonly blocks?: readonly {
|
|
75
|
+
readonly kind?: string;
|
|
76
|
+
readonly blockId?: string;
|
|
77
|
+
}[];
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function freezeList<T>(values: readonly T[] | undefined): readonly T[] | undefined {
|
|
82
|
+
return values ? Object.freeze([...values]) : undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function unique<T>(values: readonly T[]): readonly T[] {
|
|
86
|
+
return Object.freeze([...new Set(values)]);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function parseTableFamilyScopeId(scopeId: string):
|
|
90
|
+
| { readonly scopeKind: "table"; readonly blockIndex: number }
|
|
91
|
+
| { readonly scopeKind: "table-row"; readonly blockIndex: number; readonly rowIndex: number }
|
|
92
|
+
| {
|
|
93
|
+
readonly scopeKind: "table-cell";
|
|
94
|
+
readonly blockIndex: number;
|
|
95
|
+
readonly rowIndex: number;
|
|
96
|
+
readonly cellIndex: number;
|
|
97
|
+
}
|
|
98
|
+
| null {
|
|
99
|
+
const table = /^table:(\d+)$/.exec(scopeId);
|
|
100
|
+
if (table) return { scopeKind: "table", blockIndex: Number(table[1]) };
|
|
101
|
+
const row = /^row:(\d+):(\d+)$/.exec(scopeId);
|
|
102
|
+
if (row) {
|
|
103
|
+
return {
|
|
104
|
+
scopeKind: "table-row",
|
|
105
|
+
blockIndex: Number(row[1]),
|
|
106
|
+
rowIndex: Number(row[2]),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const cell = /^cell:(\d+):(\d+):(\d+)$/.exec(scopeId);
|
|
110
|
+
if (cell) {
|
|
111
|
+
return {
|
|
112
|
+
scopeKind: "table-cell",
|
|
113
|
+
blockIndex: Number(cell[1]),
|
|
114
|
+
rowIndex: Number(cell[2]),
|
|
115
|
+
cellIndex: Number(cell[3]),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function candidateTableBlockIds(
|
|
122
|
+
blockIndex: number,
|
|
123
|
+
mapped?: ReadonlyMap<number, string>,
|
|
124
|
+
): readonly string[] {
|
|
125
|
+
const ids: string[] = [];
|
|
126
|
+
const mappedId = mapped?.get(blockIndex);
|
|
127
|
+
if (mappedId) ids.push(mappedId);
|
|
128
|
+
ids.push(`table-${blockIndex}`, `table:${blockIndex}`, `block-${blockIndex}`);
|
|
129
|
+
return unique(ids);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function rowInFragment(
|
|
133
|
+
fragment: ScopeRuntimeLayoutFragment,
|
|
134
|
+
rowIndex: number,
|
|
135
|
+
): boolean {
|
|
136
|
+
const range = fragment.tableRowRange;
|
|
137
|
+
if (range && rowIndex >= range.from && rowIndex < range.to) return true;
|
|
138
|
+
return fragment.continuation?.repeatedHeaderRowIndexes?.includes(rowIndex) === true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function fragmentMatchesScope(
|
|
142
|
+
fragment: ScopeRuntimeLayoutFragment,
|
|
143
|
+
parsed: NonNullable<ReturnType<typeof parseTableFamilyScopeId>>,
|
|
144
|
+
): boolean {
|
|
145
|
+
if (parsed.scopeKind === "table") return true;
|
|
146
|
+
return rowInFragment(fragment, parsed.rowIndex);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function collectTableFragments(
|
|
150
|
+
layout: ScopeRuntimeLayoutEvidenceSource,
|
|
151
|
+
blockIds: readonly string[],
|
|
152
|
+
parsed: NonNullable<ReturnType<typeof parseTableFamilyScopeId>>,
|
|
153
|
+
): readonly ScopeRuntimeLayoutFragment[] {
|
|
154
|
+
const matches: ScopeRuntimeLayoutFragment[] = [];
|
|
155
|
+
const blockIdSet = new Set(blockIds);
|
|
156
|
+
for (let pageIndex = 0; pageIndex < layout.getPageCount(); pageIndex += 1) {
|
|
157
|
+
for (const fragment of layout.getFragmentsForPage(pageIndex)) {
|
|
158
|
+
if (!blockIdSet.has(fragment.blockId)) continue;
|
|
159
|
+
if (fragment.kind !== undefined && fragment.kind !== "table-slice" && fragment.kind !== "whole") {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (!fragmentMatchesScope(fragment, parsed)) continue;
|
|
163
|
+
matches.push(fragment);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return Object.freeze(matches);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function projectTableFramePage(
|
|
170
|
+
fragment: ScopeRuntimeLayoutFragment,
|
|
171
|
+
): ScopeTableFramePageEvidence {
|
|
172
|
+
const repeated = fragment.continuation?.repeatedHeaderRowIndexes;
|
|
173
|
+
const splitRowCarry = fragment.continuation?.splitRowCarry;
|
|
174
|
+
const carry = fragment.continuation?.verticalMergeCarry;
|
|
175
|
+
return {
|
|
176
|
+
pageId: fragment.pageId,
|
|
177
|
+
pageIndex: fragment.pageIndex,
|
|
178
|
+
fragmentId: fragment.fragmentId,
|
|
179
|
+
...(fragment.tableRowRange ? { rowRange: { ...fragment.tableRowRange } } : {}),
|
|
180
|
+
...(fragment.continuation?.continuesFromPreviousPage !== undefined
|
|
181
|
+
? { continuesFromPreviousPage: fragment.continuation.continuesFromPreviousPage }
|
|
182
|
+
: {}),
|
|
183
|
+
...(fragment.continuation?.continuesToNextPage !== undefined
|
|
184
|
+
? { continuesToNextPage: fragment.continuation.continuesToNextPage }
|
|
185
|
+
: {}),
|
|
186
|
+
...(repeated ? { repeatedHeaderRowIndexes: unique(repeated) } : {}),
|
|
187
|
+
...(splitRowCarry ? { splitRowCarry: Object.freeze(splitRowCarry.map((item) => ({ ...item }))) } : {}),
|
|
188
|
+
...(carry ? { verticalMergeCarry: Object.freeze(carry.map((item) => ({ ...item }))) } : {}),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function projectTableFrame(
|
|
193
|
+
blockId: string,
|
|
194
|
+
parsed: NonNullable<ReturnType<typeof parseTableFamilyScopeId>>,
|
|
195
|
+
fragments: readonly ScopeRuntimeLayoutFragment[],
|
|
196
|
+
): ScopeTableFrameEvidence {
|
|
197
|
+
const pageIds = unique(fragments.map((fragment) => fragment.pageId));
|
|
198
|
+
const pageSliceIds = unique(fragments.map((fragment) => fragment.fragmentId));
|
|
199
|
+
const layoutObjectIds = unique(
|
|
200
|
+
fragments
|
|
201
|
+
.map((fragment) => fragment.layoutObject?.objectId)
|
|
202
|
+
.filter((objectId): objectId is string => typeof objectId === "string" && objectId.length > 0),
|
|
203
|
+
);
|
|
204
|
+
const rowRangesByPage = Object.freeze(fragments.map(projectTableFramePage));
|
|
205
|
+
const repeatedHeaderRowIndexes = unique(
|
|
206
|
+
fragments.flatMap((fragment) => fragment.continuation?.repeatedHeaderRowIndexes ?? []),
|
|
207
|
+
);
|
|
208
|
+
const verticalMergeCarry = Object.freeze(
|
|
209
|
+
fragments
|
|
210
|
+
.flatMap((fragment) => fragment.continuation?.verticalMergeCarry ?? [])
|
|
211
|
+
.map((item) => ({ ...item })),
|
|
212
|
+
);
|
|
213
|
+
const splitRowCarry = Object.freeze(
|
|
214
|
+
fragments
|
|
215
|
+
.flatMap((fragment) => fragment.continuation?.splitRowCarry ?? [])
|
|
216
|
+
.map((item) => ({ ...item })),
|
|
217
|
+
);
|
|
218
|
+
return {
|
|
219
|
+
source: "runtime.layout.table-frame-continuation",
|
|
220
|
+
blockId,
|
|
221
|
+
scopeKind: parsed.scopeKind,
|
|
222
|
+
...(parsed.scopeKind === "table-row" || parsed.scopeKind === "table-cell"
|
|
223
|
+
? { rowIndex: parsed.rowIndex }
|
|
224
|
+
: {}),
|
|
225
|
+
...(parsed.scopeKind === "table-cell" ? { cellIndex: parsed.cellIndex } : {}),
|
|
226
|
+
...(pageIds.length > 0 ? { pageIds } : {}),
|
|
227
|
+
...(pageSliceIds.length > 0 ? { pageSliceIds } : {}),
|
|
228
|
+
...(layoutObjectIds.length > 0 ? { layoutObjectIds } : {}),
|
|
229
|
+
...(rowRangesByPage.length > 0 ? { rowRangesByPage } : {}),
|
|
230
|
+
...(repeatedHeaderRowIndexes.length > 0 ? { repeatedHeaderRowIndexes } : {}),
|
|
231
|
+
...(splitRowCarry.length > 0 ? { splitRowCarry } : {}),
|
|
232
|
+
...(verticalMergeCarry.length > 0 ? { verticalMergeCarry } : {}),
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function continuationFromTableFrame(
|
|
237
|
+
fragments: readonly ScopeRuntimeLayoutFragment[],
|
|
238
|
+
): ScopeLayoutContinuationEvidence {
|
|
239
|
+
const pageIds = unique(fragments.map((fragment) => fragment.pageId));
|
|
240
|
+
return {
|
|
241
|
+
...(pageIds.length > 0 ? { pageIds } : {}),
|
|
242
|
+
pageCount: pageIds.length,
|
|
243
|
+
crossesPageBoundary: pageIds.length > 1,
|
|
244
|
+
continuedFromPreviousPage: fragments.some(
|
|
245
|
+
(fragment) => fragment.continuation?.continuesFromPreviousPage === true,
|
|
246
|
+
),
|
|
247
|
+
continuesToNextPage: fragments.some(
|
|
248
|
+
(fragment) => fragment.continuation?.continuesToNextPage === true,
|
|
249
|
+
),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export function createRuntimeTableFrameLayoutEvidenceProvider(
|
|
254
|
+
options: RuntimeTableFrameLayoutEvidenceOptions,
|
|
255
|
+
): ScopeLayoutEvidenceProvider {
|
|
256
|
+
return {
|
|
257
|
+
getScopeLayoutEvidence(scopeId) {
|
|
258
|
+
const parsed = parseTableFamilyScopeId(scopeId);
|
|
259
|
+
if (!parsed) return null;
|
|
260
|
+
|
|
261
|
+
const blockIds = candidateTableBlockIds(
|
|
262
|
+
parsed.blockIndex,
|
|
263
|
+
options.tableBlockIdsByBlockIndex,
|
|
264
|
+
);
|
|
265
|
+
const fragments = collectTableFragments(options.layout, blockIds, parsed);
|
|
266
|
+
if (fragments.length === 0) return null;
|
|
267
|
+
|
|
268
|
+
const blockId = fragments[0]?.blockId ?? blockIds[0] ?? `table-${parsed.blockIndex}`;
|
|
269
|
+
const tableFrame = projectTableFrame(blockId, parsed, fragments);
|
|
270
|
+
const pageSliceIds = tableFrame.pageSliceIds;
|
|
271
|
+
const layoutObjectIds = tableFrame.layoutObjectIds;
|
|
272
|
+
const cellScoped = parsed.scopeKind === "table-cell";
|
|
273
|
+
return {
|
|
274
|
+
status: "available",
|
|
275
|
+
completeness: cellScoped ? "partial" : "complete",
|
|
276
|
+
reason: cellScoped
|
|
277
|
+
? "l04-table-frame-row-level-evidence"
|
|
278
|
+
: "l04-table-frame-continuation",
|
|
279
|
+
...(pageSliceIds ? { pageSliceIds } : {}),
|
|
280
|
+
...(layoutObjectIds ? { layoutObjectIds } : {}),
|
|
281
|
+
continuationState: continuationFromTableFrame(fragments),
|
|
282
|
+
tableFrame,
|
|
283
|
+
};
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export function collectTopLevelTableBlockIdsFromRenderSnapshot(
|
|
289
|
+
snapshot: ScopeRuntimeRenderSnapshotLike | null | undefined,
|
|
290
|
+
): ReadonlyMap<number, string> {
|
|
291
|
+
const out = new Map<number, string>();
|
|
292
|
+
const blocks = snapshot?.surface?.blocks ?? [];
|
|
293
|
+
blocks.forEach((block, blockIndex) => {
|
|
294
|
+
if (block.kind === "table" && typeof block.blockId === "string") {
|
|
295
|
+
out.set(blockIndex, block.blockId);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
return out;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function cloneTableFrame(
|
|
302
|
+
tableFrame: ScopeTableFrameEvidence,
|
|
303
|
+
): ScopeTableFrameEvidence {
|
|
304
|
+
return {
|
|
305
|
+
...tableFrame,
|
|
306
|
+
...(tableFrame.pageIds ? { pageIds: freezeList(tableFrame.pageIds) } : {}),
|
|
307
|
+
...(tableFrame.pageSliceIds ? { pageSliceIds: freezeList(tableFrame.pageSliceIds) } : {}),
|
|
308
|
+
...(tableFrame.layoutObjectIds ? { layoutObjectIds: freezeList(tableFrame.layoutObjectIds) } : {}),
|
|
309
|
+
...(tableFrame.rowRangesByPage
|
|
310
|
+
? {
|
|
311
|
+
rowRangesByPage: Object.freeze(
|
|
312
|
+
tableFrame.rowRangesByPage.map((row) => ({
|
|
313
|
+
...row,
|
|
314
|
+
...(row.rowRange ? { rowRange: { ...row.rowRange } } : {}),
|
|
315
|
+
...(row.repeatedHeaderRowIndexes
|
|
316
|
+
? { repeatedHeaderRowIndexes: freezeList(row.repeatedHeaderRowIndexes) }
|
|
317
|
+
: {}),
|
|
318
|
+
...(row.splitRowCarry
|
|
319
|
+
? { splitRowCarry: Object.freeze(row.splitRowCarry.map((item) => ({ ...item }))) }
|
|
320
|
+
: {}),
|
|
321
|
+
...(row.verticalMergeCarry
|
|
322
|
+
? { verticalMergeCarry: Object.freeze(row.verticalMergeCarry.map((item) => ({ ...item }))) }
|
|
323
|
+
: {}),
|
|
324
|
+
})),
|
|
325
|
+
),
|
|
326
|
+
}
|
|
327
|
+
: {}),
|
|
328
|
+
...(tableFrame.repeatedHeaderRowIndexes
|
|
329
|
+
? { repeatedHeaderRowIndexes: freezeList(tableFrame.repeatedHeaderRowIndexes) }
|
|
330
|
+
: {}),
|
|
331
|
+
...(tableFrame.splitRowCarry
|
|
332
|
+
? { splitRowCarry: Object.freeze(tableFrame.splitRowCarry.map((item) => ({ ...item }))) }
|
|
333
|
+
: {}),
|
|
334
|
+
...(tableFrame.verticalMergeCarry
|
|
335
|
+
? { verticalMergeCarry: Object.freeze(tableFrame.verticalMergeCarry.map((item) => ({ ...item }))) }
|
|
336
|
+
: {}),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export function deriveScopeLayoutEvidence(
|
|
341
|
+
scopeId: string,
|
|
342
|
+
provider?: ScopeLayoutEvidenceProvider,
|
|
343
|
+
): ScopeLayoutEvidence {
|
|
344
|
+
if (!provider) {
|
|
345
|
+
return {
|
|
346
|
+
status: "unavailable",
|
|
347
|
+
completeness: "unavailable",
|
|
348
|
+
reason: "layout-evidence-provider-unavailable",
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const entry = provider.getScopeLayoutEvidence(scopeId);
|
|
353
|
+
if (!entry) {
|
|
354
|
+
return {
|
|
355
|
+
status: "requires-rehydration",
|
|
356
|
+
completeness: "requires-rehydration",
|
|
357
|
+
reason: "scope-layout-evidence-unavailable",
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const status = entry.status ?? "available";
|
|
362
|
+
return {
|
|
363
|
+
status,
|
|
364
|
+
completeness: entry.completeness ?? (status === "available" ? "complete" : status),
|
|
365
|
+
...(entry.reason ? { reason: entry.reason } : {}),
|
|
366
|
+
...(entry.pageSliceIds ? { pageSliceIds: freezeList(entry.pageSliceIds) } : {}),
|
|
367
|
+
...(entry.layoutObjectIds ? { layoutObjectIds: freezeList(entry.layoutObjectIds) } : {}),
|
|
368
|
+
...(entry.continuationState
|
|
369
|
+
? { continuationState: { ...entry.continuationState } }
|
|
370
|
+
: {}),
|
|
371
|
+
...(entry.divergenceIds ? { divergenceIds: freezeList(entry.divergenceIds) } : {}),
|
|
372
|
+
...(entry.tableFrame ? { tableFrame: cloneTableFrame(entry.tableFrame) } : {}),
|
|
373
|
+
};
|
|
374
|
+
}
|