SPB Git forge

spb/lou-ka

Public

Lou·Ka — tous les logements à louer du Québec, un seul endroit.

232commits 1branches 0releases
172.9 MBsize
maindefault branch
2 days agolast push
HTML 98.9% Python 0.6%

page 1

  1. Tue, Sep 22, 2026 1

    1. Simon-Pierre Boucher committed 2 days ago · 50 files +27,628 −888
  2. Mon, Sep 21, 2026 1

    1. [ka2] fix connecteur sotramont: erreur franche + retry sur le GET du portfolio — fini le « 0 trouvé ok » silencieux sur hoquet réseau. Les syncs du 2026-09-21 11:42 et 19:07 rapportaient found=0 ok (médiane 8, dérive déclenchée, retraits suspendus → stale) alors que le site est parfaitement sain : les seuls autres zéros de l'historique (2×09-10, 1×09-18, seconds: 0.0) tombent PILE dans les vagues DNS systémiques du nœud — le `except Exception: return listings` de fetch() avalait l'échec transitoire du GET de liste et le transformait en zéro silencieux. Vérifié live : curl 3/3 → 200, 130 Ko ; requests venv 8/8 → 200, 76 cartes ; Apache/Ubuntu direct sur DigitalOcean, aucun WAF ; aucun autre connecteur en échec dans les fenêtres des zéros du 09-21 (pas systémique app). Fix minimal, pattern devimco (edd968e) : le GET du portfolio tente 3 fois (backoff 3/6 s) puis lève une erreur FRANCHE au lieu de retourner [] ; erreur franche aussi si la soupe ne contient AUCUNE carte article.c--article-project (gabarit remanié ≠ vrai zéro — le vrai zéro reste possible : cartes présentes mais toutes « Vendu »/« En construction »). Fixture enregistrée pour la première fois (run.py record sotramont, 8 requêtes). Testé : fetch() venv → 8 annonces (Liveo Pointe-Claire 3 1 620 $, Curtiss Charlie Saint-Laurent 1 460 $, 8-10 photos — médiane 6.0 couverte), pytest sotramont 2 passed, run.py sync sotramont → found=8 ok (8,3 s), pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 3 days ago · 11 files +6,931 −5
  3. Thu, Sep 17, 2026 2

    1. [ka2] fix connecteur halfred: refonte Eversa « Editorial » du site — préfixe de locale /fr + nouveau gabarit de cartes. Le sync du 2026-09-17 (dernier succès 06:46, stale 5,2 h) rapportait found=0 : halfred.ca (plateforme Eversa, cf. gestion_cem 7f020de) a basculé sur des routes préfixées de locale (/listings/list → 301 /fr/listings/list) ET un nouveau gabarit : les cartes sont désormais des <a data-sentry-component="EditorialListingCard"> avec hrefs /fr/listings/…/details (le sélecteur a[href^='/listings/'] ne matchait plus rien), titre en h3 (plus h1), lieu « Secteur · Ville » (plus « Ville (Secteur) »), SpecItem textuels sans icônes lucide, prix « À partir de $1,559 » avec ancien prix .line-through dans un composant line, disponibilité en pill « Disponible le … » ; la fiche détail expose la description via RichTextDisplay (plus de h2 « Description de l'annonce ») et des Walk/Bike Score® en anglais. Fix minimal : LIST_URL → /fr/listings/list, _external_id retire le préfixe de locale (ids historiques préservés, aucune ré-ingestion), _city_sector gère « Secteur · Ville » (ancien format en repli, normalisation Gatineau intacte), _features lit SpecItem/pills/line, _fetch_detail lit RichTextDisplay et les scores bilingues. Testé : fetch() venv → 173 annonces en 133 s (30 Rue De Matapédia Gatineau/Pointe-Gatineau 4½ 1 300 $ promo, 12 fiches détail avec description+contact+scores — médiane 172 couverte), fixtures ré-enregistrées + pytest 2 passed, run.py sync halfred → found=174 ok (added=1, 131 s), pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 7 days ago · 31 files +14,340 −13,246
  4. Mon, Sep 14, 2026 3

    1. Simon-Pierre Boucher committed 11 days ago · 1 file +43 −13
    2. [ka2] fix connecteur devimco: escalade Scrapfly contre le pare-feu Sucuri CloudProxy apparu sur devimco.com — même cause et même fix que brio (195f19a). Les syncs du 2026-09-13 (05:03, 15:16, 20:16... puis 23:23) rapportaient found=0 ok par INTERMITTENCE (médiane 695, dérive déclenchée, retraits suspendus) : devimco.com est passé derrière Sucuri/Cloudproxy, qui répond 307 + challenge JavaScript (cookie sucuri_cloudproxy, en-tête x-sucuri-id, ~1,4 Ko sans Location) aux clients sans navigateur selon l'humeur du filtre IP — un statut < 400 invisible de raise_for_status(), le hub sans lien projet devenait « 0 trouvé ok » silencieux via le `except Exception: return listings` de fetch(). Le diagnostic « échec transitoire » du passage ka2 de 08:08 était donc incomplet : le hoquet se répétait un sync sur deux. Vérifié live : 3 GET directs consécutifs → 307 challenge ; Scrapfly ASP + rendu JS → 200, 297 Ko, 10 pages projets. Fix minimal, pattern brio : _get_html() tente le direct (gratuit quand Sucuri laisse passer), détecte le challenge (statut 307 ou marqueur sucuri_cloudproxy) et escalade vers get_rendered() (Scrapfly ASP + rendu JS, standard du repo) ; hub ET pages projets passent par _get_html() ; le hub lève désormais une erreur franche au lieu de retourner [] (fini le zéro silencieux, idem si aucun lien projet dans la soupe) ; les pages projets gardent le continue (résultats partiels acceptables) ; l'API Planpoint (app.planpoint.io, domaine distinct) reste en direct. Testé : pytest fixtures devimco 2 passed, fetch() venv → 695 annonces (13 phases : Cosma 237, Ostral 160, Maestria A/B 121, Alexander 66... — unité 309 Alexander 2 130 $/mois, 2255 René-Lévesque O, 13 photos — médiane 695 restaurée), run.py sync devimco → found=695 ok (161 s), pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 11 days ago · 1 file +26 −5
  5. Sun, Sep 13, 2026 11

    1. [ka2] fix connecteur mondev: contournement du challenge sgcaptcha SiteGround via proxy résidentiel Oxylabs — même cause et même fix que boreal_abitibi (8923045), citiluxx (d17f5fe), cromwell (8351131), deschenes_pepin (f8aca03), gestion_habitation (8b0660b), gimcote (12df764), appartements_rimouski (af2be7c), lbm (5decd97), gestion_mj (15d2bbb) et mercini (5125859), hébergeur SiteGround identique (11e connecteur touché). Le sync du 2026-09-12 22:42 a rapporté found=0 ok (médiane 20.0, stale) : SiteGround sert son anti-bot sgcaptcha (HTTP 202, 199 octets, en-tête sg-captcha: challenge, meta refresh vers /.well-known/sgcaptcha/) à l'IP datacenter du nœud — un 2xx sans HTTPError, avalé par le `except Exception: return listings` de fetch() en « 0 trouvé ok », invisible du disjoncteur. Vérifié live : IP directe → 202 challenge ; IP résidentielle Oxylabs CA → 200, 557 Ko, 30 immeubles présents. Fix minimal, pattern lbm (liste unique + fiches immeubles re-fetchées à chaque sync, pas de detail_cache) : _get_html() détecte le challenge (en-tête sg-captcha ou marqueur /.well-known/sgcaptcha/) et bascule la session sur pr.oxylabs.io:7777 en session collante -cc-CA (liste + fiches immeubles partagent l'IP), erreur franche si le challenge persiste — la page de liste (unique, pas de pagination) lève désormais au lieu de retourner [] (fini le zéro silencieux, ingest journalise ok=0) ; _parse_building() passe aussi par _get_html() et garde le continue autour (résultats partiels acceptables). Le chemin direct reste tenté d'abord (gratuit si SiteGround déflague l'IP). Testé : fetch() venv → 40 annonces (Florence 3½ 1 500 $ → 5½ 2 600 $ rue Florian, Jacques Studio 1 630 $ rue Fullum — adresses complètes, 16-40 photos, médiane 20.0 largement couverte, dernier sync sain à 43), pytest fixtures 2 passed, run.py sync mondev → found=40 ok (94 s), pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 12 days ago · 1 file +45 −5
    2. [ka2] fix connecteur mercini: contournement du challenge sgcaptcha SiteGround via proxy résidentiel Oxylabs — même cause et même fix que boreal_abitibi (8923045), citiluxx (d17f5fe), cromwell (8351131), deschenes_pepin (f8aca03), gestion_habitation (8b0660b), gimcote (12df764), appartements_rimouski (af2be7c), lbm (5decd97) et gestion_mj (15d2bbb), hébergeur SiteGround identique (10e connecteur touché). Le sync du 2026-09-12 22:40 a rapporté found=0 ok (médiane 20.0, stale) : SiteGround sert son anti-bot sgcaptcha (HTTP 202, 181 octets, en-tête sg-captcha: challenge, meta refresh vers /.well-known/sgcaptcha/) à l'IP datacenter du nœud (76.70.60.50 flaguée « ipr ») — un 2xx sans HTTPError, avalé par le `except Exception: break` de fetch() en « 0 trouvé ok », invisible du disjoncteur. Vérifié live : IP directe → 202 challenge ; IP résidentielle Oxylabs CA → 200, 244 Ko, 24 blocs property_listing page 1. Fix minimal, pattern gimcote (liste paginée + detail_cache identiques) : _get_html() détecte le challenge (en-tête sg-captcha ou marqueur /.well-known/sgcaptcha/) et bascule la session sur pr.oxylabs.io:7777 en session collante -cc-CA (liste paginée + fiches détail partagent l'IP), erreur franche si le challenge persiste — la 1re page de liste lève désormais au lieu de break (fini le zéro silencieux, ingest journalise ok=0), les pages suivantes gardent le break (résultats partiels acceptables) ; _fetch_detail() passe aussi par _get_html() pour ne pas empoisonner detail_cache avec un payload vide (clé figée jamais invalidée) ; les cartes gardent le continue (résultats partiels acceptables). Le chemin direct reste tenté d'abord (gratuit si SiteGround déflague l'IP). Testé : fetch() venv → 40 annonces (4½ Duberger 1 895 $, projet neuf Limoilou 1 595 $, 5½ Nicolet 1 550 $ — adresses complètes, 7-21 photos, médiane 20.0 largement couverte), pytest fixtures 2 passed, run.py sync mercini → found=40 ok (53 s), pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 12 days ago · 1 file +52 −5
    3. [ka2] fix connecteur gestion_mj: contournement du challenge sgcaptcha SiteGround via proxy résidentiel Oxylabs — même cause et même fix que boreal_abitibi (8923045), citiluxx (d17f5fe), cromwell (8351131), deschenes_pepin (f8aca03), gestion_habitation (8b0660b), gimcote (12df764), appartements_rimouski (af2be7c) et lbm (5decd97), hébergeur SiteGround identique (9e connecteur touché). Les syncs du 2026-09-13 03:03 et 04:44 ont rapporté found=0 ok x2 (médiane 9, stale) : SiteGround sert son anti-bot sgcaptcha (HTTP 202, 166 octets, en-tête sg-captcha: challenge, meta refresh vers /.well-known/sgcaptcha/) à l'IP datacenter du nœud — un 2xx sans HTTPError dont le body HTML fait lever .json(), avalé par le `except Exception: return listings` de fetch() en « 0 trouvé ok », invisible du disjoncteur. Vérifié live : IP directe → 202 challenge ; IP résidentielle Oxylabs CA → 200, 2 090 octets JSON, les 9 posts du CPT a-louer présents. Fix minimal, pattern appartements_rimouski : _get_html() détecte le challenge (en-tête sg-captcha ou marqueur /.well-known/sgcaptcha/) et bascule la session sur pr.oxylabs.io:7777 en session collante -cc-CA (API wp-json + fiches détail partagent l'IP), erreur franche si le challenge persiste — l'appel API (liste unique, pas de pagination) lève désormais au lieu de retourner [] (fini le zéro silencieux, ingest journalise ok=0), idem si la réponse wp-json n'est plus une liste ; _fetch_detail() passe aussi par _get_html() pour ne pas empoisonner detail_cache avec un payload vide (clé figée jamais invalidée) ; les posts gardent le continue (résultats partiels acceptables). Le chemin direct reste tenté d'abord (gratuit si SiteGround déflague l'IP). Testé : fetch() venv → 9 annonces (studios 1 400-1 600 $, 4½ 1 650 $, 5½ 2 199 $ — 9155 Meilleur, 9820 Verville, 9050 av. du Parc, 4 photos chacune — médiane 9 restaurée), run.py sync gestion_mj → found=9 ok, pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 12 days ago · 1 file +50 −6
    4. [ka2] fix connecteur lbm: contournement du challenge sgcaptcha SiteGround via proxy résidentiel Oxylabs — même cause et même fix que boreal_abitibi (8923045), citiluxx (d17f5fe), cromwell (8351131), deschenes_pepin (f8aca03), gestion_habitation (8b0660b), gimcote (12df764) et appartements_rimouski (af2be7c), hébergeur SiteGround identique (8e connecteur touché). Le sync du 2026-09-12 22:19 a rapporté found=0 ok (médiane 8.0, stale) : SiteGround sert son anti-bot sgcaptcha (HTTP 202, 166 octets, en-tête sg-captcha: challenge, meta refresh vers /.well-known/sgcaptcha/) à l'IP datacenter du nœud — un 2xx sans HTTPError, avalé par le `except Exception: return listings` de fetch() en « 0 trouvé ok », invisible du disjoncteur. Vérifié live : IP directe → 202 challenge ; IP résidentielle Oxylabs CA → 200, 161 Ko, les 3 pages projet (le-2922, le-3215, le-3537) présentes. Fix minimal, pattern appartements_rimouski : _get_html() détecte le challenge (en-tête sg-captcha ou marqueur /.well-known/sgcaptcha/) et bascule la session sur pr.oxylabs.io:7777 en session collante -cc-CA (accueil + pages projet partagent l'IP), erreur franche si le challenge persiste — la page d'accueil (liste des projets, pas de pagination) lève désormais au lieu de retourner [] (fini le zéro silencieux, ingest journalise ok=0) ; les pages projet gardent le continue (résultats partiels acceptables). Pas de detail_cache dans ce connecteur. Le chemin direct reste tenté d'abord (gratuit si SiteGround déflague l'IP). Testé : fetch() venv → 8 annonces (Le 3537 modèles 1-4 : 3½ 1 370 $ → 5½ 1 895 $, 15 photos ; typologies 4½/5½ Le 3215 et Le 2922 — médiane 8.0 restaurée), run.py sync lbm → found=8 ok, pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 12 days ago · 1 file +45 −5
    5. [ka2] fix connecteur appartements_rimouski: contournement du challenge sgcaptcha SiteGround via proxy résidentiel Oxylabs — même cause et même fix que boreal_abitibi (8923045), citiluxx (d17f5fe), cromwell (8351131), deschenes_pepin (f8aca03), gestion_habitation (8b0660b) et gimcote (12df764), hébergeur SiteGround identique (7e connecteur touché). Les syncs du 2026-09-13 02:13→02:40 ont rapporté found=0 ok x5 (médiane 16-17, disjoncteur de dérive déclenché puis médiane érodée à 0) : SiteGround sert son anti-bot sgcaptcha (HTTP 202, 186 octets, en-tête sg-captcha: challenge, meta refresh vers /.well-known/sgcaptcha/) à l'IP datacenter du nœud (76.70.60.50 flaguée « ipr ») — un 2xx sans HTTPError, la soupe sans lien /logements/ devenait « 0 trouvé ok », invisible du disjoncteur. Vérifié live : IP directe → 202 challenge ; IP résidentielle Oxylabs CA → 200, 229 Ko, les 16 cartes /logements/ présentes. Fix minimal, pattern gimcote : _get_html() détecte le challenge (en-tête sg-captcha ou marqueur /.well-known/sgcaptcha/) et bascule la session sur pr.oxylabs.io:7777 en session collante -cc-CA (liste + fiches détail partagent l'IP), erreur franche si le challenge persiste — la page de liste (unique, pas de pagination) lève désormais au lieu de retourner 0 carte (fini le zéro silencieux, ingest journalise ok=0) ; _fetch_detail() passe aussi par _get_html() pour ne pas empoisonner detail_cache avec un payload vide (clé figée jamais invalidée) ; les fiches gardent le except autour de detail() (résultats partiels acceptables). Le chemin direct reste tenté d'abord (gratuit si SiteGround déflague l'IP). Testé : fetch() venv → 16 annonces (studio 675 $ → 6½ 2 300 $, photos 4-13, Rimouski/Le Bic — médiane 16 restaurée), pytest fixtures 2 passed, run.py sync appartements_rimouski → found=16 ok, pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 12 days ago · 1 file +47 −2
    6. [ka2] fix connecteur gimcote: contournement du challenge sgcaptcha SiteGround via proxy résidentiel Oxylabs — même cause et même fix que boreal_abitibi (8923045), citiluxx (d17f5fe), cromwell (8351131), deschenes_pepin (f8aca03) et gestion_habitation (8b0660b), hébergeur SiteGround identique (6e connecteur touché). Le sync du 2026-09-12 21:51 a rapporté found=0 ok (médiane 79.0, stale) : SiteGround sert son anti-bot sgcaptcha (HTTP 202, 166 octets, en-tête sg-captcha: challenge, meta refresh vers /.well-known/sgcaptcha/) à l'IP datacenter du nœud — un 2xx sans HTTPError, avalé par le `except Exception: break` de fetch() en « 0 trouvé ok », invisible du disjoncteur. Distinct de la panne du 2026-09-06 (vhost suspendu, 503 x-suspended-vhost) : celle-là est résolue, le connecteur était sain. Vérifié live : IP directe → 202 challenge ; IP résidentielle Oxylabs CA → 200, 148 Ko, 20 cartes item-listing-wrap page 1. Fix minimal, pattern gestion_habitation : _get_html() détecte le challenge (en-tête sg-captcha ou marqueur /.well-known/sgcaptcha/) et bascule la session sur pr.oxylabs.io:7777 en session collante -cc-CA (liste paginée + fiches détail partagent l'IP), erreur franche si le challenge persiste — la 1re page de liste lève désormais au lieu de break (fini le zéro silencieux, ingest journalise ok=0), les pages suivantes gardent le break (résultats partiels acceptables) ; _fetch_detail() passe aussi par _get_html() pour ne pas empoisonner detail_cache avec un payload vide (clé figée jamais invalidée). Le chemin direct reste tenté d'abord (gratuit si SiteGround déflague l'IP). Nota : une IP résidentielle collante peut elle-même être flaguée (1 run sur 2 en test) — l'échec est alors franc et le sync suivant retire une nouvelle IP. Testé : fetch() venv → 79 annonces (médiane 79.0 pile, prix 855-1395 $, photos 8-14, Québec/Lévis), pytest fixtures 2 passed, run.py sync gimcote → found=79 ok, pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 12 days ago · 1 file +54 −5
    7. [ka2] fix connecteur gestion_habitation: contournement du challenge sgcaptcha SiteGround via proxy résidentiel Oxylabs — même cause et même fix que boreal_abitibi (8923045), citiluxx (d17f5fe), cromwell (8351131) et deschenes_pepin (f8aca03), hébergeur SiteGround identique. Le sync du 2026-09-12 21:50 a rapporté found=0 ok (médiane 4.0, stale) : SiteGround sert son anti-bot sgcaptcha (HTTP 202, 176 octets, meta refresh vers /.well-known/sgcaptcha/) à l'IP datacenter du nœud (76.70.60.50 flaguée « ipr ») — un 2xx sans HTTPError, la soupe sans .location-card devenait « 0 trouvé ok », invisible du disjoncteur. Vérifié live : IP directe → 202 challenge ; IP résidentielle Oxylabs CA → 200, 130 Ko, 12 cartes dont 8 « NON DISPONIBLE » (4 disponibles, cohérent avec la médiane). Fix minimal, pattern deschenes_pepin : _get_html() détecte le challenge (en-tête sg-captcha ou marqueur /.well-known/sgcaptcha/) et bascule la session sur pr.oxylabs.io:7777 en session collante -cc-CA (liste + fiches détail partagent l'IP), erreur franche si le challenge persiste — la page de liste lève désormais au lieu de retourner 0 carte (fini le zéro silencieux, ingest journalise ok=0) ; _fetch_detail() passe aussi par _get_html() et lève sur challenge pour ne pas empoisonner detail_cache avec un payload vide (clé figée jamais invalidée) ; les fiches détail gardent le except autour de detail() (résultats partiels acceptables). Le chemin direct reste tenté d'abord (gratuit si SiteGround déflague l'IP). Testé : fetch() venv → 4 annonces (4 ch. Malartic 3 200 $, 225 1e Av. O. Amos 900 $, 3½ Malartic 1 250 $ juin 2026, 3½ Amos 1 050 $ juillet 2026, photos 8-25 — médiane 4.0 restaurée), pytest fixtures 2 passed, run.py sync gestion_habitation → found=4 ok, pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 12 days ago · 1 file +48 −2
    8. [ka2] fix connecteur deschenes_pepin: contournement du challenge sgcaptcha SiteGround via proxy résidentiel Oxylabs — même cause et même fix que boreal_abitibi (8923045), citiluxx (d17f5fe) et cromwell (8351131), hébergeur SiteGround identique. Le sync du 2026-09-13 01:56 a rapporté found=0 ok=1 missed=5 (médiane 5.0, stale) : SiteGround sert son anti-bot sgcaptcha (HTTP 202, 174 octets, en-tête sg-captcha: challenge, meta refresh vers /.well-known/sgcaptcha/) à l'IP datacenter du nœud — un 2xx sans HTTPError, avalé par le `except Exception: return listings` de fetch() en « 0 trouvé ok », invisible du disjoncteur. Vérifié live : IP directe → 202 challenge ; IP résidentielle Oxylabs CA → 200, 234 Ko, les 2 liens /projet/ (Le Blüm Longueuil + Sainte-Julie) présents. Fix minimal, pattern cromwell : _get_html() détecte le challenge (en-tête sg-captcha ou marqueur /.well-known/sgcaptcha/) et bascule la session sur pr.oxylabs.io:7777 en session collante -cc-CA (liste + fiches projet partagent l'IP), erreur franche si le challenge persiste — la page de liste lève désormais au lieu de retourner [] (fini le zéro silencieux, ingest journalise ok=0), les fiches projet gardent le continue (résultats partiels acceptables) ; _fetch_project() passe aussi par _get_html(). Le chemin direct reste tenté d'abord (gratuit si SiteGround déflague l'IP). Testé : fetch() venv → 5 annonces (Le Blüm Sainte-Julie 3½/4½, Le Blüm Longueuil 3½/4½/5½, photos 12-20, adresses complètes — médiane 5.0 restaurée), run.py sync deschenes_pepin → found=5 ok, pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 12 days ago · 1 file +45 −5
    9. [ka2] fix connecteur cromwell: contournement du challenge sgcaptcha SiteGround via proxy résidentiel Oxylabs — même cause et même fix que boreal_abitibi (8923045) et citiluxx (d17f5fe), hébergeur SiteGround identique. Le sync du 2026-09-13 01:16 a rapporté found=0 ok=1 (médiane 11.0, stale, retraits suspendus par le disjoncteur de dérive) : SiteGround sert son anti-bot sgcaptcha (HTTP 202, 197 octets, meta refresh vers /.well-known/sgcaptcha/, en-tête sg-captcha: challenge) à l'IP datacenter du nœud (76.70.60.50 flaguée « ipr ») — un 2xx sans HTTPError, avalé par le `except Exception: break` de fetch() en « 0 trouvé ok », invisible du disjoncteur. Vérifié live : IP directe → 202 challenge ; IP résidentielle Oxylabs CA → 200, 244 Ko, les 11 cartes item-listing-wrap présentes. Fix minimal, pattern citiluxx : _get_html() détecte le challenge (en-tête sg-captcha ou marqueur /.well-known/sgcaptcha/) et bascule la session sur pr.oxylabs.io:7777 en session collante -cc-CA (liste + fiches détail partagent l'IP), erreur franche si le challenge persiste — la 1re page de liste lève désormais au lieu de break (fini le zéro silencieux), les pages suivantes gardent le break (résultats partiels acceptables) ; _fetch_detail() passe aussi par _get_html() pour ne pas empoisonner detail_cache avec un payload vide. Le chemin direct reste tenté d'abord (gratuit si SiteGround déflague l'IP). Testé : fetch() venv → 11 annonces (Studio 1 345 $ → 6½ 3 995 $, photos 7-10, dispo + promos), pytest fixtures 2 passed, run.py sync cromwell → found=11 ok (médiane 11.0 restaurée), pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 12 days ago · 1 file +54 −7
    10. [ka2] fix connecteur boreal_abitibi: contournement du challenge sgcaptcha SiteGround via proxy résidentiel Oxylabs. Le sync du 2026-09-13 01:07 échouait honnêtement (« ajax_object introuvable sur /locations/ », ok=0) : SiteGround sert désormais son anti-bot sgcaptcha (HTTP 202 + meta refresh vers /.well-known/sgcaptcha/, en-tête sg-captcha: challenge) à l'IP datacenter du nœud — un 2xx qui ne lève pas d'HTTPError, donc invisible du wrapper résilient (même angle mort que brio/Sucuri 195f19a). Vérifié live : le challenge frappe tout UA depuis notre IP (76.70.60.50 flaguée « ipr/ipc »), mais une IP résidentielle Oxylabs CA passe (200, 52 Ko, ajax_object présent) et le POST admin-ajax get_rents fonctionne sur la même session collante (nonce af45b697e0 → 1 rent). Fix minimal dans le connecteur : _get_html() détecte le challenge (en-tête sg-captcha ou marqueur /.well-known/sgcaptcha/) et bascule la session sur pr.oxylabs.io:7777 en session collante -cc-CA (nonce + POST admin-ajax + fiches détail partagent l'IP, pattern fb_marketplace/_resilient), erreur franche si le challenge persiste ; _fetch_detail() lève aussi sur challenge pour ne pas empoisonner detail_cache avec un payload vide (clé figée jamais invalidée). Le chemin direct reste tenté d'abord (gratuit si SiteGround déflague l'IP). Testé : fetch() venv → 1 annonce (App. 205 Esplanade Val-d'Or, 3½, 1 465 $, dispo octobre, 11 photos — médiane 1.0), pytest fixtures 2 passed, run.py sync boreal_abitibi → found=1 ok, pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 12 days ago · 1 file +42 −2
  6. Fri, Sep 11, 2026 2

    1. Revert "[ka2] fix connecteur vision_immo: échec honnête au lieu d'un « 0 trouvé ok » qui a déjà dépublié les 6 annonces. Le sync du 2026-09-11 10:43 a rapporté found=0 ok=1 missed=6 (médiane 6, stale) : fetch() avalait toute exception sur la page liste (`except Exception: return []`) — un échec réseau transitoire devenait un succès à 0, invisible du disjoncteur. L'historique montre le coût réel : pendant la panne DNS systémique du 2026-09-10 (14:17 et 15:22), deux « 0 ok » silencieux ont abouti à removed=6 — les 6 annonces dépubliées puis re-publiées au sync suivant. Reproduit en live : la source est SAINE (page 200, 177 Ko, 6 liens /logements/), seul le silence sur erreur était fautif — même situation que thrace e5379b0 et novelo 6bf26bd, distinct du cas lienard (rollback d1571fc, source en panne). Fix : (1) fetch() laisse remonter les exceptions réseau (ingest journalise ok=0) et lève RuntimeError si 0 lien parsé ET formulaire de filtres Search & Filter absent (rendu partiel/refonte) — un vrai zéro (0 lien mais squelette présent) reste possible car la page ne liste que les unités offertes ; (2) _parse_detail() ne retourne plus {} sur exception : detail() aurait mis ce {} en cache PERMANENT (clé figée « v1 », jamais invalidée) et l'unité aurait disparu pour toujours — vérifié : cache actuel sain, 7 payloads complets. Testé : fetch() venv → 6 annonces (4½ Terrebonne 1 720 $, 4½ Lachine 1 995 $, 3½ St-Henri 1 395 $, 4½ J180 2 195 $, 5½ 2 395 $, 6½ 2 695 $), run.py sync vision_immo → found=6 ok, pm2 restart lou-ka-sync, site :8095 → 200."
      …
      This reverts commit 602ff085f8e5b57320fc15852598d73d6a057a76.
      Simon-Pierre Boucher committed 13 days ago · 1 file +8 −15
    2. [ka2] fix connecteur vision_immo: échec honnête au lieu d'un « 0 trouvé ok » qui a déjà dépublié les 6 annonces. Le sync du 2026-09-11 10:43 a rapporté found=0 ok=1 missed=6 (médiane 6, stale) : fetch() avalait toute exception sur la page liste (`except Exception: return []`) — un échec réseau transitoire devenait un succès à 0, invisible du disjoncteur. L'historique montre le coût réel : pendant la panne DNS systémique du 2026-09-10 (14:17 et 15:22), deux « 0 ok » silencieux ont abouti à removed=6 — les 6 annonces dépubliées puis re-publiées au sync suivant. Reproduit en live : la source est SAINE (page 200, 177 Ko, 6 liens /logements/), seul le silence sur erreur était fautif — même situation que thrace e5379b0 et novelo 6bf26bd, distinct du cas lienard (rollback d1571fc, source en panne). Fix : (1) fetch() laisse remonter les exceptions réseau (ingest journalise ok=0) et lève RuntimeError si 0 lien parsé ET formulaire de filtres Search & Filter absent (rendu partiel/refonte) — un vrai zéro (0 lien mais squelette présent) reste possible car la page ne liste que les unités offertes ; (2) _parse_detail() ne retourne plus {} sur exception : detail() aurait mis ce {} en cache PERMANENT (clé figée « v1 », jamais invalidée) et l'unité aurait disparu pour toujours — vérifié : cache actuel sain, 7 payloads complets. Testé : fetch() venv → 6 annonces (4½ Terrebonne 1 720 $, 4½ Lachine 1 995 $, 3½ St-Henri 1 395 $, 4½ J180 2 195 $, 5½ 2 395 $, 6½ 2 695 $), run.py sync vision_immo → found=6 ok, pm2 restart lou-ka-sync, site :8095 → 200.
      Simon-Pierre Boucher committed 13 days ago · 1 file +15 −8
  7. Thu, Sep 10, 2026 1

  8. Wed, Sep 9, 2026 1

    1. [ka2] fix connecteur groupe_theoret: réécriture pour la refonte du site (GoDaddy Website Builder → GoDaddy Airo, ~2026-09-09) — le widget « menu » n'existe plus. Le sync de 15:40 a rapporté found=0 ok=1 (médiane 23, retraits suspendus) : reproduit en live, l'URL accentuée /appartements-%C3%A0-louer redirige 301 vers /appartements-a-louer et la nouvelle page (React Router, 88 Ko) ne contient plus aucun marqueur data-aid MENU_SECTION_*. Le nouveau site embarque TOUT le catalogue dans le payload d'hydratation window.__staticRouterHydrationData (données créées le 2026-09-01, unités ajoutées encore aujourd'hui) : 40 immeubles avec adresse + ville + code postal + slug /proprietes/<slug> + services + photos (/airo-assets/images/<slotKey>, vérifiées 200 image/jpeg) + contact, et par unité DISPONIBLE un id stable, le type, le loyer et la date de dispo ISO. Nouveau fetch() : une seule requête (plus de pages immeuble ni de cache détail), extraction du littéral JS par regex tolérante aux guillemets échappés puis double json.loads, external_id=u<id> (clé BD du site), RuntimeError si le payload est absent ou sans immeuble (une page saine embarque toujours les ~40 immeubles même à 0 dispo — même pattern que c3r/brio). Gain net vs l'ancien site : photos 25/25 (avant 0 %), inclusions 25/25, contact 24/25, code postal systématique. Testé : run.py sync groupe_theoret → found=25 ok (médiane 23, added=25 — nouveaux ids, les 23 anciennes annonces seront dépubliées par les retraits), fixtures ré-enregistrées (record → 1 requête, 25 annonces ; pytest 2 passed), pm2 restart lou-ka-sync, site :8095 → 200. sources.json : listing_url → /appartements-a-louer.
      …
      Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
      Simon-Pierre Boucher committed 15 days ago · 18 files +364 −8,785
  9. Tue, Sep 8, 2026 4

    1. [ka2] fix connecteur c3r: réécriture pour la refonte du site (Wix → Astro, 2026-09-08) — l'API wix-data n'existe plus. Le sync de 12:32 a rapporté found=0 ok=1 (médiane 8, retraits suspendus) : reproduit en live, les collections Wix Import1/Import2 renvoient 404 WDE0025 « collection does not exist » et les anciennes URLs d'unités (/terrasses-st-maurice/…) répondent 302 → /logements. Gestion C3R a lancé aujourd'hui (sitemap lastmod 2026-09-08) un nouveau site statique Astro servi par Express : catalogue /logements?page=N paginé côté serveur (5 pages, 73 unités, 4 projets — Chemin du Lac, Terrasses St-Maurice, Rue des Tournesols, Maisons St-Bo), chaque unité en <article data-rental-unit> avec data-city/project/bedrooms/price/status + type, adresse, sdb, superficie, photo. Nouveau fetch() : pagination avec dédup par slug (au-delà de la dernière page le serveur re-sert la même page), décodage UTF-8 forcé (pas de charset dans les en-têtes → requests décodait « Loué » en « Loué »), filtre statut Disponible conservé, RuntimeError si 0 carte parsée (garde contre rendu partiel/structure changée, même pattern que brio/le_fjord). Testé : parsing 73/73 unités (prix 73, adresses 73, sdb 73, superficie 73, photos 65), found=0 en prod — VRAI zéro : les 73 unités du nouveau site sont toutes « Loué », y compris les 8 qui étaient « Disponible » ce matin sur l'ancien CMS. Le garde-fou lèvera la suspension des retraits après le 3e sync à 0 (DRIFT_HISTORY=5) et les 8 annonces périmées seront dépubliées naturellement. pm2 restart lou-ka-sync, site :8095 → 200. sources.json : listing_url → /logements, + Shawinigan.
      …
      Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
      Simon-Pierre Boucher committed 16 days ago · 2 files +112 −124
  10. Mon, Sep 7, 2026 2

  11. Sun, Sep 6, 2026 3

  12. Sat, Sep 5, 2026 1

    1. Simon-Pierre Boucher committed 19 days ago · 2 files +7 −7
  13. Fri, Sep 4, 2026 8

    1. feat(fiche): refonte premium mobile-first de la fiche logement (2026-09-04)
      …
      Frontend (frontend/src/fiche/, nouvelle arborescence) : héro prix → adresse →
      résumé → galerie → actions ; Lou-Ka Score (60 % KA Score emplacement + 40 %
      prix vs juste valeur, partiel si une composante manque) ; « En bref »
      déterministe (prix, accessibilité, air, inondation, coûts, TAL, chaleur,
      baisse de prix) ; navigation sticky par sections (scroll-spy) ; Prix et marché
      (juste valeur + histogramme) ; Le logement (grille icône/valeur) ; description
      tronquée + texte original ; inclusions dédoublonnées FR/EN ; grande carte 3D
      Ka Maps avec filtres de lieux (transport, épiceries, pharmacies, commerces,
      écoles, parcs, essence) ; À proximité / Transport en carrousels + bottom sheet ;
      Quartier en KPI compacts + accessibilité en lignes ; KA Scores compacts ;
      Registre des loyers orienté décision (jauge p10–p90, médianes par chambres,
      3 comparables + sheet filtrable) ; coût réel + Hydro ; risque d'inondation
      (statut clair, juridique en accordéon) ; qualité de l'air en tuiles ; essence
      (3 stats, 3 stations, sheet) ; Dossier de l'immeuble en accordéons (historique,
      passeport, gestionnaire, TAL, hiver) ; Sources et méthodologie + fin de fiche.
      Primitives : SectionCard, Accordion, BottomSheet (modale ≥ 900 px), StatTile,
      StatusBadge, Skeleton, états vides/erreur, toast. Données : useFicheData
      (groupe critique au montage, groupe différé à l'approche de la carte).
      Tokens --lk-* scopés (.lk-fiche) : fond #F7F7F5, cartes blanches bord 1 px,
      ombres légères, rayons 10/14/18/22, orange réservé CTA/prix/score. Desktop
      ≥ 1024 : aside sticky (prix, CTA, score, constats, Demander à Ka). CTA sticky
      compact affiché seulement après le héro ; bouton « ✦ Demander à Ka » discret
      branché sur le widget KA Agent existant (contexte de la fiche transmis).
      Header compact sur la fiche (56 px, ticker masqué, favoris + partage,
      connexion en icône sur mobile). Aucun `order` CSS ; scrollIntoView banni de la
      barre de sections (faisait ouvrir la page à 434 px). Anciennes classes
      .fiche/.f-* intactes pour la fiche court terme. 16 anciens composants de fiche
      supprimés (remplacés). check-order.mjs mis à jour + shots.mjs / interactions.mjs.
      
      Backend (additif, rétrocompatible) : poi.py conserve lat/lng des POI (carte) ;
      gaz.py expose lat/lng des stations ; /api/gaz et /api/rdl acceptent `limit`
      (sheets « Voir les N »). vite.config : proxy /api paramétrable (LOUKA_API).
      
      Validé : tsc + vite build, check-order OK (scrollY 0, ordre croissant, sans
      overflow 375→1440), captures Playwright 6 largeurs, sheets/carte/Ka/404,
      fiche sans KA Score. node_modules frontend réinstallés (typescript/esbuild
      tronqués par ka2 le 2026-08-31 pour ENOSPC).
      Simon-Pierre Boucher committed 20 days ago · 54 files +4,182 −2,266
    2. Simon-Pierre Boucher committed 20 days ago · 32 files +2,862
    3. Simon-Pierre Boucher committed 20 days ago · 4 files +187 −38