All benefits

Plan Facts Parsing Analysis · v1

Group Life

Per-class Basic Life parse with AD&D and Dependent Life riders. Class-aware coverage formulas (fixed amount or salary multiplier), age reduction schedules, waiver of premium, conversion, portability, and accelerated death benefit.

Endpoint
POST /life_add
Parse method
parseQuoteGroupLife()
Source range
PlanfactService.php:972–1362 (~391 lines)
Source pull
plansight - Bit Bucket Pull 4.26

Bottom line

Three items worth real attention.

(1) The parser writes to a Disability-prefixed field name (disabilityWaiverWaitingPeriod) that doesn't belong here. (2) The Contribution Type enum mapping reverses semantics: "noncontributory" (employer-paid) maps to "contributory". (3) Child benefit dollar amounts are stored in fields named "Reduction" — the same naming concern as Voluntary Life. All three have Cursor prompts.

Per-class handling

Group Life uses a suffixed-field model for multi-class support — each class gets indexed fields:

Quote fieldSourceNotes
groupLifeCalculation-Nderived from Benefit Amount"fixed" or "salary"
deathBenefit-NBenefit AmountAmount or salary multiplier
maximumBenefit-NBenefit Amount (salary cap)Salary cap if calculation = "salary"

Classes parsed from Basic Life.Classes (split on " - "). Lines 986–1036.

Other fields (waiver, conversion, portability, age reductions, AD&D, Dependent Life) use the first class only. Line 1035.

What's mapped

Plan Facts fieldQuote fieldNotes
Basic Life.Classes (all)groupLifeCalculation-N + deathBenefit-N + maximumBenefit-NPer-class loop (line 1010)
Basic AD&D presencegroupLifeCoverage"basicLifeAndADD" / "basicLifeOnly" (line 1038)
Basic Dependent Life presencegroupLifeDependentBenefitsIncluded / Not Included (line 1045)
Basic Life.Contributions.[Class].Contribution TypecontributionVoluntaryEnum reversal — see issue below (line 1052)
Basic Life.Employee Age Reductions.[Class] (up to 4)groupLifeTier{1..4}Age + groupLifeTier{1..4}Reduction + groupLifeReductionRateTiersLine 1072
Basic Life.Waiver of Premium.[Class].Elimination PeriodeliminationPeriodSwitch: 3/6/9/12 Mo., "Determined By Carrier" (line 1105)
Basic Life.Waiver of Premium.[Class].DurationdisabilityWaiverWaitingPeriodField name belongs in Disability — see issue below (line 1140)
Basic Life.Accelerated Death Benefit.[Class].Benefit AmountacceleratedDeathBenefit + percentDeathBenefitPresence + regex % (line 1162)
Basic Life.Accelerated Death Benefit.[Class].Life ExpectancylifeExpectancySwitch: 6/12/24 (line 1178)
Basic Life.Conversion.[Class].ConversionconversionIncluded / Not Included (line 1195)
Basic Life.Portability.[Class].PortabilityportabilityIncluded / Not Included (line 1210)
Basic Life.Rates.[Class].Composite Rate.RateLifeComposite only (line 1225)
Basic AD&D.[Service].[Class].Benefit Amount (6 services)seatBelt, airBag, repatriation, education, childCare, commonCarrierIncluded / Not Included (line 1235)
Basic AD&D.Rates.[Class].Composite Rate.RateADDComposite (line 1262)
Basic Dependent Life.Contributions.[Class].Contribution TypegroupLifePremiumPaidBy"Employer" / "Employee" / "Shared" (line 1272)
Basic Dependent Life.Spouse Death Benefit.[Class].Spouse Benefit AmountspouseBenefitDollar amount (line 1292)
Basic Dependent Life.Child Death Benefit.[Class].Child Benefit AmountgroupLifeDependentTier3Reduction + groupLifeDependentReductionRateTiersStored in "Reduction" field — see issue below (line 1304)
Basic Dependent Life.Child Death Benefit.[Class].Child Benefit from Birth to 14 daysgroupLifeDependentTier1Reduction(line 1318)
Basic Dependent Life.Child Death Benefit.[Class].Child Benefit from 15 days to 6 monthsgroupLifeDependentTier2Reduction(line 1332)
Basic Dependent Life.Child Death Benefit.[Class].Student Extension AgegroupLifeStudentAgeRangeTo(line 1346)
Basic Dependent Life.Rates.[Class].Composite Rate.RateSPOUSE + CHILDSame rate to both (line 1353)

Plan-level / not mapped

Potentially mapped incorrectly

Three items.

Group Life writes to a Disability-prefixed field PlanfactService.php:1140–1158

