Spaces:
Sleeping
Sleeping
| """Regression guard β recommendation-path scorecard == marketplace scorecard. | |
| ROOT CAUSE THIS LOCKS DOWN | |
| -------------------------- | |
| 1. KI-FULLFACTS (2026-05-17): `brain_tools._scorecard_signal` fed | |
| `build_scorecard` the 7-key eligibility subset β every recommended | |
| policy came back grade "β"/0 β the >=70 fitness gate dropped 100% β | |
| empty `citations` β CitedPolicyCards never rendered. | |
| 2. #40 (2026-05-18): even after (1), `_scorecard_signal` kept its OWN | |
| doctype-rank + `_merge_curated` re-implementation that *mirrored* | |
| `/api/policies/all`. Two parallel implementations drift: marketing- | |
| rename / KI-145 variant / multi-doctype ids graded a different file | |
| than the marketplace card (e.g. `my:Optima Secure (older variant)` | |
| recommended at one grade, marketplace card at another). | |
| THE FIX β SINGLE SOURCE OF TRUTH | |
| -------------------------------- | |
| `backend.main._marketplace_catalogue()` is the ONE place a card set is | |
| computed. `backend.main.marketplace_grade(policy_id)` resolves a policy's | |
| canonical card (UIN-primary) from it. `_scorecard_signal` simply delegates | |
| to `marketplace_grade`. The two surfaces can no longer diverge because | |
| there is exactly one computation. | |
| This test makes that *provable*: for the ENTIRE id universe the | |
| recommender can cite β every marketplace card id, every curated id, every | |
| extracted stem incl. `__wordings/__brochure/__cis/__prospectus` | |
| permutations, and every alias name β the recommendation-path GRADE must | |
| equal the marketplace GRADE. 0 mismatches, by construction. | |
| """ | |
| from __future__ import annotations | |
| import sys | |
| import unittest | |
| from pathlib import Path | |
| _REPO_ROOT = Path(__file__).resolve().parent.parent | |
| if str(_REPO_ROOT) not in sys.path: | |
| sys.path.insert(0, str(_REPO_ROOT)) | |
| class TestScorecardParity(unittest.TestCase): | |
| """Rec-path _scorecard_signal grade == marketplace grade, everywhere.""" | |
| def setUpClass(cls): | |
| import backend.main as M | |
| from backend.brain_tools import _scorecard_signal | |
| cls.M = M | |
| cls._scorecard_signal = staticmethod(_scorecard_signal) | |
| cls._cards = M._marketplace_catalogue(None) | |
| cls._cur = M._load_curated_facts() | |
| def test_full_id_universe_parity(self): | |
| """The #40 oracle: rec grade == marketplace grade for EVERY id a | |
| recommendation can surface (card ids + curated ids + extracted | |
| stems + doctype permutations + aliases). Must be 0 mismatches.""" | |
| M = self.M | |
| ids = {c.policy_id for c in self._cards} | |
| ids |= set(self._cur.keys()) | |
| ids |= {p.stem for p in M.settings.EXTRACTED_DIR.glob("*.json")} | |
| for c in self._cards: | |
| ids |= set(c.aliases or []) | |
| mismatches = [] | |
| checked = 0 | |
| for pid in sorted(ids): | |
| exp = M.marketplace_grade(pid).get("_grade") | |
| if exp is None: | |
| continue # not a marketplace card (e.g. regulatory) β skip | |
| checked += 1 | |
| rec = (self._scorecard_signal(pid) or {}).get("_grade") | |
| if rec != exp: | |
| mismatches.append(f"{pid}: rec={rec!r} marketplace={exp!r}") | |
| self.assertGreater(checked, 140, "id universe collapsed β guard broke") | |
| self.assertEqual( | |
| mismatches, [], | |
| f"#40 PARITY BROKEN ({len(mismatches)}/{checked}): the " | |
| "recommendation grade diverged from the marketplace grade. " | |
| "Both MUST flow through backend.main.marketplace_grade (the " | |
| "single source of truth); do not re-implement scoring in " | |
| "brain_tools._scorecard_signal.\n " + "\n ".join(mismatches[:40]), | |
| ) | |
| def test_proven_alias_and_doctype_edges(self): | |
| """The exact cases #40 used to break: a marketing-rename variant id | |
| and doctype-permuted ids must each equal their canonical card.""" | |
| M = self.M | |
| for pid in ( | |
| "hdfc-ergo__my-optima-secure-older-variant", | |
| "hdfc-ergo__optima-restore__brochure", | |
| "hdfc-ergo__optima-restore__cis", | |
| "royal-sundaram__lifeline__cis", | |
| "new-india__mediclaim-policy__brochure", | |
| ): | |
| mkt = M.marketplace_grade(pid).get("_grade") | |
| if mkt is None: | |
| continue # absent in this env β skip, don't false-fail | |
| rec = (self._scorecard_signal(pid) or {}).get("_grade") | |
| self.assertEqual( | |
| rec, mkt, | |
| f"{pid}: rec grade {rec!r} != marketplace {mkt!r} " | |
| "(alias/doctype canonicalisation regressed)", | |
| ) | |
| def test_optima_restore_is_a_strong_recommendable_grade(self): | |
| # The user's own policy β a genuinely strong plan. It must NOT come | |
| # back as the data-starved "β"/0 sentinel, and must clear the Bug | |
| # #71 recommendation fitness floor so its card can render. | |
| from backend.single_brain import _recommendation_fit | |
| sig = self._scorecard_signal("hdfc-ergo__optima-restore", profile=None) | |
| self.assertIn(sig.get("_grade"), ("A", "B"), | |
| f"Optima Restore must be A/B, got {sig!r}") | |
| strong, overall, grade = _recommendation_fit({ | |
| "_overall_score": sig.get("_overall_score"), | |
| "_grade": sig.get("_grade"), | |
| }) | |
| self.assertTrue( | |
| strong, | |
| f"Optima Restore must clear the rec-fit floor " | |
| f"(grade={grade} overall={overall})", | |
| ) | |
| class TestProfileSummaryEndpointParity(unittest.TestCase): | |
| """Task #31 β profile_summary returned by | |
| /api/policies/{id}/scorecard?session_id MUST be byte-identical to the | |
| same canonical card's profile_summary in /api/policies/all?session_id | |
| (both flow through the SAME build_scorecard pass with the SAME resolved | |
| profile). Proven across the FULL catalogue for a β₯0.6 profile.""" | |
| def setUpClass(cls): | |
| from fastapi.testclient import TestClient | |
| import backend.main as M | |
| from backend.session_state import get_session | |
| cls.M = M | |
| cls.client = TestClient(M.app, raise_server_exceptions=False) | |
| # Build a β₯0.6-complete session profile so the catalogue is | |
| # profile-scored (otherwise both sides are profile-neutral and the | |
| # parity is trivial). | |
| cls.sid = "pytest-task31-parity" | |
| sess = get_session(cls.sid) | |
| p = sess.profile | |
| p.name = "Parity Tester" | |
| p.age = 52 | |
| p.dependents = "self+spouse" | |
| p.income_band = "25L+" | |
| p.primary_goal = "upgrade" | |
| p.location_tier = "metro" | |
| p.health_conditions = ["diabetes"] | |
| p.existing_cover_inr = 500000 | |
| p.copay_pct = 0 | |
| p.family_medical_history = ["heart"] | |
| # Mark them answered so profile_completeness counts them (parity | |
| # with the live save path). | |
| p.asked = [ | |
| "name", "age", "dependents", "income_band", "primary_goal", | |
| "location_tier", "health_conditions", | |
| ] | |
| def test_endpoint_profile_summary_matches_catalogue(self): | |
| M = self.M | |
| r = self.client.get(f"/api/policies/all?session_id={self.sid}") | |
| self.assertEqual(r.status_code, 200, r.text) | |
| cards = r.json()["policies"] | |
| self.assertGreater(len(cards), 100, "catalogue collapsed") | |
| # Confirm the catalogue is actually profile-scored (else the parity | |
| # is vacuous): at least one card must carry profile-aware strengths. | |
| self.assertTrue( | |
| any((c.get("profile_summary") or {}).get("strengths") for c in cards), | |
| "no card has a profile_summary β catalogue not profile-scored", | |
| ) | |
| mismatches = [] | |
| for c in cards: | |
| pid = c["policy_id"] | |
| cat_ps = c.get("profile_summary") | |
| er = self.client.get( | |
| f"/api/policies/{pid}/scorecard?session_id={self.sid}" | |
| ) | |
| self.assertEqual(er.status_code, 200, (pid, er.text[:200])) | |
| ep_ps = er.json().get("profile_summary") | |
| if cat_ps != ep_ps: | |
| mismatches.append( | |
| f"{pid}: catalogue={cat_ps!r} endpoint={ep_ps!r}" | |
| ) | |
| self.assertEqual( | |
| mismatches, [], | |
| f"TASK #31 PARITY BROKEN ({len(mismatches)}/{len(cards)}): the " | |
| "single-scorecard endpoint diverged from the marketplace card " | |
| "profile_summary for the same canonical id. Both MUST resolve " | |
| "the session profile identically (brain_tools.union_snapshot) " | |
| "and run the SAME build_scorecard.\n " + "\n ".join(mismatches[:30]), | |
| ) | |
| if __name__ == "__main__": | |
| unittest.main() | |