Engine Phase 4: curate robustness + calibration + seniority inference
The measurement showed the USER-FACING Opus score is already well-calibrated — the real bug was curate FAILING and dropping to the bad white-box fallback: - curate.py: _salvage_kept() brace-scans + parses each kept object independently, so one bad char or a max-tokens truncation no longer drops the whole shortlist. max_tokens 4000 → 8000 (28 sifted jobs × full report cards overflowed). This fixed the sales case (was failing → fallback). - curate.py: calibration nudge in the prompt — a genuinely strong current-state match is a real low-80s, partial/stretch 60s-70s; don't under-sell strong matches into the 60s (without inflating weak ones). - normalize.py + search.py: _seniority_from_title() infers seniority from the title (conservative) when a board omits it, applied centrally in the sweep → the experience factor + Opus brief aren't blind. Verified (live Opus on the regression cases): tech MAE 9.8→4.5, sales FAILED→MAE 5.3 (kept 13), ops 4.2→3.3 — user-facing scores now MAE 3-5 with zero curate failures. 31 tests pass.
This commit is contained in:
@@ -106,6 +106,25 @@ def _salary_from_amount(amount: int | None, per_year: bool) -> tuple[float | Non
|
||||
return lpa, f"₹{lpa:g}L/yr"
|
||||
|
||||
|
||||
_TITLE_SENIORITY = [
|
||||
(r"\b(intern|trainee|fresher|graduate|entry[- ]?level|jr|junior)\b", "junior"),
|
||||
(r"\b(associate)\b", "mid"),
|
||||
(r"\b(senior|sr|staff|manager|specialist)\b", "senior"),
|
||||
(r"\b(lead|principal|head|director|vp|chief|cxo|founding)\b", "lead"),
|
||||
]
|
||||
|
||||
|
||||
def _seniority_from_title(title: str | None):
|
||||
"""Infer seniority from a job title when the board omits it — so the experience factor + Opus brief
|
||||
aren't blind. Conservative: only clear signal words; ambiguous titles stay None."""
|
||||
t = (title or "").lower()
|
||||
hit = None
|
||||
for pat, sen in _TITLE_SENIORITY: # last match wins → "Lead"/"Director" beats "Senior"
|
||||
if re.search(pat, t):
|
||||
hit = sen
|
||||
return hit
|
||||
|
||||
|
||||
def _seniority_from_years(min_yrs: int | None):
|
||||
if min_yrs is None:
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user