@beyondwork/docx-react-component 1.0.106 → 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 +2 -1
- 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-time.ts +5 -0
- package/src/api/v3/ai/_pe2-evidence.ts +38 -0
- package/src/api/v3/ai/attach.ts +7 -2
- package/src/api/v3/ai/replacement.ts +101 -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 +1 -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 +149 -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 +13 -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 +22 -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 +118 -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 +240 -97
- 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 +591 -20
- 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 +181 -16
- package/src/runtime/layout/layout-facet-types.ts +6 -0
- package/src/runtime/layout/page-graph.ts +21 -4
- package/src/runtime/layout/paginated-layout-engine.ts +139 -15
- package/src/runtime/layout/project-block-fragments.ts +265 -7
- package/src/runtime/layout/public-facet.ts +78 -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 +3 -0
- package/src/runtime/workflow/overlay-lane-types.ts +58 -0
- package/src/runtime/workflow/overlay-lanes.ts +168 -10
- 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 +0 -1
- package/src/ui/ui-controller-factory.ts +7 -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
|
@@ -22,11 +22,10 @@
|
|
|
22
22
|
* `attachExplanation` / `createIssue` inputs, this resolver accepts
|
|
23
23
|
* the override via the second argument.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* but no consumer asks for it yet.
|
|
25
|
+
* Table-family scopeIds are also supported for metadata fallback. Their
|
|
26
|
+
* compiler ranges are synthetic subdivisions of the table block, so metadata
|
|
27
|
+
* anchors intentionally bind to the containing table block while preserving
|
|
28
|
+
* the exact `scopeId` on the metadata entry.
|
|
30
29
|
*/
|
|
31
30
|
|
|
32
31
|
import type {
|
|
@@ -42,6 +41,16 @@ import {
|
|
|
42
41
|
detectParagraphKind,
|
|
43
42
|
} from "../../model/paragraph-scope-ids.ts";
|
|
44
43
|
|
|
44
|
+
type TableFamilyScopeRef =
|
|
45
|
+
| { readonly kind: "table"; readonly blockIndex: number }
|
|
46
|
+
| { readonly kind: "row"; readonly blockIndex: number; readonly rowIndex: number }
|
|
47
|
+
| {
|
|
48
|
+
readonly kind: "cell";
|
|
49
|
+
readonly blockIndex: number;
|
|
50
|
+
readonly rowIndex: number;
|
|
51
|
+
readonly cellIndex: number;
|
|
52
|
+
};
|
|
53
|
+
|
|
45
54
|
function inlineLength(node: InlineNode): number {
|
|
46
55
|
switch (node.type) {
|
|
47
56
|
case "text":
|
|
@@ -69,6 +78,38 @@ function paragraphLength(paragraph: ParagraphNode): number {
|
|
|
69
78
|
);
|
|
70
79
|
}
|
|
71
80
|
|
|
81
|
+
function parseTableFamilyScopeId(scopeId: string): TableFamilyScopeRef | null {
|
|
82
|
+
const table = /^table:(\d+)$/.exec(scopeId);
|
|
83
|
+
if (table) return { kind: "table", blockIndex: Number(table[1]) };
|
|
84
|
+
const row = /^row:(\d+):(\d+)$/.exec(scopeId);
|
|
85
|
+
if (row) {
|
|
86
|
+
return {
|
|
87
|
+
kind: "row",
|
|
88
|
+
blockIndex: Number(row[1]),
|
|
89
|
+
rowIndex: Number(row[2]),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const cell = /^cell:(\d+):(\d+):(\d+)$/.exec(scopeId);
|
|
93
|
+
if (cell) {
|
|
94
|
+
return {
|
|
95
|
+
kind: "cell",
|
|
96
|
+
blockIndex: Number(cell[1]),
|
|
97
|
+
rowIndex: Number(cell[2]),
|
|
98
|
+
cellIndex: Number(cell[3]),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function tableRefExists(block: BlockNode, ref: TableFamilyScopeRef): boolean {
|
|
105
|
+
if (block.type !== "table") return false;
|
|
106
|
+
if (ref.kind === "table") return true;
|
|
107
|
+
const row = block.rows[ref.rowIndex];
|
|
108
|
+
if (!row) return false;
|
|
109
|
+
if (ref.kind === "row") return true;
|
|
110
|
+
return row.cells[ref.cellIndex] !== undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
72
113
|
/**
|
|
73
114
|
* Walk the canonical document and resolve a derived paragraph-like
|
|
74
115
|
* scopeId to its range anchor. Returns `null` when no paragraph /
|
|
@@ -79,11 +120,11 @@ export function resolveDerivedScopeAnchorFromCanonical(
|
|
|
79
120
|
scopeId: string,
|
|
80
121
|
assoc: { readonly start: -1 | 1; readonly end: -1 | 1 } = { start: 1, end: -1 },
|
|
81
122
|
): EditorAnchorProjection | null {
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
// match in this pass.
|
|
123
|
+
const tableRef = parseTableFamilyScopeId(scopeId);
|
|
124
|
+
// Fast-reject: derived metadata targets are paragraph-like or table-family
|
|
125
|
+
// scopeIds. Field/review/comment ids need their own source identity.
|
|
86
126
|
if (
|
|
127
|
+
!tableRef &&
|
|
87
128
|
!scopeId.startsWith("para:") &&
|
|
88
129
|
!scopeId.startsWith("heading:") &&
|
|
89
130
|
!scopeId.startsWith("li:")
|
|
@@ -118,6 +159,19 @@ export function resolveDerivedScopeAnchorFromCanonical(
|
|
|
118
159
|
};
|
|
119
160
|
}
|
|
120
161
|
|
|
162
|
+
if (
|
|
163
|
+
tableRef &&
|
|
164
|
+
tableRef.blockIndex === index &&
|
|
165
|
+
tableRefExists(block, tableRef)
|
|
166
|
+
) {
|
|
167
|
+
return {
|
|
168
|
+
kind: "range",
|
|
169
|
+
from: cursor,
|
|
170
|
+
to: cursor + thisBlockLength,
|
|
171
|
+
assoc,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
121
175
|
cursor += thisBlockLength;
|
|
122
176
|
if (index < blocks.length - 1) cursor += 1;
|
|
123
177
|
}
|
|
@@ -24,3 +24,6 @@ export * from "./coordinator.ts";
|
|
|
24
24
|
export * from "./visibility-policy.ts";
|
|
25
25
|
export * from "./markup-mode-policy.ts";
|
|
26
26
|
export * from "./scope-rail-composer.ts";
|
|
27
|
+
export * from "./word-field-matrix-calibration.ts";
|
|
28
|
+
export * from "./redline-posture-calibration.ts";
|
|
29
|
+
export * from "./ai-issue-lifecycle.ts";
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { GeometryRect } from "../geometry/geometry-types.ts";
|
|
2
|
+
|
|
3
|
+
export type WorkflowOverlayAnchorQuery =
|
|
4
|
+
| { kind: "block"; value: string }
|
|
5
|
+
| { kind: "scope"; value: string }
|
|
6
|
+
| { kind: "comment"; value: string }
|
|
7
|
+
| { kind: "revision"; value: string }
|
|
8
|
+
| { kind: "page"; value: number }
|
|
9
|
+
| { kind: "selection" };
|
|
10
|
+
|
|
11
|
+
export type WorkflowOverlayLaneKind =
|
|
12
|
+
| "selection"
|
|
13
|
+
| "caret"
|
|
14
|
+
| "redlines"
|
|
15
|
+
| "field-scopes"
|
|
16
|
+
| "broad-scopes"
|
|
17
|
+
| "comments"
|
|
18
|
+
| "issues"
|
|
19
|
+
| "tables"
|
|
20
|
+
| "objects"
|
|
21
|
+
| "search"
|
|
22
|
+
| "presence";
|
|
23
|
+
|
|
24
|
+
export type WorkflowOverlayLaneStatus =
|
|
25
|
+
| "resolved"
|
|
26
|
+
| "requires-rehydration"
|
|
27
|
+
| "unavailable";
|
|
28
|
+
|
|
29
|
+
export type WorkflowOverlayLaneSource =
|
|
30
|
+
| "geometry"
|
|
31
|
+
| "workflow"
|
|
32
|
+
| "search"
|
|
33
|
+
| "awareness"
|
|
34
|
+
| "controller"
|
|
35
|
+
| "unavailable";
|
|
36
|
+
|
|
37
|
+
export interface WorkflowOverlayLaneEntry {
|
|
38
|
+
readonly id: string;
|
|
39
|
+
readonly status: WorkflowOverlayLaneStatus;
|
|
40
|
+
readonly anchor?: WorkflowOverlayAnchorQuery;
|
|
41
|
+
readonly rects?: readonly GeometryRect[];
|
|
42
|
+
readonly reason?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Lane-specific plain payload. Examples: peer identity for presence,
|
|
45
|
+
* issue severity, search rank, table/object classification. Kept plain
|
|
46
|
+
* so non-React consumers and debug runners can serialize snapshots.
|
|
47
|
+
*/
|
|
48
|
+
readonly data?: Readonly<Record<string, unknown>>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface WorkflowOverlayLaneSnapshot {
|
|
52
|
+
readonly kind: WorkflowOverlayLaneKind;
|
|
53
|
+
readonly status: WorkflowOverlayLaneStatus;
|
|
54
|
+
readonly entries: readonly WorkflowOverlayLaneEntry[];
|
|
55
|
+
readonly revision: number;
|
|
56
|
+
readonly source: WorkflowOverlayLaneSource;
|
|
57
|
+
readonly reason?: string;
|
|
58
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
CommentSidebarSnapshot,
|
|
3
|
+
OverlayKind,
|
|
3
4
|
SuggestionsSnapshot,
|
|
4
5
|
TrackedChangesSnapshot,
|
|
5
6
|
WorkflowMarkupSnapshot,
|
|
@@ -7,16 +8,44 @@ import type {
|
|
|
7
8
|
} from "../../api/public-types.ts";
|
|
8
9
|
import { ISSUE_METADATA_ID } from "../../api/public-types.ts";
|
|
9
10
|
import type {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from "
|
|
11
|
+
WorkflowOverlayLaneEntry,
|
|
12
|
+
WorkflowOverlayLaneKind,
|
|
13
|
+
WorkflowOverlayLaneSnapshot,
|
|
14
|
+
WorkflowOverlayLaneStatus,
|
|
15
|
+
} from "./overlay-lane-types.ts";
|
|
15
16
|
|
|
16
17
|
export type WorkflowReviewOverlayLaneKind = Extract<
|
|
17
|
-
|
|
18
|
+
WorkflowOverlayLaneKind,
|
|
18
19
|
"redlines" | "comments" | "issues" | "field-scopes" | "broad-scopes" | "presence"
|
|
19
20
|
>;
|
|
21
|
+
export type WorkflowReviewOverlayLaneSnapshot = WorkflowOverlayLaneSnapshot;
|
|
22
|
+
export type WorkflowReviewOverlayLaneListener = (
|
|
23
|
+
snapshot: WorkflowReviewOverlayLaneSnapshot,
|
|
24
|
+
) => void;
|
|
25
|
+
export type WorkflowReviewOverlayLaneRefreshEvent = {
|
|
26
|
+
readonly type:
|
|
27
|
+
| "ready"
|
|
28
|
+
| "comment_added"
|
|
29
|
+
| "comment_resolved"
|
|
30
|
+
| "comments_changed"
|
|
31
|
+
| "change_authored"
|
|
32
|
+
| "change_accepted"
|
|
33
|
+
| "change_rejected"
|
|
34
|
+
| "suggestion_authored"
|
|
35
|
+
| "suggestion_updated"
|
|
36
|
+
| "workflow_metadata_changed"
|
|
37
|
+
| "workflow_overlay_changed"
|
|
38
|
+
| "workflow_active_work_item_changed"
|
|
39
|
+
| "workflow_shared_state_changed"
|
|
40
|
+
| "workflow_visibility_policy_changed"
|
|
41
|
+
| "workflow_markup_mode_policy_changed"
|
|
42
|
+
| "toc_auto_refreshed"
|
|
43
|
+
| "warning_added"
|
|
44
|
+
| "warning_cleared"
|
|
45
|
+
| "error"
|
|
46
|
+
| string;
|
|
47
|
+
readonly kind?: unknown;
|
|
48
|
+
};
|
|
20
49
|
|
|
21
50
|
export interface WorkflowReviewOverlayLaneInput {
|
|
22
51
|
readonly comments?: CommentSidebarSnapshot;
|
|
@@ -38,7 +67,7 @@ export interface WorkflowReviewOverlayLaneInput {
|
|
|
38
67
|
export function projectWorkflowReviewOverlayLane(
|
|
39
68
|
kind: WorkflowReviewOverlayLaneKind,
|
|
40
69
|
input: WorkflowReviewOverlayLaneInput,
|
|
41
|
-
):
|
|
70
|
+
): WorkflowOverlayLaneSnapshot {
|
|
42
71
|
if (kind === "presence") {
|
|
43
72
|
return {
|
|
44
73
|
kind,
|
|
@@ -60,10 +89,94 @@ export function projectWorkflowReviewOverlayLane(
|
|
|
60
89
|
};
|
|
61
90
|
}
|
|
62
91
|
|
|
92
|
+
export function shouldRefreshWorkflowReviewOverlayLane(
|
|
93
|
+
kind: WorkflowReviewOverlayLaneKind,
|
|
94
|
+
event: WorkflowReviewOverlayLaneRefreshEvent,
|
|
95
|
+
): boolean {
|
|
96
|
+
if (kind === "presence") return false;
|
|
97
|
+
switch (event.type) {
|
|
98
|
+
case "ready":
|
|
99
|
+
return true;
|
|
100
|
+
case "comment_added":
|
|
101
|
+
case "comment_resolved":
|
|
102
|
+
case "comments_changed":
|
|
103
|
+
return kind === "comments";
|
|
104
|
+
case "change_authored":
|
|
105
|
+
case "change_accepted":
|
|
106
|
+
case "change_rejected":
|
|
107
|
+
case "suggestion_authored":
|
|
108
|
+
case "suggestion_updated":
|
|
109
|
+
return kind === "redlines";
|
|
110
|
+
case "workflow_metadata_changed":
|
|
111
|
+
return kind === "issues" || kind === "broad-scopes";
|
|
112
|
+
case "workflow_overlay_changed":
|
|
113
|
+
case "workflow_active_work_item_changed":
|
|
114
|
+
case "workflow_shared_state_changed":
|
|
115
|
+
return kind === "issues" || kind === "broad-scopes";
|
|
116
|
+
case "workflow_visibility_policy_changed":
|
|
117
|
+
return shouldRefreshForVisibilityPolicy(
|
|
118
|
+
kind,
|
|
119
|
+
isOverlayKind(event.kind) ? event.kind : undefined,
|
|
120
|
+
);
|
|
121
|
+
case "workflow_markup_mode_policy_changed":
|
|
122
|
+
return kind === "redlines";
|
|
123
|
+
case "toc_auto_refreshed":
|
|
124
|
+
case "warning_added":
|
|
125
|
+
case "warning_cleared":
|
|
126
|
+
case "error":
|
|
127
|
+
return kind === "field-scopes";
|
|
128
|
+
default:
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function areWorkflowReviewOverlayLaneSnapshotsEqual(
|
|
134
|
+
left: WorkflowReviewOverlayLaneSnapshot,
|
|
135
|
+
right: WorkflowReviewOverlayLaneSnapshot,
|
|
136
|
+
): boolean {
|
|
137
|
+
return (
|
|
138
|
+
left.kind === right.kind &&
|
|
139
|
+
left.status === right.status &&
|
|
140
|
+
left.source === right.source &&
|
|
141
|
+
left.reason === right.reason &&
|
|
142
|
+
entriesEqual(left.entries, right.entries)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function isOverlayKind(value: unknown): value is OverlayKind {
|
|
147
|
+
return (
|
|
148
|
+
value === "scope-rail" ||
|
|
149
|
+
value === "comments" ||
|
|
150
|
+
value === "tracked-changes" ||
|
|
151
|
+
value === "suggestions" ||
|
|
152
|
+
value === "debug-panel" ||
|
|
153
|
+
value === "presence"
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function shouldRefreshForVisibilityPolicy(
|
|
158
|
+
kind: Exclude<WorkflowReviewOverlayLaneKind, "presence">,
|
|
159
|
+
overlayKind: OverlayKind | undefined,
|
|
160
|
+
): boolean {
|
|
161
|
+
switch (overlayKind) {
|
|
162
|
+
case "comments":
|
|
163
|
+
return kind === "comments";
|
|
164
|
+
case "tracked-changes":
|
|
165
|
+
case "suggestions":
|
|
166
|
+
return kind === "redlines";
|
|
167
|
+
case "scope-rail":
|
|
168
|
+
return kind === "broad-scopes";
|
|
169
|
+
case "presence":
|
|
170
|
+
case "debug-panel":
|
|
171
|
+
case undefined:
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
63
176
|
function projectEntries(
|
|
64
177
|
kind: Exclude<WorkflowReviewOverlayLaneKind, "presence">,
|
|
65
178
|
input: WorkflowReviewOverlayLaneInput,
|
|
66
|
-
):
|
|
179
|
+
): WorkflowOverlayLaneEntry[] {
|
|
67
180
|
switch (kind) {
|
|
68
181
|
case "comments":
|
|
69
182
|
return (input.comments?.threads ?? []).map((thread) => ({
|
|
@@ -165,7 +278,7 @@ function projectEntries(
|
|
|
165
278
|
}
|
|
166
279
|
}
|
|
167
280
|
|
|
168
|
-
function projectIssueEntries(input: WorkflowReviewOverlayLaneInput):
|
|
281
|
+
function projectIssueEntries(input: WorkflowReviewOverlayLaneInput): WorkflowOverlayLaneEntry[] {
|
|
169
282
|
const suggestionGroupsByIssueId = new Map<string, string[]>();
|
|
170
283
|
for (const group of input.suggestions?.groups ?? []) {
|
|
171
284
|
if (!group.issueId) continue;
|
|
@@ -207,12 +320,57 @@ function projectIssueEntries(input: WorkflowReviewOverlayLaneInput): UiOverlayLa
|
|
|
207
320
|
});
|
|
208
321
|
}
|
|
209
322
|
|
|
210
|
-
function summarizeStatus(entries: readonly
|
|
323
|
+
function summarizeStatus(entries: readonly WorkflowOverlayLaneEntry[]): WorkflowOverlayLaneStatus {
|
|
211
324
|
return entries.some((entry) => entry.status === "requires-rehydration")
|
|
212
325
|
? "requires-rehydration"
|
|
213
326
|
: "resolved";
|
|
214
327
|
}
|
|
215
328
|
|
|
329
|
+
function entriesEqual(
|
|
330
|
+
left: readonly WorkflowOverlayLaneEntry[],
|
|
331
|
+
right: readonly WorkflowOverlayLaneEntry[],
|
|
332
|
+
): boolean {
|
|
333
|
+
if (left.length !== right.length) return false;
|
|
334
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
335
|
+
const leftEntry = left[index];
|
|
336
|
+
const rightEntry = right[index];
|
|
337
|
+
if (!leftEntry || !rightEntry) return false;
|
|
338
|
+
if (
|
|
339
|
+
leftEntry.id !== rightEntry.id ||
|
|
340
|
+
leftEntry.status !== rightEntry.status ||
|
|
341
|
+
leftEntry.reason !== rightEntry.reason ||
|
|
342
|
+
!jsonValueEqual(leftEntry.anchor, rightEntry.anchor) ||
|
|
343
|
+
!jsonValueEqual(leftEntry.rects, rightEntry.rects) ||
|
|
344
|
+
!jsonValueEqual(leftEntry.data, rightEntry.data)
|
|
345
|
+
) {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function jsonValueEqual(left: unknown, right: unknown): boolean {
|
|
353
|
+
return stableJson(left) === stableJson(right);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function stableJson(value: unknown): string {
|
|
357
|
+
return JSON.stringify(sortJsonValue(value));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function sortJsonValue(value: unknown): unknown {
|
|
361
|
+
if (Array.isArray(value)) {
|
|
362
|
+
return value.map(sortJsonValue);
|
|
363
|
+
}
|
|
364
|
+
if (!isRecord(value)) {
|
|
365
|
+
return value;
|
|
366
|
+
}
|
|
367
|
+
const sorted: Record<string, unknown> = {};
|
|
368
|
+
for (const key of Object.keys(value).sort()) {
|
|
369
|
+
sorted[key] = sortJsonValue(value[key]);
|
|
370
|
+
}
|
|
371
|
+
return sorted;
|
|
372
|
+
}
|
|
373
|
+
|
|
216
374
|
function compactData(input: Record<string, unknown>): Readonly<Record<string, unknown>> {
|
|
217
375
|
const output: Record<string, unknown> = {};
|
|
218
376
|
for (const [key, value] of Object.entries(input)) {
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
*
|
|
23
23
|
* What it does NOT own (by design — those belong to the coordinator):
|
|
24
24
|
* - interaction-guard / workflow-scope / workflow-markup snapshot
|
|
25
|
-
* caches (require runtime-scope deps like
|
|
26
|
-
*
|
|
25
|
+
* caches (require runtime-scope deps like render snapshot,
|
|
26
|
+
* selection, protection, and active story).
|
|
27
27
|
* - blocked-reason composition + scope-matching heuristics (require
|
|
28
28
|
* protection snapshot + viewState.documentMode).
|
|
29
29
|
* - rail / card composition (requires page graph + render frame).
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
export type WorkflowRedlinePosture = "all-markup" | "final" | "original" | "unknown";
|
|
2
|
+
|
|
3
|
+
export interface WorkflowRedlineDatasetDocumentLike {
|
|
4
|
+
readonly docId: string;
|
|
5
|
+
readonly status: string;
|
|
6
|
+
readonly pages: number;
|
|
7
|
+
readonly revisions: number;
|
|
8
|
+
readonly comments: number;
|
|
9
|
+
readonly fields?: number;
|
|
10
|
+
readonly uiaLines?: number;
|
|
11
|
+
readonly datasetPath?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface WorkflowRedlineDatasetManifestLike {
|
|
15
|
+
readonly schemaVersion: string;
|
|
16
|
+
readonly sourceRun: string;
|
|
17
|
+
readonly captureMatrix?: {
|
|
18
|
+
readonly markupModes?: readonly string[];
|
|
19
|
+
};
|
|
20
|
+
readonly targetedWord?: {
|
|
21
|
+
readonly version?: string;
|
|
22
|
+
readonly build?: string;
|
|
23
|
+
readonly activePrinter?: string;
|
|
24
|
+
};
|
|
25
|
+
readonly documents: readonly WorkflowRedlineDatasetDocumentLike[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface WorkflowRedlineFieldIdentityTotalsLike {
|
|
29
|
+
readonly wordFields: number;
|
|
30
|
+
readonly joined: number;
|
|
31
|
+
readonly missingSourceField: number;
|
|
32
|
+
readonly missingCanonicalField: number;
|
|
33
|
+
readonly missingRuntimeRegion: number;
|
|
34
|
+
readonly actionableL04: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type WorkflowRedlinePostureFactId =
|
|
38
|
+
| "all-markup-review-posture"
|
|
39
|
+
| "revision-comment-counts"
|
|
40
|
+
| "clean-all-markup-measurement-handoff"
|
|
41
|
+
| "redline-field-identity-posture";
|
|
42
|
+
|
|
43
|
+
export type WorkflowRedlinePostureRepresentation =
|
|
44
|
+
| "durable-workflow-review-posture"
|
|
45
|
+
| "measurement-handoff"
|
|
46
|
+
| "field-region-posture-handoff"
|
|
47
|
+
| "blocked-until-identity-join";
|
|
48
|
+
|
|
49
|
+
export interface WorkflowRedlinePostureFact {
|
|
50
|
+
readonly factId: WorkflowRedlinePostureFactId;
|
|
51
|
+
readonly representation: WorkflowRedlinePostureRepresentation;
|
|
52
|
+
readonly posture: WorkflowRedlinePosture;
|
|
53
|
+
readonly sourceRun: string;
|
|
54
|
+
readonly l06Surfaces: readonly string[];
|
|
55
|
+
readonly downstreamRoutes: readonly string[];
|
|
56
|
+
readonly evidence: Readonly<Record<string, number | string | boolean>>;
|
|
57
|
+
readonly note: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface WorkflowRedlinePostureCalibration {
|
|
61
|
+
readonly schemaVersion: "l06-redline-posture-calibration/v0";
|
|
62
|
+
readonly facts: readonly WorkflowRedlinePostureFact[];
|
|
63
|
+
readonly summary: {
|
|
64
|
+
readonly documentCount: number;
|
|
65
|
+
readonly availableDocumentCount: number;
|
|
66
|
+
readonly pageCount: number;
|
|
67
|
+
readonly revisionCount: number;
|
|
68
|
+
readonly commentCount: number;
|
|
69
|
+
readonly fieldCount: number;
|
|
70
|
+
readonly uiaLineCount: number;
|
|
71
|
+
readonly posture: WorkflowRedlinePosture;
|
|
72
|
+
readonly downstreamRouteCount: number;
|
|
73
|
+
readonly l04ActionableFieldRows: number;
|
|
74
|
+
readonly ownsGeometry: false;
|
|
75
|
+
readonly ownsVisualPaint: false;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface WorkflowRedlinePostureCalibrationInput {
|
|
80
|
+
readonly manifest: WorkflowRedlineDatasetManifestLike;
|
|
81
|
+
readonly fieldIdentityTotals?: WorkflowRedlineFieldIdentityTotalsLike;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface WorkflowRedlinePostureTotals {
|
|
85
|
+
readonly documentCount: number;
|
|
86
|
+
readonly availableDocumentCount: number;
|
|
87
|
+
readonly pageCount: number;
|
|
88
|
+
readonly revisionCount: number;
|
|
89
|
+
readonly commentCount: number;
|
|
90
|
+
readonly fieldCount: number;
|
|
91
|
+
readonly uiaLineCount: number;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function calibrateWorkflowReviewRedlinePosture(
|
|
95
|
+
input: WorkflowRedlinePostureCalibrationInput,
|
|
96
|
+
): WorkflowRedlinePostureCalibration {
|
|
97
|
+
const documents = input.manifest.documents;
|
|
98
|
+
const availableDocuments = documents.filter((document) => document.status === "available");
|
|
99
|
+
const posture = resolvePosture(input.manifest.captureMatrix?.markupModes);
|
|
100
|
+
const totals = {
|
|
101
|
+
documentCount: documents.length,
|
|
102
|
+
availableDocumentCount: availableDocuments.length,
|
|
103
|
+
pageCount: sum(availableDocuments, (document) => document.pages),
|
|
104
|
+
revisionCount: sum(availableDocuments, (document) => document.revisions),
|
|
105
|
+
commentCount: sum(availableDocuments, (document) => document.comments),
|
|
106
|
+
fieldCount: sum(availableDocuments, (document) => document.fields ?? 0),
|
|
107
|
+
uiaLineCount: sum(availableDocuments, (document) => document.uiaLines ?? 0),
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const facts = [
|
|
111
|
+
buildAllMarkupPostureFact(input.manifest, posture, totals),
|
|
112
|
+
buildReviewCountFact(input.manifest, posture, totals),
|
|
113
|
+
buildMeasurementHandoffFact(input.manifest, posture, totals),
|
|
114
|
+
buildFieldIdentityFact(input.manifest, posture, totals, input.fieldIdentityTotals),
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
schemaVersion: "l06-redline-posture-calibration/v0",
|
|
119
|
+
facts,
|
|
120
|
+
summary: {
|
|
121
|
+
...totals,
|
|
122
|
+
posture,
|
|
123
|
+
downstreamRouteCount: new Set(facts.flatMap((fact) => fact.downstreamRoutes)).size,
|
|
124
|
+
l04ActionableFieldRows: input.fieldIdentityTotals?.actionableL04 ?? 0,
|
|
125
|
+
ownsGeometry: false,
|
|
126
|
+
ownsVisualPaint: false,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function buildAllMarkupPostureFact(
|
|
132
|
+
manifest: WorkflowRedlineDatasetManifestLike,
|
|
133
|
+
posture: WorkflowRedlinePosture,
|
|
134
|
+
totals: WorkflowRedlinePostureTotals,
|
|
135
|
+
): WorkflowRedlinePostureFact {
|
|
136
|
+
return {
|
|
137
|
+
factId: "all-markup-review-posture",
|
|
138
|
+
representation: "durable-workflow-review-posture",
|
|
139
|
+
posture,
|
|
140
|
+
sourceRun: manifest.sourceRun,
|
|
141
|
+
l06Surfaces: [
|
|
142
|
+
"WorkflowMarkupModePolicy",
|
|
143
|
+
"WorkflowMarkupSnapshot.revisions",
|
|
144
|
+
"TrackedChangesSnapshot.revisions",
|
|
145
|
+
],
|
|
146
|
+
downstreamRoutes: ["L04 redline measurement posture", "L11 redline overlay paint"],
|
|
147
|
+
evidence: {
|
|
148
|
+
documents: totals.documentCount,
|
|
149
|
+
availableDocuments: totals.availableDocumentCount,
|
|
150
|
+
wordVersion: manifest.targetedWord?.version ?? "unknown",
|
|
151
|
+
wordBuild: manifest.targetedWord?.build ?? "unknown",
|
|
152
|
+
},
|
|
153
|
+
note:
|
|
154
|
+
"The redline Word JSON dataset is captured in all-markup posture; L06 names that durable review posture before layout or paint consume it.",
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function buildReviewCountFact(
|
|
159
|
+
manifest: WorkflowRedlineDatasetManifestLike,
|
|
160
|
+
posture: WorkflowRedlinePosture,
|
|
161
|
+
totals: WorkflowRedlinePostureTotals,
|
|
162
|
+
): WorkflowRedlinePostureFact {
|
|
163
|
+
return {
|
|
164
|
+
factId: "revision-comment-counts",
|
|
165
|
+
representation: "durable-workflow-review-posture",
|
|
166
|
+
posture,
|
|
167
|
+
sourceRun: manifest.sourceRun,
|
|
168
|
+
l06Surfaces: [
|
|
169
|
+
"WorkflowMarkupSnapshot.revisions",
|
|
170
|
+
"WorkflowMarkupSnapshot.comments",
|
|
171
|
+
"TrackedChangesSnapshot.revisions",
|
|
172
|
+
"CommentSidebarSnapshot.threads",
|
|
173
|
+
],
|
|
174
|
+
downstreamRoutes: ["L11 review/comment lane visibility", "L08 comment/revision scope posture"],
|
|
175
|
+
evidence: {
|
|
176
|
+
revisions: totals.revisionCount,
|
|
177
|
+
comments: totals.commentCount,
|
|
178
|
+
documentsWithReviewData: totals.availableDocumentCount,
|
|
179
|
+
},
|
|
180
|
+
note:
|
|
181
|
+
"Revision and comment totals are L06 review-store facts; geometry and balloon placement stay with downstream consumers.",
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function buildMeasurementHandoffFact(
|
|
186
|
+
manifest: WorkflowRedlineDatasetManifestLike,
|
|
187
|
+
posture: WorkflowRedlinePosture,
|
|
188
|
+
totals: WorkflowRedlinePostureTotals,
|
|
189
|
+
): WorkflowRedlinePostureFact {
|
|
190
|
+
return {
|
|
191
|
+
factId: "clean-all-markup-measurement-handoff",
|
|
192
|
+
representation: "measurement-handoff",
|
|
193
|
+
posture,
|
|
194
|
+
sourceRun: manifest.sourceRun,
|
|
195
|
+
l06Surfaces: ["EffectiveLayoutFormatting.revisionPosture", "WorkflowMarkupModePolicy"],
|
|
196
|
+
downstreamRoutes: ["L04 clean-vs-all-markup page/frame delta", "L11 render-word assertion planning"],
|
|
197
|
+
evidence: {
|
|
198
|
+
pagesInAllMarkupPosture: totals.pageCount,
|
|
199
|
+
uiaLinesInAllMarkupPosture: totals.uiaLineCount,
|
|
200
|
+
ownsGeometry: false,
|
|
201
|
+
},
|
|
202
|
+
note:
|
|
203
|
+
"L06 names the measurement-affecting review posture; L04 owns page/frame deltas and L11 owns visual assertion planning.",
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function buildFieldIdentityFact(
|
|
208
|
+
manifest: WorkflowRedlineDatasetManifestLike,
|
|
209
|
+
posture: WorkflowRedlinePosture,
|
|
210
|
+
totals: WorkflowRedlinePostureTotals,
|
|
211
|
+
fieldIdentityTotals: WorkflowRedlineFieldIdentityTotalsLike | undefined,
|
|
212
|
+
): WorkflowRedlinePostureFact {
|
|
213
|
+
const actionableRows = fieldIdentityTotals?.actionableL04 ?? 0;
|
|
214
|
+
return {
|
|
215
|
+
factId: "redline-field-identity-posture",
|
|
216
|
+
representation: actionableRows > 0 ? "field-region-posture-handoff" : "blocked-until-identity-join",
|
|
217
|
+
posture,
|
|
218
|
+
sourceRun: manifest.sourceRun,
|
|
219
|
+
l06Surfaces: ["WorkflowMarkupModePolicy", "WorkflowMarkupSnapshot.fields"],
|
|
220
|
+
downstreamRoutes: [
|
|
221
|
+
"L01 source field identity",
|
|
222
|
+
"L02 canonical field identity",
|
|
223
|
+
"L04 redline field-region measurement",
|
|
224
|
+
],
|
|
225
|
+
evidence: {
|
|
226
|
+
redlineWordFields: fieldIdentityTotals?.wordFields ?? totals.fieldCount,
|
|
227
|
+
sourceJoinedRows: fieldIdentityTotals?.joined ?? 0,
|
|
228
|
+
missingSourceField: fieldIdentityTotals?.missingSourceField ?? 0,
|
|
229
|
+
missingCanonicalField: fieldIdentityTotals?.missingCanonicalField ?? 0,
|
|
230
|
+
missingRuntimeRegion: fieldIdentityTotals?.missingRuntimeRegion ?? 0,
|
|
231
|
+
actionableL04: actionableRows,
|
|
232
|
+
},
|
|
233
|
+
note:
|
|
234
|
+
actionableRows > 0
|
|
235
|
+
? "L06 review posture is named and the field rows may proceed to L04 with identity joins present."
|
|
236
|
+
: "L06 review posture is named as all-markup, but redline field-region rows remain blocked on source/canonical/runtime identity joins.",
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function resolvePosture(markupModes: readonly string[] | undefined): WorkflowRedlinePosture {
|
|
241
|
+
if (!markupModes || markupModes.length !== 1) return "unknown";
|
|
242
|
+
switch (markupModes[0]) {
|
|
243
|
+
case "all":
|
|
244
|
+
case "all-markup":
|
|
245
|
+
return "all-markup";
|
|
246
|
+
case "final":
|
|
247
|
+
return "final";
|
|
248
|
+
case "original":
|
|
249
|
+
return "original";
|
|
250
|
+
default:
|
|
251
|
+
return "unknown";
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function sum<T>(items: readonly T[], selector: (item: T) => number): number {
|
|
256
|
+
return items.reduce((total, item) => total + selector(item), 0);
|
|
257
|
+
}
|