@claritylabs/cl-sdk 3.2.5 → 3.2.7

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
@@ -3576,6 +3576,16 @@ var OPERATIONAL_COVERAGE_TERM_KINDS2 = [
3576
3576
  "other"
3577
3577
  ];
3578
3578
  var OperationalCoverageTermKindSchema = z21.enum(OPERATIONAL_COVERAGE_TERM_KINDS2);
3579
+ var CleanupTermSchema = z21.object({
3580
+ kind: OperationalCoverageTermKindSchema,
3581
+ label: z21.string(),
3582
+ value: z21.string(),
3583
+ amount: z21.number().nullable().optional(),
3584
+ appliesTo: z21.string().nullable().optional(),
3585
+ sourceNodeIds: z21.array(z21.string()).optional(),
3586
+ sourceSpanIds: z21.array(z21.string()).optional(),
3587
+ reason: z21.string().optional()
3588
+ });
3579
3589
  var OperationalProfileCleanupSchema = z21.object({
3580
3590
  coverageDecisions: z21.array(z21.object({
3581
3591
  coverageIndex: z21.number().int().nonnegative(),
@@ -3599,7 +3609,8 @@ var OperationalProfileCleanupSchema = z21.object({
3599
3609
  appliesTo: z21.string().nullable().optional(),
3600
3610
  sourceNodeIds: z21.array(z21.string()).optional(),
3601
3611
  sourceSpanIds: z21.array(z21.string()).optional()
3602
- })).optional()
3612
+ })).optional(),
3613
+ termAdditions: z21.array(CleanupTermSchema).optional()
3603
3614
  })).default([]),
3604
3615
  warnings: z21.array(z21.string()).default([])
3605
3616
  });
@@ -3607,6 +3618,7 @@ var CLEANUP_CANDIDATE_ID_LIMIT = 12;
3607
3618
  var CLEANUP_SOURCE_NODE_LIMIT = 90;
3608
3619
  var CLEANUP_SIBLING_WINDOW = 4;
3609
3620
  var CLEANUP_KEYWORD = /\b(coverage|limit|liability|deductible|retention|retroactive|premium|aggregate|sublimit|sub-limit|claim|occurrence|loss|proceeding|endorsement|declarations?)\b|\$[0-9]/i;
