"""Phase-0 contract checks — the guardrails that catch silent failures BEFORE they ship. These assert the load-bearing contracts the engine-improvement plan depends on: 1. BOARDS ↔ NORMALIZERS alignment (an enabled board with no normalizer = silent drop). 2. The funnel shapes (sift fusion weights, embed text fns, SIFT_TOP_K) are where the plan expects. 3. overlap() returns None when a side has no skills (the floor-free contract). 4. The frontend↔backend EXACT-STRING vocab contract: every ScoutPrefs ROLE/INDUSTRY option the UI offers must resolve to a coerce.py board code, else it silently degrades to a keyword fold. (Cross-repo read of growqr-demo's scout.ts; skipped if the sibling repo isn't present.) """ from __future__ import annotations import re from pathlib import Path import pytest from app.engine import search, normalize, sift, embed from app.engine.board_adapters import coerce as C from app.engine import skills as S from app.config import get_settings # ── 1. BOARDS ↔ NORMALIZERS alignment ──────────────────────────────────────── def test_boards_have_normalizers(): for board in search.BOARDS: assert board in normalize.NORMALIZERS, f"BOARDS has '{board}' with no NORMALIZERS entry" def test_enabled_boards_are_registered(): enabled = [b.strip() for b in get_settings().BOARDS_ENABLED.split(",") if b.strip()] for b in enabled: assert b in search.BOARDS, f"BOARDS_ENABLED lists '{b}' which is not a registered board" assert b in normalize.NORMALIZERS, f"enabled board '{b}' has no normalizer" # ── 2. Funnel shapes (guards the Phase-2 edits) ────────────────────────────── def test_sift_fusion_weights_present_and_normalized(): assert hasattr(sift, "W_WHITEBOX") and hasattr(sift, "W_VIBE") assert abs((sift.W_WHITEBOX + sift.W_VIBE) - 1.0) < 1e-9, "sift fusion weights must sum to 1" def test_embed_text_builders_exist(): # the Phase-2 richer-embedding work edits these; assert they exist + return strings assert callable(embed._job_text) and callable(embed._profile_text) assert isinstance(embed._job_text({"title": "X", "organization": "Y"}), str) assert isinstance(embed._profile_text({"title": "X"}, None), str) def test_sift_top_k_configured(): assert isinstance(get_settings().SIFT_TOP_K, int) and get_settings().SIFT_TOP_K > 0 # ── 3. Floor-free skill contract ───────────────────────────────────────────── def test_overlap_none_when_a_side_is_empty(): assert S.overlap([], ["python", "sql"]) is None, "empty user skills must yield None (not a floor)" assert S.overlap(["python"], []) is None, "empty job skills must yield None (not a floor)" # both present → a real dict with a score o = S.overlap(["python", "sql"], ["python", "django"]) assert isinstance(o, dict) and "score" in o # ── 4. Frontend↔backend EXACT-STRING vocab contract ────────────────────────── # Values the UI sends that are intentionally NOT numeric board codes — they fold into the keyword. # The ACTIVE boards (naukri-feed, linkedin-recall, foundit, indeed, workindia) all search by keyword + # city NAME, so the non-tech vocab below works WITHOUT a code (the code maps are only for the off, # code-based actors). Codes for these are deferred per plan; listed here so drift still fails loudly. _ROLE_KEYWORD_ONLY = {"Open to any", "Finance", "HR", "Customer Support", "Supply Chain", "Business Development", "Legal"} _INDUSTRY_KEYWORD_ONLY = {"Any", "Open to any", "", "Banking", "Insurance", "Retail", "FMCG", "Pharma", "Manufacturing", "Logistics"} _SCOUT_TS = Path(__file__).resolve().parents[2] / "growqr-demo/frontend/src/scout/data/scout.ts" def _extract_array(name: str, text: str) -> list[str]: m = re.search(rf"{name}\s*[:=]\s*\[(.*?)\]", text, re.S) if not m: return [] return re.findall(r'"([^"]+)"', m.group(1)) @pytest.mark.skipif(not _SCOUT_TS.exists(), reason="growqr-demo frontend not present (cross-repo)") def test_frontend_roles_resolve_in_backend(): text = _SCOUT_TS.read_text() roles = _extract_array("ROLE_OPTIONS", text) assert roles, "could not extract ROLE_OPTIONS from scout.ts — regex/contract drift" unmapped = [r for r in roles if r not in C.ROLE_NAUKRI_DEPT and r not in _ROLE_KEYWORD_ONLY] assert not unmapped, f"frontend ROLE options with no coerce.py code (silent keyword-fold): {unmapped}" @pytest.mark.skipif(not _SCOUT_TS.exists(), reason="growqr-demo frontend not present (cross-repo)") def test_frontend_industries_resolve_in_backend(): text = _SCOUT_TS.read_text() inds = _extract_array("INDUSTRY_OPTIONS", text) assert inds, "could not extract INDUSTRY_OPTIONS from scout.ts — regex/contract drift" unmapped = [i for i in inds if i not in C.INDUSTRY_NAUKRI and i not in _INDUSTRY_KEYWORD_ONLY] assert not unmapped, f"frontend INDUSTRY options with no coerce.py code (silent keyword-fold): {unmapped}"