• contact@verticalserve.com
Home / Engineering / Post 91
Engineering Blog · Post #91

Three Quotes for One Submission: How InsightUW Does Multi-Option Programs Without Forking the Quote Entity

From "the broker called asking about Option B but I sent them Option A; let me re-issue" to "Option A, B, C are real quote rows under one set; the broker picked B; the policy bound from B; audit trail intact" — through one grouping table, twelve options max, and a deliberate refusal to invent a parent-child quote tree.


The Problem

A broker calls. "Hey, we love the $5M limit option, but the CFO is asking about a $10M version with a higher deductible — and what about a layered program at $5M xs $5M? Send all three by tomorrow." The UW types furiously and produces three quote letters, three premium calculations, three subjectivity lists. Two days later the broker emails: "Going with the layered one." The UW now has to remember which of the three rows in the database that is, copy the right one, mark the others "not selected somehow," and somehow produce a one-page comparison sheet that legal asked for last week.

The usual fixes don't fix:

  • One quote row with options stored as JSON. Now subjectivities, referrals, forms, the email composer all need to learn that "premium" might be three values. They don't. Things break.
  • Three independent quotes with no grouping. Comparison sheets are a manual exercise; "which option won?" requires hunting through email; the broker thinks it's a price increase, not a structure choice.
  • Parent-child quote tree. Tempting. Catastrophic. Every binding-eligibility, subjectivity-rollup, referrals query becomes conditional on tree depth.

The root cause: the system treats quote as the unit of work, but programs presented to a broker are a different unit. Without a grouping concept, you're forced to choose between collapsing the options or duplicating everything to keep them apart.

The InsightUW Approach

Add a set above the quote — and stop there. Real quote rows under one Quote Option Set. Every existing system that keys off quote id continues to work; the set carries the intent of "these are alternatives I'm presenting together."

graph TD subgraph Submission["Submission Queue"] SUB["Acme Holdings — D&O 2026"] end subgraph Set["Quote Option Set"] S["set name: '3-option program'<br/>set purpose: program options<br/>selected quote guid: → Option B<br/>comparison document guid: → PDF"] end subgraph Quotes["Quote rows (real, indexed, fully-functional)"] A["Option A · $5M limit · $25k ded<br/>Premium $182,500"] B["Option B · $10M limit · $50k ded<br/>Premium $278,000<br/>★ is selected"] C["Option C · $5M xs $5M layered<br/>Premium $215,000"] end subgraph Generator["Variant generator (coordinator)"] G["Loops Quote create primitive<br/>Cap 12 options/set<br/>matrix / layers / coverage"] end subgraph Bind["Bind"] POL["Policy<br/>source quote guid: → Option B<br/>source option set guid: → Set"] end SUB --> S S --> A S --> B S --> C G --> A G --> B G --> C B -->|"broker picks"| POL

Three input shapes, one generator

The variant generator takes three composable inputs and loops the quote-creation primitive:

  • Priced matrix[{total_limit: 5_000_000, deductible: 25_000}, {10_000_000, 50_000}]
  • Layer variants[{option_label: "Layered", layers: [{layer_number: 1, limit: 5M, attachment_point: 0}, {layer_number: 2, limit: 5M, attachment_point: 5M}]}]
  • Coverage variants — same numbers, different attached Quote Form bundles

These compose. A 3×2 matrix × 2 coverage variants = 12 quotes. The generator caps at 12 per set; a typo doesn't fan out 400 rows.

Two selection columns, deliberately

The UW marks Option A as their preferred — "this is what I'm pushing." The broker comes back asking for Option B. The soft pin doesn't have to change. Policy.source_quote_guid records what bound, regardless of the soft pin. Different decisions, different fields.

Worked Example: Acme Holdings, D&O Renewal

Sarah is renewing Acme Holdings' D&O. The broker (Marsh) wants three options on the desk by Friday.

Step 1 — Open the options panel