Inside parseQuoteGroupLife(), the Waiver of Premium Duration is assigned to disabilityWaiverWaitingPeriod — a field name that belongs in the Disability parsers (ST/LT). Likely a copy-paste artifact. Either the field needs renaming to a Group Life equivalent, or there's an unintended cross-write into a Disability field on the Quote.

Cursor prompt
In app/Services/PlanfactService.php around lines 1140–1158, inside parseQuoteGroupLife(), the Waiver of Premium Duration is being assigned to a field named disabilityWaiverWaitingPeriod. The "disability" prefix doesn't belong in a Group Life parser.

Please:
1. Confirm the field name and the assignment by showing me the relevant lines.
2. Find where disabilityWaiverWaitingPeriod is consumed (form templates, presentation rendering, exports). Is it actually a Disability field, or a misnamed Life field?
3. If it's a Disability field, rename the assignment in this Group Life context to something like groupLifeWaiverDuration (and add the field to the Quote model + form if it doesn't already exist).
4. If it's a misnamed Life field, rename the field everywhere — Quote model, form, parser — to something like groupLifeWaiverDuration.
5. Don't change anything yet — show the proposed end-to-end change.
Contribution Type enum reversal PlanfactService.php:1052–1070

The Contribution Type switch maps Plan Facts "noncontributory" (employer pays everything; no employee contribution) to the Quote value "contributory". Semantically backward — "noncontributory" should map to something like "employer" or stay as "noncontributory", not "contributory". Worth confirming because contribution type drives downstream rendering and broker conversation.

Cursor prompt
In app/Services/PlanfactService.php around lines 1052–1070, inside parseQuoteGroupLife(), the Contribution Type switch maps the Plan Facts value "noncontributory" to the Quote value "contributory" (assigned to the contributionVoluntary field).

This looks semantically backward — "noncontributory" means the employer pays the full premium and the employee contributes nothing.

Please:
1. Show me the current switch statement.
2. Find where contributionVoluntary is read downstream (form rendering, presentation, etc.) to understand what values that field is expected to take.
3. Tell me what the correct mapping should be:
   - "noncontributory" (employer pays) → ?
   - "voluntary" / "gross-up" → ?
   - "contributory" / "tax choice" → ?
4. Show me a draft fix.
5. Note: the same enum is used in multiple parsers (Disability, Life, others). If we change it here, the same change might be needed in other parsers — check first.
Child benefit amounts stored in "Reduction" fields PlanfactService.php:1304–1344

Same pattern as in Voluntary Life: Child Benefit Amount and the age-stratified breakdowns are stored in fields named groupLifeDependentTier{1..3}Reduction. The "Reduction" suffix implies a percentage; the values are dollar benefit amounts.

Cursor prompt
In app/Services/PlanfactService.php inside parseQuoteGroupLife() (around lines 1304–1344), Child Benefit Amount values are being assigned to fields named groupLifeDependentTier{1..3}Reduction. The "Reduction" suffix is misleading because the values are dollar benefit amounts, not reduction percentages.

The same pattern exists in parseQuoteVoluntaryLife() (lines 841–880).

Please:
1. Find the form templates that consume groupLifeDependentTier{1..3}Reduction and voluntaryLifeDependentTier{1..3}Reduction. Confirm whether the form treats them as benefit amounts.
2. If yes, propose a coordinated rename to groupLifeChildTier{1..3}Benefit and voluntaryLifeChildTier{1..3}Benefit (or similar) end-to-end — Quote model, form templates, parser, any export / presentation code.
3. Don't change anything yet — show the impact analysis and a draft diff.

Manual-entry-only fields

Recommendations

  1. Resolve the disabilityWaiver field naming Hour

    Either rename to a Group Life equivalent or confirm intentional shared field usage.

  2. Fix the Contribution Type enum reversal Half day

    Verify the correct semantic mapping, then update. Check other parsers using the same enum for the same bug.

  3. Coordinate Tier-Reduction naming with Voluntary Life Day

    Rename across both parsers and the form templates that consume the fields.

  4. Consider extracting Guarantee Issue amounts Day

    Group Life GI is often carrier-underwritten and meaningful at the plan level. Worth adding if Plan Facts returns it.

Code references

FileLinesPurpose
app/Services/PlanfactService.php272–302life_add endpoint config
app/Services/PlanfactService.php464Dispatch to parseQuoteGroupLife
app/Services/PlanfactService.php972–1362parseQuoteGroupLife() — full parser
app/Services/PlanfactService.php986–1036Per-class basic life loop
app/Services/PlanfactService.php1052–1070Contribution Type enum (reversal concern)
app/Services/PlanfactService.php1140–1158disabilityWaiverWaitingPeriod assignment (concern)
app/Services/PlanfactService.php1304–1344Child benefit / Tier-Reduction concern