From cec3be73fb47df78aa34e97eda1e028c6dc80233 Mon Sep 17 00:00:00 2001 From: Talha Ahmed Date: Tue, 25 Aug 2026 19:46:34 +0500 Subject: [PATCH] Title tier of relevance_score accepts token containment Live case: the job titled "Generative Engineer" sourced a pool titled "Generative AI Engineer" -- the exact phrase never occurs in that title, so every genuine match fell through to the scattered 35 tier and the whole pool compressed into the 40s. A current title containing every job-title token now earns the full 55. The headline tier stays phrase-only so keyword-stuffed headlines still cap at the 35 tier. Co-Authored-By: Claude Fable 5 --- backend/talent/plugins.py | 22 ++++++++++++++++------ backend/tests/test_talent_plugins.py | 20 +++++++++++++++++++- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/backend/talent/plugins.py b/backend/talent/plugins.py index 2bca488..a0409fc 100644 --- a/backend/talent/plugins.py +++ b/backend/talent/plugins.py @@ -418,11 +418,17 @@ def _match_tokens(*texts) -> set[str]: def relevance_score(job: dict, profile: dict) -> int: """0-100 job-fit rank for sorting, computed when a profile is persisted. - Deterministic and free. Title component: the job title as an exact PHRASE - in the person's current title scores 55, in their headline 45; scattered + Deterministic and free. Title component: a current title CONTAINING every + job-title token scores 55 — containment, not exact phrase, because job + titles rarely reappear verbatim ("Generative Engineer" vs the pool's + "Generative AI Engineer"; seen live: the phrase rule dropped every real + match to the scattered tier and compressed the whole pool into the 40s). + The job title as an exact phrase in the headline scores 45; scattered token overlap caps at 35 — a keyword-stuffed headline ("AI/ML Engineer | Python | FastAPI | ...") must not outrank someone whose title IS the job - title, which is exactly what token overlap alone did on live data. + title, which is exactly what token overlap alone did on live data. The + headline tier stays phrase-only for the same reason: stuffed headlines + contain every token of every hot title. Skills component (up to 45): GRADED token overlap between the content words of the job's requirements + optional skills and the person's @@ -432,16 +438,20 @@ def relevance_score(job: dict, profile: dict) -> int: whole live pool on exactly 60. """ job_title = _clean_phrase(job.get("title")) + job_title_tokens = set(job_title.split()) title_text = _clean_phrase(profile.get("current_title")) headline_text = _clean_phrase(profile.get("headline")) - if job_title and job_title in title_text: + if job_title and job_title_tokens <= set(title_text.split()): title_component = 55.0 elif job_title and job_title in headline_text: title_component = 45.0 else: - title_tokens = set(job_title.split()) role_tokens = set(title_text.split()) | set(headline_text.split()) - ratio = len(title_tokens & role_tokens) / len(title_tokens) if title_tokens else 0.0 + ratio = ( + len(job_title_tokens & role_tokens) / len(job_title_tokens) + if job_title_tokens + else 0.0 + ) title_component = 35 * ratio job_tokens = _match_tokens( diff --git a/backend/tests/test_talent_plugins.py b/backend/tests/test_talent_plugins.py index 4aeef2a..e16c6d1 100644 --- a/backend/tests/test_talent_plugins.py +++ b/backend/tests/test_talent_plugins.py @@ -404,7 +404,25 @@ def test_headline_phrase_scores_below_title_phrase(): scattered = plugins.relevance_score(job, {"current_title": "Engineer", "headline": "Agentic AI | Python"}) assert in_title == 55 assert in_headline == 45 - assert scattered == 35 # both tokens present but never as the phrase + assert scattered == 35 # tokens split across title and headline never combine + + +def test_title_containment_scores_like_an_exact_title(): + # Live case: job "Generative Engineer", pool titled "Generative AI + # Engineer" — the exact phrase never occurs, so every genuine match fell + # to the scattered 35 tier and the whole pool compressed into the 40s. + job = {"title": "Generative Engineer", "requirements": [], "optional_skills": []} + interleaved = plugins.relevance_score(job, {"current_title": "Generative AI Engineer"}) + senior = plugins.relevance_score(job, {"current_title": "Senior Generative AI Engineer"}) + assert interleaved == 55 + assert senior == 55 + # Containment applies to the TITLE only: the same tokens scattered across + # a keyword-stuffed headline still cap at the 35 tier. + stuffed = plugins.relevance_score( + job, + {"current_title": "Developer", "headline": "Generative AI | Engineer | Python"}, + ) + assert stuffed == 35 # ---------------------------------------------------------------- detail extraction