Sarah opens /uw/quotes/QT-2026-DO-0188 and clicks Add options. The drawer opens; she clicks New set, names it "Acme renewal — 3-option program," picks program options purpose, ticks "Add the currently-open quote as Option A." The existing QT-2026-DO-0188 becomes Option A automatically.

Step 2 — Generate variants

She opens the matrix builder:

Click Generate. The service loops: three rows in the matrix → three options on the set. (Option A skipped — already exists.)

For Option C, she opens the row in the editor and adds a layers JSON:
The set now shows three options, premiums populated, layers visualised in the table.

Step 3 — Render the comparison sheet

Sarah clicks Render comparison. Server pulls the set, builds an HTML matrix (LOB header, three columns, rows for premium / limit / deductible / SIR / effective dates / layers / forms-attached count), runs it through html to docx bytes, stores as a Submission Document. She downloads "Acme — Quote Comparison.docx," reviews it, attaches it to the broker email composer (capability #4), authorizes the send.

Step 4 — Soft pick

Sarah marks Option B as her preferred — "the $10M with $50k deductible is the right answer for this account." The set's selected quote guid updates; Option B's row in the panel gets a green star icon.

The other Forms strip cards on the quote-manager view show OPT A, OPT B ★, OPT C chips so any UW glancing at the list knows what set they belong to and which is preferred.

Step 5 — Broker comes back

Two days later: "We're going with C. The CFO liked the layered structure for the buffer." Sarah doesn't have to rewrite anything. She marks Option C as is selected (clears B's star). Option B is still on file — the audit story records the soft-pick changed.

Step 6 — Bind

When binding, the policy creates with source_quote_guid = <Option C's guid>. Audit-time question "what bound?" has a definitive answer. The set's selected quote guid (the soft pin, which by then matches the hard pin) tells you "what the UW was pushing"; the policy's source quote guid tells you "what got bound" — independent fields, both populated, both meaningful.

What if the broker asks for a fourth option?

Sarah hits + Option on the panel. The set has 3 options, max is 12. New option spawns. Re-render the comparison sheet (replaces the prior comparison document guid). Send the new sheet via the broker email composer. Audit trail records "comparison_rendered" twice with two different timestamps.

What if a referral fires on Option B?

It fires on the quote — Option B is a real Quote row, so all the referral plumbing works: rules evaluate, manager queue surfaces it, send-gate (cap #6 of referrals) blocks the send for that option specifically. Options A and C aren't blocked. The set sends only the unblocked options to the broker; capability #4's email composer attaches the per-option finalized form artefacts.

What This Means for Underwriters

  1. Real rows, not JSON. Every option is a queryable Quote. Referrals, subjectivities, forms, the email composer — every existing surface keeps working without learning a new shape.
  2. Soft pin and hard pin are different fields. "What I'm pushing" (Quote Option Set.selected_quote_guid) vs. "what bound" (Policy.source_quote_guid). The broker can change their mind without rewriting the UW's preference.
  3. The generator is a coordinator, not a new pricing model. It loops the existing quote-creation primitive with override dicts. The rating service contract is untouched.
  4. Caps prevent typos. 12 options/set keeps a [1_000_000, 1_000_001] typo from fanning out 400 rows.
  5. No parent-child trees. Flat sets, period. Every queryable is one join, not a recursive CTE.
  6. Comparison sheet is one render, not three quote letters glued together. Built-in HTML layout; no template authoring required for v1.
  7. Bind audit is definitive. Policy.source_quote_guid was the missing column. Now bound policies tell you which option won, with the option label preserved on source option label.

What's Next

Next: Three Endorsements Per Layer: How InsightUW Filters the Picker by Attachment Point Without Hiding Anything


Want to see how multi-option programs roll up into your bind audit story without inventing parent-child trees? Request a demo.

See InsightUW run on your data

A 45-minute working session with a real broker email and your LOBs.

Request a demo