SPB Git

spb/job-ka

Public
page 1
  1. Mon, Sep 14, 2026 2

    1. [ka6] fix connecteur lassonde: faux positif de supervision (épisode Sucuri transitoire) — repli Bright Data sur la page liste — le statut stale vient d'un unique échec à 08:17 (RuntimeError explicite de la garde du 2026-09-05 : 3× « HTTP 200 via scrapfly, 4515 octets » sans le conteneur job-result-default), combiné à la panne SQLite du matin (2b01fd4) qui avait empêché tout sync entre 05:32 et 08:17 — le connecteur est INTACT : rejeu = found=35, médiane exacte. Vraie faiblesse corrigée : pendant un épisode Sucuri, TOUTE la chaîne principale (direct→oxylabs→scrapfly) sert la même page tronquée « propre en apparence » (200 sans marqueur connu — 'access denied', 'sucuri_cloudproxy' etc. déjà couverts par is_blocked) à chaque essai, et le backoff 10-20 s ne suffit pas à sortir de l'épisode ; escalate() acceptait la réponse Scrapfly et ne tentait jamais Bright Data. La liste étant rendue serveur (render_js ne sert qu'au challenge), _fetch_list tente désormais Bright Data Web Unlocker (vendeur de déblocage différent) à chaque essai raté — vérifié live : BD livre 200/110 ko/35 cartes au moment même où le direct sert le challenge Sucuri 307. L'échec reste explicite (offres conservées) si BD échoue aussi. Test unitaire ajouté (repli BD gagnant, échec explicite si BD muet, BD jamais sollicité sur liste saine). Syncs rejoués post-patch : found=35 ok ×2. 104 tests pytest verts. pm2 restart job-ka-sync OK, site 200.
      …
      Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
      Simon-Pierre Boucher · 2 files +77 −2
    2. [ka6] fix site down jobka: convoi de verrous SQLite (journal DELETE) — bascule en WAL — le site était muet (ReadTimeout public+local depuis 03:38) alors que pm2 affichait online : la BD data/jobka.db (740 Mo, 64 340 offres) tournait en journal_mode=delete, où lecteurs et écrivains se bloquent mutuellement. Un cycle de sync long (agropur 92 s, airbus suspendu ~03:36) a tenu le verrou d'écriture ; chaque requête web (SSR d'accueil = plusieurs agrégats sur la table jobs) restait coincée dans sqlite3_step jusqu'au busy_timeout de 30 s, les 40 slots du threadpool AnyIO de FastAPI se sont remplis (sample : ~24 threads dans sqlite3_step, /emploi statique répondait mais /, /health et toute route sync-def étaient muets), et job-ka-sync crashait en boucle sur « database is locked » (18 restarts, journal chaud data/jobka.db-journal). Le restart pm2 automatique ne réglait rien : le sync relançait aussitôt son cycle d'écritures et le convoi se reformait. Mesure à froid : COUNT(*) sur 64 k lignes = 60 s sous contention, 0,03 s BD libérée — volumétrie saine (freelist 6 pages), quick_check ok, 0 offre perdue. Correctif racine : PRAGMA journal_mode=WAL (persistant, appliqué à la BD après arrêt propre + sauvegarde data/backup-jobka-20260914.db) + synchronous=NORMAL, inscrits dans db.connect() ; .gitignore couvre désormais data/jobka.db-* (journal/wal/shm). Post-fix : /health ok (24 719 offres actives, sync live), / local 200 en 0,1 s, public 200 en 0,55 s pendant que le cycle de sync écrit — plus aucun « database is locked ». 103 tests pytest verts.
      …
      Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
      Simon-Pierre Boucher · 2 files +8 −2
  2. Sun, Sep 13, 2026 3

    1. Simon-Pierre Boucher · 1 file +1 −1
  3. Sat, Sep 12, 2026 4

    1. [ka6] fix connecteur cambria: ajout de Fermont au dictionnaire _QC_CITIES (normalize.py) — l'offre QC courante du tenant workday cambria.wd1 (« Mechanic » R-103013, site minier Sitec à Fermont, Côte-Nord, publiée le 2026-04-10, description en français) était INVISIBLE depuis la création du connecteur (Vague D 2026-08-25) : Workday l'affiche sous le libellé « Sitec Fermont » sans province ni code postal, et Fermont manquait au dictionnaire partagé _QC_CITIES, si bien que is_quebec_location la rejetait au filtre client ET au repli de facette serveur (_find_qc_facet — ce tenant n'expose aucune facette province, seulement pays Canada=1 + lieux plats). Le connecteur ne voyait donc que l'offre montréalaise historique (Market Sales Representative R-103079), dépubliée par l'employeur le 2026-09-02 (miss_count=2, retrait normal) → found=0 depuis, d'où le statut stale (la supervision date le succès au dernier sync found>0). L'unique vrai échec (2026-09-12 03:08, « Workday non-JSON HTTP 200 text/html ») est la fenêtre de maintenance hebdomadaire Workday du vendredi nuit, transitoire. Correctif minimal dans la couche partagée (même famille que f4038e4) : « fermont »: « Fermont » — mot à graphie unique, aucun homonyme hors QC (≠ Fremont), garde-fous _NON_QC_CITIES/_NON_QC_REGION_RE intacts ; test ajouté sur le libellé exact « Sitec Fermont ». Sync isolé rejoué : found=1, added=1 en 2,9 s — R-103013 en base, ville Fermont, région Côte-Nord, statut ok (médiane historique 0–1). 102 tests pytest verts. pm2 restart job-ka-sync OK, site 200.
      Simon-Pierre Boucher · 2 files +7 −2
    2. [ka6] fix connecteur altusgroup: external_id régional → ID de réquisition (hook _external_id dans la plateforme workday, défaut inchangé) — le tenant altusgroup.wd3 préfixe bulletFields par la région quand il y en a une (['Ontario','R0013639'] vs ['R0013942'] seul), si bien que bullets[0] devenait l'external_id : l'offre QC historique était en base sous external_id='Quebec', et le sync du 2026-08-26 trouvait 2 offres pour 1 seule stockée (collision d'ID entre postes d'une même région). L'extraction est désormais isolée dans un hook _external_id() de WorkdayConnector (comportement par défaut strictement identique pour les autres tenants) et surchargée dans altusgroup.py : premier bullet au format réquisition R+chiffres, sinon suffixe du chemin. Vérifié live : 36 postes scannés → 36 IDs uniques au format R00xxxxx, 0 poste non conforme. Volume 0 légitime AUJOURD'HUI : 7 postes Canada, tous Toronto — aucune offre QC depuis la dépublication de l'offre montréalaise le 2026-08-26 (médiane historique 0.0). Le statut stale vient de là (la supervision date le dernier succès au dernier sync found>0, 2026-08-26 14:19) ; l'unique échec récent (2026-09-12 03:04, « Workday non-JSON HTTP 200 text/html ») est la fenêtre de maintenance hebdomadaire Workday du vendredi/samedi nuit (28 occurrences multi-sources cette nuit, mêmes plages 02h30–03h15 les 2026-08-29 et 2026-09-05), transitoire et déjà retryée. Sync isolé rejoué : found=0 en 2,4 s, statut ok. 101 tests pytest verts. pm2 restart job-ka-sync OK, site 200.
      …
      Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
      Simon-Pierre Boucher · 2 files +28 −4
  4. Fri, Sep 11, 2026 3

    1. [ka6] fix connecteur findevcanada: volume 0 légitime confirmé en direct — l'employeur a dépublié ses 2 dernières parutions QC le 2026-09-11 (Principal, Financial Institutions FR+EN du 09-03 et Principal, Business Integrity Officer FR+EN du 09-04 : /j/<code> → /oops, tenant-scoped → ?not_found=true, API détail 404) entre 11h31 et 12h41 EDT. Le tenant Workable findevcanada reste le système ACTUEL et vivant (widget v1 200 {name: FinDev Canada, jobs: []} ; API v3 de la SPA total=0 — concordance parfaite) : la migration est dans l'AUTRE sens que ce que suggère la page carrières findevcanada.ca, dont le lien « View our job openings » → edc.taleo.net/careersection/findevcanada_corporate est un VESTIGE pré-migration (instantané Wayback 2026-05-30 : seul le lien Taleo existait, les boutons Workable ont été ajoutés depuis ; la zone edc.taleo.net entière renvoie 503 Zone Maintenance Oracle, et EDC société mère publie elle-même sur apply.workable.com/export-development-canada — 57 lignes vérifiées, aucun poste FinDev). Aucune offre FinDev courante ailleurs (LinkedIn : mêmes parutions désormais fermées ; ecoworks : offre de juillet périmée, Toronto). Employeur ~150 personnes, médiane 4 (2 parutions × 2 langues) : zéro ouverture ponctuelle est normal. Le connecteur est INTACT et fonctionnel — aucune modification du code (plateforme workable et tenant corrects). Correction au passage d'un artefact de génération dans data/sources.json : url vide → https://www.findevcanada.ca (la fiche affichait « Site : []() »). Sync isolé rejoué : found=0 en 0,1 s, statut ok. 101 tests pytest verts. pm2 restart job-ka-sync OK, site 200.
      …
      Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
      Simon-Pierre Boucher · 1 file +1 −1
    2. [ka6] fix connecteur derumarketcatering: retrait définitif de la source (précédent projevia 7b871e8) — double condamnation confirmée en direct le 2026-09-11 : (1) le compte JazzHR du tenant est désactivé de façon permanente (page 200 « Inactive Career Page / this account is no longer active », détectée explicitement par jazzhr._fetch_list depuis la mission du 2026-09-04 → RuntimeError sans retry, 60 échecs consécutifs) ; (2) l'employeur était un faux positif de génération : Deru Market + Catering est un restaurant de Kirkland, État de WASHINGTON (derumarket.com, ZipRecruiter « Kirkland, WA »), pas Kirkland QC — sa seule offre jamais ingérée (FOH Staff, Kirkland WA) était américaine et est inactive en base depuis le fix is_quebec_location f4038e4. Deux missions ka6 (2026-08-26, 2026-09-04) avaient déjà conclu site_source_mort sans retirer la source : la supervision la resynchronisait donc en boucle (statut broken). Retrait complet selon le pattern maison : suppression de jobka/connectors/derumarketcatering.py (registre auto-découvrant → 1105 connecteurs), de l'entrée data/sources.json (1107 sources, employeurs_directs 1048→1047, page Sources vérifiée sans Deru) et de la fiche docs/connecteurs/derumarketcatering.md (INDEX/ats-jazzhr seront nettoyés à la prochaine régénération gen_connector_docs). Données en base conservées (offre déjà active=0, historique sync_log intact). Aucune modification de la plateforme jazzhr : non-régression tenant cliniqued found=1 ok. run.py sync derumarketcatering → « connecteur inconnu » (comportement attendu). 101 tests pytest verts. pm2 restart job-ka-sync OK, site 200.
      …
      Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
      Simon-Pierre Boucher · 3 files +2 −136
    3. [ka6] fix connecteur euromoneyplc: balayage fr-CA + en-CA + en-GB dans la plateforme dayforce (tenant seul) — la dernière offre QC du tenant (4827 « Partenaire, Acquisition de talent », Montréal, publiée en français) a été dépubliée par l'employeur le 2026-09-11 entre 09h19 et 11h40 EDT ; le tenant euromoneyplc publie désormais 0 poste TOTAL (vérifié en direct : boards CANDIDATEPORTAL + EUROMONEY × cultures fr-CA/en-CA/en-GB/en-US = 0 partout, détail id bidon → 404) → volume 0 légitime AUJOURD'HUI. Mais la recherche Dayforce étant PARTITIONNÉE par culture de publication (cf. harrisrebar 788bfb4) et le portail officiel de l'employeur étant en-GB (delinian.com/careers → dayforcehcm CandidatePortal en-GB du même tenant), fr-CA seul rendrait le connecteur aveugle à toute future offre QC publiée en anglais : fetch() balaie désormais fr-CA PUIS en-CA PUIS en-GB (pattern harrisrebar : CULTURE permuté en attribut d'instance, dédup par jobPostingId, version française gagnante — la classe plateforme dayforce et les autres tenants sont intacts). Correction au passage de EMPLOYER, artefact de génération (intitulé de poste) : « Talent Acquisition Partner » → « Delinian (ex-Euromoney) » (Euromoney Institutional Investor plc rebrandé Delinian en 2023, bureau de Montréal au 1001 De Maisonneuve Ouest). Sync isolé rejoué : found=0 en 7,2 s (exact, l'offre 4827 avait déjà été retirée par le mécanisme normal miss_count=2 au sync de 14h04), statut ok. 101 tests pytest verts. pm2 restart job-ka-sync OK, site 200.
      Simon-Pierre Boucher · 1 file +32 −3
  5. Thu, Sep 10, 2026 6

    1. [ka6] fix connecteur harrisrebar: balayage en-CA complémentaire dans la plateforme dayforce (tenant seul) — la recherche Dayforce est PARTITIONNÉE par culture de publication, sans repli serveur (vérifié : lavieenrose fr-CA 172 / en-CA 281, soprema fr 23 / en 20). Le tenant harrisrebar (Harris Rebar, rebrandé Nucor Rebar Fabrication — harrisrebar.com redirige vers nucor.com) publie ses 12 postes actuels (ON/AB/NS/NB/BC) en en-CA seulement : la recherche fr-CA du connecteur renvoie 0 poste TOTAL. L'unique offre QC historique (16804 « AIDE À L'EXPÉDITION/À LA RÉCEPTION », Montréal, publiée en français) a été dépubliée par l'employeur le 2026-09-10 entre 10h04 et 14h35 EDT — absente des listings des 2 boards (CANDIDATEPORTAL + HarrisCanada) × 2 cultures, mot-clé compris ; le détail API 200 est un rendu résiduel (createdTimestampUTC = heure de la requête ; id bidon → 404). Volume 0 légitime AUJOURD'HUI, mais fr-CA seul rendrait le connecteur aveugle à toute future offre QC publiée en anglais : fetch() balaie désormais fr-CA PUIS en-CA (dédup par jobPostingId, version française gagnante, CULTURE restaurée en attribut d'instance — la classe plateforme et les ~124 autres tenants dayforce sont intacts). Correction au passage de EMPLOYER, artefact de génération (titre de poste) → « Nucor Rebar Fabrication (Harris Rebar) ». Test réel : fr-CA 0 + en-CA 12 postes scannés → 0 offre QC (exact). Sync isolé rejoué : found=0, removed=1 (16804 retirée par le mécanisme normal miss_count=2), statut ok. 101 tests pytest verts. pm2 restart job-ka-sync OK, site 200.
      …
      Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
      Simon-Pierre Boucher · 1 file +28 −3
    2. Simon-Pierre Boucher · 1 file +14 −2
  6. Wed, Sep 9, 2026 6

    1. [ka6] fix connecteur sante_montreal: Radware étendu au domaine personnalisé post-maintenance Njoyn — bascule Scrapfly + sessions Scrapfly pour la pagination
      …
      Depuis la maintenance Njoyn du 2026-09-05→07, Radware Bot Manager couvre aussi
      emplois.santemontreal.qc.ca (avant : seulement *.njoyn.com). Chronologie des
      syncs : 731 offres (08/09 14h32) → 50 (POST de pagination rejeté) → 0 (page
      liste bloquée). La page « Radware Block Page » embarque l'URL Xweb.asp dans ses
      paramètres et passait le garde-fou de _fetch_listing → faux « 0 offre, ok ».
      
      - sante_montreal.py : USE_SCRAPFLY = True (pattern des 10 autres tenants Njoyn)
      - njoyn.py : détection _RADWARE_RE (Radware Block Page/shieldsquare/perfdrive)
        dans _html avec bascule Scrapfly pour tout le reste du sync ; sessions
        Scrapfly (_sf_session) partagées entre GET liste / POST pagination / détails
        — sans session le tbtoken (lié aux cookies ASP du GET) est rejeté en
        400 Bad Request au POST ; casse Xweb.asp forcée sur l'action du formulaire
        (gotcha 2026-09-02)
      - base.py : kwarg optionnel session sur scrapfly()/get_scrapfly()
        (session + session_sticky_proxy), rétrocompatible
      
      Sync rejoué : 726 offres (médiane historique ~706), removed=16 offres
      dépubliées pendant la panne. pm2 restart job-ka-sync OK, site 200.
      
      Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
      Simon-Pierre Boucher · 3 files +52 −12
  7. Tue, Sep 8, 2026 2

    1. [ka6] connecteur neweratech: volume 0 légitime — les 2 offres QC (« Infraction Review Technician » 8684549002 et « Représentant service à la clientèle - Révision des infractions » 8684559002, Saint-Jean-sur-Richelieu) ont été dépubliées par l'employeur le 2026-09-08 entre 14h19 et 17h39 EDT (détail → 404). Multinationale TI américaine à volume QC naturellement très faible (médiane 2.0, seules ses offres de contrôle du stationnement à Saint-Jean sont québécoises). Vérifications réelles : boards-api Greenhouse 200 avec 61 offres (É.-U./Inde/Asie-Pacifique/Remote, aucune mention Québec — toutes correctement rejetées par is_quebec_location, 0 faux positif), board vivant, neweratech.com/careers consomme toujours boards-api.greenhouse.io/v1/boards/neweratech (pas de migration d'ATS). Le statut stale venait du volume 0 compté comme échec par la supervision ; le connecteur est sain (tous les syncs ok=1, 0.1 s). Purge par le mécanisme normal : sync isolé rejoué → miss_count=2 → active=0 (found=0, removed=2, statut ok). Test final : fetch réel = 61 bruts, 0 retenus (QC) = comportement correct, les offres QC réapparaîtront d'elles-mêmes quand New Era republiera à Saint-Jean-sur-Richelieu. Même famille de vides légitimes que rollstack (8636932), vasco (d6009d3), tefron (e62dc72), altom_transport (2fa16cd), onrunning (1155f22). Note de contexte ajoutée au connecteur, aucun changement de logique. pm2 restart job-ka-sync OK, site 200.
      …
      Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
      Simon-Pierre Boucher · 1 file +13 −1
  8. Mon, Sep 7, 2026 3

    1. feat(fiche): refonte premium mobile-first de la fiche d'offre (2026-09-07)
      …
      Même socle que les fiches Lou-Ka v3 / Immo-Ka v3 (frontend/src/fiche/,
      préfixe jk-, tokens --jk-*, fond papier, cartes blanches bord 1 px, cyan
      réservé aux CTA/salaire ; header encre conservé en version compacte) :
      héro (logo + employeur · lieu, salaire en exergue + équivalent annuel,
      capsules marché / nouveau / offre directe, titre, actions favoris / partage /
      Postuler) ; « En bref » déterministe (salaire vs médiane de la catégorie,
      source directe ou portail, exigences, mode/type/niveau, fraîcheur et date
      limite, volume de l'employeur, avantages) ; navigation sticky ; « Salaire et
      marché » (KPI, jauge P25–P75 du point médian, historique du salaire affiché,
      méthodologie — jamais d'estimation) ; « Le poste » (grille icône/valeur,
      rangées, avantages, description tronquée, champs bruts en accordéon) ; « Où
      travailler » (carte OSM) ; Dossier de l'offre ; Sources et méthodologie. CTA
      sticky après le héro, aside desktop sticky, « Demander à Ka » via le widget
      KA Agent. Header compact sur /emploi/ (favoris + partage via fiche/current.ts,
      badge masqué). Rangées d'offres de la liste : surface blanche, bord 1 px,
      ombre légère au survol. Icons.tsx (pictos partagés) ajouté. Aucun order CSS ;
      pas de scrollIntoView à l'ouverture. Scripts QA : preview.mjs,
      check-order.mjs, shots.mjs, interactions.mjs (Playwright via lien vers
      vrai-prix/node_modules).
      
      Validé sur M3U96a : tsc + vite build, check-order OK, interactions OK,
      captures 6 largeurs ; dist basculé, aucun changement API.
      Simon-Pierre Boucher · 18 files +2,150 −193
  9. Sun, Sep 6, 2026 1

  10. Sat, Sep 5, 2026 1

  11. Fri, Sep 4, 2026 8

    1. Simon-Pierre Boucher · 1 file +19 −2
  12. Mon, Aug 31, 2026 1

Menu

Theme