@claritylabs/cl-sdk 3.2.9 → 3.2.11
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/README.md +6 -8
- package/dist/index.js +51 -232
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +51 -232
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3773,9 +3773,11 @@ Task:
|
|
|
3773
3773
|
Projection defects to look for:
|
|
3774
3774
|
- Generic labels such as "Column 3" that should be renamed from nearby row/header evidence.
|
|
3775
3775
|
- Declaration or section headers projected as coverage names when the row evidence is actually a specific coverage, sub-limit, deductible, retention, retroactive date, or premium.
|
|
3776
|
+
- Premium-only, tax-only, fee-only, rating, exposure, reporting-value, or payment-plan rows projected as coverage rows.
|
|
3776
3777
|
- Dangling continuation punctuation such as a trailing "/" copied into values.
|
|
3777
3778
|
- Item references such as "shown in Item 7" or bare item numbers treated as money amounts.
|
|
3778
3779
|
- Policy wording, exclusions, or unsupported prose copied into operational limit/deductible fields.
|
|
3780
|
+
- Premium, MGA Fee, taxes, stamping fees, total premium, total due, reporting values, or exposure annual rate used as a coverage limit.
|
|
3779
3781
|
- Header/value splits where "Limit of Liability", "Deductible", "Retroactive Date", "Aggregate", "Each Claim", or similar terms are attached to the wrong coverage row.
|
|
3780
3782
|
- Repeated schedule headings projected as separate coverages when they only introduce the next coverage group.
|
|
3781
3783
|
|
|
@@ -3785,7 +3787,8 @@ Rules:
|
|
|
3785
3787
|
- Use sourceNodeIds and sourceSpanIds only from the provided source nodes or from the existing candidate entry.
|
|
3786
3788
|
- Prefer dropping a malformed fact over speculative rewriting.
|
|
3787
3789
|
- Keep a coverage when it is a real operational coverage/benefit even if only one term needs cleanup.
|
|
3788
|
-
-
|
|
3790
|
+
- Drop a coverage row when its only facts are premium, tax, fee, rating, reporting-value, exposure, or payment-plan facts and it has no source-backed limit, deductible, retention, retroactive date, sublimit, or benefit term.
|
|
3791
|
+
- Never drop a declaration or schedule coverage row that names a coverage and states policy-specific limits, dates, deductibles, retentions, sublimits, or benefit terms. Repair its terms instead.
|
|
3789
3792
|
- When changing a term's semantic meaning, set kind to the corrected normalized term kind.
|
|
3790
3793
|
- Do not add new coverage rows or new terms; this pass cleans the existing projection.
|
|
3791
3794
|
- 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.
|
|
@@ -4207,36 +4210,6 @@ function spanPageEnd(span) {
|
|
|
4207
4210
|
function spanSourceUnit(span) {
|
|
4208
4211
|
return span.sourceUnit ?? span.metadata?.sourceUnit ?? span.metadata?.elementType;
|
|
4209
4212
|
}
|
|
4210
|
-
function formNumberFromText(value) {
|
|
4211
|
-
return cleanText(value, "").match(/\b[A-Z]{2,}(?:-[A-Z0-9]+)+\s+\d{2}\s+\d{2}\b/)?.[0]?.replace(/\s+/g, " ");
|
|
4212
|
-
}
|
|
4213
|
-
function editionDateFromFormNumber(formNumber) {
|
|
4214
|
-
const match = formNumber?.match(/\b(\d{2})\s+(\d{2})$/);
|
|
4215
|
-
return match ? `${match[1]}/${match[2]}` : void 0;
|
|
4216
|
-
}
|
|
4217
|
-
function pageTitleFromText(text, fallback) {
|
|
4218
|
-
const normalized = cleanText(text, fallback);
|
|
4219
|
-
const patterns = [
|
|
4220
|
-
/\bIMPORTANT NOTICE\s+[—-]\s+HOW TO REPORT A CLAIM\b/i,
|
|
4221
|
-
/\bPRIVACY NOTICE TO POLICYHOLDERS\b/i,
|
|
4222
|
-
/\bOFAC ADVISORY NOTICE\b/i,
|
|
4223
|
-
/\bTERRORISM RISK INSURANCE ACT\s*\(TRIA\)\s*DISCLOSURE AND REJECTION\b/i,
|
|
4224
|
-
/\bDECLARATIONS PAGE\b/i,
|
|
4225
|
-
/\bTECHNOLOGY ERRORS?\s*&\s*OMISSIONS AND CYBER LIABILITY INSURANCE POLICY\b/i,
|
|
4226
|
-
/\bTRADE OR ECONOMIC SANCTIONS LIMITATION\b/i,
|
|
4227
|
-
/\bFORMS? AND ENDORSEMENTS\b/i
|
|
4228
|
-
];
|
|
4229
|
-
for (const pattern of patterns) {
|
|
4230
|
-
const match = normalized.match(pattern)?.[0];
|
|
4231
|
-
if (match) return cleanText(match, fallback);
|
|
4232
|
-
}
|
|
4233
|
-
const endorsement = normalized.match(/\bENDORSEMENT\s+(?:NO\.?|NUMBER|#)\s*[A-Z0-9][A-Z0-9.-]*\b/i)?.[0];
|
|
4234
|
-
if (endorsement) return cleanText(endorsement, fallback);
|
|
4235
|
-
const firstSentence = normalized.split(/(?<=\.)\s+/)[0];
|
|
4236
|
-
if (/^page\s+\d+\b/i.test(firstSentence)) return fallback;
|
|
4237
|
-
if (firstSentence && firstSentence.length <= 120) return firstSentence.replace(/[.]$/, "");
|
|
4238
|
-
return fallback;
|
|
4239
|
-
}
|
|
4240
4213
|
function pageHeadingTitleFromText(text, fallback) {
|
|
4241
4214
|
const normalized = cleanText(text, "");
|
|
4242
4215
|
const headingText = normalized.replace(/^page\s+\d+\s*(?:\|\s*page\s*\|\s*page\s+\d+\s*\|?)?/i, "").slice(0, 700);
|
|
@@ -4256,194 +4229,9 @@ function pageHeadingTitleFromText(text, fallback) {
|
|
|
4256
4229
|
}
|
|
4257
4230
|
return fallback;
|
|
4258
4231
|
}
|
|
4259
|
-
function pageFormTypeFromText(text) {
|
|
4260
|
-
if (hasSubstantiveDeclarationsScheduleText(text)) return "declarations";
|
|
4261
|
-
if (/\b(declarations?\s+page|declarations?\s+schedule)\b/i.test(text)) return "declarations";
|
|
4262
|
-
if (/\b(endorsement\s+(?:no\.?|number|#)|this endorsement changes the policy|[A-Z]{2,}-END\s+\d{2,})\b/i.test(text)) return "endorsement";
|
|
4263
|
-
if (/\b(technology errors?\s*&?\s*omissions.*liability insurance policy|policy form|coverage form|insuring agreement|definitions?|exclusions?|conditions?)\b/i.test(text)) return "coverage";
|
|
4264
|
-
if (/\b(important notice|privacy notice|ofac advisory|terrorism risk insurance act|tria|trade or economic sanctions)\b/i.test(text)) return "notice";
|
|
4265
|
-
return "other";
|
|
4266
|
-
}
|
|
4267
4232
|
function hasSubstantiveDeclarationsScheduleText(text) {
|
|
4268
4233
|
return /\bitem\s+\d+\.?\s*(?:named insured|policy number|policy period|renewal|form of business|coverage parts?|limits?|premium|extended reporting|producer|forms? and endorsements?)\b/i.test(text) || /\bforms? and endorsements attached at inception\b/i.test(text) || /\bcoverage parts?,?\s+limits? of liability,?\s+deductibles?,?\s+and retroactive dates\b/i.test(text) || /\bannual premium\s*\(all coverage parts?\)\b/i.test(text) || /\berp option\b/i.test(text) || /\bproducer\b[\s\S]{0,240}\blicense\b/i.test(text);
|
|
4269
4234
|
}
|
|
4270
|
-
function administrativeFormTypeFromText(text) {
|
|
4271
|
-
if (hasSubstantiveDeclarationsScheduleText(text)) return void 0;
|
|
4272
|
-
if (/\b(important notice|privacy notice|ofac advisory|terrorism risk insurance act|tria|trade or economic sanctions|economic sanctions limitation|how to report a claim)\b/i.test(text)) {
|
|
4273
|
-
return "notice";
|
|
4274
|
-
}
|
|
4275
|
-
if (/\b(specimen policy|policy jacket|countersigned|countersignature|licensed resident agent|corporate secretary|president and ceo|application of insurance executed)\b/i.test(text)) {
|
|
4276
|
-
return "other";
|
|
4277
|
-
}
|
|
4278
|
-
return void 0;
|
|
4279
|
-
}
|
|
4280
|
-
function pageTextByNumber(sourceSpans) {
|
|
4281
|
-
const pageTexts = /* @__PURE__ */ new Map();
|
|
4282
|
-
const pageSpanTexts = /* @__PURE__ */ new Map();
|
|
4283
|
-
for (const span of sourceSpans) {
|
|
4284
|
-
const start = spanPageStart(span);
|
|
4285
|
-
if (typeof start !== "number") continue;
|
|
4286
|
-
const end = spanPageEnd(span) ?? start;
|
|
4287
|
-
for (let page = start; page <= end; page += 1) {
|
|
4288
|
-
if (spanSourceUnit(span) === "page") {
|
|
4289
|
-
pageSpanTexts.set(page, cleanText(span.text, ""));
|
|
4290
|
-
continue;
|
|
4291
|
-
}
|
|
4292
|
-
const existing = pageTexts.get(page) ?? "";
|
|
4293
|
-
if (existing.length < 4e3) pageTexts.set(page, cleanText([existing, span.text].filter(Boolean).join(" "), ""));
|
|
4294
|
-
}
|
|
4295
|
-
}
|
|
4296
|
-
return new Map([.../* @__PURE__ */ new Set([...pageTexts.keys(), ...pageSpanTexts.keys()])].map((page) => [
|
|
4297
|
-
page,
|
|
4298
|
-
pageSpanTexts.get(page) ?? pageTexts.get(page) ?? ""
|
|
4299
|
-
]));
|
|
4300
|
-
}
|
|
4301
|
-
function reconcileFormTypeWithSourceText(form, pageTexts) {
|
|
4302
|
-
const pages = [];
|
|
4303
|
-
const start = form.pageStart;
|
|
4304
|
-
const end = form.pageEnd ?? start;
|
|
4305
|
-
if (typeof start === "number" && typeof end === "number") {
|
|
4306
|
-
for (let page = start; page <= end; page += 1) pages.push(pageTexts.get(page) ?? "");
|
|
4307
|
-
}
|
|
4308
|
-
const text = cleanText([form.title, form.formNumber, ...pages].filter(Boolean).join(" "), "");
|
|
4309
|
-
const administrativeType = administrativeFormTypeFromText(text);
|
|
4310
|
-
if (administrativeType && form.formType !== administrativeType) return administrativeType;
|
|
4311
|
-
return form.formType;
|
|
4312
|
-
}
|
|
4313
|
-
function inferFormHintsFromSourceSpans(sourceSpans) {
|
|
4314
|
-
const pageTexts = pageTextByNumber(sourceSpans);
|
|
4315
|
-
if (pageTexts.size === 0) return [];
|
|
4316
|
-
const pageHints = [...pageTexts.keys()].sort((left, right) => left - right).map((page) => {
|
|
4317
|
-
const text = pageTexts.get(page) ?? "";
|
|
4318
|
-
const formNumber = formNumberFromText(text);
|
|
4319
|
-
return {
|
|
4320
|
-
formNumber,
|
|
4321
|
-
editionDate: editionDateFromFormNumber(formNumber),
|
|
4322
|
-
title: pageTitleFromText(text, `Page ${page}`),
|
|
4323
|
-
formType: pageFormTypeFromText(text),
|
|
4324
|
-
pageStart: page,
|
|
4325
|
-
pageEnd: page
|
|
4326
|
-
};
|
|
4327
|
-
});
|
|
4328
|
-
const merged = [];
|
|
4329
|
-
for (const hint of pageHints) {
|
|
4330
|
-
const previous = merged[merged.length - 1];
|
|
4331
|
-
const startsNewEndorsement = hint.formType === "endorsement" && /\bendorsement\s+(?:no\.?|number|#)\s*[A-Z0-9]|this endorsement changes the policy/i.test(hint.title ?? "");
|
|
4332
|
-
const canMerge = previous && previous.formType === hint.formType && previous.pageEnd !== void 0 && hint.pageStart === previous.pageEnd + 1 && (hint.formType === "declarations" || hint.formType === "coverage" || hint.formType === "endorsement" && !startsNewEndorsement);
|
|
4333
|
-
if (!canMerge) {
|
|
4334
|
-
merged.push(hint);
|
|
4335
|
-
continue;
|
|
4336
|
-
}
|
|
4337
|
-
previous.pageEnd = hint.pageEnd;
|
|
4338
|
-
previous.title = previous.title ?? hint.title;
|
|
4339
|
-
previous.formNumber = previous.formNumber ?? hint.formNumber;
|
|
4340
|
-
previous.editionDate = previous.editionDate ?? hint.editionDate;
|
|
4341
|
-
}
|
|
4342
|
-
return merged;
|
|
4343
|
-
}
|
|
4344
|
-
function normalizeFormHints(forms, sourceSpans) {
|
|
4345
|
-
const pageTexts = pageTextByNumber(sourceSpans);
|
|
4346
|
-
const provided = (forms ?? []).filter(
|
|
4347
|
-
(form) => typeof form.pageStart === "number" && typeof form.pageEnd === "number" && form.pageStart > 0 && form.pageEnd >= form.pageStart
|
|
4348
|
-
).map((form) => ({
|
|
4349
|
-
...form,
|
|
4350
|
-
formType: reconcileFormTypeWithSourceText(form, pageTexts),
|
|
4351
|
-
title: form.title ? cleanText(form.title, "") : void 0
|
|
4352
|
-
})).sort(
|
|
4353
|
-
(left, right) => (left.pageStart ?? Number.MAX_SAFE_INTEGER) - (right.pageStart ?? Number.MAX_SAFE_INTEGER) || (left.pageEnd ?? Number.MAX_SAFE_INTEGER) - (right.pageEnd ?? Number.MAX_SAFE_INTEGER)
|
|
4354
|
-
);
|
|
4355
|
-
return provided.length ? provided : inferFormHintsFromSourceSpans(sourceSpans);
|
|
4356
|
-
}
|
|
4357
|
-
function formHintForPage(forms, page) {
|
|
4358
|
-
return forms.find(
|
|
4359
|
-
(form) => typeof form.pageStart === "number" && typeof form.pageEnd === "number" && page >= form.pageStart && page <= form.pageEnd
|
|
4360
|
-
);
|
|
4361
|
-
}
|
|
4362
|
-
function titleFromFormHint(form, fallback) {
|
|
4363
|
-
if (form.formType === "declarations") return "Declarations";
|
|
4364
|
-
if (form.formType === "coverage") return "Policy Form";
|
|
4365
|
-
if (form.formType === "endorsement") return endorsementTitle([form.title, form.formNumber].filter(Boolean).join(" ")) ?? cleanText(form.title, fallback);
|
|
4366
|
-
return cleanText(form.title, fallback);
|
|
4367
|
-
}
|
|
4368
|
-
function formGroupConfig(form) {
|
|
4369
|
-
if (form.formType === "declarations") {
|
|
4370
|
-
return {
|
|
4371
|
-
kind: "page_group",
|
|
4372
|
-
title: "Declarations",
|
|
4373
|
-
description: "Declarations pages and schedules grouped from form inventory",
|
|
4374
|
-
organizer: "form_inventory_declarations_grouping"
|
|
4375
|
-
};
|
|
4376
|
-
}
|
|
4377
|
-
if (form.formType === "coverage") {
|
|
4378
|
-
return {
|
|
4379
|
-
kind: "form",
|
|
4380
|
-
title: "Policy Form",
|
|
4381
|
-
description: "Policy form pages grouped from form inventory",
|
|
4382
|
-
organizer: "form_inventory_policy_form_grouping"
|
|
4383
|
-
};
|
|
4384
|
-
}
|
|
4385
|
-
if (form.formType === "endorsement") {
|
|
4386
|
-
const title = titleFromFormHint(form, "Endorsement");
|
|
4387
|
-
return {
|
|
4388
|
-
kind: "endorsement",
|
|
4389
|
-
title,
|
|
4390
|
-
description: `${title} grouped from form inventory`,
|
|
4391
|
-
organizer: "form_inventory_endorsement_grouping"
|
|
4392
|
-
};
|
|
4393
|
-
}
|
|
4394
|
-
return void 0;
|
|
4395
|
-
}
|
|
4396
|
-
function applyFormInventoryHints(sourceTree, forms) {
|
|
4397
|
-
if (forms.length === 0) return sourceTree;
|
|
4398
|
-
const rootId = sourceTreeRootId(sourceTree);
|
|
4399
|
-
if (!rootId) return sourceTree;
|
|
4400
|
-
const byParent = nodesByParent(sourceTree);
|
|
4401
|
-
const children = (byParent.get(rootId) ?? []).filter((node) => node.kind !== "document").sort((left, right) => left.order - right.order);
|
|
4402
|
-
const rootPages = children.filter((node) => node.kind === "page" && typeof node.pageStart === "number");
|
|
4403
|
-
let nextTree = sourceTree.map((node) => {
|
|
4404
|
-
if (node.kind !== "page" || typeof node.pageStart !== "number") return node;
|
|
4405
|
-
const form = formHintForPage(forms, node.pageStart);
|
|
4406
|
-
if (!form) return node;
|
|
4407
|
-
const isStartPage = form.pageStart === node.pageStart;
|
|
4408
|
-
const shouldRetitle = isStartPage && form.formType !== "other";
|
|
4409
|
-
return {
|
|
4410
|
-
...node,
|
|
4411
|
-
title: shouldRetitle ? titleFromFormHint(form, node.title) : node.title,
|
|
4412
|
-
metadata: {
|
|
4413
|
-
...node.metadata,
|
|
4414
|
-
formInventoryHint: {
|
|
4415
|
-
formType: form.formType,
|
|
4416
|
-
formNumber: form.formNumber,
|
|
4417
|
-
title: form.title,
|
|
4418
|
-
pageStart: form.pageStart,
|
|
4419
|
-
pageEnd: form.pageEnd
|
|
4420
|
-
}
|
|
4421
|
-
}
|
|
4422
|
-
};
|
|
4423
|
-
});
|
|
4424
|
-
const claimed = /* @__PURE__ */ new Set();
|
|
4425
|
-
for (const form of forms) {
|
|
4426
|
-
const config = formGroupConfig(form);
|
|
4427
|
-
const pageStart2 = form.pageStart;
|
|
4428
|
-
const pageEnd2 = form.pageEnd;
|
|
4429
|
-
if (!config || typeof pageStart2 !== "number" || typeof pageEnd2 !== "number") continue;
|
|
4430
|
-
const childIds = rootPages.filter(
|
|
4431
|
-
(page) => !claimed.has(page.id) && typeof page.pageStart === "number" && page.pageStart >= pageStart2 && page.pageStart <= pageEnd2
|
|
4432
|
-
).map((page) => page.id);
|
|
4433
|
-
if (childIds.length === 0) continue;
|
|
4434
|
-
nextTree = groupAdjacentChildren({
|
|
4435
|
-
sourceTree: nextTree,
|
|
4436
|
-
children,
|
|
4437
|
-
childIds,
|
|
4438
|
-
kind: config.kind,
|
|
4439
|
-
title: config.title,
|
|
4440
|
-
description: config.description,
|
|
4441
|
-
organizer: config.organizer
|
|
4442
|
-
});
|
|
4443
|
-
childIds.forEach((id) => claimed.add(id));
|
|
4444
|
-
}
|
|
4445
|
-
return normalizeDocumentSourceTreePaths(nextTree);
|
|
4446
|
-
}
|
|
4447
4235
|
function looksLikeDeclarationsStart(node) {
|
|
4448
4236
|
const title = cleanText(node.title, "");
|
|
4449
4237
|
const text = sourceNodeText(node);
|
|
@@ -4454,13 +4242,13 @@ function looksLikeDeclarationsStart(node) {
|
|
|
4454
4242
|
}
|
|
4455
4243
|
function looksLikeDeclarationsContinuation(node) {
|
|
4456
4244
|
const text = sourceNodeText(node);
|
|
4457
|
-
return looksLikeDeclarationsStart(node) || /\b(item\s+\d+\.|coverage part|each claim limit|aggregate limit|retroactive date|self-insured retention|premium|payment plan|producer|broker|forms? and endorsements?|extended reporting period|discovery period)\b/i.test(text);
|
|
4245
|
+
return looksLikeDeclarationsStart(node) || /\b(item\s+\d+\.|coverage part|limits?,?\s+sub-limits?|each claim limit|aggregate limit|retroactive date|self-insured retention|premium|payment plan|producer|broker|forms? and endorsements?|attached at inception|extended reporting period|discovery period)\b/i.test(text) || /\b(these declarations|policy form|[A-Z]{2,}-END\s+\d{3}|endorsement\s+(?:no\.?|number|#)?\s*\d+)\b/i.test(text);
|
|
4458
4246
|
}
|
|
4459
4247
|
function looksLikePolicyFormStart(node) {
|
|
4460
4248
|
const text = sourceNodeText(node);
|
|
4461
4249
|
const excerpt = cleanText(node.textExcerpt, "");
|
|
4462
4250
|
if (isAdministrativeNoticeNode(node) || looksLikeDeclarationsStart(node)) return false;
|
|
4463
|
-
return /\bpolicy form\b/i.test(node.title) || /^policy\s+form\b/i.test(excerpt) || /\btechnology errors?\s*&?\s*omissions\b/i.test(text) && /\bplease read this entire policy carefully\b/i.test(text) || /\bform\s+[A-Z]{2,}-[A-Z0-9-]+\s+\d{2}\s+\d{2}\b/i.test(text);
|
|
4251
|
+
return /\bpolicy form\b/i.test(node.title) || /^policy\s+form\b/i.test(excerpt) || /\btechnology errors?\s*&?\s*omissions\b/i.test(text) && /\bplease read this entire policy carefully\b/i.test(text) || /\bsection\s+[IVX0-9]+\s*[—-]\s*(insuring agreements?|definitions?|exclusions?|conditions?)\b/i.test(text) || /\bform\s+[A-Z]{2,}-[A-Z0-9-]+\s+\d{2}\s+\d{2}\b/i.test(text);
|
|
4464
4252
|
}
|
|
4465
4253
|
function looksLikePolicyFormContinuation(node) {
|
|
4466
4254
|
const text = sourceNodeText(node);
|
|
@@ -5222,25 +5010,51 @@ function isOperationalEvidenceAnchor(span) {
|
|
|
5222
5010
|
if (/\$[\d,.]+|[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{2,4}|[0-9]{1,2}\s+[A-Za-z]{3,9}\s+[0-9]{4}/.test(text)) return true;
|
|
5223
5011
|
return false;
|
|
5224
5012
|
}
|
|
5013
|
+
function operationalEvidencePages(sourceSpans) {
|
|
5014
|
+
const scores = /* @__PURE__ */ new Map();
|
|
5015
|
+
for (const span of sourceSpans) {
|
|
5016
|
+
const page = spanPageStart(span);
|
|
5017
|
+
if (typeof page !== "number") continue;
|
|
5018
|
+
const text = cleanText([span.text, span.formNumber, spanSourceUnit(span)].filter(Boolean).join(" "), "");
|
|
5019
|
+
if (!text) continue;
|
|
5020
|
+
let score = Math.max(0, operationalEvidenceScore(span));
|
|
5021
|
+
if (/\bdeclarations?\s+(page|schedule)?\b/i.test(text)) score += 24;
|
|
5022
|
+
if (/\bitem\s+\d+\.?\s*(?:named insured|policy number|policy period|coverage parts?|limits?|premium|producer|forms? and endorsements?)\b/i.test(text)) score += 20;
|
|
5023
|
+
if (/\bcoverage parts?,?\s+limits? of liability,?\s+deductibles?,?\s+and retroactive dates\b/i.test(text)) score += 24;
|
|
5024
|
+
if (/\b(policy\s*(number|period|term)|effective date|expiration date|expiry date|named insured|insurer|carrier|security)\b/i.test(text)) score += 12;
|
|
5025
|
+
if (/\b(premium|total due|tax|fee|producer|broker)\b/i.test(text)) score += 10;
|
|
5026
|
+
if (/\b(endorsement\s+(?:no\.?|number|#)?\s*[A-Z0-9]|attached at inception|forms? and endorsements?)\b/i.test(text)) score += 8;
|
|
5027
|
+
if (/\b(definitions?|exclusions?|conditions?|duties in the event|action against|cancellation by)\b/i.test(text)) score -= 12;
|
|
5028
|
+
if (score > 0) scores.set(page, (scores.get(page) ?? 0) + score);
|
|
5029
|
+
}
|
|
5030
|
+
return new Set(
|
|
5031
|
+
[...scores.entries()].filter(([, score]) => score >= 18).sort((left, right) => right[1] - left[1] || left[0] - right[0]).slice(0, 12).map(([page]) => page)
|
|
5032
|
+
);
|
|
5033
|
+
}
|
|
5225
5034
|
function operationalProfileEvidence(sourceTree, sourceSpans) {
|
|
5226
5035
|
const sorted = [...sourceSpans].sort(
|
|
5227
5036
|
(left, right) => (spanPageStart(left) ?? Number.MAX_SAFE_INTEGER) - (spanPageStart(right) ?? Number.MAX_SAFE_INTEGER) || (left.location?.charStart ?? Number.MAX_SAFE_INTEGER) - (right.location?.charStart ?? Number.MAX_SAFE_INTEGER) || left.id.localeCompare(right.id)
|
|
5228
5037
|
);
|
|
5038
|
+
const selectedPages = operationalEvidencePages(sorted);
|
|
5229
5039
|
const selected = /* @__PURE__ */ new Set();
|
|
5230
5040
|
const selectedTableIds = /* @__PURE__ */ new Set();
|
|
5231
5041
|
for (let index = 0; index < sorted.length; index += 1) {
|
|
5232
|
-
const
|
|
5042
|
+
const span = sorted[index];
|
|
5043
|
+
const score = operationalEvidenceScore(span);
|
|
5233
5044
|
if (score < 8) continue;
|
|
5234
|
-
if (!isOperationalEvidenceAnchor(
|
|
5235
|
-
const
|
|
5236
|
-
if (
|
|
5237
|
-
const
|
|
5238
|
-
|
|
5045
|
+
if (!isOperationalEvidenceAnchor(span)) continue;
|
|
5046
|
+
const page = spanPageStart(span);
|
|
5047
|
+
if (selectedPages.size > 0 && typeof page === "number" && !selectedPages.has(page) && score < 30) continue;
|
|
5048
|
+
const tableId2 = spanTableId(span);
|
|
5049
|
+
if (tableId2 && !isTableCellSpan(span)) selectedTableIds.add(tableId2);
|
|
5050
|
+
const neighborWindow = score >= 24 ? 2 : 1;
|
|
5051
|
+
for (let offset = -neighborWindow; offset <= neighborWindow; offset += 1) {
|
|
5239
5052
|
const neighborIndex = index + offset;
|
|
5240
5053
|
const neighbor = sorted[neighborIndex];
|
|
5241
5054
|
if (!neighbor || spanPageStart(neighbor) !== page) continue;
|
|
5055
|
+
if (selectedPages.size > 0 && typeof page === "number" && !selectedPages.has(page) && operationalEvidenceScore(neighbor) < 30) continue;
|
|
5242
5056
|
const neighborText = cleanText(neighbor.text, "");
|
|
5243
|
-
if (!neighborText || neighborText.length >
|
|
5057
|
+
if (!neighborText || neighborText.length > 3e3) continue;
|
|
5244
5058
|
selected.add(neighborIndex);
|
|
5245
5059
|
}
|
|
5246
5060
|
}
|
|
@@ -5249,7 +5063,7 @@ function operationalProfileEvidence(sourceTree, sourceSpans) {
|
|
|
5249
5063
|
const tableId2 = spanTableId(span);
|
|
5250
5064
|
if (!tableId2 || !selectedTableIds.has(tableId2) || isTableCellSpan(span)) return;
|
|
5251
5065
|
const text = cleanText(span.text, "");
|
|
5252
|
-
if (text && text.length <=
|
|
5066
|
+
if (text && text.length <= 3e3) selected.add(index);
|
|
5253
5067
|
});
|
|
5254
5068
|
}
|
|
5255
5069
|
const nodeIdsBySpanId = sourceNodeIdsBySpanId(sourceTree);
|
|
@@ -5267,12 +5081,12 @@ function operationalProfileEvidence(sourceTree, sourceSpans) {
|
|
|
5267
5081
|
pageEnd: spanPageEnd(span),
|
|
5268
5082
|
sourceUnit: spanSourceUnit(span),
|
|
5269
5083
|
formNumber: span.formNumber,
|
|
5270
|
-
text: text.slice(0, span.sourceUnit === "page" ?
|
|
5084
|
+
text: text.slice(0, span.sourceUnit === "page" ? 900 : 700)
|
|
5271
5085
|
}];
|
|
5272
5086
|
});
|
|
5273
5087
|
const detailEntries = entries.filter((entry) => entry.sourceUnit !== "page");
|
|
5274
5088
|
const pageEntries = entries.filter((entry) => entry.sourceUnit === "page");
|
|
5275
|
-
return [...detailEntries, ...pageEntries
|
|
5089
|
+
return [...detailEntries.slice(0, 80), ...pageEntries.slice(0, 8)];
|
|
5276
5090
|
}
|
|
5277
5091
|
function sourceTreeRootId(sourceTree) {
|
|
5278
5092
|
return sourceTree.find((node) => node.kind === "document")?.id;
|
|
@@ -5315,13 +5129,15 @@ Rules:
|
|
|
5315
5129
|
- When citing an evidence entry, copy its sourceSpanId into the returned sourceSpanIds array.
|
|
5316
5130
|
- If a value is not directly supported, omit it.
|
|
5317
5131
|
- Prefer declarations, schedules, premium tables, and endorsement schedules over generic policy wording.
|
|
5132
|
+
- For effective, expiration, retroactive, and other date fields, return a normalized YYYY-MM-DD value when the source date is unambiguous, including month-name dates such as "20 Feb 2026". Do not emit fragmented date text such as "20 2 2026".
|
|
5318
5133
|
- For broker/producer, extract the agency or company legal name, not the license role, credential, or type. In a block like "Bayshore Insurance Brokers, LLC" followed by "Surplus Lines Broker - CA License No. ...", broker.value must be "Bayshore Insurance Brokers, LLC"; the surplus-lines role and license number are not the broker name.
|
|
5319
5134
|
- On declarations pages, treat "Item N" labels as section boundaries. Use Item 6 or equivalent coverage-schedule rows for coverage limits, deductibles, aggregate terms, and retroactive dates; do not merge Item 7 premium, Item 8 ERP, Item 9 producer, or Item 10 forms into Item 6 coverage facts.
|
|
5135
|
+
- Premium, tax, fee, payment-plan, rating, exposure, and reporting-value schedules are billing evidence, not coverage schedules. Extract the total policy premium into premium when supported, but do not create coverages[] entries from premium-only or fee-only rows, and never use Total Premium, MGA Fee, tax, stamping fee, reporting values, or exposure annual rate as a coverage limit.
|
|
5320
5136
|
- A coverage schedule row's coverage name should come from the "Coverage Part" or equivalent row label. Limit, deductible, aggregate, sublimit, retention, and retroactive-date values belong as nested terms under that coverage, not in the coverage title.
|
|
5321
5137
|
- If a coverage schedule continues onto the next page before the next item marker, include the continuation rows in the same coverage or declaration item.
|
|
5322
5138
|
- If one schedule row or continuation row states the same amount with multiple bases, such as "$1,000,000 Each Claim / Aggregate", return separate limit terms for each basis using the same value instead of one combined "Each Claim / Aggregate" term.
|
|
5323
5139
|
- LiteParse text can fragment visual table cells into adjacent lines. Before extracting coverage terms, mentally join adjacent lines in the same declaration item or schedule row. For example, "$2,000,000 Policy Each Claim" followed immediately by "Aggregate" means "$2,000,000 Policy Aggregate"; a line ending with "/" followed by "Aggregate ..." means the limit cell continues, not a new coverage.
|
|
5324
|
-
- Forms-and-endorsements schedules are
|
|
5140
|
+
- Forms-and-endorsements schedules are form schedule evidence, not coverage limits. Do not turn form schedule rows into coverage units unless the row also states a coverage-specific limit or deductible.
|
|
5325
5141
|
- Keep each coverage unit tied to one evidence scope: a declaration/core schedule row, a core policy form section, or one specific endorsement schedule. Do not merge declaration facts and endorsement schedule facts into the same coverage unit, even when they use the same coverage name.
|
|
5326
5142
|
- If the declarations schedule and an endorsement schedule both list Network Security, Social Engineering Fraud, Regulatory Proceedings, or another same-named coverage, return separate coverage units for each supported source scope.
|
|
5327
5143
|
- Use the declaration coverage name for declaration/core schedule rows. Use the endorsement title or endorsement schedule coverage name for endorsement rows, and include formNumber and endorsementNumber when source-backed.
|
|
@@ -5366,7 +5182,10 @@ var NORMALIZED_COMPATIBILITY_FIELDS = /* @__PURE__ */ new Set([
|
|
|
5366
5182
|
"policyNumber",
|
|
5367
5183
|
"namedInsured",
|
|
5368
5184
|
"insurer",
|
|
5369
|
-
"broker"
|
|
5185
|
+
"broker",
|
|
5186
|
+
"effectiveDate",
|
|
5187
|
+
"expirationDate",
|
|
5188
|
+
"retroactiveDate"
|
|
5370
5189
|
]);
|
|
5371
5190
|
function valueOf(profile, key) {
|
|
5372
5191
|
const value = profile[key];
|
|
@@ -5560,8 +5379,8 @@ async function cleanupOperationalCoverageSchedules(params) {
|
|
|
5560
5379
|
}
|
|
5561
5380
|
async function runSourceTreeExtraction(params) {
|
|
5562
5381
|
const sourceSpans = normalizeSourceSpans(params.sourceSpans);
|
|
5563
|
-
const formHints =
|
|
5564
|
-
let sourceTree = applySemanticPageGrouping(
|
|
5382
|
+
const formHints = [];
|
|
5383
|
+
let sourceTree = applySemanticPageGrouping(buildDocumentSourceTree(sourceSpans, params.id));
|
|
5565
5384
|
const warnings = [];
|
|
5566
5385
|
let modelCalls = 0;
|
|
5567
5386
|
let callsWithUsage = 0;
|