david-leads / app /coverage.py
betterwithage's picture
Deploy V8.2 P1 gap-fill from GitHub main
550e047 verified
Raw
History Blame Contribute Delete
3.35 kB
# SPDX-License-Identifier: Apache-2.0
# © 2026 SZL Holdings — David Leads V8.2 · P1-E coverage-gap identifier
"""
coverage.py — pure-function "Likely gap" identifier (Salesforce FSC coverage-gap detection,
EZLynx renewal cross-sell, lighter-weight + rules-based).
Given an event_type and the prospect's OPTIONAL held_policies (default: none known), compute
the single most-likely coverage gap to lead the conversation with. No network, no fabrication
— if nothing applies and policies are unknown, returns a generic coverage-review prompt.
"""
from __future__ import annotations
from typing import Any, Iterable
# event_type -> (gap label, the held-policy keyword that would CLOSE this gap, recommended product)
_GAP_RULES: dict[str, tuple[str, tuple[str, ...], str]] = {
"business_formation": ("key-person gap", ("key-person", "key_person", "keyperson", "buy-sell", "buy_sell"),
"Key-person life + buy-sell funding"),
"home_purchase": ("mortgage-protection gap", ("mortgage", "mortgage-protection", "mortgage_protection"),
"Mortgage-protection term tied to the loan balance"),
"new_baby": ("education-funding gap", ("education", "529", "college", "education_funding"),
"Education-funding strategy + family term coverage"),
"near_retirement": ("income/LTC gap", ("annuity", "ltc", "long-term-care", "long_term_care"),
"Annuity + long-term-care review"),
"promotion": ("income-protection gap", ("disability", "di", "income-protection"),
"Disability-income to protect peak earnings"),
"new_professional_license": ("starter-coverage gap", ("term", "disability", "di"),
"Starter term + disability income"),
"address_change": ("beneficiary/coverage-refresh gap", ("review", "refresh"),
"Coverage refresh + beneficiary review"),
}
def _has_policy(held: Iterable[str] | None, keywords: tuple[str, ...]) -> bool:
if not held:
return False
blob = " ".join(str(h).lower() for h in held)
return any(k in blob for k in keywords)
def likely_gap(event_type: str, held_policies: Iterable[str] | None = None) -> dict[str, Any]:
"""Compute the likely coverage gap for an event_type given optional held policies."""
rule = _GAP_RULES.get(event_type or "")
if rule is None:
return {
"has_gap": True,
"label": "coverage-review opportunity",
"recommended": "General coverage review",
"basis": "no event-specific rule; defaulting to a coverage review",
"held_policies_known": bool(held_policies),
"advisory": True,
}
label, close_keywords, recommended = rule
closed = _has_policy(held_policies, close_keywords)
return {
"has_gap": not closed,
"label": ("covered: " + label.replace(" gap", "")) if closed else label,
"recommended": recommended,
"basis": ("held policy appears to close this gap" if closed
else "no closing policy supplied (default: gap likely open)"),
"held_policies_known": bool(held_policies),
"advisory": True,
}