feat: add canonical profile merger with warnings

This commit is contained in:
Antoine 2026-05-28 18:07:51 +02:00
parent 042feab4fd
commit 3c331ef687
2 changed files with 84 additions and 0 deletions

View File

@ -0,0 +1,56 @@
from __future__ import annotations
from job_research.models import (
CandidateProfileOutput,
EducationEntry,
ExperienceEntry,
WarningItem,
)
from job_research.profile.profile_parser import AuthoredProfile
def build_candidate_profile_output(
cv_signals: dict[str, object], authored: AuthoredProfile
) -> CandidateProfileOutput:
warnings: list[WarningItem] = []
if "years_of_experience" in cv_signals and any(
"experience" in note.lower() for note in authored.notes
):
warnings.append(
WarningItem(
field="years_of_experience",
message=(
"CV-derived experience may differ from markdown interpretation. "
"Review manually."
),
)
)
merged_skills: list[str] = []
for skill in [
*(cv_signals.get("skills") or []),
*authored.strengths,
*authored.skills_to_emphasize,
]:
if skill not in merged_skills:
merged_skills.append(skill)
experience_entries = cv_signals.get("experience_entries") or []
education_entries = cv_signals.get("education_entries") or []
return CandidateProfileOutput(
name=cv_signals.get("name"),
summary=authored.summary,
target_roles=authored.target_roles,
strengths=authored.strengths,
skills_to_emphasize=authored.skills_to_emphasize,
constraints=authored.constraints,
notes=authored.notes,
location=cv_signals.get("location"),
languages=cv_signals.get("languages") or [],
skills=merged_skills,
experience_entries=[ExperienceEntry.model_validate(item) for item in experience_entries],
education_entries=[EducationEntry.model_validate(item) for item in education_entries],
warnings=warnings,
)

View File

@ -0,0 +1,28 @@
from job_research.profile.merge import build_candidate_profile_output
from job_research.profile.profile_parser import AuthoredProfile
def test_build_candidate_profile_output_writes_warning_when_facts_conflict() -> None:
cv_signals = {
"name": "Tonio",
"location": "France",
"languages": ["French", "English"],
"skills": ["Python", "SQL"],
"experience_entries": [{"title": "Data Engineer", "company": "A"}],
"education_entries": [],
"years_of_experience": 2,
}
authored = AuthoredProfile(
summary="Junior data engineer focused on GCP.",
target_roles=["Data Engineer"],
strengths=["Python"],
skills_to_emphasize=["BigQuery", "GCP"],
constraints=["CDI only"],
notes=["Years of experience feels closer to 3."],
)
output = build_candidate_profile_output(cv_signals, authored)
assert output.summary == "Junior data engineer focused on GCP."
assert output.constraints == ["CDI only"]
assert output.warnings[0].field == "years_of_experience"