[ka6] fix connecteur solmentalhealth: faux positif du filtre Québec — « Quebec St. » (nom de rue à Denver) matchait \bquebec\b — le statut stale vient de la dépublication NORMALE de l'unique offre du tenant (Psychiatric Clinician, id 4704220005, 404 live, retirée à 16:08 miss_count=2 → active=0), mais cette offre n'aurait JAMAIS dû être publiée : son lieu réel est « 3401 Quebec St. Suite 8000, Denver, CO, 80207 » (bureau de SOL Mental Health sur Quebec Street à Denver), classé ville=Québec/Capitale-Nationale et géocodé à Québec parce que _QC_MARKERS (\bquebec\b) est évalué avant le rejet _NON_QC_REGION_RE (« , CO ») dans is_quebec_location. La médiane historique 1.0 est donc elle-même un artefact : le bon volume QC de ce tenant est 0 (vérifié live : API Greenhouse 200, 65 offres, toutes aux États-Unis — NY/VA/MD/CO/DC). Correctif : nouveau _QUEBEC_STREET_RE — « quebec » suivi d'un type de voie anglophone (st/street/ave/blvd/rd/dr/ct/ln/way/pl/hwy/pkwy…) = nom de rue, neutralisé avant tout matching dans is_quebec_location ET parse_location ; le garde (?!-) préserve les abréviations de saints des libellés QC légitimes vérifiés en base (« CAN Quebec St-Hubert/St-Laurent/St-Hyacinthe/Ste-Thérèse », agropur). Tests unitaires ajoutés (4 rues US rejetées, libellés agropur et QC classiques conservés). Correction au passage du même artefact sources.json que samsara/delos_data/findevcanada/dupont : url vide → https://www.solmentalhealth.com (la fiche affichait « Site : []() »). Sync isolé rejoué post-patch : found=0 en 0,2 s, ok — 0 est le volume légitime, l'offre Denver ne reviendra plus même si republiée. 104 tests pytest verts. pm2 restart job-ka-sync OK, site 200.
3 changed files +27 −5
modified
data/sources.json
+1 −1
@@ -7515,7 +7515,7 @@ | ||
| 7515 | 7515 | { |
| 7516 | 7516 | "id": "solmentalhealth", |
| 7517 | 7517 | "name": "SOL Mental Health", |
| 7518 | − "url": "", | |
| 7518 | + "url": "https://www.solmentalhealth.com", | |
| 7519 | 7519 | "careers_url": "https://job-boards.greenhouse.io/solmentalhealth", |
| 7520 | 7520 | "sectors": [ |
| 7521 | 7521 | "Santé", |
modified
jobka/normalize.py
+12 −3
@@ -6,7 +6,7 @@ | ||
| 6 | 6 | # Rôle : Normalisation commune des offres (salaires, dates, mode/type |
| 7 | 7 | # d'emploi, lieu, catégorie, exigences, séniorité) — jamais de |
| 8 | 8 | # valeur inventée |
| 9 | −# Créé : 2026-08-17 Modifié : 2026-09-12 | |
| 9 | +# Créé : 2026-08-17 Modifié : 2026-09-14 | |
| 10 | 10 | # ============================================================================= |
| 11 | 11 | """Couche de normalisation commune appelée par JobPosting.finalize(). |
| 12 | 12 | |
@@ -436,6 +436,15 @@ _QC_MARKERS = re.compile( | ||
| 436 | 436 | r"\bqc\b|\bquebec\b|\bqu[e]bec, canada\b|province de quebec", re.I) |
| 437 | 437 | _POSTAL_RE = re.compile(r"\b([GHJ]\d[A-Z])\s*(\d[A-Z]\d)\b", re.I) # G/H/J = Québec |
| 438 | 438 | |
| 439 | +# « Quebec » suivi d'un type de voie anglophone = nom de RUE, pas la province | |
| 440 | +# (« 3401 Quebec St. Suite 8000, Denver, CO » — bug solmentalhealth 2026-09-14 : | |
| 441 | +# offre de Denver publiée comme Québec/Capitale-Nationale). Neutralisé avant | |
| 442 | +# tout matching de marqueur/ville. Le (?!-) protège les abréviations de saints | |
| 443 | +# des libellés québécois légitimes (« CAN Quebec St-Hubert », « Ste-Thérèse »). | |
| 444 | +_QUEBEC_STREET_RE = re.compile( | |
| 445 | + r"\bquebec\s+(?:st|street|ave|avenue|blvd|boulevard|rd|road|dr|drive|" | |
| 446 | + r"ct|court|ln|lane|way|pl|place|hwy|highway|pkwy|parkway)\b\.?(?!-)") | |
| 447 | + | |
| 439 | 448 | # Villes canadiennes hors Québec (et grandes villes étrangères) fréquentes |
| 440 | 449 | # dans les flux pancanadiens/mondiaux — jamais des villes d'offres |
| 441 | 450 | # québécoises : à rejeter lors du parsing de lieu (clés sans accents). |
@@ -493,7 +502,7 @@ def parse_location(raw: str) -> dict: | ||
| 493 | 502 | m = _POSTAL_RE.search(s) |
| 494 | 503 | if m: |
| 495 | 504 | out["postal_code"] = f"{m.group(1).upper()} {m.group(2).upper()}" |
| 496 | − key = _key(s) | |
| 505 | + key = _QUEBEC_STREET_RE.sub(" ", _key(s)) | |
| 497 | 506 | for ck, city in _QC_CITIES.items(): |
| 498 | 507 | if re.search(rf"(?<![a-z]){re.escape(ck)}(?![a-z])", key): |
| 499 | 508 | out["city"] = city |
@@ -533,7 +542,7 @@ _NON_QC_REGION_RE = re.compile( | ||
| 533 | 542 | |
| 534 | 543 | def is_quebec_location(raw: str) -> bool: |
| 535 | 544 | """Vrai si le libellé pointe vers le Québec (filtre des ATS pancanadiens).""" |
| 536 | − key = _key(clean_text(raw)) | |
| 545 | + key = _QUEBEC_STREET_RE.sub(" ", _key(clean_text(raw))) | |
| 537 | 546 | if not key: |
| 538 | 547 | return False |
| 539 | 548 | if key in _NON_QC_CITIES: # libellé = ville canadienne/monde hors QC |
modified
tests/test_normalize.py
+14 −1
@@ -5,7 +5,7 @@ | ||
| 5 | 5 | # Fichier : tests/test_normalize.py |
| 6 | 6 | # Rôle : Tests unitaires de la couche de normalisation (salaires, dates, |
| 7 | 7 | # mode/type d'emploi, lieux, catégories) |
| 8 | −# Créé : 2026-08-17 Modifié : 2026-09-12 | |
| 8 | +# Créé : 2026-08-17 Modifié : 2026-09-14 | |
| 9 | 9 | # ============================================================================= |
| 10 | 10 | import datetime as dt |
| 11 | 11 | |
@@ -163,6 +163,19 @@ def test_is_quebec_location(): | ||
| 163 | 163 | assert not is_quebec_location("Richmond, BC") |
| 164 | 164 | assert not is_quebec_location("Paris, IDF, France") |
| 165 | 165 | assert not is_quebec_location("") |
| 166 | + # « Quebec St./Street/Ave » = nom de RUE hors Québec, pas la province (bug | |
| 167 | + # solmentalhealth 2026-09-14 : bureau de Denver sur Quebec Street publié | |
| 168 | + # comme Québec/Capitale-Nationale — le marqueur \bquebec\b gagnait avant | |
| 169 | + # le rejet « , CO ») | |
| 170 | + assert not is_quebec_location("3401 Quebec St. Suite 8000, Denver, CO, 80207") | |
| 171 | + assert not is_quebec_location("3401 Quebec St. Suite 8000") | |
| 172 | + assert not is_quebec_location("2600 Quebec Street NW, Washington, DC") | |
| 173 | + assert not is_quebec_location("Quebec Ave, Golden Valley, MN") | |
| 174 | + # …mais les abréviations de saints des libellés QC légitimes survivent | |
| 175 | + assert is_quebec_location("CAN Quebec St-Hubert") | |
| 176 | + assert is_quebec_location("CAN Quebec Ste-Thérèse") | |
| 177 | + assert is_quebec_location("CAN Quebec Plessisville") | |
| 178 | + assert not parse_location("3401 Quebec St. Suite 8000, Denver, CO, 80207")["region"] | |
| 166 | 179 | |
| 167 | 180 | |
| 168 | 181 | # --- catégories / HTML ------------------------------------------------------------ |
| 169 | 182 | |