Migrating insurance coverage records (GL, Auto, WC, Umbrella, Liquor, Other, User-Defined) and linking them to certificates and requirements.
Migration of insurance coverage data from DTX 1.0 to DTX 2.0. This is Phase 3 β depends on Accounts (Area 2) and Certificates (Area 4). This area also performs the Carrier A-F backfill on Certificate records deferred from Area 4 (Decision #16).
DTX 2.0 coverage models were designed with migration in mind β most fields map 1:1 with identical ACORD field names (lowercased). This is the most straightforward area since Area 2.
Important: Full production data is not available. Migration scripts must be built defensively with dry-run mode, self-validation, and graceful error handling.
| Table | Columns | Purpose |
|---|---|---|
general_liability |
47 | GL coverage β carrier, 6 limits, applies-to flags, deductible |
automobile_liability |
32 | Auto coverage β carrier, auto type flags, 4 limits |
workers_comp |
20 | WC coverage β carrier, statutory flag, 3 disease limits |
umbrella_liability |
28 | Umbrella/excess β carrier, retention, 2 limits, applies-to |
liquor_liability |
19 | Liquor liability β carrier, 2 limits, not-applicable flag |
other_coverage |
19 | Misc types (Crime, E&O, Property, etc.) β type desc, 3 desc/limit pairs |
user_defined_policy |
18 | Custom policy types β UDPType, loss_payee, mortgagee |
requirement_coverage |
10 | Requirement-to-coverage tracking β vendor, email, source |
| Model | Purpose |
|---|---|
GeneralLiability |
GL coverage (certificate FK or coi_risk_profile FK) |
AutoLiability |
Auto coverage |
WorkersCompensation |
WC coverage |
UmbrellaLiability |
Umbrella/excess coverage |
LiquorLiability |
Liquor liability coverage |
PropertyCoverage |
Property coverage (type FK to PropertyCoverageType) |
OtherCoverage |
Misc coverage (type FK to OtherCoverageType) |
PropertyCoverageType |
Type definitions for property coverages |
OtherCoverageType |
Type definitions for other coverages |
CarrierRating |
AM Best rating requirement (avii_or_above flag) |
| Item | Estimate |
|---|---|
| GL records | 50K-200K |
| Auto records | 40K-150K |
| WC records | 30K-120K |
| UMB records | 20K-80K |
| LL records | 2K-10K |
| Other/Property records | 10K-50K |
| UDP (cert data) | 0-10K (sample has 0 β may be sparse) |
| CarrierRating records | 10K-50K |
| Certificate carrier backfills | 50K-200K |
| Total records created | 160K-660K |
These must be resolved before running the migration.
llsamepot Typo in DTX 2.0 ModelPriority: HIGH β do this first
The LiquorLiability model has field llsamepot β should be llsamepol (same policy). This is a typo baked into the Django model. Fixing it after data migration requires a data migration too. Fix now via a Django schema migration while the table is empty.
# Current (wrong):
llsamepot = models.TextField(null=True, blank=True)
# Should be:
llsamepol = models.TextField(null=True, blank=True)
Priority: HIGH β potential UI breakage
All coverage models have *_options FKs to DropdownOptions (e.g., general_aggregate_options, each_occurrence_options). Migration leaves all these NULL β there's no DTX 1.0 equivalent.
Risk: If DTX 2.0 frontend/API accesses coverage.general_aggregate_options.options without null-checking, every migrated coverage record will crash the UI.
Action: Review DTX 2.0 frontend code for null-safe access on all *_options FKs. If not null-safe, either:
- Fix the frontend to handle NULL (preferred)
- Create stub DropdownOptions records with empty option arrays
Priority: HIGH β silent data disconnect
Area 4 created EvaluationCoverage records with coverage_type strings like "GeneralLiability", "AutoLiability", etc. (from certificate_status.field_name prefix mapping). DTX 2.0's evaluation engine presumably uses these strings to match coverage records to evaluations.
Action: Verify that DTX 2.0's evaluation engine expects exactly these strings. If it uses different casing, display names, or model-derived names, the evaluations created in Area 4 will disconnect from the coverage records created here.
Area 4 sets: EvaluationCoverage.coverage_type = "GeneralLiability"
DTX 2.0 expects: ??? (must match)
Priority: MEDIUM
Decision #5 creates CarrierRating records from certificate.AMBestRatingOK with NULL carrier info (name/naic/code). The model has per-carrier fields, suggesting it's designed for per-carrier rating tracking β not per-certificate flags.
Action: Confirm with DTX 2.0 team:
- One CarrierRating per certificate (flag approach β current plan)?
- Or one per unique carrier on the certificate, each with avii_or_above=True (per-carrier approach)?
| # | Issue | Impact | Mitigation |
|---|---|---|---|
| 1 | CarrierCode NULL in 4 largest tables β GL, Auto, WC, UMB samples all have CarrierCode=NULL. Only LL and Other have codes ("A", "C", "F"). The Carrier A-F backfill for the majority of records has no direct slot assignment. |
Carrier A-F slots may not match original ACORD form layout | Use NAIC cross-referencing: if LL/Other record says CarrierCode="A", NAIC=14377, propagate slot A to any GL/Auto/WC/UMB record sharing NAIC 14377. See Decision #2. |
| 2 | Carrier name variants waste A-F slots β Same carrier appears as "Continental Casualty Co.", "Continental Casualty Company", "Continental Casualty Company " (trailing space). All share NAIC 20443. Name-based dedup treats these as 3 different carriers. |
Wrong carrier count, wasted A-F slots | Deduplicate by NAIC first (when populated). Fall back to normalized name only when NAIC is NULL. See Decision #2. |
| 3 | Coverage timestamps lost β DTX 1.0 coverage tables have no create_time/update_time columns. DTX 2.0's TimestampedModel auto-sets created/modified to migration run time. All 160K-660K records will share the same created date. |
Cannot answer "when was this coverage recorded?" for migrated data | Use parent certificate's create_time as proxy. See Decision #12. |
| # | Issue | Impact | Mitigation |
|---|---|---|---|
| 4 | NULL DropdownOptions may break UI β All *_options FKs left NULL for migrated records. If frontend doesn't null-check, every coverage view crashes. |
Broken UI for all migrated coverage | Pre-migration action #2: investigate frontend null safety. |
| 5 | EvaluationβCoverage type string mismatch β No FK between coverage records and evaluations. Linkage is by coverage_type string convention. If strings don't match, evaluations disconnect. |
Evaluations appear to have no coverage data | Pre-migration action #3: verify type strings match. |
| 6 | Wrong-table coverage types β Sample shows "Commercial Umbrella" and "HNOA" (Hired/Non-Owned Auto) in other_coverage. If DTX 2.0's evaluation engine only checks UmbrellaLiability and AutoLiability models, these records are invisible to compliance. |
Missed compliance data | Flag other_coverage types matching standard coverage names. See Decision #3. |
| # | Issue | Impact | Mitigation |
|---|---|---|---|
| 7 | user_defined_policy cert path untestable β 100% of sample records are templates (certificate_id=NULL). The certificate migration path has zero test coverage. |
Production may hit unexpected patterns | Extra dry-run validation for this subset. See Decision #4. |
| 8 | Cascade from Area 4 skips β If Area 4 skipped certificates (missing customer/vendor), all their coverage records are also skipped. One bad customer could mean hundreds of orphaned coverage records. | Silent data loss | Dry-run must quantify cascade: "N coverage records orphaned by M Area 4 certificate skips." |
| 9 | Suspicious limit values β LL sample shows "1000000000" ($1B) β almost certainly a data entry error ($1M = "1000000"). Plan stores as-is (correct), but doesn't flag. |
Bad data migrated silently | Dry-run flags limits exceeding thresholds (GL >$100M, Auto >$50M, etc.). See Decision #10. |
| 10 | Coverage type dedup is case-sensitive β "Equipment Floater" vs "Equipment floater" creates two separate types. |
Duplicate OtherCoverageType/PropertyCoverageType records | Case-insensitive, whitespace-normalized dedup. See Decision #3. |
| # | Issue | Impact | Mitigation |
|---|---|---|---|
| 11 | GLLimMisc has no DTX 2.0 target β No gllimmisc field exists. NULL in all samples but may be populated in full data. |
Minor data loss | Append to gldescmisc with label. See Decision #11. |
| 12 | Other1Desc1 has no DTX 2.0 target β No other1desc1 field exists. Contains labels like "Per Limit", "Each Claim/ Agg." |
Minor data loss | Log all unique values. Store raw Other1Lim1 in both limit and other1lim1. See Decision #11. |
Risk Level: Low
All coverage records use certificate FK (actual data). coi_risk_profile FK stays NULL (templates, Area 6). All *_options FKs stay NULL (UI config, not data β pending Pre-Migration Action #2).
For each coverage record:
1. Look up certificate_id in id_mapping_certificates.csv
2. If found β set certificate FK to mapped DTX 2.0 Certificate ID
3. If not found β log to migration_issues.csv, skip record
Risk Level: HIGH
Area 4 (Decision #16) left Certificate carrier_a_name through carrier_f_naic NULL. This area backfills them from coverage data.
| Table | CarrierCode populated? | Sample values |
|---|---|---|
general_liability |
Rarely β NULL in all samples | β |
automobile_liability |
Rarely β NULL in all samples | β |
workers_comp |
Rarely β NULL in all samples | β |
umbrella_liability |
Rarely β NULL in all samples | β |
liquor_liability |
Yes | "A", "C" |
other_coverage |
Sometimes | "A", "C", "F" |
CarrierCode values "A" through "F" are ACORD insurer letter designations that directly map to Certificate slots.
For each migrated Certificate:
1. Collect all coverage records linked to this certificate
(across all 6 tables + user_defined_policy)
2. Build NAIC β Slot mapping from records WITH CarrierCode:
- LL record with CarrierCode="A", NAIC=14377 β slot A owns NAIC 14377
- Other record with CarrierCode="C", NAIC=31194 β slot C owns NAIC 31194
3. Assign carriers to slots:
Phase A β Direct code assignment:
Records with CarrierCode populated β assign to that slot
Phase B β NAIC cross-reference:
Records without CarrierCode but with NAIC matching a Phase A carrier
β assign to the same slot
Phase C β Remaining unassigned:
Deduplicate by NAIC (when populated), then by normalized name
β assign to next available slot A-F
4. Normalize carrier names for dedup:
- Strip leading/trailing whitespace
- Collapse multiple spaces
5. If >6 unique carriers β fill A-F, log overflow to migration_issues.csv
6. Update Certificate record with populated carrier slots
Key insight: NAIC is more reliable than carrier name for dedup. Same carrier appears as "Continental Casualty Co." / "Continental Casualty Company" / "Continental Casualty Company " β all NAIC 20443.
other_coverage β OtherCoverage vs PropertyCoverageRisk Level: Medium
DTX 1.0 has a single other_coverage table. DTX 2.0 splits into PropertyCoverage (with loss_payee, mortgagee) and OtherCoverage. The other_coverage table has no loss_payee/mortgagee fields, so routing is based on the Other1 type description.
Other1Property-like: "Extra Expense", "Equipment Floater", "Business Pers(onal Property)",
"Scheduled Equipment", "Contents", "Leased/Rented Equipment",
"Installation Floater", "Business Income", "Inland Marine"
Liability/Other: "Professional Liability", "Professional-Claims Made",
"TECHNOLOGY E & O", "Crime Policy", "Crime", "EPLI",
"Fire Legal Liability", "Poll Legal Liab", "HNOA"
Pollution: "Transportation Pollution-Occ", "Contractor Pollution-Occ",
"Professional/ Pollution Liab.", "Pollution-worksite"
Wrong-table: "Commercial Umbrella" (should be umbrella_liability)
"Business Pers " appears as both carrier name AND coverage type"99999" (e.g., "Grand Rapids" with NAIC 99999)"500000/1000000", "$2000,000 Limit Ded $2,500", "1000000 Limit Ded 2500"1. Extract all unique Other1 values from full dataset
2. Normalize: strip whitespace, title case
3. Case-insensitive dedup (so "Equipment Floater" and "Equipment floater"
become one type)
4. Classify each into "property" or "other" using keyword matching:
Property keywords: property, equipment, floater, inland marine,
business personal, building, contents, real property, business income,
extra expense, boiler, machinery, scheduled, installation
Everything else β OtherCoverage
5. Flag wrong-table types for post-migration review:
Wrong-table keywords: umbrella, hired auto, non-owned auto, HNOA,
workers comp, general liability
These types are in other_coverage but logically belong in standard tables.
DTX 2.0's evaluation engine may not find them.
6. Create PropertyCoverageType / OtherCoverageType (case-insensitive deduped)
7. Route each record to the appropriate model
8. Log all classifications to migration report for manual review
Fallback: Uncertain β OtherCoverage. Safer than misclassifying as PropertyCoverage.
user_defined_policy β Template vs Certificate DataRisk Level: Medium
Dual-purpose table:
- Template records: certificate_id=NULL, requirements_id set β Area 6
- Certificate records: certificate_id set β this area
All 100 sample records are templates. Single customer (815), 3 UDPType values repeating: "Professional Liability", "Cyber Liability", "Pollution Liability". All have UDPLimits=-1, all other fields NULL. The certificate data path cannot be validated from sample data.
1. Split:
a. Template records (certificate_id=NULL) β defer to Area 6, log count
b. Certificate records (certificate_id set) β migrate here
2. For each certificate record:
a. Route to target model:
- If UDPLossPayeeCB or UDPMortgageeCB is truthy β PropertyCoverage
- Else if UDPType matches property keywords (Decision #3 list) β PropertyCoverage
- Otherwise β OtherCoverage
b. Find or create type record (case-insensitive dedup)
c. Create coverage record with certificate FK
d. UDPLimits: -1 or NULL β set limit = NULL
3. Dry-run MUST log (since sample is 100% templates):
- Count of template vs certificate records
- Full value distribution for EVERY field in the certificate subset
- All unique UDPType values with routing decisions
certificate.AMBestRatingOKRisk Level: Low (pending Pre-Migration Action #4)
Area 4 noted certificate.AMBestRatingOK maps here. Sample: cert 5307 has AMBestRatingOK="yes".
Open question: Is CarrierRating per-certificate or per-carrier? (See Pre-Migration Action #4)
For each certificate where AMBestRatingOK is truthy ("yes"):
1. Look up mapped Certificate ID
2. Create CarrierRating:
- certificate = mapped Certificate
- avii_or_above = True
- carrier_name/naic/code = NULL (certificate-level flag)
- effective_date/expiration_date = NULL
For each certificate where AMBestRatingOK is truthy ("yes"):
1. For each unique carrier from the Carrier A-F backfill data:
Create CarrierRating:
- certificate = mapped Certificate
- avii_or_above = True
- carrier_name = carrier's name
- carrier_naic = carrier's NAIC
Risk Level: Low
Every coverage table has *ReviewStatus and *Reason. These track DTX 1.0 review workflow results.
Drop all. Consistent with Area 4 Decision #11. Rationale:
1. Historical data β reviews are complete
2. DTX 2.0 uses a different evaluation system (Area 4's 3-tier pipeline)
3. certificate_status (migrated in Area 4) already captures compliance results
4. Redundant review state would conflict with new evaluation system
Sample values observed: NULL in most GL/Auto/WC/UMB samples. Liquor liability shows "COMPLIANT". Log all distributions in dry-run.
requirement_coverage Table β Don't MigrateRisk Level: Low
Operational tracking table: "vendor X needs coverage Y, producer email is Z, from source W."
Sample: vendor 31739, email rstowe@farmersagent.com, type COI, name "All Risk β Business Personal Property (Contents)", source certificate 1100230.
Don't migrate. DTX 2.0 handles this via:
- RequirementsGroup + COIRiskProfile β what's required
- EvaluationCoverage + EvaluationDetail β what's met
- NotificationSchedule β communication
Keep CSV for reference. The requirement_name values are useful for validating Area 6's requirements mapping.
Risk Level: Low
DTX 2.0's DescriptionOfOperations model tracks the requirement ("is ops description required?"), not the text itself. Area 4 already mapped certificate.OpsDesc β Certificate.ops_desc.
Defer. This is a requirement-level model (coi_risk_profile FK). Area 6 will create these when building COIRiskProfile templates.
Risk Level: Low
vendor.WCExempt β Record.wc_exempt (vendor-level)certificate.WCExempt β WorkersCompensation.any_excluded (coverage-level)After migrating workers_comp records:
For each certificate where WCExempt is truthy ("yes"):
If WorkersCompensation record exists for this cert:
β set any_excluded = True
If no WC record exists:
β no action (Record.wc_exempt already handles vendor-level exemption)
Risk Level: Low
DTX 1.0 limit formats observed:
Standard: "1000000", "2000000", "500000"
Combined: "500000/1000000"
Formatted: "$2000,000 Limit Ded $2,500"
Special: "-1" (user_defined_policy = no limit)
Suspicious: "1000000000" (LL sample β $1B, likely data entry error)
Store raw values as-is. Don't transform or format. Map -1 β NULL.
Dry-run must flag suspicious values:
Limits exceeding thresholds:
GL each_occurrence > $100M: ???
Auto single_limit > $50M: ???
WC disease limits > $10M: ???
LL each_occurrence > $100M: ???
UMB each_occurrence > $100M: ???
These are almost certainly data entry errors. Don't fix β flag for post-migration review.
Risk Level: Low
Two DTX 1.0 fields have no direct DTX 2.0 target.
GLLimMisc (General Liability)No gllimmisc field in DTX 2.0. NULL in all samples.
if GLLimMisc:
gldescmisc = f"{GLDescMisc or ''} | Misc Limit: {GLLimMisc}".strip(' |')
Log all records where GLLimMisc is populated.
Other1Desc1 (Other Coverage)No other1desc1 field in DTX 2.0. Contains labels like "Per Limit", "Each Claim/ Agg.", "Scheduled", "leased & rented".
# Store raw numeric value in both fields β do NOT concatenate description into limit field
limit = Other1Lim1 # primary limit value
other1lim1 = Other1Lim1 # raw backup
# Log Other1Desc1 for reference β do not store in a numeric field
# Dry-run: report all unique Other1Desc1 values
Why not concatenate: Storing "Per Limit: 5000000" in other1lim1 (a limit field) would break any downstream code that parses it as a number.
Risk Level: Medium
DTX 1.0 coverage tables have no create_time / update_time columns. Without intervention, all migrated coverage records get created = migration_date.
For each coverage record:
1. Look up the parent Certificate's created timestamp
(from id_mapping_certificates.csv or the Certificate object)
2. Set coverage_record.created = certificate.created
3. Set coverage_record.modified = certificate.modified
(or migration_date if certificate.modified is NULL)
This preserves approximate historical timing. A coverage record created as part of certificate 5307 (created 2015-06-03) will show created = 2015-06-03, not created = 2026-XX-XX.
All coverage models have both coi_risk_profile and certificate FKs. For migration: certificate FK set, coi_risk_profile = NULL.
Coverage records (this area) and evaluations (Area 4) are complementary parallel structures linked to the same Certificate: - Coverage records: what was on the certificate (limits, carriers, dates) - Evaluations: whether it met requirements (pass/fail per field)
No direct FK between them. Linkage is by EvaluationCoverage.coverage_type string convention. (See Pre-Migration Action #3.)
A single certificate typically has records in 3-5 different coverage tables. One table may also have multiple rows per certificate (e.g., cert 13957 has 3 auto policies). This is valid β one ACORD form can list multiple policies per coverage type.
| DTX 1.0 Value | Maps To | Notes |
|---|---|---|
"yes" |
True |
Primary truthy value |
NULL |
False |
Default |
"" (empty) |
False |
|
"no" |
False |
Rare but observed |
| Any other value | False |
Log the value |
general_liability β GeneralLiabilitySample (row 40718): cert 7262, carrier QBE/General Casualty (NAIC 24414), policy CCX1207877, 2014-07-30 to 2015-07-30, limits: $1M occ / $100K rented / $1M person / $2M agg / $2M prod.
| DTX 1.0 | DTX 2.0 | Notes |
|---|---|---|
general_liability_id |
(ID mapping) | β id_mapping_coverage.csv |
certificate_id |
certificate |
Via id_mapping_certificates.csv |
GLCarrierCode |
carrier_code |
NULL in all samples. Used for Carrier A-F (Decision #2) |
GLCarrierName |
carrier_name |
Direct |
GLCarrierNAIC |
carrier_naic |
Direct |
GLOccur |
occurrence |
"yes" β True |
GLClaims |
claims_made |
"yes" β True |
GLDeductible |
gldeductible |
Direct |
GLDedOccuro |
gldedoccuro |
Direct |
GLDedClaims |
gldedclaims |
Direct |
GLAddlInsd |
additional_insured |
"yes" β True |
GLSubrWvd |
subrogation_waived |
"yes" β True |
GLPolNumb |
policy_number |
Direct |
GLPolEffDate |
effective_date |
Direct |
GLPolExpDate |
expiration_date |
Direct |
GLPolicy |
applies_per_policy |
"yes" β True |
GLProject |
applies_per_project |
"yes" β True |
GLLocation |
applies_per_location |
"yes" β True |
GLLimEaOcc |
each_occurrence |
Direct |
GLLimRented |
damage_to_premises |
Direct |
GLLimEaMed |
medical_expense |
Direct |
GLLimPerson |
personal_injury |
Direct |
GLLimAgg |
general_aggregate |
Direct |
GLLimProd |
products_comp |
Direct |
GLOtherLimitDesc1 |
glotherlimitdesc1 |
Direct. Sample: "Business Owner's Liability" |
GLOtherLimit1 |
glotherlimit1 |
Direct |
GLOtherLimitDesc2 |
glotherlimitdesc2 |
Direct. Sample: "Microbial Substance" |
GLOtherLimit2 |
glotherlimit2 |
Direct |
GLOtherLimitDesc3 |
glotherlimitdesc3 |
Direct |
GLOtherLimit3 |
glotherlimit3 |
Direct |
GLDescMisc |
gldescmisc |
Direct |
GLLimMisc |
(no target) | Append to gldescmisc if populated. See Decision #11 |
GLPrimary |
primary_non_contributory |
"yes" β True |
GLAddlInsd2033 |
gladdlinsd2033 |
Direct |
GLAddlInsd2037 |
gladdlinsd2037 |
Direct |
GLAddlInsd2040 |
gladdlinsd2040 |
Direct |
GLAddlInsdForms |
additional_insured_forms |
truthy β True |
GLContLiab |
contractual_liability |
truthy β True |
GLAddlInsdCompOps |
additional_insured_completed_ops |
truthy β True |
GLTerm1 |
glterm1 |
Direct |
GLDesc1 |
gldesc1 |
Direct |
GLTerm2 |
glterm2 |
Direct |
GLDesc2 |
gldesc2 |
Direct |
GLTerm3 |
glterm3 |
Direct |
GLDesc3 |
gldesc3 |
Direct |
GLReviewStatus |
(dropped) | Decision #6 |
GLReason |
(dropped) | Decision #6 |
| (no source) | created |
Certificate's create_time. Decision #12 |
| (no source) | coi_risk_profile |
NULL |
| (no source) | all *_options FKs |
NULL |
automobile_liability β AutoLiabilitySample (row 38978): cert 13957, carrier State Farm (NAIC 25178), scheduled auto, $1M single. Note: cert 13957 has 3 rows β multiple policies per cert is valid.
| DTX 1.0 | DTX 2.0 | Notes |
|---|---|---|
automobile_liability_id |
(ID mapping) | |
certificate_id |
certificate |
Via mapping |
AutoCarrierCode |
carrier_code |
NULL in all samples |
AutoCarrierName |
carrier_name |
Direct |
AutoCarrierNAIC |
carrier_naic |
Direct |
AutoAny |
any_auto |
"yes" β True |
AutoOwned |
all_owned_autos |
"yes" β True |
AutoSched |
scheduled_autos |
"yes" β True |
AutoHired |
hired_autos |
"yes" β True |
AutoNonOwned |
non_owned_autos |
"yes" β True |
AutoAddlInsd |
additional_insured |
"yes" β True |
AutoSubrWvd |
subrogation_waived |
"yes" β True |
AutoPolNumb |
policy_number |
Direct |
AutoPolEffDate |
effective_date |
Direct |
AutoPolExpDate |
expiration_date |
Direct |
AutoSingle |
single_limit_per_accident |
Direct |
AutoBodilyPerson |
bodily_per_person |
Direct |
AutoBodilyAccident |
bodily_per_accident |
Direct |
AutoProperty |
property_per_accident |
Direct |
AutoDescMisc |
autodescmisc |
Direct |
AutoLimMisc |
autolimmisc |
Direct |
AutoDescMisc2 |
autodescmisc2 |
Direct |
AutoLimMisc2 |
autolimmisc2 |
Direct |
AutoUnknown |
autounknown |
Direct |
AutoUnknownDesc |
autounknowndesc |
Direct |
AutoAddlInsdForms |
additional_insured_forms |
truthy β True |
AutoTerm1 |
autoterm1 |
Direct |
AutoDesc1 |
autodesc1 |
Direct |
AutoTerm2 |
autoterm2 |
Direct |
AutoDesc2 |
autodesc2 |
Direct |
AutoReviewStatus |
(dropped) | Decision #6 |
AutoReason |
(dropped) | Decision #6 |
| (no source) | created |
Certificate's create_time. Decision #12 |
workers_comp β WorkersCompensationSample (row 34752): cert 11666, carrier State National (NAIC 12831), statutory: yes, $1M all limits.
| DTX 1.0 | DTX 2.0 | Notes |
|---|---|---|
workers_comp_id |
(ID mapping) | |
certificate_id |
certificate |
Via mapping |
WCCarrierCode |
carrier_code |
NULL in all samples |
WCCarrierName |
carrier_name |
Direct |
WCCarrierNAIC |
carrier_naic |
Direct |
WCAddlInsd |
additional_insured |
"yes" β True |
WCSubrWvd |
subrogation_waived |
"yes" β True |
WCPolNumb |
policy_number |
Direct |
WCPolEffDate |
effective_date |
Direct |
WCPolExpDate |
expiration_date |
Direct |
WCExec |
any_excluded |
truthy β True. Per-coverage flag, distinct from Record.wc_exempt |
WCStatutory |
statutory_limits |
"yes" β True. All samples: "yes" |
WCOther |
wcother |
Direct |
WCEachAcc |
disease_accident |
Direct |
WCDiseaseEachEmpl |
disease_each_employee |
Direct |
WCDiseasePolicyLimit |
disease_policy |
Direct |
WCDescMisc |
wcdescmisc |
Direct |
WCLimMisc |
wclimmisc |
Direct |
WCReviewStatus |
(dropped) | Decision #6 |
WCReason |
(dropped) | Decision #6 |
| (no source) | created |
Certificate's create_time. Decision #12 |
umbrella_liability β UmbrellaLiabilitySample (row 30139): cert 12843, Continental Casualty (NAIC 20443), umbrella/occurrence, $10M occ/$10M agg, retention $0.
Critical: UMBRetention holds dollar amounts ("0", "10000"), NOT booleans. UMBRetentionCB is the checkbox (NULL in all samples).
| DTX 1.0 | DTX 2.0 | Notes |
|---|---|---|
umbrella_liability_id |
(ID mapping) | |
certificate_id |
certificate |
Via mapping |
UMBCarrierCode |
carrier_code |
NULL in all samples |
UMBCarrierName |
carrier_name |
Direct |
UMBCarrierNAIC |
carrier_naic |
Direct |
UMBLiability |
umbliability |
Direct. Sample: "yes" |
UMBExcess |
excess |
"yes" β True |
UMBOccur |
occurrence |
"yes" β True |
UMBClaims |
claims_made |
"yes" β True |
UMBDeduct |
deduct |
"yes" β True |
UMBRetentionCB |
retention |
Checkbox β True/False. DTX 1.0 "CB" = checkbox |
UMBRetention |
retention_cb |
Dollar amount (e.g., "0", "10000"). NOT a boolean |
UMBAddlInsd |
additional_insured |
"yes" β True |
UMBSubrWvd |
subrogation_waived |
"yes" β True |
UMBPolNumb |
policy_number |
Direct |
UMBPolEffDate |
effective_date |
Direct |
UMBPolExpDate |
expiration_date |
Direct |
UMBLimEaOcc |
each_occurrence |
Direct |
UMBCombined |
umbcombined |
Direct |
UMBLimAgg |
aggregate |
Direct |
UMBDescMisc |
umbdescmisc |
Direct |
UMBLimMisc |
umblimmisc |
Direct |
UMBApplyGl |
umbapplygl |
Direct. "yes" or NULL |
UMBApplyAuto |
umbapplyauto |
Direct. "yes" or NULL |
UMBApplyEl |
umbapplyel |
Direct. "yes" or NULL |
UMBAddlInsdForms |
additional_insured_forms |
truthy β True |
UMBReviewStatus |
(dropped) | Decision #6 |
UMBReason |
(dropped) | Decision #6 |
| (no source) | created |
Certificate's create_time. Decision #12 |
liquor_liability β LiquorLiabilitySample (row 12848): cert 333063, CarrierCode "A" β Selective Fire & Casualty (NAIC 14377), $1B limits (likely data entry error), ReviewStatus: COMPLIANT.
Data note: Only table with populated CarrierCode AND ReviewStatus in samples.
| DTX 1.0 | DTX 2.0 | Notes |
|---|---|---|
liquor_liability_id |
(ID mapping) | |
certificate_id |
certificate |
Via mapping |
LLNotApplicable |
llnotapplicable |
Direct |
LLSamePol |
llsamepot |
Direct. Model typo β fix per Pre-Migration Action #1 |
LLCarrierCode |
carrier_code |
ACORD insurer letter: "A", "C", etc. |
LLCarrierName |
carrier_name |
Direct |
LLCarrierNAIC |
carrier_naic |
Direct |
LLAddlInsd |
additional_insured |
"yes" β True |
LLSubrWvd |
subrogation_waived |
"yes" β True |
LLPolNumb |
policy_number |
Direct |
LLPolEffDate |
effective_date |
Direct |
LLPolExpDate |
expiration_date |
Direct |
LLLimEaOcc |
each_occurrence |
Direct |
LLLimAgg |
general_aggregate |
Direct |
LLDescMisc |
lldescmisc |
Direct |
LLLimMisc |
lllimmisc |
Direct |
LLAddlInsdForms |
additional_insured_forms |
truthy β True |
LLReviewStatus |
(dropped) | Decision #6. Sample: "COMPLIANT" |
LLReason |
(dropped) | Decision #6 |
| (no source) | created |
Certificate's create_time. Decision #12 |
other_coverage β OtherCoverage or PropertyCoverageRouting per Decision #3.
How desc/limit pairs work (sample row 25187, type="Poll Legal Liab"):
Other1Desc1="Per Limit" Other1Lim1="5000000" β limit + other1lim1
Other1Desc2="Per aggregate" Other1Lim2="5000000" β other1desc2 + other1lim2
Other1Desc3="SIR" Other1Lim3="50000" β other1desc3 + other1lim3
| DTX 1.0 | DTX 2.0 | Notes |
|---|---|---|
other_coverage_id |
(ID mapping) | |
certificate_id |
certificate |
Via mapping |
OtherCarrierCode |
carrier_code |
ACORD letter: "A", "C", "F" (sometimes populated) |
OtherCarrierName |
carrier_name |
Direct |
OtherCarrierNAIC |
carrier_naic |
Direct. Watch for placeholder "99999" |
Other1 |
type (FK) |
Create OtherCoverageType or PropertyCoverageType |
Other1AddlInsd |
additional_insured |
"yes" β True |
Other1SubrWvd |
subrogation_waived |
"yes" β True |
Other1PolNumb |
policy_number |
Direct |
Other1PolEffDate |
effective_date |
Direct |
Other1PolExpDate |
expiration_date |
Direct |
Other1Desc1 |
(no target) | Log unique values. See Decision #11 |
Other1Lim1 |
limit + other1lim1 |
Raw numeric value in both fields |
Other1Desc2 |
other1desc2 |
Direct |
Other1Lim2 |
other1lim2 |
Direct |
Other1Desc3 |
other1desc3 |
Direct |
Other1Lim3 |
other1lim3 |
Direct |
OtherReviewStatus |
(dropped) | Decision #6 |
OtherReason |
(dropped) | Decision #6 |
| (no source) | created |
Certificate's create_time. Decision #12 |
| (no source) | required |
Default False |
user_defined_policy β OtherCoverage or PropertyCoverageCertificate records only. Routing per Decision #4.
| DTX 1.0 | DTX 2.0 | Notes |
|---|---|---|
user_defined_policy_id |
(ID mapping) | |
certificate_id |
certificate |
Via mapping. NULL = template β skip |
requirements_id |
(deferred) | Area 6 |
customer_id |
(deferred) | Area 6 |
UDPType |
type (FK) |
Create type record (case-insensitive dedup) |
UDPCarrierName |
carrier_name |
Direct |
UDPCarrierNAIC |
carrier_naic |
Direct |
UDPPolEffDate |
effective_date |
Direct |
UDPPolExpDate |
expiration_date |
Direct |
UDPLimits |
limit |
Direct. Map -1 and NULL β NULL |
UDPAddlInsd |
additional_insured |
truthy β True |
UDPSubrWvd |
subrogation_waived |
truthy β True |
UDPLossPayeeCB |
loss_payee |
truthy β True (PropertyCoverage only β triggers routing) |
UDPMortgageeCB |
mortgagee |
truthy β True (PropertyCoverage only β triggers routing) |
UDPPolNumb |
policy_number |
Direct |
UDPRequired |
required |
truthy β True |
UDPReviewStatus |
(dropped) | Decision #6 |
UDPReason |
(dropped) | Decision #6 |
| (no source) | created |
Certificate's create_time. Decision #12 |
| Source | Field(s) | Reason |
|---|---|---|
| All 6 coverage tables | *ReviewStatus, *Reason |
Review workflow not migrated (Decision #6) |
user_defined_policy |
UDPReviewStatus, UDPReason |
Review workflow not migrated |
user_defined_policy (templates) |
requirements_id, customer_id |
Deferred to Area 6 |
requirement_coverage |
(entire table) | Don't migrate (Decision #7) |
| Model | Field | Value |
|---|---|---|
| All coverage models | coi_risk_profile |
NULL β template FK, set by Area 6 |
| All coverage models | All *_options FKs |
NULL β UI dropdown config (Action #2) |
OtherCoverage |
required |
Default False (no DTX 1.0 equivalent on other_coverage) |
| All coverage models | created, modified |
Certificate's timestamp (Decision #12) |
1. Validate prerequisites:
- id_mapping_certificates.csv exists and is complete
- Pre-migration actions 1-4 resolved
2. Dry-run validation report
3. Create OtherCoverageType records (case-insensitive dedup from Other1 + UDPType)
4. Create PropertyCoverageType records (property-classified types)
5. Migrate general_liability β GeneralLiability (batched, 1000/batch)
6. Migrate automobile_liability β AutoLiability (batched)
7. Migrate workers_comp β WorkersCompensation (batched)
8. Migrate umbrella_liability β UmbrellaLiability (batched)
9. Migrate liquor_liability β LiquorLiability (batched)
10. Migrate other_coverage β OtherCoverage or PropertyCoverage (batched, classified)
11. Migrate user_defined_policy (certificate records only) β OtherCoverage or PropertyCoverage
12. Apply WCExempt flag to WorkersCompensation records (Decision #9)
13. Create CarrierRating records from certificate.AMBestRatingOK (Decision #5)
14. Backfill Certificate carrier_a through carrier_f (Decision #2)
15. Generate and export all ID mapping tables
16. Verify
=== DTX 1.0 Coverage & Insurance Migration - Dry Run Report ===
PREREQUISITES:
id_mapping_certificates.csv: ??? records loaded
Certificates skipped in Area 4: ???
Coverage records orphaned by
Area 4 skips: ??? (across ??? customers)
GENERAL LIABILITY:
Total records: ???
Mapped to certificate: ???
Missing certificate_id: ???
CarrierCode populated: ???
Booleans: GLOccur=yes: ???, GLClaims=yes: ???, GLAddlInsd=yes: ???
GLLimMisc populated: ???
Suspicious limits (>$100M): ???
AUTOMOBILE LIABILITY:
Total records: ???
Multi-row certs (>1 row): ???
Auto types: Any: ???, Owned: ???, Hired: ???, NonOwned: ???, Sched: ???
Suspicious limits (>$50M): ???
WORKERS COMPENSATION:
Total records: ???
WCStatutory=yes: ???
WCExec populated: ???
Suspicious limits (>$10M): ???
UMBRELLA LIABILITY:
Total records: ???
UMBLiability vs UMBExcess: ???/???
UMBRetention values: min: ???, max: ???, avg: ???
UMBRetentionCB populated: ???
Suspicious limits (>$100M): ???
LIQUOR LIABILITY:
Total records: ???
LLNotApplicable populated: ???
CarrierCode distribution: A: ???, B: ???, C: ???, ...
ReviewStatus values: [distribution]
Suspicious limits (>$100M): ???
OTHER COVERAGE:
Total records: ???
Unique Other1 types: [list all with count]
Classified as Property: ??? types β ??? records
Classified as Other: ??? types β ??? records
Wrong-table types flagged: [list] (e.g., "Commercial Umbrella")
Other1Desc1 unique values: [list all]
CarrierCode populated: ???
NAIC=99999 (placeholder): ???
Suspicious limits: ???
USER DEFINED POLICY:
Total records: ???
Template records (no cert): ??? β Area 6
Certificate records: ??? β this area
Unique UDPType values: [list all]
With loss_payee: ???
With mortgagee: ???
[If cert records > 0: full field distribution for every field]
COVERAGE TYPE DEDUP:
Raw unique names: ???
After normalization: ??? (deduped by case/whitespace)
OtherCoverageType to create: ???
PropertyCoverageType to create: ???
CARRIER A-F BACKFILL:
Certificates to update: ???
Avg carriers per cert: ???
Max carriers per cert: ???
Phase A (CarrierCode): ??? assignments
Phase B (NAIC cross-ref): ??? assignments
Phase C (remaining): ??? assignments
Certs with >6 carriers: ??? (overflow)
Carrier name variants
(same NAIC, different name): [list]
CARRIER RATING:
AMBestRatingOK=yes: ???
AMBestRatingOK=NULL/other: ???
REQUIREMENT COVERAGE (reference only):
Total records: ???
Unique requirement_names: [list]
REVIEW STATUS (reference only, not migrated):
GL: [distribution]
Auto: [distribution]
WC: [distribution]
UMB: [distribution]
LL: [distribution]
Other: [distribution]
UDP: [distribution]
Issues flagged: ???
Ready to migrate: ???
| Scenario | Behavior |
|---|---|
| certificate_id not in mapping | Skip record, log to issues CSV |
| certificate_id in mapping but cert was Area 4 skip | Skip record, log as cascade skip |
| Unknown Other1 type | Default to OtherCoverage, create new type, log |
| Wrong-table type (e.g., "Commercial Umbrella") | Migrate as OtherCoverage, flag for review |
| UDPLimits = -1 or NULL | Set limit = NULL |
| Boolean field unexpected value | Default to False, log the value |
| CarrierCode not A-F | Use next available slot, log |
| >6 unique carriers per certificate | Fill A-F, log overflow |
| Date parse failure | Set to NULL, log |
| NAIC = 99999 (placeholder) | Store as-is, flag in report |
| Truncated/malformed carrier name | Store as-is, flag in report |
| Limit exceeds threshold | Store as-is, flag as suspicious |
| Duplicate type name (case variant) | Merge to normalized form |
| File | Purpose |
|---|---|
id_mapping_coverage.csv |
table_name β old_id β new_id β certificate_id β model_name |
id_mapping_coverage_types.csv |
source_value β normalized β target_model β type_id |
carrier_backfill_report.csv |
certificate_id β slots A-F (name + NAIC) β method (code/naic/sequential) β overflow |
migration_issues.csv |
All flagged records with issue description |
migration_report.txt |
Summary statistics and validation results |
| # | Check | Method |
|---|---|---|
| 1 | Record counts | DTX 1.0 count per table == DTX 2.0 count (minus skipped) |
| 2 | Certificate linkage | Every coverage record has a valid Certificate FK |
| 3 | Carrier A-F | Spot-check 20 certs β verify slots match coverage carrier info |
| 4 | NAIC cross-reference | For spot-checked certs, verify same NAIC is in same slot across tables |
| 5 | Type coverage | Every OtherCoverage/PropertyCoverage has a valid Type FK |
| 6 | Type dedup | No duplicate type names (case-insensitive) |
| 7 | Limit values | Spot-check 20 records per table β values match originals |
| 8 | Booleans | Spot-check 10 records per table β booleans match "yes"/NULL |
| 9 | Timestamps | Coverage created matches parent certificate's created |
| 10 | CarrierRating count | Count == certificates with AMBestRatingOK=yes |
| 11 | No orphans | No coverage records pointing to non-existent certificates |
| 12 | ID mapping complete | Every source PK in every table exists in mapping CSV |
| 13 | Wrong-table types | Review flagged types (Decision #3) β confirm DTX 2.0 can find them |
| 14 | Evaluation cross-link | Spot-check 10 certs β verify EvaluationCoverage.coverage_type strings match model names |
| 15 | Cascade check | Skipped coverage records == expected (from Area 4 skip count) |
| Depends On | What's Needed |
|---|---|
| Area 2: Customers β Accounts | Account context (indirect, via certificates) |
| Area 4: Certificates & Documents | id_mapping_certificates.csv, certificate.AMBestRatingOK, certificate.WCExempt, certificate create_time for timestamp preservation |
| Depended On By | For |
|---|---|
| Area 6: Requirements & Compliance | COIRiskProfile template coverage (user_defined_policy templates), evaluation validation |
Significantly easier than Areas 3 and 4. Most fields map 1:1 with identical names.
| Factor | Impact |
|---|---|
| 1:1 field mapping (90%+) | Makes this manageable |
| No structural transformation | Flat table β flat model |
| DTX 2.0 "Additional fields" match exactly | gldescmisc, autoterm1, etc. |
| Carrier A-F backfill with NAIC cross-ref | Main complexity |
| other_coverage classification | Requires keyword matching + manual review |
| user_defined_policy untestable | 100% templates in sample β cert path unknown |
| 4 pre-migration actions | Must resolve before starting |
| # | Decision | Status | Approach |
|---|---|---|---|
| 1 | Certificate FK linking | Resolved | certificate FK set, coi_risk_profile + _options FKs NULL |
| 2 | Carrier A-F backfill | Resolved | NAIC cross-reference from LL/Other CarrierCodes, then sequential for unmatched |
| 3 | other_coverage classification | Resolved | Keyword-match β Property vs Other, case-insensitive dedup, flag wrong-table types |
| 4 | user_defined_policy split | Resolved | Templates β Area 6; cert records β Property (if loss_payee/mortgagee) or Other |
| 5 | CarrierRating | Pending Action #4 | Per-certificate with NULL carrier info (default), or per-carrier (if confirmed) |
| 6 | ReviewStatus/Reason | Resolved | Drop all β consistent with Area 4 |
| 7 | requirement_coverage | Resolved | Don't migrate β operational tracking |
| 8 | DescriptionOfOperations | Deferred | Area 6 β requirement-level model |
| 9 | WCExempt cross-ref | Resolved | Set any_excluded=True on WC records for WCExempt certificates |
| 10 | Limit value format | Resolved | Store raw as-is, -1 β NULL, flag suspicious values in dry-run |
| 11 | Missing target fields | Resolved | GLLimMisc β append to gldescmisc; Other1Desc1 β log only, don't pollute limit fields |
| 12 | Timestamp preservation | Resolved | Use parent certificate's create_time for coverage created/modified |