feat: personalize scoring and add skills radar

This commit is contained in:
Jens
2026-07-22 19:33:29 +02:00
parent 029df89265
commit a30ecbc553
33 changed files with 1529 additions and 114 deletions
+87
View File
@@ -55,6 +55,72 @@ def test_matching_job_gets_recommendation(matching_job, profile):
assert not result.hard_exclusions
def test_broad_relevant_skill_profile_is_not_diluted_without_limit(matching_job, profile):
profile.desired_skills = [
"microsoft 365",
"vmware",
"windows server",
"active directory",
"intune",
"networking",
"veeam",
"powershell",
"3cx",
"zabbix",
]
result = calculate_score(matching_job, profile)
assert result.components["skills"] == 12.5
assert result.evidence["skills"]["configured_count"] == 10
assert result.evidence["skills"]["match_target"] == 4
assert not any("Niet duidelijk teruggevonden" in concern for concern in result.concerns)
def test_skill_aliases_match_common_product_names(matching_job, profile):
profile.desired_skills = ["microsoft 365", "entra id", "group policy", "vmware"]
matching_job.skills_required = []
matching_job.skills_preferred = []
matching_job.description_text = "Beheer M365, Azure AD, GPO en vSphere voor meerdere klanten."
result = calculate_score(matching_job, profile)
assert result.components["skills"] == 25.0
assert result.evidence["skills"]["matched"] == [
"entra id",
"group policy",
"microsoft 365",
"vmware",
]
def test_experience_never_changes_score_or_recommendation(matching_job, profile):
profile.experience_years = 10
matching_job.analysis_features = {
**matching_job.analysis_features,
"experience_years_max": 8,
}
experienced = calculate_score(matching_job, profile)
profile.experience_years = 3
less_experienced = calculate_score(matching_job, profile)
assert experienced.score == less_experienced.score
assert experienced.recommendation == less_experienced.recommendation
assert "seniority" not in experienced.components
assert "experience" not in experienced.evidence
assert not any("ervaring" in concern.lower() for concern in less_experienced.concerns)
def test_ai_seniority_label_is_informational_only():
base = {"support_ratio": 0.1, "consultancy_ratio": 0.2, "travel_ratio": 0.0}
junior = scoring._ai_feature_score({**base, "seniority": "junior"})
expert = scoring._ai_feature_score({**base, "seniority": "expert"})
assert junior == expert
def test_hard_title_exclusion_wins(matching_job, profile):
matching_job.original_title = "IT Sales Infrastructure Engineer"
matching_job.save(update_fields=["original_title"])
@@ -63,6 +129,27 @@ def test_hard_title_exclusion_wins(matching_job, profile):
assert any("sales" in reason.lower() for reason in result.hard_exclusions)
def test_short_title_exclusion_uses_word_boundaries(matching_job, profile):
profile.excluded_titles = ["ai"]
matching_job.original_title = "Maintenance IT Engineer"
allowed = calculate_score(matching_job, profile)
matching_job.original_title = "AI Engineer"
excluded = calculate_score(matching_job, profile)
assert not any("Uitgesloten titelterm" in reason for reason in allowed.hard_exclusions)
assert any("Uitgesloten titelterm: ai" in reason for reason in excluded.hard_exclusions)
def test_title_exclusion_matches_simple_english_plural(matching_job, profile):
profile.excluded_titles = ["developer"]
matching_job.original_title = "Full Stack Developers"
result = calculate_score(matching_job, profile)
assert any("Uitgesloten titelterm: developer" in reason for reason in result.hard_exclusions)
def test_non_it_vacancy_is_hidden_for_it_profile(matching_job, profile):
matching_job.original_title = "Spontane sollicitatie - logopedist"
matching_job.normalized_title = "spontane sollicitatie logopedist"