3621
+ var CLEANUP_CONTINUATION_KEYWORD = /\b(coverage part|limit of liability|deductible|retention|retroactive date|aggregate|sublimit|sub-limit|each claim|each occurrence|each loss|each proceeding|coinsurance)\b|\$[0-9]/i;
3610
3622
  function compactNode(node, maxText = 700) {
3611
3623
  return {
3612
3624
  id: node.id,
@@ -3735,11 +3747,15 @@ function selectCoverageCleanupNodes(sourceTree, coverages) {
3735
3747
  const children = childrenByParent.get(selectedNode.id) ?? [];
3736
3748
  for (const child of children.slice(0, 24)) addNode(child, 760);
3737
3749
  }
3750
+ const continuationPages = new Set([...coveragePages].map((page) => page + 1));
3738
3751
  for (const node of sourceTree) {
3739
3752
  if (node.kind === "document") continue;
3740
- if (!node.pageStart || !coveragePages.has(node.pageStart)) continue;
3753
+ if (typeof node.pageStart !== "number") continue;
3754
+ const samePage = coveragePages.has(node.pageStart);
3755
+ const nearbyContinuationPage = continuationPages.has(node.pageStart);
3756
+ if (!samePage && !nearbyContinuationPage) continue;
3741
3757
  const text = nodeTextForSelection(node);
3742
- if (CLEANUP_KEYWORD.test(text) || nodeTextMatchesCoverage(node, coverageTerms)) {
3758
+ if (CLEANUP_KEYWORD.test(text) || nodeTextMatchesCoverage(node, coverageTerms) || nearbyContinuationPage && CLEANUP_CONTINUATION_KEYWORD.test(text)) {
3743
3759
  addNode(node, 600);
3744
3760
  }
3745
3761
  }
@@ -3753,7 +3769,7 @@ function buildOperationalProfileCleanupPrompt(sourceTree, profile, options = {})
3753
3769
  const coverageEntries = coverageCleanupEntries(profile, options.coverageIndexes);
3754
3770
  const nodes = selectCoverageCleanupNodes(sourceTree, coverageEntries.map((entry) => entry.coverage)).map((node) => compactNode(
3755
3771
  node,
3756
- node.kind === "page" || node.kind === "page_group" ? 260 : node.kind === "table_row" || node.kind === "table_cell" ? 520 : 360
3772
+ node.kind === "page" || node.kind === "page_group" ? 520 : node.kind === "table_row" || node.kind === "table_cell" ? 520 : 360
3757
3773
  ));
3758
3774
  const candidate = {
3759
3775
  documentType: profile.documentType,
@@ -3777,19 +3793,24 @@ Projection defects to look for:
3777
3793
  - Item references such as "shown in Item 7" or bare item numbers treated as money amounts.
3778
3794
  - Policy wording, exclusions, or unsupported prose copied into operational limit/deductible fields.
3779
3795
  - Header/value splits where "Limit of Liability", "Deductible", "Retroactive Date", "Aggregate", "Each Claim", or similar terms are attached to the wrong coverage row.
3796
+ - Collapsed combined bases where one candidate term says "Each Claim / Aggregate", "Each Loss / Aggregate", "Each Proceeding / Aggregate", or a continuation line supplies a separate policy aggregate, sub-limit, deductible, retention, retroactive date, or coinsurance term.
3780
3797
  - Repeated schedule headings projected as separate coverages when they only introduce the next coverage group.
3798
+ - Generic policy form rows projected as scheduled coverages when their values only say "as stated in Item...", "shown in the Declarations", or similar cross-references instead of actual scheduled amounts.
3781
3799
 
3782
3800
  Rules:
3783
3801
  - Use internal reasoning, but return JSON decisions only.
3784
- - Do not invent policy facts. Keep, drop, or update only existing coverageIndex and termIndex entries.
3802
+ - Do not invent policy facts. Keep, drop, or update only existing coverageIndex and termIndex entries, except for source-backed termAdditions on an existing coverage.
3785
3803
  - Use sourceNodeIds and sourceSpanIds only from the provided source nodes or from the existing candidate entry.
3786
3804
  - Prefer dropping a malformed fact over speculative rewriting.
3787
3805
  - Keep a coverage when it is a real operational coverage/benefit even if only one term needs cleanup.
3788
3806
  - When changing a term's semantic meaning, set kind to the corrected normalized term kind.
3789
- - Do not add new coverage rows or new terms; this pass cleans the existing projection.
3790
- - If one existing term combines multiple real limit bases, such as "Each Claim / Aggregate", keep the combined term unless another existing term already represents the other basis. Do not relabel it to only one basis and lose information.
3807
+ - Do not add new coverage rows.
3808
+ - Add termAdditions only when a provided source node directly supports the missing term and the candidate already has the correct coverage row.
3809
+ - When replacing one combined term with split terms, drop the combined term and add one term per basis. For example, "$1,000,000 Each Claim / Aggregate" should become one each_claim_limit term and one aggregate_limit term, both with value "$1,000,000".
3810
+ - When a schedule continues onto the next page before the next item marker, attach continuation terms such as "Aggregate", "Policy Aggregate", coinsurance, deductible, or retroactive date to the previous coverage row.
3811
+ - Drop a coverage row when it is only generic policy wording that points back to a declarations item or schedule and does not itself state policy-specific limits, deductibles, retentions, premiums, dates, or coverage names.
3791
3812
  - Include every JSON key in each decision. Use null for scalar fields you are not changing and [] for source ID lists you are not changing.
3792
- - For each coverage decision, always include termDecisions. Use [] when no terms need cleanup.
3813
+ - For each coverage decision, always include termDecisions and termAdditions. Use [] when no existing terms need cleanup or no new terms are needed.
3793
3814
  - Keep reasons concise and factual.
3794
3815
 
3795
3816
  Candidate projection:
@@ -3930,9 +3951,50 @@ function applyTermCleanupDecision(term, decision, validNodeIds, validSpanIds) {
3930
3951
  }
3931
3952
  return next;
3932
3953
  }
3954
+ function termAdditionTouches(addition, predicate) {
3955
+ return predicate({
3956
+ kind: addition.kind,
3957
+ label: cleanProfileValue(addition.label) ?? "",
3958
+ value: cleanProfileValue(addition.value) ?? ""
3959
+ });
3960
+ }
3933
3961
  function termDecisionsTouch(coverage, decisions, predicate) {
3934
3962
  return decisions.filter((decision) => decision.action !== "keep").some((decision) => termDecisionTouches(coverage, decision, predicate));
3935
3963
  }
3964
+ function termAdditionsTouch(additions, predicate) {
3965
+ return additions.some((addition) => termAdditionTouches(addition, predicate));
3966
+ }
3967
+ function termKey(term) {
3968
+ return [
3969
+ term.kind,
3970
+ cleanProfileValue(term.label)?.toLowerCase(),
3971
+ cleanProfileValue(term.value)?.toLowerCase()
3972
+ ].join("|");
3973
+ }
3974
+ function applyTermAddition(addition, validNodeIds, validSpanIds) {
3975
+ const label = cleanProfileValue(addition.label);
3976
+ const value = cleanProfileValue(addition.value);
3977
+ if (!label || !value) return void 0;
3978
+ const sourceNodeIds = validIds(addition.sourceNodeIds, validNodeIds);
3979
+ const sourceSpanIds = validIds(addition.sourceSpanIds, validSpanIds);
3980
+ if (sourceNodeIds.length === 0 && sourceSpanIds.length === 0) return void 0;
3981
+ const term = {
3982
+ kind: addition.kind,
3983
+ label,
3984
+ value,
3985
+ sourceNodeIds,
3986
+ sourceSpanIds
3987
+ };
3988
+ if (typeof addition.amount === "number" && Number.isFinite(addition.amount)) {
3989
+ term.amount = addition.amount;
3990
+ } else if (term.kind !== "retroactive_date") {
3991
+ const amount = amountFromOperationalValue(value);
3992
+ if (amount !== void 0) term.amount = amount;
3993
+ }
3994
+ const appliesTo = cleanProfileValue(addition.appliesTo);
3995
+ if (appliesTo) term.appliesTo = appliesTo;
3996
+ return term;
3997
+ }
3936
3998
  function applyCoverageCleanupDecision(coverage, decision, validNodeIds, validSpanIds) {
3937
3999
  if (!decision || decision.action === "keep") return coverage;
3938
4000
  if (decision.action === "drop") return void 0;
@@ -3963,23 +4025,31 @@ function applyCoverageCleanupDecision(coverage, decision, validNodeIds, validSpa
3963
4025
  const termDecisions = (decision.termDecisions ?? []).filter((termDecision) => termDecision.termIndex < coverage.limits.length);
3964
4026
  const termDecisionByIndex = new Map(termDecisions.map((termDecision) => [termDecision.termIndex, termDecision]));
3965
4027
  next.limits = coverage.limits.map((term, index) => applyTermCleanupDecision(term, termDecisionByIndex.get(index), validNodeIds, validSpanIds)).filter((term) => Boolean(term));
3966
- if (termDecisions.length > 0) {
3967
- if (decision.limit == null && termDecisionsTouch(coverage, termDecisions, isLimitTerm)) {
4028
+ const termAdditions = (decision.termAdditions ?? []).map((addition) => applyTermAddition(addition, validNodeIds, validSpanIds)).filter((term) => Boolean(term));
4029
+ const existingTermKeys = new Set(next.limits.map(termKey));
4030
+ for (const term of termAdditions) {
4031
+ const key = termKey(term);
4032
+ if (existingTermKeys.has(key)) continue;
4033
+ next.limits.push(term);
4034
+ existingTermKeys.add(key);
4035
+ }
4036
+ if (termDecisions.length > 0 || termAdditions.length > 0) {
4037
+ if (decision.limit == null && (termDecisionsTouch(coverage, termDecisions, isLimitTerm) || termAdditionsTouch(termAdditions, isLimitTerm))) {
3968
4038
  const value = primaryLimitFromTerms(next.limits);
3969
4039
  if (value) next.limit = value;
3970
4040
  else delete next.limit;
3971
4041
  }
3972
- if (decision.deductible == null && termDecisionsTouch(coverage, termDecisions, isDeductibleTerm)) {
4042
+ if (decision.deductible == null && (termDecisionsTouch(coverage, termDecisions, isDeductibleTerm) || termAdditionsTouch(termAdditions, isDeductibleTerm))) {
3973
4043
  const value = deductibleFromTerms(next.limits);
3974
4044
  if (value) next.deductible = value;
3975
4045
  else delete next.deductible;
3976
4046
  }
3977
- if (decision.premium == null && termDecisionsTouch(coverage, termDecisions, isPremiumTerm)) {
4047
+ if (decision.premium == null && (termDecisionsTouch(coverage, termDecisions, isPremiumTerm) || termAdditionsTouch(termAdditions, isPremiumTerm))) {
3978
4048
  const value = premiumFromTerms(next.limits);
3979
4049
  if (value) next.premium = value;
3980
4050
  else delete next.premium;
3981
4051
  }
3982
- if (decision.retroactiveDate == null && termDecisionsTouch(coverage, termDecisions, isRetroactiveDateTerm)) {
4052
+ if (decision.retroactiveDate == null && (termDecisionsTouch(coverage, termDecisions, isRetroactiveDateTerm) || termAdditionsTouch(termAdditions, isRetroactiveDateTerm))) {
3983
4053
  const value = retroactiveDateFromTerms(next.limits);
3984
4054
  if (value) next.retroactiveDate = value;
3985
4055
  else delete next.retroactiveDate;