Engine Phase 3: non-tech scoring (role-aware weights + curator) + vocab

- rank.py: get_weights(profile) — when the profile reads non-tech (sales/finance/HR/ops/support/…),
  tilt the weights to role(0.16)/industry(0.12)/semantic(0.12), drop skill(0.18). Tech weights
  unchanged. (The competency-skill-backfill was tried + REVERTED — uniform per-role competencies
  added no discrimination and Phase 2's real-cosine f_semantic already supplies the non-tech signal.)
- curate.py: non-tech instruction — role/responsibility fit is the spine; a missing skill list is NOT
  a negative; a strong role+industry+responsibility+seniority match is a genuine ~80, not ~65.
- test_contracts.py: allowlist the new keyword-handled non-tech vocab (active boards keyword-fold;
  numeric codes deferred since the active feed/recall paths don't use them).

Regression (120 pairs): MAE 18.4 → 16.1 (all from non-tech: sales 17.1→13.0, ops 16.3→11.7), recall
holds 0.92, tech unchanged. 31 tests pass.
This commit is contained in:
raulgupta
2026-06-25 16:03:20 +05:30
parent eb6ded5b3d
commit 7c5a88dd3f
3 changed files with 36 additions and 6 deletions

View File

@@ -61,9 +61,14 @@ def test_overlap_none_when_a_side_is_empty():
# ── 4. Frontend↔backend EXACT-STRING vocab contract ──────────────────────────
# Values the UI may send that are intentionally NOT board codes (keyword-only / "open").
_ROLE_KEYWORD_ONLY = {"Open to any"}
_INDUSTRY_KEYWORD_ONLY = {"Any", "Open to any", ""}
# 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"