# 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, }