InsuranceBot / tests /test_recommendation_fit_gate.py
rohitsar567's picture
deploy#2: unified reco-fit gate + session-privacy fix + profile-completeness + full UI rebuild
b134f5b
Raw
History Blame Contribute Delete
31.3 kB
"""KI-280 (2026-05-16) β€” UNIFIED recommendation-fit gate.
Pins all 7 personas from the live Playwright audit
(/tmp/persona_[1-7]_result.json) so the CITED card list and the advisory
prose are gated by the SAME fitness logic.
The unified gate (backend/retrieval_filters.filter_pipeline, on the live
single_brain β†’ brain_tools.retrieve_policies path) requires the cited set
to pass ALL of:
1. Product-type vs intent β€” no fixed-benefit / hospital-cash / PA / CI
to a comprehensive-indemnity buyer (KI-279, preserved). Inverse
preserved: top-up seeker (P4) + explicit-CI seeker (P6) still get
those products.
2. Hard eligibility β€” when insuring seniors / parents (~70), drop
plans whose max entry age can't accept them; surface senior-eligible.
3. Required features β€” explicit maternity/newborn need β†’ only cite
plans whose facts confirm it (unverified ones ranked strictly below).
4. Objective / fit ranking β€” cited list ordered by scorecard fit-score /
stated objective; #1 = best fit for THIS profile (fixes the
grade/rank inversion + P5 cost-objective lead).
5. Dedup β€” same-product / marketing-variant duplicates
collapsed (shared canonical/UIN identity from policy_identity).
Audit personas (transcripts + observed-bad outcomes drive the asserts):
P1 Young first-timer comprehensive β€” Star Hospital Cash wrongly cited;
C/65 ranked above B/75. EXPECT: no fixed-benefit; #1 = best grade.
P2 Senior + PED β€” New National Parivar Mediclaim cited
twice; A/77 ranked LAST. EXPECT: deduped; A-grade #1.
P3 Family + maternity (very imp.) β€” non-maternity plans cited equal to
the maternity-confirmed one; Star Hospital Cash cited.
EXPECT: maternity-confirmed first, fixed-benefit dropped.
P4 Top-up seeker (INVERSE) β€” Advanced Top Up cited twice.
EXPECT: top-up KEPT (inverse preserved) + deduped.
P5 Budget, cost is #1 need β€” leads with non-cheapest.
EXPECT: cost-objective β‡’ cheapest-appropriate ranks first.
P6 Critical-illness seeker (INV.) β€” EXPECT: CI plans KEPT.
P7 Parents both 70 + PED β€” max-entry-65 plans cited; Chola
Flexi Supreme + Flexi Health (same insurer) both cited.
EXPECT: entry-age-65 plans dropped; senior-eligible surfaced; deduped.
Run:
.venv/bin/python -m pytest -q tests/test_recommendation_fit_gate.py
"""
from __future__ import annotations
import unittest
from backend.policy_identity import canonical_key, normalize_uin, product_key
from backend.retrieval_filters import (
apply_eligibility_filter,
dedup_by_policy,
filter_pipeline,
rank_by_profile_fit,
)
from backend.single_brain import _build_recommendation_citations
def _chunk(
policy_id,
policy_name,
*,
score=0.5,
policy_type=None,
policy_type_canonical=None,
uin_code=None,
copay_pct=None,
sum_insured_options=None,
max_entry_age=None,
min_entry_age=None,
maternity=None,
newborn=None,
grade=None,
overall_score=None,
doc_type="policy",
):
"""Chunk dict shaped like brain_tools.retrieve_policies output AFTER the
policy_facts + scorecard enrichment step (KI-280 added uin_code /
max_entry_age / maternity_coverage / newborn_coverage)."""
return {
"policy_id": policy_id,
"policy_name": policy_name,
"insurer_slug": policy_id.split("__")[0],
"doc_type": doc_type,
"score": score,
"chunk_text": "",
"policy_type_indemnity_or_fixed": policy_type_canonical,
"policy_type": policy_type,
"uin_code": uin_code,
"deductible_amount": None,
"co_payment_pct": copay_pct,
"sum_insured_options": sum_insured_options,
"max_entry_age": max_entry_age,
"min_entry_age": min_entry_age,
"maternity_coverage": maternity,
"newborn_coverage": newborn,
"_grade": grade,
"_overall_score": overall_score,
}
# ── Shared catalog slices ───────────────────────────────────────────────────
GOOD_INDEMNITY_A = _chunk(
"niva-bupa__reassure-3", "ReAssure 3.0",
score=0.55, policy_type_canonical="indemnity", policy_type="family_floater",
uin_code="MAXHLIP21177V032122", copay_pct=0,
sum_insured_options=[1_000_000, 1_500_000, 2_000_000, 5_000_000],
max_entry_age=70, maternity=True, newborn=True, grade="A", overall_score=88,
)
DECENT_INDEMNITY_C = _chunk(
"cholamandalam__flexi-health-supreme__wordings", "Chola Flexi Health Supreme",
score=0.72, policy_type_canonical="family_floater", policy_type=None,
uin_code="CHOHLIP27040V032627", copay_pct=0,
sum_insured_options=[1_000_000, 1_500_000, 2_500_000],
max_entry_age=75, maternity=True, grade="C", overall_score=65,
)
STAR_HOSPITAL_CASH = _chunk(
"star-health__star-hospital-cash__brochure", "Star Hospital Cash",
score=0.71, policy_type="hospital_cash", uin_code="SHAHLIP20046V011920",
max_entry_age=65, grade="D", overall_score=60,
)
# ════════════════════════════════════════════════════════════════════════════
# Shared canonical-identity helper (Rule 5 building block)
# ════════════════════════════════════════════════════════════════════════════
class TestPolicyIdentity(unittest.TestCase):
def test_uin_primary(self):
a = {"policy_id": "hdfc-ergo__optima-secure__wordings",
"uin_code": "HDFHLIP25041V062425"}
b = {"policy_id": "hdfc-ergo__optima-secure-older-variant",
"uin_code": "HDFHLIP25041V062425"}
self.assertEqual(canonical_key(a), canonical_key(b),
"Same UIN β‡’ same product (marketing rename).")
def test_product_key_collapses_doctype_siblings(self):
self.assertEqual(
product_key("acko__health-iii__wordings"), "acko__health-iii")
self.assertEqual(
product_key("acko__health-iii__brochure"), "acko__health-iii")
a = {"policy_id": "acko__health-iii__wordings"}
b = {"policy_id": "acko__health-iii__brochure"}
self.assertEqual(canonical_key(a), canonical_key(b))
def test_distinct_products_stay_distinct(self):
a = {"policy_id": "cholamandalam__flexi-health-supreme__wordings",
"uin_code": "CHOHLIP27040V032627"}
b = {"policy_id": "cholamandalam__flexi-health__wordings",
"uin_code": "CHOHLIP24145V062526"}
self.assertNotEqual(canonical_key(a), canonical_key(b),
"Different UIN β‡’ genuinely different products.")
def test_normalize_uin_rejects_junk(self):
self.assertEqual(normalize_uin(""), "")
self.assertEqual(normalize_uin("N/A"), "")
self.assertEqual(normalize_uin({"value": "SHAHLIP20046V011920"}),
"SHAHLIP20046V011920")
# ════════════════════════════════════════════════════════════════════════════
# P1 β€” Young first-timer comprehensive (15L, zero co-pay)
# ════════════════════════════════════════════════════════════════════════════
P1 = {
"age": 29, "location_tier": "metro", "income_band": "25L+",
"primary_goal": "first_buy", "existing_cover_inr": 0,
"health_conditions": ["none"], "desired_sum_insured_inr": 1_500_000,
"copay_pct": 0, "dependents": "self",
}
class TestPersona1(unittest.TestCase):
def test_no_fixed_benefit_and_best_grade_first(self):
catalog = [DECENT_INDEMNITY_C, STAR_HOSPITAL_CASH, GOOD_INDEMNITY_A]
filtered, guard = filter_pipeline(
catalog, profile=P1,
query="comprehensive metro 15 lakh zero co-pay first-time buyer",
intent="recommendation")
ids = [c["policy_id"] for c in filtered]
self.assertNotIn("star-health__star-hospital-cash__brochure", ids,
"P1: fixed-benefit hospital-cash must not be cited")
self.assertTrue(ids)
self.assertEqual(ids[0], "niva-bupa__reassure-3",
"P1: #1 must be the best-fit (A/88), not C/65")
# ════════════════════════════════════════════════════════════════════════════
# P2 β€” Senior + PED. Dedup + grade/rank inversion (A/77 was LAST).
# ════════════════════════════════════════════════════════════════════════════
P2 = {
"age": 58, "location_tier": "tier-2", "income_band": "10L-25L",
"primary_goal": "first_buy", "existing_cover_inr": 0,
"health_conditions": ["diabetes", "hypertension"],
"desired_sum_insured_inr": 1_000_000, "copay_pct": 10,
"dependents": "self+spouse",
}
P2_NNP_A = _chunk(
"national-insurance__new-national-parivar-mediclaim__wordings",
"New National Parivar Mediclaim", score=0.70,
policy_type_canonical="family_floater", uin_code="NICHLIP26999V010203",
copay_pct=10, sum_insured_options=[500_000, 1_000_000, 1_500_000],
max_entry_age=80, grade="C", overall_score=66)
P2_NNP_DUP = _chunk(
"national-insurance__new-national-parivar-mediclaim__brochure",
"New National Parivar Mediclaim", score=0.62,
policy_type_canonical="family_floater", uin_code="NICHLIP26999V010203",
copay_pct=10, sum_insured_options=[500_000, 1_000_000, 1_500_000],
max_entry_age=80, grade="C", overall_score=66)
P2_REASSURE_A = _chunk(
"niva-bupa__reassure-3", "ReAssure 3.0", score=0.55,
policy_type_canonical="indemnity", uin_code="MAXHLIP21177V032122",
copay_pct=10, sum_insured_options=[1_000_000, 1_500_000],
max_entry_age=70, grade="A", overall_score=77)
class TestPersona2(unittest.TestCase):
def test_dedup_variant_and_a_grade_leads(self):
catalog = [P2_NNP_A, P2_NNP_DUP, P2_REASSURE_A]
filtered, _ = filter_pipeline(
catalog, profile=P2,
query="senior 58 family floater diabetes hypertension 10 lakh",
intent="recommendation")
ids = [c["policy_id"] for c in filtered]
# Same-UIN doctype siblings collapse to one card.
nnp = [i for i in ids if "new-national-parivar" in i]
self.assertEqual(len(nnp), 1,
"P2: New National Parivar must appear ONCE, not twice")
self.assertEqual(ids[0], "niva-bupa__reassure-3",
"P2: A/77 must lead, not be last")
# ════════════════════════════════════════════════════════════════════════════
# P3 β€” Family + maternity (explicitly "very important")
# ════════════════════════════════════════════════════════════════════════════
P3 = {
"age": 34, "location_tier": "metro", "income_band": "25L-40L",
"primary_goal": "first_buy maternity newborn family floater",
"existing_cover_inr": 0, "health_conditions": ["none"],
"desired_sum_insured_inr": 2_500_000, "copay_pct": 0,
"dependents": "self+spouse+kids",
}
P3_MATERNITY_OK = _chunk(
"cholamandalam__flexi-health-supreme__wordings", "Chola Flexi Health Supreme",
score=0.60, policy_type_canonical="family_floater",
uin_code="CHOHLIP27040V032627", copay_pct=0,
sum_insured_options=[2_500_000], max_entry_age=75,
maternity=True, newborn=True, grade="C", overall_score=65)
P3_NO_MATERNITY = _chunk(
"hdfc-ergo__optima-secure", "my:Optima Secure", score=0.71,
policy_type_canonical="indemnity", uin_code="HDFHLIP25041V062425",
copay_pct=0, sum_insured_options=[2_500_000], max_entry_age=65,
maternity=False, newborn=False, grade="B", overall_score=75)
P3_HOSPITAL_CASH = _chunk(
"star-health__star-hospital-cash__brochure", "Star Hospital Cash",
score=0.68, policy_type="hospital_cash", uin_code="SHAHLIP20046V011920",
max_entry_age=65, maternity=True, grade="D", overall_score=60)
class TestPersona3(unittest.TestCase):
def test_maternity_confirmed_first_fixed_benefit_dropped(self):
catalog = [P3_MATERNITY_OK, P3_NO_MATERNITY, P3_HOSPITAL_CASH]
filtered, _ = filter_pipeline(
catalog, profile=P3,
query="family floater maternity newborn 25 lakh metro first-time",
intent="recommendation")
ids = [c["policy_id"] for c in filtered]
self.assertNotIn("star-health__star-hospital-cash__brochure", ids,
"P3: hospital-cash is not a comprehensive family plan")
self.assertTrue(ids)
self.assertEqual(
ids[0], "cholamandalam__flexi-health-supreme__wordings",
"P3: maternity-confirmed plan must rank above the "
"non-maternity B-grade plan when maternity is required")
# The non-maternity plan, if present at all, ranks strictly below.
if "hdfc-ergo__optima-secure" in ids:
self.assertLess(
ids.index("cholamandalam__flexi-health-supreme__wordings"),
ids.index("hdfc-ergo__optima-secure"))
# ════════════════════════════════════════════════════════════════════════════
# P4 β€” Top-up seeker (INVERSE β€” top-up must be KEPT). + dedup of Γ—2.
# ════════════════════════════════════════════════════════════════════════════
P4 = {
"age": 44, "location_tier": "metro", "income_band": "10L-25L",
"primary_goal": "cheapest top-up over existing employer cover",
"existing_cover_inr": 500_000, "health_conditions": ["none"],
"desired_sum_insured_inr": 2_000_000, "copay_pct": 10,
"dependents": "self",
}
P4_TOPUP_A = _chunk(
"royal-sundaram__advanced-top-up__wordings", "Advanced Top Up",
score=0.76, policy_type_canonical="super_top_up",
uin_code="RSAHLIP21055V032021", copay_pct=0,
sum_insured_options=[1_000_000, 2_000_000], max_entry_age=65,
grade="A", overall_score=76)
P4_TOPUP_DUP = _chunk(
"royal-sundaram__advanced-top-up__brochure", "Advanced Top Up",
score=0.69, policy_type_canonical="super_top_up",
uin_code="RSAHLIP21055V032021", copay_pct=0,
sum_insured_options=[1_000_000, 2_000_000], max_entry_age=65,
grade="A", overall_score=76)
P4_SBI = _chunk(
"sbi-general__arogya-supreme", "Arogya Supreme", score=0.60,
policy_type_canonical="family_floater", uin_code="SBIHLIP21099V012021",
copay_pct=10, sum_insured_options=[2_000_000], max_entry_age=65,
grade="B", overall_score=75)
class TestPersona4Inverse(unittest.TestCase):
def test_topup_kept_and_deduped(self):
catalog = [P4_TOPUP_A, P4_TOPUP_DUP, P4_SBI]
filtered, _ = filter_pipeline(
catalog, profile=P4,
query="cheapest top-up over existing 5 lakh employer cover 20 lakh",
intent="recommendation")
ids = [c["policy_id"] for c in filtered]
topups = [i for i in ids if "advanced-top-up" in i]
self.assertEqual(len(topups), 1,
"P4: Advanced Top Up must appear ONCE (was Γ—2)")
self.assertTrue(any("advanced-top-up" in i for i in ids),
"P4 INVERSE: top-up seeker MUST still get top-up plans")
# ════════════════════════════════════════════════════════════════════════════
# P5 β€” Budget-constrained; cost is the #1 stated objective.
# ════════════════════════════════════════════════════════════════════════════
P5 = {
"age": 31, "location_tier": "tier-3", "income_band": "<10L",
"primary_goal": "cost_optimize cheapest lowest premium",
"existing_cover_inr": 0, "health_conditions": ["none"],
"desired_sum_insured_inr": 500_000, "copay_pct": 30,
"dependents": "self",
}
# The live P5 audit defect was COSINE-DRIVEN inversion: the bot led with
# the highest-cosine plan even though, at the same scorecard fit tier, it
# was not the cost-appropriate pick for a "lowest premium is my top
# priority" user. We pin the true root cause: at an equal scorecard tier,
# a higher-cosine plan must NOT out-rank an equal-fit plan when cost is the
# stated #1 objective (cosine is damped; the scorecard fit-score decides).
P5_CHEAPEST = _chunk(
"royal-sundaram__arogya-sanjeevani", "Arogya Sanjeevani", score=0.55,
policy_type_canonical="indemnity", uin_code="RSAHLIP21010V012021",
copay_pct=5, sum_insured_options=[500_000], max_entry_age=65,
grade="C", overall_score=66)
P5_PRICIER = _chunk(
"hdfc-ergo__optima-secure", "my:Optima Secure", score=0.75,
policy_type_canonical="indemnity", uin_code="HDFHLIP25041V062425",
copay_pct=0, sum_insured_options=[500_000, 1_000_000], max_entry_age=65,
grade="C", overall_score=64)
class TestPersona5(unittest.TestCase):
def test_cost_objective_not_cosine_dominated(self):
# Both plans are the SAME scorecard grade tier (C). The pricier
# plan's ONLY advantage is raw cosine (0.75 vs 0.55) β€” exactly the
# live-audit inversion. With cost the #1 objective, the gate damps
# cosine so the marginally-better-fit cost-appropriate plan (the
# canonical Arogya Sanjeevani standard product, 66 vs 64) leads
# instead of the higher-cosine one.
ranked = rank_by_profile_fit([P5_PRICIER, P5_CHEAPEST], P5)
ids = [c["policy_id"] for c in ranked]
self.assertEqual(len(ids), 2)
self.assertEqual(
ids[0], "royal-sundaram__arogya-sanjeevani",
"P5: cost objective β€” fit-score decides, NOT raw cosine")
def test_without_cost_objective_cosine_still_breaks_ties(self):
# Sanity / non-regression: for a NON-cost profile the cosine weight
# is unchanged, so the higher-cosine plan can still win a near-tie.
non_cost = dict(P5, primary_goal="first_buy comprehensive")
ranked = rank_by_profile_fit([P5_CHEAPEST, P5_PRICIER], non_cost)
self.assertEqual(
[c["policy_id"] for c in ranked][0], "hdfc-ergo__optima-secure",
"non-cost profile: cosine still contributes normally")
# ════════════════════════════════════════════════════════════════════════════
# P6 β€” Critical-illness seeker (INVERSE β€” CI must be KEPT).
# ════════════════════════════════════════════════════════════════════════════
P6 = {
"age": 42, "location_tier": "metro", "income_band": "25L+",
"primary_goal": "critical illness lump-sum fixed-benefit plan only",
"existing_cover_inr": 1_500_000, "health_conditions": ["none"],
"desired_sum_insured_inr": 2_500_000, "copay_pct": 0,
"dependents": "self",
}
P6_CI_1 = _chunk(
"national-insurance__national-critical-illness", "National Critical Illness",
score=0.54, policy_type="critical_illness",
policy_type_canonical="fixed_benefit", uin_code="NICCIIP20001V010203",
sum_insured_options=[2_500_000], max_entry_age=65, grade="D",
overall_score=54)
P6_CI_2 = _chunk(
"go-digit__digit-health-care-plus", "Digit Health Care Plus", score=0.75,
policy_type="critical_illness", policy_type_canonical="fixed_benefit",
uin_code="GODHLIP21099V012021", sum_insured_options=[2_500_000],
max_entry_age=65, grade="B", overall_score=75)
class TestPersona6Inverse(unittest.TestCase):
def test_ci_plans_kept_for_explicit_ci_seeker(self):
catalog = [P6_CI_1, P6_CI_2]
filtered, _ = filter_pipeline(
catalog, profile=P6,
query="critical illness lump-sum 25 lakh fixed benefit",
intent="recommendation")
ids = {c["policy_id"] for c in filtered}
self.assertIn("national-insurance__national-critical-illness", ids,
"P6 INVERSE: explicit CI seeker MUST still get CI plans")
self.assertIn("go-digit__digit-health-care-plus", ids)
# ════════════════════════════════════════════════════════════════════════════
# P7 β€” Parents both 70 + PED. Entry-age gate + dedup + senior surfacing.
# ════════════════════════════════════════════════════════════════════════════
P7 = {
"age": 36, "location_tier": "metro", "income_band": "10L-25L",
"primary_goal": "parents health cover senior citizens",
"existing_cover_inr": 0,
"health_conditions": ["father diabetes", "mother hypertension arthritis"],
"desired_sum_insured_inr": 1_000_000, "copay_pct": 10,
"dependents": "self+parents", "parents_to_insure": True,
"parents_age_max": 70, "parents_has_ped": True,
}
P7_CHOLA_SUPREME = _chunk(
"cholamandalam__flexi-health-supreme__wordings", "Chola Flexi Health Supreme",
score=0.72, policy_type_canonical="family_floater",
uin_code="CHOHLIP27040V032627", copay_pct=10,
sum_insured_options=[1_000_000], max_entry_age=75, grade="C",
overall_score=65)
P7_CHOLA_FLEXI = _chunk( # same insurer, DIFFERENT product, max_entry 65
"cholamandalam__flexi-health__wordings", "Flexi Health", score=0.67,
policy_type_canonical="individual", uin_code="CHOHLIP24145V062526",
copay_pct=10, sum_insured_options=[1_000_000], max_entry_age=65,
grade="C", overall_score=67)
P7_OPTIMA_65 = _chunk(
"hdfc-ergo__optima-secure", "my:Optima Secure", score=0.70,
policy_type_canonical="indemnity", uin_code="HDFHLIP25041V062425",
copay_pct=10, sum_insured_options=[1_000_000], max_entry_age=65,
grade="B", overall_score=75)
P7_SENIOR_OK = _chunk(
"star-health__senior-citizens-red-carpet__brochure",
"Star Senior Citizens Red Carpet", score=0.50,
policy_type_canonical="indemnity", uin_code="SHAHLIP26041V082526",
copay_pct=10, sum_insured_options=[1_000_000], min_entry_age=60,
max_entry_age=75, grade="B", overall_score=74)
class TestPersona7(unittest.TestCase):
def test_entry_age_gate_dedup_and_senior_surfaced(self):
catalog = [P7_CHOLA_SUPREME, P7_CHOLA_FLEXI, P7_OPTIMA_65,
P7_SENIOR_OK]
filtered, _ = filter_pipeline(
catalog, profile=P7,
query="parents cover both age 70 diabetes hypertension senior "
"citizen 10 lakh",
intent="recommendation")
ids = [c["policy_id"] for c in filtered]
# max_entry_age 65 < 70 β‡’ those plans cannot accept 70yo parents.
self.assertNotIn("cholamandalam__flexi-health__wordings", ids,
"P7: max_entry_age 65 cannot accept a 70yo parent")
self.assertNotIn("hdfc-ergo__optima-secure", ids,
"P7: max_entry_age 65 cannot accept a 70yo parent")
# Entry-age-75 plans survive; senior-eligible surfaces.
self.assertIn("star-health__senior-citizens-red-carpet__brochure", ids,
"P7: a senior-eligible plan must be surfaced")
self.assertIn("cholamandalam__flexi-health-supreme__wordings", ids,
"P7: max_entry_age 75 accepts a 70yo parent")
def test_same_insurer_distinct_products_not_collapsed(self):
# Chola Supreme vs Flexi Health are DIFFERENT UINs β‡’ they are NOT a
# dedup pair; the gate must not over-collapse them. (Flexi Health is
# dropped here by the age gate, not by dedup.)
self.assertNotEqual(
canonical_key(P7_CHOLA_SUPREME), canonical_key(P7_CHOLA_FLEXI))
# ════════════════════════════════════════════════════════════════════════════
# Direct unit coverage for the new gate primitives
# ════════════════════════════════════════════════════════════════════════════
class TestEntryAgeEligibility(unittest.TestCase):
def test_parents_age_drives_entry_age_gate(self):
kept = apply_eligibility_filter(
[P7_OPTIMA_65, P7_CHOLA_SUPREME], P7)
ids = {c["policy_id"] for c in kept}
self.assertNotIn("hdfc-ergo__optima-secure", ids)
self.assertIn("cholamandalam__flexi-health-supreme__wordings", ids)
def test_payer_only_profile_does_not_trip_entry_age(self):
# P1 is self-only, age 29 β€” the parents-age gate must NOT fire and
# drop a normal adult plan whose max_entry_age is 65.
kept = apply_eligibility_filter([P3_NO_MATERNITY], P1)
self.assertEqual(len(kept), 1,
"self-only 29yo must not be entry-age-gated by a "
"parents rule")
class TestMaternityRequirement(unittest.TestCase):
def test_unverified_maternity_ranked_below_confirmed(self):
ranked = rank_by_profile_fit([P3_NO_MATERNITY, P3_MATERNITY_OK], P3)
ids = [c["policy_id"] for c in ranked]
self.assertLess(
ids.index("cholamandalam__flexi-health-supreme__wordings"),
ids.index("hdfc-ergo__optima-secure"),
"maternity-confirmed must outrank maternity=False when the "
"profile explicitly needs maternity")
def test_no_maternity_need_does_not_penalize(self):
# P1 has no maternity need β€” the maternity rule must be inert.
ranked = rank_by_profile_fit([P3_NO_MATERNITY, GOOD_INDEMNITY_A], P1)
self.assertEqual(len(ranked), 2)
class TestCanonicalDedupInPipeline(unittest.TestCase):
def test_dedup_by_policy_uses_canonical_key(self):
deduped = dedup_by_policy([P2_NNP_A, P2_NNP_DUP])
self.assertEqual(len(deduped), 1,
"same-UIN doctype siblings collapse to one")
# Highest-score chunk wins.
self.assertEqual(deduped[0]["policy_id"],
"national-insurance__new-national-parivar-mediclaim"
"__wordings")
# ════════════════════════════════════════════════════════════════════════════
# LIVE PATH β€” single_brain._build_recommendation_citations must emit the
# GATED, fit-ranked, canonically-deduped cited set (not the LLM's order).
# ════════════════════════════════════════════════════════════════════════════
def _live_chunk(pid, name, slug, score, cid, uin=None):
return {
"chunk_id": cid, "policy_id": pid, "policy_name": name,
"insurer_slug": slug, "doc_type": "policy",
"source_url": f"https://example.com/{pid}.pdf",
"score": score, "uin_code": uin,
}
class TestLivePathCitationGate(unittest.TestCase):
def test_cards_ordered_by_gate_rank_not_llm_order(self):
# filter_pipeline returns chunks in profile-fit order; the union the
# citation builder sees preserves that. Best-fit appears FIRST.
gated_stream = [
_live_chunk("niva-bupa__reassure-3", "ReAssure 3.0",
"niva-bupa", 0.55, "c1", "MAXHLIP21177V032122"),
_live_chunk("cholamandalam__flexi-health-supreme__wordings",
"Chola Flexi Health Supreme", "cholamandalam",
0.72, "c2", "CHOHLIP27040V032627"),
]
# LLM marked them in the WRONG order (Chola first).
cites, is_rec = _build_recommendation_citations(
reply_text="see options",
retrieved_chunks_all=gated_stream,
marked_policy_ids=[
"cholamandalam__flexi-health-supreme__wordings",
"niva-bupa__reassure-3",
],
)
self.assertTrue(is_rec)
self.assertEqual(
[c["policy_id"] for c in cites],
["niva-bupa__reassure-3",
"cholamandalam__flexi-health-supreme__wordings"],
"Cited cards must follow the GATE's fit order, not the LLM's "
"mark_recommendation order")
def test_canonical_dedup_at_citation_layer(self):
# Same UIN under two doctype-sibling ids across the turn's union.
stream = [
_live_chunk("national-insurance__new-national-parivar-mediclaim"
"__wordings", "New National Parivar Mediclaim",
"national-insurance", 0.70, "c1",
"NICHLIP26999V010203"),
_live_chunk("national-insurance__new-national-parivar-mediclaim"
"__brochure", "New National Parivar Mediclaim",
"national-insurance", 0.62, "c2",
"NICHLIP26999V010203"),
]
cites, is_rec = _build_recommendation_citations(
reply_text="I recommend New National Parivar Mediclaim",
retrieved_chunks_all=stream,
marked_policy_ids=[], # prose path
)
self.assertTrue(is_rec)
self.assertEqual(len(cites), 1,
"same-UIN duplicate must be cited ONCE (audit P2)")
self.assertEqual(cites[0]["chunk_id"], "c1",
"highest-score chunk hydrates the single card")
if __name__ == "__main__":
unittest.main()