From Ticker to Premium in One Quote Run: How InsightUW Auto-Populates a Public D&O Rater from EDGAR, S&P Capital IQ, and LinkedIn
A broker submits a public-company D&O renewal with only the ticker symbol. On quote-run, InsightUW fetches SEC EDGAR company facts, S&P Capital IQ financials, auto-generates LinkedIn officer search links for every named executive, populates 11 rating features — and hands a complete input set to the D&O rater. No typing. No copy-paste. No "we'll get back to you on the exposure data."
The Problem
A public D&O submission's rating inputs are 90% public record:
- Market cap (EDGAR, Capital IQ)
- Total assets (EDGAR 10-K balance sheet)
- Annual revenue (EDGAR 10-K income statement)
- Officer count + named executives (EDGAR DEF 14A proxy)
- Securities class action history (EDGAR litigation + specialized databases)
- S&P rating + analyst target prices (Capital IQ)
- CEO name + tenure (Capital IQ)
- NAICS sector + industry classification (D&B, EDGAR 10-K Item 1)
But in most workstations, the UW types it all in. Or asks the broker to fill a 30-field intake form. Or copy-pastes from Bloomberg. Each account takes 20-40 minutes of data entry before rating can even begin. A portfolio UW working $25M-$500M market-cap D&O is on a 45-submission-per-week pace and spends three hours a day typing exposure data that's already in the public domain.
The InsightUW approach: declare the data sources once, let the engine fetch on every quote run.
The Architecture
Four cap-level concepts combine to make this work end-to-end:
The UW types one thing: the insured's ticker (or the submission intake bot extracts it from the broker's email). The rest is a single run quote call away.
The Account
- Insured: ACME Semiconductor Corp
- Ticker: ACME
- Broker-provided data: ticker + requested $25M limit + $50k retention + 7/1/2026 effective
- LOB: public_company_dno
That's all that comes in the submission. The broker doesn't attach a 10-K. They don't list the officers. They don't note the litigation history. That's fine — the system finds all of it.
Step 1 — Submission Intake
Submission lands. Submission Queue row created. The Insured row has ticker = 'ACME' populated (either by the broker's structured intake or by the cap #5 broker submission facts enrichment which scans the submission PDF).
At this point the rater has nothing. If we ran us public dno v1 2026 now, every feature:* field would come up null and the quote would fail validation.
Step 2 — The Risk Assessment Profile Fires
The UW opens the submission and clicks Risk Assessment in the toolbar. The workbench route /uw/risk-assessment/<submissionGuid> loads. The applicable profile for lob=dno, product=public_company is us_public_dno_pack — auto-selected.
She clicks Compute snapshot. The service iterates four exposure sources:
Source 1: edgar public company
Callback lands with company facts:
The output_mapping walks JSON pointers → feature values:
| source_path | feature_code | value |
|---|---|---|
/facts/cik |
edgar cik | "0001234567" |
/facts/market_cap |
edgar market cap | 18,500,000,000 |
/facts/total_assets |
edgar total assets | 24,100,000,000 |
/facts/revenue |
edgar revenue | 9,800,000,000 |
/facts/officer_count |
edgar officer count | 12 |
/facts/securities_class_actions_5y |
edgar securities class actions 5y | 1 |
/facts/latest_10k_filed_at |
edgar latest 10k filed at | "2026-02-14" |
Seven Rating Feature Value rows written, all citing the same Exposure Fetch lineage. Audit viewer later shows the raw EDGAR payload behind every value.
Source 2: sec filings list
Same platform (sec_edgar), different contract (edgar filings list). Returns a list of recent filings:
The asset_output_mapping (not feature mapping — these aren't scalar values) produces three document-link assets:
On the workbench, these render as clickable PDF buttons. The UW can click into the 10-K directly from the submission without leaving the workstation.
Source 3: sp capital iq profile
Identifier: {{ insured.ticker | default(insured.cik) }} = "ACME". Platform sp capital iq, contract sp capital iq profile. Returns:
Four more feature values written:
| source_path | feature_code | value |
|---|---|---|
/profile/market_cap |
ciq market cap | 18,500,000,000 |
/profile/sp_rating |
ciq sp rating | "BBB+" |
/profile/analyst_target |
ciq analyst target | 142.50 |
/profile/ceo_name |
ciq ceo name | "Jane Chen" |
Note: edgar market cap and ciq market cap can disagree (EDGAR lags in real-time price; Capital IQ is intraday-fresh). Both are stored separately — UW sees both on the features panel.
Source 4: linkedin officer search
This one never dispatches. source_type = link_only. The link template jinja renders:
A fetch row is written with fetch_status = success and raw_response_json = {"link_url": "...", "provider": "LinkedIn"}. No external call.
The workbench renders it as a clickable LinkedIn-branded button. Click opens in a new tab. The UW can vet the officers' backgrounds without leaving the submission.
Step 3 — The Snapshot
Risk Assessment Snapshot row is written. by source json:
Status: completed. Features produced: 11. Assets produced: 3 filing docs + 1 LinkedIn link.
Step 4 — Run the Quote
Sarah opens the rater workbench at /uw/rater/<submissionGuid>. Picks us public dno v1 2026. Clicks Run quote.
Pricing Model Service.run_quote does three things before dispatching to the builtin engine:
1. Refresh on-quote exposure sources. Any source with refresh_policy = on_quote fires again if stale. edgar public company has stale_after_days = 30 — still fresh, skipped. sp capital iq profile has stale_after_days = 30 — skipped. No extra latency.
2. Auto-populate feature-sourced fields. The pricing model's input_schema.fields list declares which inputs read from the feature store:
The service reads each source: "feature:<code>" field and populates it from Rating Feature Value (insured-scoped, current). requested limit and retention came from the broker's structured submission. Now the inputs dict is complete:
3. Validate + dispatch. Schema validation runs (all fields present, types correct), then the builtin engine renders compute formula jinja:
Output:
Factor stack: 1.185 × 1.15 × 0.97 = 1.322. Subtotal: $18,000 × 1.322 = $23,796. Taxes: $0 for US D&O (no surplus lines here because admitted). Fees: broker commission 15% × $23,796 = $3,569; policy fee $2,500 → $6,069. Final: $29,865.
Step 5 — The UW Sees the Factor Lineage
Every factor in the quote's factors json carries a source key. On the quote summary page, the premium buildup shows:
| Step | Value | Source |
|---|---|---|
| Base premium | $18,000 | — |
| × size (market cap band) | 1.185 | compute_formula |
| × litigation (5y) | 1.15 | compute_formula |
| × rating (S&P) | 0.97 | compute_formula |
| Subtotal | $23,796 | |
| + taxes | $0 | |
| + broker commission (15%) | $3,569 | |
| + policy fee | $2,500 | |
| Final premium | $29,865 |
The UW knows why each factor has the value it does — click on the litigation factor and the lineage popover shows "input: sec_class_actions_5y = 1 (source: feature)". Click the feature, and the feature audit viewer shows "populated from edgar public company exposure fetch on 2026-04-24 09:15, raw EDGAR payload attached."
Zero black box. Zero guessing.
Step 6 — What Happens on a Stale Fetch?
Suppose Sarah opens the same quote 45 days later (new market cap, new analyst targets). She clicks Re-run quote.
refresh_policy = on_quote sources check staleness. sp capital iq profile has stale_after_days = 30 and was fetched 45 days ago → stale. The engine re-fires the exposure source:
- New dispatch to Capital IQ
- Callback lands with updated
market_cap = 17,200,000,000(market is off) - apply output mapping writes a new Rating Feature Value row with
is_current = true; prior row flips tois_current = false
When the quote runs, feature:ciq_market_cap now reads 17.2B. Size factor re-computes to 1.172. Subtotal drops. The summary page's comparison-vs-original shows the delta if this is a re-quote of an overridden version, or simply the new premium if a fresh run.
UWs never have to remember to refresh. Staleness is a declarative property of the source.
Step 7 — What About D&B + LinkedIn on Private D&O?
The us_private_dno_pack profile is the same architecture with different sources:
Private D&O has no EDGAR (private company), no Capital IQ (mostly). What it does have is D&B's firmographics + social data via LinkedIn. Same pattern: D&B dispatch returns employee count + revenue, populates features → rater consumes. LinkedIn is link-only, renders deep-links the UW clicks through.
Point is: same framework, different source pack per LOB. New sector (e.g. financial_institutions_dno)? Ops adds a new profile and assembles the source codes — zero code change.
Step 8 — The Cyber Variant
us_cyber_pack uses:
CyberCube populates 7 cyber-specific features (cyber security rating, cyber known breaches 5y, cyber dark web exposure score, etc.). The cyber rater's input schema reads all of them via source: "feature:cyber_*". Same engine, different provider pack.
The Lineage Panel
For any quote, Sarah can open the risk-assessment workbench and see the full provenance:
Each section expands to show the raw response JSON. Each feature value shows the producing fetch. The entire rating input set has a traceable origin.
Config — Defining a New Source
To add a new external provider (e.g. Moody's ESG score), ops navigates to /uw/admin/exposure-sources:
Adds four Rating Feature Definition rows for the output features. Optionally adds the source to us public dno pack profile. Optionally adds the features to the D&O rater's input schema as new source: "feature:moodys_esg_*" fields.
Zero deploy. Next quote run picks it up.
What This Replaces
Before InsightUW's exposure-source framework, carriers handle public company data one of three ways:
- Broker fills a questionnaire. 30 fields, manual, error-prone, 2-day turnaround, brokers hate it.
- UW looks it up manually. Bloomberg terminal, SEC website, S&P portal, three tabs, 20 minutes per account, $200k per UW per year in lost capacity.
- Automated integration with one provider. Usually Capital IQ or D&B. Hardcoded. Breaks when the provider changes their API. Adding LinkedIn takes 6 months of engineering.
The InsightUW approach: declarative sources, one framework, three-field admin UI to add a new provider. Current state: 11 seeded sources across Edgar, CyberCube, D&B, Capital IQ, FEMA Flood, Google Street View, Munich Re CATNet, LinkedIn, and internal (broker SOV, prior-year pull-forward, broker submission facts). A new carrier LOB = new profile + reuse of existing sources.
Data Model Summary
- Exposure Source — declarative source spec: source_type, identifier_jinja, platform_code + contract_code (external) OR internal_fetcher_key (internal), output_mapping (JSON-pointer → feature_code), asset_output_mapping (image/map/doc URLs), link_template_jinja (link_only), refresh_policy, entity_scope.
- Exposure Fetch — per (source, entity) cached fetch with raw_response_json and supersede chain. Links back to a cap #20 Platform Dispatch when external.
- Rating Feature Definition — feature catalog with output_type, target_range (for RAG zones), refresh_policy.
- Rating Feature Value — cached value per (entity, feature) with supersede chain + lineage_json citing the producing fetch.
- Risk Assessment Profile — per-LOB pack: source_codes list.
- Risk Assessment Snapshot — per (submission, profile) materialized output for the workbench.
All of these ship as seeded catalogs with idempotent startup seeding. Ops extends via admin UIs. UWs experience it as: "I typed the ticker. Premium came back. Everything's filled in. Everything has a source."
Quick Reference
Trigger a fetch manually: POST /api/uw_exposure_source/sources/{guid}/fetch
Refresh all sources for an entity: POST /api/uw_exposure_source/refresh-entity
Compute a risk assessment snapshot: POST /api/uw_risk_assessment/submissions/{guid}/snapshot/{profile_code}/compute
Pull prior-year data for a renewal: POST /api/uw_exposure_source/pull-forward
Workflow effect that fires an exposure source: fetch exposure source with source code in effect config json.
Jinja helpers (workflow rules):
One ticker symbol → 11 rating features + 3 document links + 1 deep-link, all traceable back to a named external source — in the time it takes to click "Run quote." That's the standard the framework sets.