DEV Community

Multigrid
Multigrid

Posted on • Originally published at multigrid.ai

Extracting Exclusions From an Insurance Policy Document

An exclusion is defined by what it removes from cover. That makes the set of exclusions in force the answer, and the set is not printed anywhere in the document. It has to be computed from a base form plus a stack of endorsements listed by number on a page that does not contain their text.

Why the exclusions are not where you look

The coverage form has a section headed “Exclusions” with a lettered list. On a general liability form that list runs from a. through to the letter the current edition happens to end at, covering expected or intended injury, contractual liability, liquor, workers compensation, employer’s liability, pollution, aircraft and autos, damage to property, damage to your product and your work, and so on. If you extract that list you have extracted the exclusions the form was printed with, which is not the same thing as the exclusions that apply.

Almost every real placement amends it. An endorsement removes an exclusion the insured paid to have removed, adds one the underwriter required, or replaces one with narrower or broader wording. The endorsements are physically in the PDF, usually after the coverage form, each a page or two of text beginning with a line saying which section of which form it modifies. Nothing in the coverage form points forward to them. The only forward pointer is the schedule of forms on the declarations page.

The consequence for extraction is direct: a single-pass read of the document with a prompt asking for “the exclusions” returns the base list, high confidence, wrong. It is wrong in the safest possible direction to look correct, because the base list is real text, correctly quoted, from the right document.

The schedule of forms is the index

The declarations page carries a schedule of forms and endorsements: a list of form numbers with edition dates and titles, one line per form attached to the policy. That list is the manifest. Extract it first, before any clause-level work, because everything downstream is a join against it.

An ISO form number is a stable identifier with an edition date attached — a two-letter line prefix, a numeric form identifier, and the month and year of the edition. Two things follow. First, the same form number in two editions is two different texts, so the edition date is part of the key, not decoration. Second, the number is exact enough to look up in a form library you maintain yourself, which means you can resolve the reference without reading the endorsement text at all when the text is a standard form — and you must read it when the form number is a carrier’s own manuscript endorsement, which is the case whenever the prefix is not one you recognise.

So the pipeline has three passes rather than one: extract the schedule, locate each listed form inside the document by its printed form number, then extract the modification each one makes. Each pass is cheap and checkable. The join between pass one and pass two is where the interesting failures live.

Added, deleted, replaced

An endorsement that touches an exclusion almost always announces what it does in its first line, and the verb is the field. The recurring patterns, in the language forms actually use:

  • Add. “The following exclusion is added to Section I — Coverages”. New exclusion, base list unchanged.
  • Delete. “Exclusion X. is deleted”. Cover restored. This is the case a base-list extraction gets exactly backwards, reporting an exclusion that has been bought out.
  • Replace. “Exclusion X. is replaced by the following”. Both the deletion and the addition, and the replacement text may be wider or narrower than what it replaced.
  • Amend in part. “Paragraph (2) of Exclusion X. does not apply to”. Surgical, and the piece being amended is identified by a sub-paragraph number that only exists in one edition of the form.

Two traps. An endorsement’s title is not a reliable guide to whether it touches an exclusion — an endorsement whose title is about adding an insured can carry an exclusion in its operative text, so title-based filtering drops real modifications. And the section letter it references is edition-specific: a rule that maps “Exclusion j.” to a named exclusion is correct for one edition of one form and silently wrong for another. Resolve the letter against the base form you actually attached, keyed by form number and edition, or store the reference unresolved and say so.

The exception inside the exclusion

Exclusions contain exceptions, and an exception restores cover. The text runs: this exclusion does not apply to, or but this exclusion does not apply if, or except with respect to. Extract the exclusion sentence without its exceptions and you have inverted the meaning of the passage for exactly the fact pattern the exception was negotiated to address.

This is a chunking problem before it is a prompting problem. Exclusion text is deeply nested — a lettered exclusion, numbered paragraphs beneath it, lettered sub-paragraphs beneath those, and an unnumbered trailing paragraph that qualifies the whole thing. Split it on sentences or on a fixed token window and the qualifier lands in a different chunk from the rule it qualifies. Split it on the numbering hierarchy and the structure survives. That means detecting the numbering scheme first, which is a layout and reading-order job rather than a semantic one; the general treatment is in how PDF text extraction reconstructs structure.

Model an exclusion as a node with its own text, an ordered list of child paragraphs, and an explicit list of exceptions, each carrying the text and the identifier of the paragraph it attaches to. A flat string field cannot express “this applies except in these three circumstances”, and a reviewer reading a flat string has no way to tell whether the exception was dropped or was never there.

A missing endorsement is the finding

Now the join pays for itself. You have a schedule listing every form attached to the policy, and you have the set of form numbers actually found printed in the document. The set difference is a real output.

A form listed on the schedule and absent from the PDF means the copy you were given is incomplete — a scan that missed pages, an email attachment that lost a section, a policy assembled from two deliveries. A form present in the PDF and absent from the schedule means either the schedule was extracted badly or a page from another policy is in the file. Both are conditions a person needs to see, and neither is visible to any per-field confidence score, because every field that was extracted was extracted perfectly well.

Report the completeness result as a first-class part of the extraction: forms expected, forms located, forms unresolved, and the exclusion set marked as partial whenever the unresolved list is not empty. A downstream consumer that receives a list of exclusions with no completeness marker will treat it as the answer. The absence of a clause is a finding, and it is only a finding if the schema has somewhere to put it.

Resolving a reference chain is not one call per document, it is one call for the schedule and one per endorsement, so a policy with fourteen endorsements is fifteen requests before the first exclusion is read. That shape rewards routing the cheap structural passes to a small model and reserving a larger one for endorsement text, and it makes per-request cost attribution genuinely useful — a gateway that tags each call with the policy it belongs to turns a bill into a cost per policy you can actually act on.

Related

Top comments (0)