@claritylabs/cl-sdk 3.0.5 → 3.0.6

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/dist/index.mjs CHANGED
@@ -9069,6 +9069,7 @@ function simplifyOrganizerTitle(value, fallback, kind) {
9069
9069
  if (/^declarations\b/i.test(title)) return "Declarations";
9070
9070
  if (/^policy\s+form\b/i.test(title)) return "Policy Form";
9071
9071
  if (/^definitions\b/i.test(title)) return "Definitions";
9072
+ if (kind === "page_group" && /^endorsements?\b/i.test(title)) return "Endorsements";
9072
9073
  const endorsementNumber = title.match(/^endorsement\s+(?:no\.?|number|#)?\s*([A-Z0-9][A-Z0-9.-]*)\b/i)?.[1];
9073
9074
  if (endorsementNumber) return `Endorsement No. ${endorsementNumber}`;
9074
9075
  if (kind === "endorsement" && /^endorsements?\s+\d+\s*[–-]\s*\d+\b/i.test(title)) {
@@ -9079,7 +9080,13 @@ function simplifyOrganizerTitle(value, fallback, kind) {
9079
9080
  function endorsementReference(value) {
9080
9081
  return value?.match(/\bendorsement\s+(?:no\.?|number|#)?\s*([A-Z0-9][A-Z0-9.-]*)\b/i)?.[1]?.toUpperCase();
9081
9082
  }
9083
+ function endorsementTitle(value) {
9084
+ const text = cleanText(value, "");
9085
+ const number = text.match(/\bendorsement\s+(?:no\.?|number|#)\s*([A-Z0-9][A-Z0-9.-]*)\b/i)?.[1]?.toUpperCase();
9086
+ return number ? `Endorsement No. ${number}` : void 0;
9087
+ }
9082
9088
  function rejectsOrganizerGroup(group, children) {
9089
+ if (/^endorsements?\b/i.test(group.title) && group.kind !== "page_group") return true;
9083
9090
  if (group.kind !== "endorsement") return false;
9084
9091
  if (/^endorsements?\s+\d+\s*[–-]\s*\d+\b/i.test(group.title)) return true;
9085
9092
  const childNumbers = new Set(
@@ -9087,6 +9094,120 @@ function rejectsOrganizerGroup(group, children) {
9087
9094
  );
9088
9095
  return childNumbers.size > 1;
9089
9096
  }
9097
+ function isEndorsementGroup(node) {
9098
+ return node.kind === "page_group" && /^endorsements?\b/i.test(node.title);
9099
+ }
9100
+ function endorsementGroupNodeId(documentId, parentId) {
9101
+ return [
9102
+ documentId.replace(/[^a-zA-Z0-9_.:-]/g, "_"),
9103
+ "source_node",
9104
+ "page_group",
9105
+ "endorsements",
9106
+ parentId?.replace(/[^a-zA-Z0-9_.:-]/g, "_").slice(0, 48) ?? "root"
9107
+ ].join(":");
9108
+ }
9109
+ function applyEndorsementGrouping(sourceTree) {
9110
+ const relabeledTree = sourceTree.map((node) => {
9111
+ if (node.kind === "document" || isEndorsementGroup(node) || node.kind === "endorsement") return node;
9112
+ const title = endorsementTitle([node.title, node.description, node.textExcerpt].filter(Boolean).join(" "));
9113
+ if (!title) return node;
9114
+ return {
9115
+ ...node,
9116
+ kind: "endorsement",
9117
+ title,
9118
+ description: cleanText(
9119
+ [title, "endorsement", node.pageStart ? `page ${node.pageStart}` : void 0, node.textExcerpt].filter(Boolean).join(" | "),
9120
+ title
9121
+ ),
9122
+ metadata: {
9123
+ ...node.metadata,
9124
+ organizerRepair: "normalize_endorsement_grouping"
9125
+ }
9126
+ };
9127
+ });
9128
+ const byParent = nodesByParent(relabeledTree);
9129
+ const groupsByParent = /* @__PURE__ */ new Map();
9130
+ const endorsementGroupIds = new Set(
9131
+ relabeledTree.filter(isEndorsementGroup).map((node) => node.id)
9132
+ );
9133
+ let nextTree = relabeledTree.map((node) => {
9134
+ if (!isEndorsementGroup(node)) return node;
9135
+ const normalized = {
9136
+ ...node,
9137
+ kind: "page_group",
9138
+ title: "Endorsements",
9139
+ description: cleanText(node.description, "Endorsement forms grouped by source order"),
9140
+ metadata: {
9141
+ ...node.metadata,
9142
+ sourceTreeVersion: "v3",
9143
+ organizer: node.metadata?.organizer ?? "endorsement_grouping"
9144
+ }
9145
+ };
9146
+ groupsByParent.set(node.parentId, normalized);
9147
+ endorsementGroupIds.add(node.id);
9148
+ return normalized;
9149
+ });
9150
+ nextTree = nextTree.map((node) => {
9151
+ if (!endorsementGroupIds.has(node.parentId ?? "")) return node;
9152
+ const title = endorsementTitle([node.title, node.description, node.textExcerpt].filter(Boolean).join(" "));
9153
+ if (!title) return node;
9154
+ return {
9155
+ ...node,
9156
+ kind: "endorsement",
9157
+ title,
9158
+ description: cleanText(
9159
+ [title, "endorsement", node.pageStart ? `page ${node.pageStart}` : void 0, node.textExcerpt].filter(Boolean).join(" | "),
9160
+ title
9161
+ ),
9162
+ metadata: {
9163
+ ...node.metadata,
9164
+ organizerRepair: "normalize_endorsement_grouping"
9165
+ }
9166
+ };
9167
+ });
9168
+ for (const [parentId, children] of byParent) {
9169
+ if (endorsementGroupIds.has(parentId ?? "")) continue;
9170
+ const endorsementChildren = children.filter((child) => child.kind === "endorsement" && !isEndorsementGroup(child));
9171
+ if (endorsementChildren.length < 2) continue;
9172
+ const documentId = endorsementChildren[0].documentId;
9173
+ const pageStarts = endorsementChildren.map((child) => child.pageStart).filter((page) => typeof page === "number");
9174
+ const pageEnds = endorsementChildren.map((child) => child.pageEnd ?? child.pageStart).filter((page) => typeof page === "number");
9175
+ const order = Math.min(...endorsementChildren.map((child) => child.order));
9176
+ const existingGroup = groupsByParent.get(parentId);
9177
+ const groupId = existingGroup?.id ?? endorsementGroupNodeId(documentId, parentId);
9178
+ const groupNode = existingGroup ?? {
9179
+ id: groupId,
9180
+ documentId,
9181
+ parentId,
9182
+ kind: "page_group",
9183
+ title: "Endorsements",
9184
+ description: "Endorsement forms grouped by source order",
9185
+ textExcerpt: void 0,
9186
+ sourceSpanIds: [],
9187
+ pageStart: pageStarts.length ? Math.min(...pageStarts) : void 0,
9188
+ pageEnd: pageEnds.length ? Math.max(...pageEnds) : void 0,
9189
+ bbox: endorsementChildren.flatMap((child) => child.bbox ?? []).slice(0, 12),
9190
+ order,
9191
+ path: "",
9192
+ metadata: { sourceTreeVersion: "v3", organizer: "endorsement_grouping" }
9193
+ };
9194
+ const childSpanIds = [...new Set(endorsementChildren.flatMap((child) => child.sourceSpanIds))];
9195
+ const normalizedGroup = {
9196
+ ...groupNode,
9197
+ sourceSpanIds: groupNode.sourceSpanIds.length ? groupNode.sourceSpanIds : childSpanIds,
9198
+ pageStart: groupNode.pageStart ?? (pageStarts.length ? Math.min(...pageStarts) : void 0),
9199
+ pageEnd: groupNode.pageEnd ?? (pageEnds.length ? Math.max(...pageEnds) : void 0),
9200
+ order
9201
+ };
9202
+ groupsByParent.set(parentId, normalizedGroup);
9203
+ if (!existingGroup) nextTree.push(normalizedGroup);
9204
+ else nextTree = nextTree.map((node) => node.id === normalizedGroup.id ? normalizedGroup : node);
9205
+ nextTree = nextTree.map(
9206
+ (node) => endorsementChildren.some((child) => child.id === node.id) ? { ...node, parentId: groupId, order: node.order + 1e-3 } : node
9207
+ );
9208
+ }
9209
+ return normalizeDocumentSourceTreePaths(nextTree);
9210
+ }
9090
9211
  function compactNode(node, maxText = 700) {
9091
9212
  return {
9092
9213
  id: node.id,
@@ -9175,7 +9296,8 @@ Rules:
9175
9296
  - Use only node IDs from the provided list.
9176
9297
  - Do not invent text, page numbers, source spans, limits, or policy facts.
9177
9298
  - You may relabel existing nodes and group adjacent top-level/page nodes from this batch only when they are clearly one continuous form, one declarations set, one schedule, or one clause family.
9178
- - Do not group separately numbered endorsements into one parent. Never create rollup titles such as "Endorsements 1-3 (...)".
9299
+ - Group adjacent separately numbered endorsements under a single generic "Endorsements" page_group parent, with each individual endorsement preserved as its own child node.
9300
+ - Never create rollup titles such as "Endorsements 1-3 (...)" or merge multiple endorsements into one endorsement node.
9179
9301
  - Add concise, human-readable titles to generic text, table, row, and cell nodes when the text makes their role clear.
9180
9302
  - Keep organizer titles terse. Use the printed heading or a compact canonical title such as "Declarations", "Policy Form", "Definitions", or "Endorsement No. 3"; do not add parenthetical summaries.
9181
9303
  - Groups must list existing childNodeIds only.
@@ -9270,7 +9392,7 @@ function applyOrganization(sourceTree, organization) {
9270
9392
  ];
9271
9393
  byId.set(id, node);
9272
9394
  }
9273
- return normalizeDocumentSourceTreePaths(nextTree);
9395
+ return applyEndorsementGrouping(normalizeDocumentSourceTreePaths(nextTree));
9274
9396
  }
9275
9397
  function sourceTreeToOutline(sourceTree) {
9276
9398
  const byParent = /* @__PURE__ */ new Map();
@@ -9489,6 +9611,7 @@ async function runSourceTreeExtraction(params) {
9489
9611
  } catch (error) {
9490
9612
  warnings.push(`Operational profile model pass failed; deterministic profile used (${error instanceof Error ? error.message : String(error)})`);
9491
9613
  }
9614
+ sourceTree = applyEndorsementGrouping(sourceTree);
9492
9615
  const document = materializeDocument({
9493
9616
  id: params.id,
9494
9617
  sourceTree,