Décisions méthodologiques

Toutes les règles structurantes du dashboard, classées par catégorie.

Chaque décision donne la règle, la raison (↳), et les alternatives écartées (✗) quand pertinentes.


🏗️ Architecture

Choix de stack, hébergement, contraintes structurantes du site.

Quarto Dashboard en R, déploiement statique

Cartes via leaflet, viz via ggplot2 + ggiraph ou SVG natif, Sankey via networkD3. Pipeline data en R (duckdb + arrow + sf).
Document lisible cellule par cellule, pas un HTML/JS opaque. Quarto = literate computing. Pas de serveur Shiny → hébergeable sur GitHub Pages statique.
HTML/JS pur (pas un notebook) · Shiny serveur (pas statique) · Shinylive WebR (gardé en option).

Multi-page sous 100 MB par fichier

Une page Quarto par thématique. Plafond cible : 45 MB HTML par page.
GitHub Pages plafonne à 100 MB par fichier. Un dashboard mono-page atteindrait 200+ MB.
Implémentation : R/setup_dashboard.R est sourcé par chaque page, charge les données conditionnellement (if (carb_ready) …). htmlwidgets n'embarque que les objets passés aux widgets de la page.

Périmètre géographique : Métropole + 5 DROM en cartouches

DROM = 971 Guadeloupe, 972 Martinique, 973 Guyane, 974 La Réunion, 976 Mayotte. Convention IGN.
Inclusivité sans dégrader la lisibilité de la carte principale.
Carte unique étirée sur Atlantique/Indien (illisible).

🗺️ Cartographie

Palettes, encodages, gestion des cas particuliers (PLM, DROM, légendes dynamiques).

Législatives : famille gagnante + opacité par marge

Variable cartographiée : famille gagnante au tour décisif (NFP/ENS/RN/LR/Divers). Opacité proportionnelle à la marge (faible marge → couleur pâle).
Le multipartisme se rend bien par couleur catégorielle. L'opacité ajoute la force de la victoire sans surcharger.

Municipales : helper dédié choropleth_municipales()

Différences vs Législatives :
  • Palette "Divers" boostée : olive #A18047 au lieu du gris national. Justification : 88% T1 + 81% T2 gagnés par "Divers" (LDIV/LDVG/LDVD/LREG) — invisibles sinon.
  • Stroke différencié : T1 → orange #F0A500 (0,6 px), T2 → blanc (0,3 px). L'œil distingue immédiatement le tour décisif.
  • Opacité fixe 0,85 pour toutes les communes avec famille, pas de fade par marge.
La marge moyenne T1 (47%) écraserait T2 (12%) ; un fade serait illisible.

Paris / Lyon / Marseille : règle par viz

Données MI agrègent au niveau commune (75056, 69123, 13055), GeoJSON expose par arrondissement (75101-75120, etc.).
  • Élections : résultat ville mère répercuté sur tous les arrondissements.
  • Mobilité Sankey : consolidation 751xx → 75056 avant agrégation (sinon 20 "Paris arrondissements" pollueraient le Sankey).
  • Profil radar : filtre les communes avec < 5/8 axes renseignés (exclut les codes PLM consolidés peu renseignés).
Sommer pop + revenus + APL des arrondissements vers la commune mère — demanderait un script PLM dédié (à faire ultérieurement).

Légendes dynamiques (page Démographie)

Quand l'utilisateur toggle entre "Population", "Densité INSEE", "Chômage", la légende swap entre format continu (5 breaks log-quantile) et format catégoriel (6 niveaux ordinaux).
Un même barème continu n'a aucun sens pour une variable catégorielle.

DROM cartouches : re-fit bounds à l'expansion

R/map_helpers.R::.add_resize_handler() capture les bounds initiaux puis ré-applique fitBounds() après chaque invalidateSize(). Observe aussi le parent .card (Quarto fullscreen).
Sans re-fit, leaflet garde l'échelle calculée pour 150×150 px. Un DROM agrandi en fullscreen restait minuscule au centre.

📊 Données par source

Une décision par source : règles métier, filtres, snapshots. 26 sources au total.

📥 Élections Législatives 2024 — T1 fallback

Min. Intérieur · 35 000 communes
Variable cartographiée = famille gagnante au tour décisif. Pour les ~6 000 communes décidées au 1er tour (majorité absolue + seuil d'inscrits), on bascule au résultat T1 ; colonne tour trace la nature du résultat affiché.
Mapping nuance MI → 5 familles :
  • NFP : UG, FI, SOC, COM, VEC, ECO
  • ENS : ENS, HOR
  • LR : LR, UDI, UDR
  • RN : RN, UXD, EXD
  • Divers : DVD, DVG, DVC, DSV, REG, EXG, DIV

📥 Municipales 2026 — T1 + T2 combinés

Min. Intérieur · ~3 300 communes
T2 prioritaire (1 526 communes) + T1 fallback (1 779 communes décidées au 1er tour) = ~3 300 communes ≥ 1 000 hab. Les ~32 000 communes < 1 000 hab. utilisent le scrutin majoritaire individuel → absentes du fichier source, affichées en beige neutre.
Mapping nuance liste (préfixe L) → famille : LUG/LFI/LSOC/LCOM/LVEC/LECO = NFP ; LUC = ENS ; LLR/LUDI/LUDR/LUD = LR ; LRN/LUXD/LEXD = RN ; LDIV/LDVG/LDVD/LDVC/LREG = Divers.

📥 DVF Immobilier — filtres standards

DGFiP · 3,98 M ventes mono-locaux agrégées, 2021-2025 (2025 provisoire)
Filtres :
  • nature_mutation = "Vente"
  • type_local ∈ {"Appartement", "Maison"}
  • surface_reelle_bati > 9 m²
  • Bornes : 200 €/m² < x < 30 000 €/m²
  • Mutations mono-local uniquement
  • Médiane comme stat d'agrégation (robuste outliers)
  • N < 5 ventes/an → estimation_insuffisante, grisée
Convention DVF standard. Mono-local évite la répartition prix sur lots. Médiane robuste.
Moyenne (sensible outliers) · Répartition proportionnelle (bruit non traçable).

📥 Atmo Air — agrégation 30 jours glissants

Atmo France · WFS · ~700 stations
Snapshot agrégé sur 30 jours glissants au lieu du jour J. EPCI expansion pour Bretagne (Air Breizh), Occitanie (Atmo Occitanie), Pays de la Loire (Air PdL) qui publient par EPCI.
L'indice journalier varie fortement (pollens, canicule). 30 j lisse les NA et reflète l'exposition chronique.
DROM couverts partiellement : Guadeloupe + Martinique seulement.

📥 SSMSI Délinquance — secret statistique

SSMSI 2025 · 11 000 à 31 000 communes selon l'indicateur · 685 pour le total
13 indicateurs (‰ habitants, sauf cambriolages : ‰ logements, dénominateur insee_log de la base SSMSI) (violences intra/hors famille, sexuelles, vols avec armes / violents / sans violence, cambriolages, vols de véhicules / dans / accessoires, dégradations, trafic, usage de stupéfiants) + total.
Secret statistique (règle SSMSI) : un décompte n'est diffusé que s'il vaut 0 ou ≥ 5 ; 1 à 4 faits = « non diffusé » = NA (jamais 0). Un 0 diffusé est un vrai zéro, mais dans les petites communes seuls les zéros sont visibles (biais de sélection : l'absence de valeur n'est pas « peu de délinquance »).
Total ‰ habitants = Σ des effectifs des 13 composantes ÷ population × 1 000 (les taux ne sont pas additionnés : le dénominateur des cambriolages diffère ; unités de compte mixtes : victimes, infractions, mis en cause), NA dès qu'une composante est non diffusée (del_n_publies donne le nombre de composantes publiées). Il n'existe donc que pour ~685 communes, les plus grandes.

📥 BAAC Accidents — taux ‰ habitants

Min. Intérieur · 34 920 communes (dont ~11 200 avec ≥ 1 accident) · 2024
Compte d'accidents corporels par commune, normalisé en ‰ habitants (acc_taux_pop = accidents / pop_latest × 1000, seule définition). Les communes sans accident valent 0, pas NA.

📥 DGFiP Finances communales

DGFiP · ~35 000 communes · 2024
Recettes, charges, dette, CAF en €/habitant. Taux de 3 taxes locales : habitation, foncier bâti, foncier non bâti.

📥 APL DREES — seuil désert médical

DREES · ~35 000 communes · 2024 (millésime lu dans les données)
5 professions : médecins (+ ≤65 ans), infirmiers, sages-femmes, dentistes, kinés.
APL médecins généralistes : palette divergente avec seuil 2,5 consultations/an/hab = désert médical (DREES). Couleur change de rouge à vert au passage du seuil.

📥 Espérance de vie INSEE — join par nom

INSEE · niveau DÉPARTEMENT (101 départements) · 2025 provisoire
L'INSEE ne publie pas d'espérance de vie communale. La variable esperance_vie est celle du département, recopiée sur chaque commune (esperance_vie_niveau = « departement »). Moyenne simple hommes/femmes (74,7 à 85,4 ans).

📥 FiLoSoFi Revenus INSEE

INSEE · ~30 000 communes · 2021
Revenu médian disponible, déciles D1/D9, indice de Gini, % ménages imposés, part prestations vs activité.
CSV séparateur point-virgule (français), filtrage des très petites communes par INSEE (secret stat).

📥 INSEE Populations + Strates de taille

INSEE · ~35 000 communes · 2017-2021
5 strates de taille INSEE :
  • Très petite (< 500 hab.)
  • Rurale (500 - 2 000)
  • Bourg / périurbain (2 000 - 10 000)
  • Ville moyenne (10 000 - 50 000)
  • Grande ville (≥ 50 000)
La densité urbaine est le principal confondant. Stratifier permet d'isoler les corrélations intra-strate.
Fallback proxy pour communes sans pop publiée : quartiles d'inscrits sur listes électorales.

📥 INSEE Grille de densité (typologie 6 niveaux)

INSEE · ~35 000 communes · 2024
Variable catégorielle ordinale rural → urbain :
  1. Rural non périurbain
  2. Rural périurbain
  3. Ceintures urbaines
  4. Petites villes
  5. Centres urbains intermédiaires
  6. Grands centres urbains
Mappée en palette catégorielle (page Démographie). Sert aussi de variable continue densite_rang (1 = rural non périurbain … 6 = grands centres urbains) dans Explorer + Bivariée. Les deux classes intermédiaires sont ordonnées par population médiane croissante ; le test monotone est dans scripts/99_validate_data.R.

📥 DARES Chômage DEFM A+B+C

DARES · 34 910 communes · 2024-T4 (moyenne trimestrielle, données brutes)
Demandeurs d'Emploi en Fin de Mois cat. A+B+C. Normalisé en taux ‰ habitants via defm_abc / pop_latest * 1000.
[2026-10-15] Decision : passage du fichier 2020-T4 déposé à la main (7 439 communes) au jeu officiel « Inscrits à France Travail, données communales » 2024-T4. Lignes agrégées (« Total France »…) et lignes ville PLM (= somme des arrondissements) écartées ; codes ramenés au COG 2026. Contrôles : somme des communes 5 563 980 vs ligne « Total France » 5 565 440 (−0,03 %) ; départements vs notes DREETS 2024-T4 (Marne +0,3 %, Moselle −0,3 %, Hauts-de-France +0,5 %, Bourgogne-Franche-Comté +0,5 %). Effectifs arrondis à 5 par la DARES : taux masqué sous 100 habitants (erreur d'arrondi ≥ ±25 ‰ pour une médiane de ~60 ‰ ; 3 382 communes), effectif conservé. Alternatives rejetées : garder 2020-T4 (couverture 21 %, millésime ancien) ; lissage bayésien (pas d'erreur de sondage ici, seulement de l'arrondi).

📥 RARE/CITEPA Empreinte carbone — approche conso

RARE · ~34 800 communes · base 2018
Empreinte carbone par habitant en approche consommation (EXIOBASE × CITEPA). Médiane FR ≈ 7,9 tCO₂eq/hab/an.
Reflète le mode de vie (logement, transport, alimentation, biens), indépendamment de la localisation des usines. Une grande ville pollue là où sont ses usines (souvent banlieue) ; l'empreinte conso lui attribue son vrai poids.
Empreinte territoriale (émissions sur le sol) — biaise les communes industrielles.

📥 INSEE MOBPRO — codes TRANS (RP 2019 puis RP 2022)

INSEE · ~34 800 communes · RP 2022 (codes TRANS identiques au RP 2019)
⚠️ INSEE a révisé le codage TRANS au RP 2017+. Codes actuels :
  • 1 Pas de transport
  • 2 Marche à pied
  • 3 Vélo (y compris VAE)
  • 4 2-roues motorisés
  • 5 Voiture / camion / fourgonnette
  • 6 Transports en commun
Un bug initial a confondu TRANS=5 avec TC → médiane voiture à 0% sur la carte. Fix appliqué et codes documentés ici pour éviter la récidive.
Indicateurs dérivés : % emploi local, % voiture/TC/vélo/marche, top destination + flux.

📥 Agence Bio Agriculture

Agence Bio · 23 100 communes · 2024
Surface bio totale = AB certifiée + en conversion (C1 + C2 + C3). Nombre d'opérateurs = exploitations + transformateurs + distributeurs.
Fichier opérateurs en long (1 ligne par production × activité) → agrégé par sum(nboperateur) par commune × année.
Couverture : 23 100 communes (les ~12 000 sans aucune exploitation bio n'apparaissent pas dans le fichier source). Échelle log-quantile sur la carte (distribution skewée, médiane 47 ha, max 16 817).

🔬 Analyse

Stratification, métriques de corrélation, filtres de tautologies.

Spearman par défaut, Pearson alternatif

Toutes les corrélations calculées en Spearman (rang) par défaut. Pearson disponible en toggle pour comparaison.
Distributions prix m², chômage, délinquance, bio ont des queues lourdes. Spearman est monotone et robuste aux outliers.

Top 25 corrélations — filtrage des tautologies

Le top affiché à droite de la heatmap Explorer exclut les paires intra-thématique. 12 groupes thématiques servent de filtre.
Sans filtre, le top serait saturé par des tautologies :
  • del_total × del_vols_pers (ρ = 0,98) — total inclut les vols
  • fin_charges × fin_recettes (ρ = 0,99) — budget équilibré
  • ctx_log_inscrits × ctx_log_pop (ρ = 0,99) — inscrits ≈ pop adulte
  • revenu_median × revenu_d9 (ρ = 0,95) — bougent ensemble
Les corrélations vraiment intéressantes traversent les sujets : revenu × vote, densité × prix, CO₂ × mobilité.

Bivariate choropleth — palette Stevens 3×3

Encodage 2 variables en terciles × terciles → 9 classes (palette Stevens 2015). Les coins donnent les associations extrêmes ; le centre rassemble les "moyennes".
16 paires pré-calculées côté R (scripts/05_merge_and_explore.R). 3 160 combinaisons disponibles côté JS via selectors X/Y.

Stratification : 5 strates × variable continue densite_rang

Les corrélations sont pré-calculées par paire × méthode × strate (Spearman/Pearson × 5 strates pop + Toutes) → 15 912 lignes dans correlations.parquet.
Variable alternative densite_rang (1-6, INSEE typologie 6 niveaux) disponible dans heatmap et Bivariée mais pas (encore) en strate Explorer.

📈 Visualisations

Choix d’encodage pour les 4 viz dérivées (radar, Sankey, small multiples, scatter Explorer).

Profil radar — 8 dimensions en rang centile

8 axes retenus, critère couverture ≥ 30 000 communes ET diversité thématique :
  1. Population (log)
  2. Revenu médian
  3. APL médecins
  4. Recettes communales €/hab
  5. Délinquance totale ‰
  6. Empreinte CO₂/hab
  7. % voiture mobilité
  8. Densité INSEE (rang 1-6)
Encodage en rang centile national (0-100) plutôt que valeur brute → lecture "rond ou écrasé" indépendante des unités. 50 = médiane FR.
Filtre : communes avec < 5/8 axes renseignés sont exclues du lookup (cas PLM consolidés).

Sankey mobilité — Top 100 flux + PLM consolidé

Préfixage des nœuds : "R · Lyon" pour résidence, "T · Lyon" pour destination. Sinon networkD3 collapse les deux côtés et perd l'orientation.
Pipeline (scripts/16_mobilite_flows.R) :
  1. Consolidation PLM (751xx→75056, 6938x→69123, 132xx→13055)
  2. Top 50 destinations par poids entrant total
  3. Filtre COMMUNE != DCLT (exclut flux intra-commune)
  4. Top 200 flux ≥ 100 actifs, puis top 100 pour le rendu

Small multiples départements — 96 tuiles métropole

Régex strict ^(0[1-9]|[1-8][0-9]|9[0-5]|2[AB])$ pour le filtre — exclut ZX (Saint-Martin), ZZ (Français hors de France) et 97x/98x (DROM, séparés).
Indicateur continu : médiane communale du département. Famille dominante : plurality (pas majorité absolue) des communes du département.
9 indicateurs sélectionnables, 8 palettes différentes selon le sens de l'indicateur (séquentielle, divergente, catégorielle).

Explorer scatter — LOESS approx + ρ live

Échantillon stratifié (max 8 000 communes) pour ne pas saturer le SVG. ρ Spearman recalculé en JS sur l'échantillon courant.
Courbe "LOESS-like" : moyenne mobile sur 30 quantiles de X. Pas un vrai LOESS (trop coûteux côté JS) mais suffisant pour donner la tendance.

🔄 Fraîcheur des données & complétions écartées

Quelles sources se rafraîchissent automatiquement, lesquelles sont figées par une limite amont, et quelles extensions ont été tentées puis écartées parce qu’elles auraient introduit un indicateur trompeur (principe d’objectivité : mieux vaut pas d’indicateur qu’un indicateur faux).

Rafraîchissement automatique mensuel

Le workflow .github/workflows/refresh-data.yml (cron, 1ᵉʳ du mois) re-télécharge les sources à URL stable et recommit les parquets modifiés : Atmo air (30 j glissants — la seule qui change vraiment souvent), SSMSI, DGFiP, APL, BAAC, carbone, FiLoSoFi, populations, bio. Scripts idempotents (cache des bruts).
Un dashboard de données publiques se périme ; l'automatisation évite la dérive sans intervention manuelle. Les versions de packages sont figées (renv.lock) pour qu'un refresh ne change jamais le comportement.

Sources figées par une limite amont (refresh manuel)

  • DEFM chômage : le script 10 télécharge désormais le jeu officiel DARES (« Inscrits à France Travail, données communales », data.gouv.fr). Ce jeu donne 2024-T4 sur 34 917 communes (valeurs arrondies à 5) ; adopté le 2026-10-15 (voir la carte DARES ci-dessus), lignes agrégées écartées.
  • MOBPRO mobilité : le fichier détail commune × commune est passé au RP 2022 le 2026-10-14 (voir « Vague 2 » ci-dessous). Décalage usuel de ~4 ans ; refresh manuel à chaque nouveau millésime INSEE.
  • Municipales 2026 : scrutin ponctuel, pas de refresh.

✗ Complétions tentées puis écartées

  • Gaz + électricité par commune (bloc G complet) — rouvert le 2026-10-14, voir « Vague 2 » : les exports agrégés côté serveur de l'Agence ORE suppriment le téléchargement de 800 MB.
  • % SAU en bio (bloc K) — deux pistes rejetées : (1) la SAU Agreste RA2020 republiée par ZABAL est en format long multi-millésimes à couverture partielle (~10 k lignes, non national) ; (2) normaliser la surface bio par l'aire communale donne des ratios > 100 % car l'Agence Bio attribue la surface au siège de l'opérateur, pas à la localisation des parcelles — dénominateur et numérateur ne portent pas sur le même territoire. On conserve donc la surface bio brute (ha) plutôt qu'un ratio trompeur.
  • Espérance de vie communale (jeu data.gouv « régions, départements et villes », 1 371 communes appariées par nom) — abandonné le 2026-10-14 : les valeurs allaient de 11 à 105 ans, ce n'était pas une espérance de vie. Remplacé par le niveau département (INSEE).

Historique des règles

  • 2026-10-14 (soir) — Vague 2 : 10 nouvelles sources, ORE rouvert, Filosofi 2023, DVF 2025 provisoire, MOBPRO 2022 ; pages Logement, Risques et sols, Services et numérique. Détail en fin de page.
  • 2026-10-14 — Correctifs de justesse des données (audit dataviz C1-C11), détail ci-dessous.
  • 2026-05-25 — Décisions initiales : Quarto + leaflet, périmètre métropole+DROM, élections 2024 T2 + T1 fallback, DVF filtres standard, Atmo WFS + EPCI expansion, stratification 4 strates pop INSEE.
  • 2026-05-26 matin — Multi-page split GitHub Pages, ajout SSMSI + BAAC, DGFiP, APL 5 pros + EV INSEE, FiLoSoFi, grille densité INSEE 6 levels, DEFM, Municipales 2026 T1+T2. Passage 4 → 5 strates pop INSEE.
  • 2026-05-26 après-midi — Blocs G (carbone RARE/CITEPA), I (mobilité MOBPRO 2019), K (Agence Bio). Helper municipales dédié. Fix démographie click+legend, fix DROM resize fitBounds. Viz radar profil, Sankey mobilité, small multiples départements. Codes TRANS RP 2019 documentés post-bug.

Correctifs de données du 2026-10-14

[2026-10-14] C1 · densite_rang

Decision : table de correspondance explicite sur les 6 libellés INSEE, 1 = rural non périurbain → 6 = grands centres urbains (ordre intermédiaire fixé par la population médiane).
Rationale : l'ancienne cascade de regex envoyait « Rural (non) périurbain » vers « urbain » (3) et « Petites villes » vers 7 ; ρ(rang, log pop) = −0,12, désormais +0,47.
Alternatives rejetées : sens inverse (1 = urbain) ; densité de population continue (non disponible dans la grille).

[2026-10-14] C2 · Finances DGFiP en €/hab

Decision : fin_recettes/charges/dette/caf/invest/emprunt = colonnes DGFiP préfixées « f » (euros par habitant, vérifié = montant × 1000 / population). Les totaux en k€ sont conservés sous fin_*_total_keur.
Rationale : l'ancien code lisait les totaux (Paris : 7 745 164 k€) en les étiquetant €/hab ; ρ(recettes, population) = 0,95. Paris = 3 604 €/hab, médiane nationale 921 €/hab.
Alternatives rejetées : recalculer total × 1000 / pop1 (identique, mais redondant avec la colonne source).

[2026-10-14] C3 · SSMSI : secret statistique et total

Decision : cellule non diffusée = NA ; total = somme des 13 composantes uniquement si toutes sont diffusées, sinon NA ; colonne del_n_publies. Libellé « Vols de véhicule » (édition 2025) ajouté à la table.
Rationale : rowSums(na.rm = TRUE) sommait des sous-ensembles différents par commune. Correction du constat de l'audit : les zéros « diffusés » sont de vrais zéros (règle 0 ou ≥ 5) ; le biais vient de la sélection, pas d'un zéro codé à la place d'un NA. Bug supplémentaire corrigé : indicateur est un facteur, l'indexation par ses codes entiers permutait les colonnes (ex. Paris del_vols_pers 5,3 → 45,1 ‰).
Alternatives rejetées : total sur composantes disponibles (biaisé) ; imputation par la valeur de groupe complement_info (valeur unique pour tous les non-diffusés).

[2026-10-14] C4 · BAAC : zéro accident

Decision : le fichier est écrit sur toutes les communes INSEE (COM + arrondissements) ; absence d'accident = 0. Ville PLM = ville + arrondissements. Une seule définition : acc_taux_pop.
Rationale : les ~23 700 communes sans accident étaient NA, donc le taux ne portait que sur les communes avec ≥ 1 accident (plancher 1/pop).
Alternatives rejetées : taux lissé bayésien (reporté).

[2026-10-14] C5 · Espérance de vie : réparée au niveau département

Decision : source INSEE « Espérance de vie en 2025 » (TCRD_050), département, hommes et femmes ; valeur départementale attribuée à chaque commune avec esperance_vie_niveau.
Rationale : l'ancienne série (11 à 105 ans) n'était pas une espérance de vie. Les cartes affichent des aplats départementaux : ne pas interpréter les différences intra-départementales.
Alternatives rejetées : retirer la variable (décision de Pierre : réparer) ; inventer des valeurs communales (aucune source INSEE fiable).

[2026-10-14] C7 · Paris, Lyon, Marseille

Decision : la géométrie est à l'arrondissement. choropleth_socio* duplique la valeur « ville » (75056, 69123, 13055) sur les arrondissements absents (.plm_expand, affichage seulement). Les populations des 3 villes sont la somme de leurs arrondissements ; DVF, APL, FiLoSoFi, DEFM, publiés par arrondissement, sont consolidés vers la ville dans commune_merged (moyenne pondérée, approximation).
Alternatives rejetées : fusionner les polygones en 3 villes (ferait perdre le détail des sources par arrondissement).

[2026-10-14] C8 · Doublons de population

Decision : pivot sur codgeo seul, libellé de l'année la plus récente. 492 codes dupliqués (communes renommées) → 0 ; commune_merged : 35 232 lignes à l'époque, 34 875 depuis le cadre COG 2026 (audit M1), 1 par commune.

[2026-10-14] C10 · Mesure du vote dans l'Explorer

Decision : elec_pct_rn/nfp/ens/lr/divers et l'abstention = parts du 1er tour (% des exprimés ; famille RN = RN + UXD + EXD). elec_marge reste celle du T2.
Rationale : les parts T2 dépendent de la configuration du duel et ne sont définies que là où la famille est qualifiée.

[2026-10-14] C11 · Départements pondérés

Decision : explorer/departements_agg.parquet : médiane pondérée par la population (prix, revenu, APL, chômage, carbone, voiture), accidents = Σ accidents / Σ population, délinquance = moyenne pondérée sur les communes où le total est publié (delinq_pop_couverte donne la part de population couverte).

[2026-10-14] Air : fenêtre d'observation

Decision : le snapshot Atmo porte date_debut, date_fin, date_fenetre (la colonne date_ech lue auparavant n'existait pas).

Vague 2 : nouvelles sources du 2026-10-14

[2026-10-14] ORE rouvert : électricité et gaz résidentiels par commune

Decision : rouvrir l'entrée « Agence ORE » classée comme écartée. Les exports agrégés côté serveur (script 27) remplacent le CSV de 800 MB. Indicateurs affichés : électricité et gaz résidentiels par habitant (INSEE 2021) et par point de livraison, part du gaz (communes raccordées seulement), évolution 2019 à 2024. Le total ORE n'est pas cartographié : il inclut ~57 TWh de clients industriels RTE.
Rationale : le blocage (volume) est levé ; les totaux nationaux sont à −1,5 % (Enedis) et −3,0 % (GRDF) des chiffres publiés. Rupture de série en 2018 : aucune comparaison avant 2019. Une évolution n'est publiée que si aucune cellule résidentielle n'est masquée en 2019 et en 2024 (sinon borne basse) ; la règle porte sur le secteur résidentiel et non sur secret_tot, qui agrège tous les secteurs et écartait des communes au résidentiel intact (6 800 communes contre 33 600).
Alternatives rejetées : garder le bloc écarté ; filtrer sur secret_tot (trop restrictif) ; afficher la borne basse avec un avertissement (une carte ne porte pas l'avertissement).

[2026-10-14] Filosofi 2023 ajouté en niveau, Filosofi 2021 conservé

Decision : garder Filosofi 2021 (composition du revenu) et ajouter Filosofi 2023 comme niveau de vie courant (médiane, et taux de pauvreté là où il est publié). Badge permanent « Filosofi 2 · série non comparable avec 2021 » et aucune comparaison 2021 à 2023 (ni graphique, ni écart).
Rationale : Filosofi 2 est une nouvelle méthode (INSEE : comparaison « à proscrire ») ; composition et déciles ne sont publiés qu'à partir du département en 2023.
Alternatives rejetées : remplacer 2021 (perte de la composition) ; évolution 2021 à 2023 (rupture de série). La corrélation entre les deux niveaux (ρ = 0,93) est classée « Revenus » dans l'Explorer, donc filtrée du classement inter-thématiques.

[2026-10-14] BPE : panier de la vie courante, 10 familles

Decision : score de 0 à 10 = nombre de familles présentes dans la commune parmi : médecin généraliste, pharmacie, boulangerie-pâtisserie, alimentation générale, école, poste, banque, coiffure, restaurant, chirurgien-dentiste. Choix de l'équipe de données, listé sur la page Services.
Rationale : un indice simple et lisible plutôt qu'un total d'équipements (qui reproduit la taille). Limite : présence dans la commune n'est pas accès ; aucun temps de trajet.
Alternatives rejetées : total d'équipements (tautologie de taille) ; panier pondéré (poids arbitraires).

[2026-10-14] CAF : taux seulement à partir de 1 000 habitants

Decision : RSA et aides au logement affichés en % de la population uniquement si la population atteint 1 000 habitants ; MSA exclue ; avertissement Guyane (population sous-estimée au recensement, Camopi à 68 % de RSA).
Rationale : la CNAF arrondit les comptes à 5 et applique le secret : sous 1 000 habitants, un taux n'est pas lisible (9 949 communes conservées).

[2026-10-14] DPE : part F/G seulement à partir de 30 diagnostics

Decision : la part de DPE classés F ou G est publiée si la commune compte au moins 30 diagnostics (22 432 communes). Libellé « part des DPE depuis 07/2021 », avec une mention explicite de non-représentativité.
Rationale : un DPE est établi à la vente ou à la location : l'échantillon n'est pas le parc ; la méthode a changé le 1er juillet 2024 ; les doublons de logement ne sont pas dédoublonnables en agrégé.

[2026-10-14] DVF 2025 : « provisoire »

Decision : DVF couvre 2021 à 2025 ; l'année 2025 est étiquetée « provisoire ».
Rationale : 740 000 ventes en 2025 contre 655 000 en 2024 : la complétude du millésime n'est pas confirmée (délais d'enregistrement), donc aucune tendance 2024 à 2025 n'est à lire comme définitive.

[2026-10-14] MOBPRO passe au RP 2022

Decision : mêmes schémas, millésime RP 2022. Changements à connaître : mob_pct_emploi_local de Paris, Lyon et Marseille vaut maintenant 70 / 63 / 84 % (0 auparavant) ; mob_pct_velo inclut les vélos à assistance électrique et n'est pas comparable avec 2019 ; la destination principale n'est plus le code 99999.

[2026-10-14] Participation électorale 2002-2026

Decision : séries d'abstention par commune depuis les élections agrégées par bureau de vote ; Français de l'étranger exclus ; blancs et nuls non distingués avant 2016. Vues : présidentielle 2022 (T1), européennes 2024, municipales 2026 (T1) et évolution 2002 à 2022.

[2026-10-14] Communes ou électeurs : chiffre corrigé

Decision : la vue « Électeurs » de la page Législatives dessine un cercle par commune (surface ∝ inscrits). La synthèse « communes contre inscrits » est calculée à chaque rendu. Sur les données actuelles, le RN gagne 49,7 % des communes mais 28,9 % des inscrits (audit initial : 50,2 % et 31,0 %, avant les corrections de données).

[2026-10-14] 28 indicateurs ajoutés à l'Explorer, sans tautologie de taille

Decision : seuls des taux, parts et densités entrent dans commune_merged (aucun total brut, donc pas de corrélation « population × effectif »). Chaque variable porte un groupe thématique (explorer/indicator_meta.parquet) ; deux variables d'un même groupe sont écartées du classement inter-thématiques. Évolution ORE, taux CAF et part DPE sont mis à NA hors de leurs règles de publication.

[2026-10-15] DGFiP : DROM et départements 90 à 95 perdus à la jointure

Decision : la DGFiP code les départements d'outre-mer 101 à 106 (101 Guadeloupe, 102 Guyane, 103 Martinique, 104 Réunion, 106 Mayotte) ; ils sont recodés en 971 à 976 avant la construction du code commune (icom DGFiP = 3 derniers chiffres du code INSEE). 129 communes d'outre-mer ont désormais des comptes. Même correction pour 601 communes du Territoire de Belfort et d'Île-de-France (90 à 95), dont le code DGFiP « 09x » n'était pas ramené à deux chiffres.
Rationale : sans recodage, les cartons DROM de la page Finances étaient entièrement hachurés alors que la donnée est publiée.
Alternatives rejetées : mention « non publié » sur les cartons (faux : la DGFiP publie).

[2026-10-14] Sécurité : taux lissés (Bayes empirique, Poisson-gamma)

Decision : les taux de délinquance peuvent être affichés lissés : modèle Poisson-gamma, prior estimé par la méthode des moments dans chaque classe de densité INSEE (code : eb_poisson_gamma dans R/socio_helpers.R). Vue par défaut = taux brut ; bascule « lissé » proposée.
Rationale : un taux sur un petit dénominateur est instable ; le lissage tire les petites communes vers leur classe sans masquer la valeur brute, qui reste la vue d'ouverture.
Alternatives rejetées : lissage par défaut (cache la donnée observée) ; prior national unique (mélange rural et urbain).

[2026-10-14] Immobilier : DVF 2025 provisoire, vue d'évolution 2021 à 2024

Decision : 2025 est provisoire ; la vue « évolution » s'ouvre sur 2021 à 2024 ; la page Immobilier s'ouvre sur Maison 2024 (3 387 communes seulement ont un prix appartement fiable contre 14 191 pour les maisons).
Rationale : la complétude de 2025 n'est pas confirmée (voir DVF 2025 ci-dessus), et un défaut sur un type presque vide donnerait une carte grise.

[2026-10-14] Départements : délinquance totale grisée sous 25 % de population couverte

Decision : la tuile « délinquance totale » d'un département est grisée si moins de 25 % de sa population vit dans une commune où le total est publié (delinq_pop_couverte).
Rationale : le total n'existe que pour 685 communes ; une moyenne sur une fraction faible de la population ne représente pas le département.

[2026-10-14] Profil : l'axe « Délinquance (total) » remplacé par Cambriolages

Decision : l'axe du radar est le taux de cambriolages et non le total de délinquance.
Rationale : le total ne couvre que 685 communes (NA dès qu'une composante est secrète) ; les cambriolages sont publiés pour bien plus de communes.

[2026-10-15] Communes semblables : k plus proches voisins sur critères au choix

Decision : les semblables d'une commune sont ses k plus proches voisins (défaut k = 15, de 5 à 30). Critères par défaut : population (log) et classe de densité INSEE ; ajoutables : revenu médian, prix m² maison et appartement (DVF 2024), part de propriétaires, APL médecins, part de la voiture, logements vacants, fibre, panier de services. Chaque critère est transformé (log1p pour les prix), centré-réduit sur toutes les communes qui l'ont, puis distance = racine de la moyenne des carrés des écarts réduits (comparable quel que soit le nombre de critères). Filtres durs facultatifs : même département, même classe de densité (si trop peu de communes dans la classe, complété hors classe et annoncé). Un critère non publié pour la commune de référence est ignoré ; une commune sans valeur sur un critère actif n'est pas candidate. Tri déterministe (distance, puis ordre de l'index). Paris, Lyon et Marseille : peu de communes de taille comparable, le groupe s'élargit et la page le dit. Code : assets/peers-core.js, test : tests/check_peers.js.
Rationale : une règle unique, lisible (« les 15 communes les plus proches sur ces critères »), qui garantit une taille de groupe stable, contrairement à une fenêtre de tolérance (±X % de population) qui donne 0 ou 400 communes selon la taille.
Alternatives rejetées : même classe de densité + population à ±X % (taille du groupe imprévisible, vide pour les très grandes villes) ; distance de Mahalanobis (opaque et dominée par les critères corrélés) ; « même région » (le registre n'a pas de région) ; part des seniors (pas dans commune_merged). La proximité est descriptive : elle dépend des critères choisis.

[2026-10-15] Constellation : un moteur de points, sans d3

Decision : la page Constellation dessine 34 875 communes et 101 départements sur un seul <canvas> (assets/constellation.js), avec quatre dispositions (carte, population, nuage, classement) liées par des transitions de 450 ms (instantanées si prefers-reduced-motion). Échelles, interpolation et brosse sont écrites à la main (~100 lignes) ; fonctions pures testées sous Node (assets/constellation-core.js, tests/check_constellation.js).
Rationale : d3 n'est pas déjà embarqué dans le site (ni dans le runtime Quarto des tableaux de bord) ; l'ajouter coûte ~90 ko gzip pour trois usages triviaux. Le reste du site est en JS sans dépendance.
Alternatives rejetées : SVG (35 000 nœuds : trop lent) ; OJS / Plot (runtime lourd, hors du format tableau de bord).

[2026-10-15] Vue population : cercles de Dorling, placement glouton

Decision : en vue « Population », la surface d'un cercle est proportionnelle aux habitants (INSEE, recensement 2021) au-dessus de ≈ 477 habitants, avec un rayon plancher de 0,7 unité (≈ 0,6 px) pour les très petites communes. Positions précalculées en R (R/dorling.R) : du plus grand au plus petit, chaque cercle est posé à sa position géographique ; s'il gêne, il prend la première position libre sur des anneaux de rayon croissant. L'échelle (surface totale des cercles de la métropole = 22 % de son cadre) est identique partout, outre-mer compris.
Rationale : aucun chevauchement par construction (contrôlé sur les cercles placés par tests/check_constellation.js), toutes les communes placées, sans graine ni itérations de relaxation à régler. Contrepartie : les plus grandes villes sont à leur place exacte et leurs banlieues sont repoussées en couronne (Paris), ce qui est précisément l'effet de lecture voulu.
Alternatives rejetées : relaxation par forces (résidus de chevauchement, réglage de convergence) ; d3-force au runtime (35 k corps, trop lent) ; cartogramme continu (déformation des formes).

[2026-10-15] Outre-mer : cinq encarts égaux, à échelle propre

Decision : Guadeloupe, Martinique, Guyane, La Réunion et Mayotte sont dans cinq encarts égaux sous la métropole, dans le même ordre dans les vues Carte et Population (Saint-Pierre-et-Miquelon et les collectivités 98x n'ont pas de géométrie dans la source : non placés). En vue Carte, chaque encart est ajusté à SA propre échelle (mention « échelle propre » sur la page) ; en vue Population, les cercles gardent la même échelle que la métropole. Projection de la métropole : Web Mercator, comme les cartes Leaflet du site. Mayotte n'a pas de population dans la base : ses communes sont au rayon plancher.
Rationale : la même place visible aux cinq territoires dans les deux vues, une convention unique et lisible. Un encart à échelle propre exagère la surface des DROM : c'est dit sur la page, et c'est la vue Population qui rétablit les proportions.
Alternatives rejetées : échelle commune (Guyane et Mayotte illisibles) ; encarts en bas à gauche de la mer (trop petits).

[2026-10-15] Constellation : départements par défaut, médiane pondérée

Decision : la vue nationale montre 101 points départementaux ; chaque valeur est la médiane des communes du département pondérée par la population (plus petite valeur dont le poids cumulé atteint la moitié ; poids tous nuls : médiane simple). Choisir un département ou une densité, ou cliquer un point départemental, révèle les communes. La couleur d'un point départemental utilise les seuils des communes.
Rationale : 35 k points d'emblée sont illisibles ; la médiane pondérée est robuste aux valeurs extrêmes et représente l'habitant médian plutôt que la commune médiane. Contrôle : tests/check_constellation.js.
Alternatives rejetées : moyenne (sensible aux queues lourdes) ; médiane simple des communes (dominée par les petites communes).

[2026-10-15] Nuage de points : association, jamais causalité

Decision : le nuage de deux indicateurs affiche le ρ de Spearman et le nombre de communes ayant les deux valeurs, calculés sur les communes du filtre (pas sur les médianes départementales, ce qui est précisé), avec la source et le millésime de chaque axe et la mention « association, pas causalité » (biais écologique, causes communes, dates différentes). Axes fixes du 1er au 99e centile, logarithmiques si toutes les valeurs sont positives et la queue haute étirée ; les points au-delà sont posés sur le bord. Les millésimes viennent de R/indicator_sources.R (le registre indicator_meta n'en porte pas).
Rationale : des axes stables permettent de comparer les filtres entre eux ; Spearman reste cohérent avec le reste du site (voir la décision Spearman par défaut).

[2026-10-15] Brosse sur histogramme : Constellation et cartes thématiques

Decision : l'histogramme sous la Constellation est brossable ; les points hors plage s'estompent (opacité 0,1) et un second indicateur montre sa distribution dans la plage contre l'ensemble. Même mécanisme, générique, dans assets/cmap.js : l'histogramme de la légende de toutes les cartes thématiques se brosse (glisser pour isoler, cliquer pour effacer ; opacité des polygones hors plage réduite ; nombre de communes et part de la population de la plage), sans modification par page. La brosse est réinitialisée à chaque changement d'indicateur.
Rationale : une seule implémentation lisant seulement CMap.cur.get(code). L'état est appliqué au relâchement de la souris (35 k polygones Leaflet à restyler).

[2026-10-15] Audit Referee 2 : corrections C1 à C5, M1 à M5

Decision (C1) : les libellés des 6 classes de densité viennent d'une seule source, grille_densite.parquet (rang 1 Rural non périurbain, 2 Rural périurbain, 3 Ceintures urbaines, 4 Petites villes, 5 Centres urbains intermédiaires, 6 Grands centres urbains), émise dans assets/data/communes.json (dl) et lue par CMap.densLabels. Le repli de cmap.js est vérifié contre les données (test Node et validateur).
Rationale : l'ordre des libellés courts était recopié à la main et faux pour les rangs 3 à 5 (Montluçon affichée « Ceintures urbaines »). Les libellés courts sont désormais indexés par le libellé INSEE, jamais par la position.
Alternatives rejetées : corriger seulement l'ordre du tableau JS (la même erreur pourrait revenir sans contrôle).
Decision (C2, M1) : les populations légales RP 2017-2021 sont sommées vers le COG 2026 (cog_map("2016-01-01"), effectifs sommés, jamais moyennés), comme les effectifs des autres sources. La table des communes (commune_merged) est le COG 2026 (34 875 communes, Paris/Lyon/Marseille sous le code ville) ; les résultats électoraux sont harmonisés au COG 2026 dans 02_elections.R (voix recombinées, pourcentages pondérés par les exprimés, abstention par les inscrits ; famille gagnante d'une commune fusionnée = famille aux voix cumulées les plus élevées). Mayotte : population légale du recensement 2017 (256 518 hab., champ insee_pop de la base SSMSI), millésime tracé dans pop_millesime. Les 7 communes rétablies ou sans habitant restent sans population (NA), jamais inventée ; la commune parente d'une commune rétablie en 2026 garde la population d'avant scission (non scindable sans source).
Rationale : numérateur (N communes) et dénominateur (une seule) divergeaient : Saint-Denis 93066 affichait 143 ‰ au lieu de 111 ‰, Montbenoît 199 ‰ au lieu de 42 ‰. Total contrôlé : 67 408 052 hab. = populations légales 2021 INSEE hors Mayotte.
Alternatives rejetées : passer aux populations légales 2023 au COG 2026 (millésime différent des autres dénominateurs et de la consigne de sommation) ; moyenner les taux.
Decision (C3) : si une source publie la ligne ville PLM (FiLoSoFi : 75056, 69123, 13055), elle est conservée telle quelle ; la ville n'est reconstruite à partir des arrondissements que lorsqu'elle manque (DVF, APL, DEFM), les effectifs étant sommés (y compris dvf_n_app/dvf_n_mai).
Rationale : la moyenne des Ginis d'arrondissements ignore l'inégalité entre arrondissements (Paris 0,410 contre 0,454 officiel) ; médiane Paris 29 730 contre 30 749.
Decision (C4) : voir SSMSI ci-dessus : cambriolages en ‰ logements, total reconstruit depuis les effectifs sur la population, lissage empirique-Bayes des cambriolages avec les logements comme exposition, effectif publié affiché tel quel (Paris 7 072).
Decision (C5) : assets/data/elections_lookup.json est produit au pré-rendu (R/build_web_assets.R) ; aucune page n'écrit plus dans assets/ (Quarto fige la liste des ressources avant le rendu des pages).
Decision (M2) : sur les cartes à l'arrondissement, la ville PLM prend la moyenne simple de ses arrondissements dans les parts de légende et le gradient (CMapStats.withPlmFallback), au lieu de « Non publié ».
Decision (M3) : le rayon plancher de la vue Population (0,7 unité) est annoncé sur la page ; seule la surface des communes au-dessus du seuil est proportionnelle aux habitants.
Decision (M4) : refresh-data.yml exécute les scripts dans l'ordre des dépendances sans || true, puis 99_validate_data.R avant tout commit ; deploy.yml se relance à la fin du refresh (workflow_run). Les millésimes affichés (DEFM, Atmo, SSMSI, DGFiP, CAF, ARCEP) sont lus dans les données (R/indicator_sources.R).
Decision (M5) : nouveaux contrôles : table des communes = COG 2026 (34 875), population totale 2021 = 67 408 052 (INSEE), PLM = ligne officielle FiLoSoFi, unités SSMSI (cambriolages ÷ logements, total ÷ population), libellés de densité du JS. La constante « 24,7 % d'abstention attendue » (non sourcée, calée sur la sortie) est supprimée, remplacée par une conservation des inscrits avant/après remappage. Les planchers de couverture sont étiquetés garde-fous de régression.
Mineurs : m1 (DEFM renommé « Demandeurs d'emploi ») et m7 (effectifs PLM sommés) corrigés. Non traités : m2 (chômage départemental = médiane pondérée), m3-m6, m8-m25 (hors périmètre de cette passe).

[2026-10-15] Audit Referee 2, tour 2 : corrections N1 à N10

[2026-10-15] Decision (N1) : chaque script du refresh télécharge lui-même son fichier brut dans data/raw/ (cache idempotent), pour que refresh-data.yml fonctionne depuis un data/raw/ vide : 07_ (SSMSI parquet et DGFiP CSV, URLs « latest » data.gouv.fr de la ressource), 11_ (BAAC Caract_2024.csv), 06_ (populations légales 2023 INSEE ensemble.zip et INSEE Focus 105 pour Mayotte). La population de Mayotte ne dépend plus d'un autre script. 08_drees_apl.R est sorti de la boucle automatique (remplacé : 08 est de nouveau dans le refresh, voir « 08, APL DREES » ci-dessous) : ses 5 XLSX (feuille « APL 2023 ») ne sont téléchargeables par aucune URL stable (anciennes ressources data.gouv supprimées, nouvelle édition à autre mise en page) ; le script s'arrête désormais avant d'écrire s'il n'a aucun fichier, et le parquet commité est conservé. 15_agriculture_bio.R est sorti de la boucle pour une autre raison, trouvée par la simulation d'un runner neuf : ses deux URL datées renvoient 404 depuis la republication Agence Bio de septembre 2026 (fichiers renommés, opérateurs en CSV à virgule, millésime 2025) ; le migrer changerait le millésime affiché (2024). Preuve : exécution complète de la boucle sur une copie sans data/raw/ (résultat dans le rapport de session).
Rationale : la réécriture M4 avait transformé « pousse des données douteuses » en « échoue toujours ». Un script non téléchargeable est mieux hors boucle (avec commentaire) que de faire échouer tout le job.
Alternatives rejetées : actions/cache sur data/raw/ (le premier run échouerait de la même façon et le cache masquerait un lien mort) ; lire Mayotte dans le fichier SSMSI brut (dépendance cachée entre scripts).
[2026-10-15] Decision (N2) : une seule définition du vainqueur pour toutes les communes (aggregate_commune, harmonise_cog2026) : la famille aux voix cumulées les plus élevées sur tous les candidats de la commune (communes coupées entre circonscriptions comprises), ses parts calculées sur les exprimés cumulés de la commune, la marge étant l'écart avec la 2e famille ; nuance_vainqueur = nuance du meilleur candidat de la famille gagnante. Une commune sans suffrage exprimé n'a pas de vainqueur (le T1 prend le relais : Geay 79131, 0 exprimé au T2 dans le fichier source). Avant : meilleur candidat d'une seule circonscription (Marseille « Divers 12,5 % » avec RN 48,0 % et NFP 39,5 %). Après : Marseille RN 48,0 %, Caen NFP 52,7 %, Angers ENS 44,8 %, Troyes RN 38,8 %, Grasse RN ; 181 communes changent de famille gagnante (150 au T2, 31 au T1) : 180 où le vainqueur affiché contredisait les parts, plus Geay (0 exprimé au T2, qui passe au T1). Contrôle de validation : famille gagnante = famille de part maximale pour toute commune sans égalité. Limite assumée : la famille « Divers » additionne des candidats sans lien (DVG, DVD, REG, ECO…) et peut devancer la première famille identifiée ; elle n'est pas exclue, pour garder une règle unique.
Alternatives rejetées : un vainqueur par (commune × circonscription) sans vainqueur de ville (casse la carte communale) ; exclure « Divers » de l'argmax (deuxième règle, difficile à justifier).
[2026-10-15] Decision (A, audit round 3) : divulguer la couverture partielle des résultats législatifs maintenant, reconstruire plus tard. Le fichier du 2nd tour ne contient que les circonscriptions allées au 2nd tour ; pour une commune coupée entre circonscriptions, le « tour décisif » ne portait que sur une partie de l'électorat (Paris : 9 députés NFP élus au 1er tour absents). 02_elections.R calcule couverture_inscrits = inscrits du résultat affiché ÷ inscrits de la commune au 1er tour (le fichier T1 couvre toutes les circonscriptions), plafonnée à 1 (les listes électorales bougent de quelques inscrits entre les deux dimanches ; arrêt si > 25 %, ou > 2 % au-dessus de 500 inscrits). Elle est transmise à commune_merged (elec_couverture_inscrits), à la fiche communale et à la carte. Valeurs : Paris 0,5035 (687 417 / 1 365 376), Marseille 0,746, Toulon 0,679, Courbevoie 0,154 ; 2 295 communes < 1, dont 194 < 0,99 et 6 < 0,5. Page Législatives : hachures sombres pour tout résultat partiel, sous 99 % (194 communes ; légende « résultat partiel (circonscriptions élues au 1er tour exclues) »), phrase « résultat sur X % des inscrits de la commune (circonscriptions élues au 1er tour exclues) » sous 99 %, et « tour décisif » remplacé par « 2nd tour, ou 1er tour là où aucun 2nd tour n'a eu lieu dans la commune ». Les arrondissements PLM héritent de la couverture de leur ville (le fichier est au niveau de la ville). Contrôle de validation : couverture dans (0, 1] et Paris recalculé depuis les fichiers bruts. Un premier seuil de hachure à 0,5 laissait Paris (0,5035) non hachuré : abandonné au profit de 0,99.
Alternatives rejetées pour l'instant : reconstruire depuis le fichier par bureau de vote avec, pour chaque circonscription, le tour qui a élu le député (couverture totale, résultat exact) : prévu dans une PR de suivi ; exclure les 194 communes (perd l'information).
[2026-10-15] Decision (A, suite — reconstruction au bureau de vote) : 02_elections.R reconstruit les résultats législatifs 2024 depuis les fichiers par bureau de vote du ministère (T1 et T2). Pour chaque circonscription, le tour décisif est celui qui a élu son député (1er tour : 76 ; 2nd tour : 501) ; chaque bureau compte avec le tour de sa circonscription ; voix cumulées par famille sur les bureaux de la commune (codes remappés au COG 2026 avant la somme, plus de recombinaison de pourcentages), parts sur exprimés cumulés, abstention sur inscrits cumulés, vainqueur = voix cumulées les plus élevées. Le fichier par bureau ne porte pas la circonscription : elle est déduite des candidats (département + nom + prénom, uniques dans le fichier par circonscription du même tour). Contrôles bloquants, sans tolérance : voix de chaque candidat sommées sur ses bureaux = fichier par circonscription (4 009 candidats au T1, 1 094 au T2, 0 écart) ; exprimés, inscrits et voix par nuance nationaux = fichier « France entière » aux deux tours (32 057 946 et 27 279 713 exprimés) ; exprimés du tour décisif bureaux = circonscriptions (31 127 127). Résultat : tour ∈ {T1, T2, mixte} (21 communes mixtes, dont Paris, Marseille, Lyon, Toulouse, Nice, Courbevoie, Toulon ; leurs parts mélangent deux tours, dit sur la page) ; couverture_inscrits ≈ 1 partout (min 0,859, 173 communes < 0,99, toutes au 2nd tour : l'écart est la différence observée d'inscrits publiés entre les deux tours dans des communes d'un seul bureau, p. ex. Louppy-le-Château 149 → 128 inscrits dans le fichier officiel ; ce n'est pas établi comme une révision des listes). Paris 0,50 → 1, Marseille 0,75 → 1, Courbevoie 0,15 → 1. Seuil de hachure/mention abaissé de 0,99 à 0,8 (accepté par le propriétaire) : l'ancien seuil aurait hachuré 173 communes pour un simple écart d'inscrits entre tours ; le mécanisme reste actif, le validateur et le script exigent couverture ≥ 0,8 (≥ 0,95 dès 500 inscrits côté script ; planchers de régression, valeurs observées 0,859 et 0,965, non ajustés pour passer). Mapping des nuances : REC (Reconquête) et RDG (Parti radical de gauche) restent dans « Divers », choix du propriétaire. Raisons : REC a présenté des candidats contre le RN dans 323 de ses 328 circonscriptions, et le candidat RDG s'est présenté contre le candidat officiel UG en 78-10, 82-02 et ZZ06 ; ni l'un ni l'autre n'appartient donc au bloc RN ou au NFP. Les deux nuances sont listées explicitement dans la table, et le repli silencieux est supprimé (une nuance absente de la table arrête le script). Une première version les avait classés REC → RN et RDG → NFP : abandonnée (Dropped, rationale contredite par les données ; elle gonflait le % NFP du 1er tour de jusqu'à 45 points dans ~180 communes). Effet sur le tour décisif : 6 communes changent de famille gagnante par la reconstruction (Paris, Marseille, Toulon, Courbevoie, Colombes, Mamoudzou) ; la révision REC/RDG → Divers rétablit la famille d'origine dans 10 petites communes du 1er tour, et la famille gagnante du 1er tour (famille_vainqueur_t1) revient à sa valeur avant mapping dans 439 communes. PLM : le code BV encode l'arrondissement (2 chiffres) + le bureau ; legislatives_2024_arrondissements.parquet (45 lignes) est produit et la ville en est la somme (contrôlé, à un bureau lyonnais « 0001 » de 386 inscrits sans arrondissement identifiable près) ; la carte Législatives, ses infobulles, la fiche communale et elections_lookup.json affichent désormais le résultat PROPRE de chaque arrondissement (Paris 16e : ENS 67,1 %, et non le NFP de la ville), avec tour/« mixte » calculé par arrondissement. Les lignes ville (75056, 69123, 13055) restent la somme et la clé de tout ce qui est par commune (explorateur, classements, constellation, permalinks). Le bureau lyonnais « 0001 » (386 inscrits, sans arrondissement) n'est compté que dans la ville. La participation 2002-2026 d'un arrondissement reste celle de la ville.
Rationale : la divulgation (hachures) signalait un résultat faux au lieu de le corriger ; avec la source par bureau, le résultat devient exact sur tout l'électorat. Vérification externe : Paris, 18 députés 2024 = 11 NFP, 6 ENS, 1 DVG (fr.wikipedia.org/wiki/Liste_des_députés_de_Paris), identiques à ceux du fichier par circonscription.
Alternatives rejetées : appariement des bureaux T1/T2 par code BV (codes non uniques : Montbéliard a 4 bureaux « 0000 » ; l'appariement par candidats est exact) ; parts T1 pour toute commune mixte (ignore l'élection du député) ; fichier agrégé general_results.parquet de data.gouv (pas de circonscription ni de voix par candidat dans general_results, circonscription vide dans les deux) ; supprimer la colonne couverture_inscrits (demandé de la garder, sert de garde-fou).
[2026-10-15] Decision (N3) : 11_baac.R remappe les codes BAAC vers le COG 2026 (cog_map("2024-01-01")) avant d'agréger, effectifs sommés : 62 accidents d'anciennes communes récupérés (Saint-Denis 259 → 286 accidents, Orée d'Anjou 0 → 4). Contrôle de validation : Σ accidents des communes du cadre = accidents bruts remappés.
[2026-10-15] Decision (N4) : les 10 communes concernées par un rétablissement 2024-2025 (MOD 21 : Essarts-en-Bocage/L'Oie/Sainte-Florence, Beaumont-les-Nonains/Les Hauts-Talican, Neussargues-Moissac + Celles, Chalinargues, Chavagnac, Sainte-Anastasie) prennent leur pop_latest dans les populations légales 2023 de l'INSEE (géographie au 1er janvier 2025, insee.fr/fr/statistiques/8680726), avec pop_millesime = 2023. pop_2021 (RP 2021 harmonisé, total contrôlé 67 408 052) n'est pas modifié. Beaumont-les-Nonains : 878 → 339 hab. ; Essarts-en-Bocage 9 399 → 6 851. Correction (audit round 3) : les numérateurs ne sont pas scindés (DEFM : 60054 libellé « Les Hauts-Talican » à toutes les dates, aucune ligne pour 60694, 85165, 85212, 15141 ; Celles apparaissait 1re de France à 368,7 ‰). Les taux par habitant de ces 10 communes (defm_taux_pop, acc_taux_pop, CAF, BPE santé, ENAF, ORE MWh/hab.) sont donc masqués dans commune_merged ; les effectifs restent publiés. Le contrôle « ≤ 10 communes sans population » est remplacé par « aucune » (0 observée) et par le millésime 2023 des 10 communes. Limite : une source encore à la géographie d'avant 2024 donne à la commune parente le total de ses ex-communes déléguées face à ce dénominateur réduit.
Alternatives rejetées : masquer les taux des 3 parents (perd l'information) ; populations 2022 (ne contiennent pas les 4 villages du Cantal rétablis en 2025). Remplace la mention « non scindable sans source » (fausse).
[2026-10-15] Decision (N6) : (a) 05_merge_and_explore.R passe toutes les sources par cog_rename(), qui applique à un seul endroit les changements de code sans changement de territoire (MOD 41 et 50, cog_map filtré) avant les jointures (Orée d'Anjou 49069 → 49126, Conques-en-Rouergue, Aurseulles, Porte des Pierres Dorées) ; les fusions ne sont pas traitées ici (un niveau ne se somme pas). Orée d'Anjou : 45 → 73 indicateurs renseignés sur 80 (12218 : 41 → 64). (b) Les contours communaux viennent maintenant d'Etalab « contours-administratifs » édition 2026 (COG 2026, 1 000 m) au lieu du dépôt gregoiredavid : 34 917 polygones (communes + 45 arrondissements PLM, villes PLM écartées pour ne pas recouvrir les arrondissements). Avant : 5 communes COG sans polygone, 1 015 polygones à d'anciens codes, 70 communes grises avec données ; après : 0 et 0. Contrôle de validation : toute commune COG 2026 a un polygone et aucun polygone n'est hors COG.
Alternatives rejetées : dissoudre les anciens polygones vers les communes fusionnées (ne crée pas les polygones des communes rétablies, qui n'existent dans aucune géométrie antérieure) ; additionner les niveaux d'une fusion.
[2026-10-15] Decision (N5, N7-N10, m10, m24) : N5 : 02_elections.R remappe depuis 2015 (4 sections réelles récupérées : Le Fresne-sur-Loire 44060, Pont-Farcy, Freigné, et la section « Cormicy » codée 02899 dans le fichier T1, rattachée à Cormicy 51171 par libellé, seul rattachement manuel) et échoue sur tout autre code non communal inconnu. N7 : strate NA, pas « Ville moyenne », sans population ni inscrits. N8 : le contrôle Paris 7 072 compare à la ligne brute SSMSI de la même édition (ignoré avec message si data/raw/ est absent) ; le contrôle de conservation de 19_ compare à un calcul indépendant (inscrits des codes vivants ou remappables), donc peut échouer ; Saint-Denis ignoré avec message en CI. N9 : pop_millesime des villes PLM = 2021 (le script sommait aussi la colonne pop_millesime). N10 : la population de Mayotte (RP 2017, plus ancienne que les numérateurs 2024-2025 ; ≈ +25 % de population depuis) est signalée sur les pages Sécurité (accidents), Démographie (DEFM), Revenus (CAF) et dans les sources de la Constellation. m10 : la légende dit « communes de France métropolitaine (hors DROM) », ce qu'elle compte. m24 : la page Profil relit l'adresse à chaque changement de #.
Non traités : m2, m3, m4, m5, m8, m11-m23, m25 ; N11 partiellement (README et décision pop mis à jour).

[2026-10-15] Sources 08 et 15, mineurs du round 3

[2026-10-15] Decision (08, APL DREES) : 08_drees_apl.R télécharge ses 5 classeurs (jeu DREES 530, éditions de juillet 2026, URL d'attachement data.drees.solidarites-sante.gouv.fr/.../attachments/indicateur_d_apl_aux_*_xlsx, également listées sur data.gouv.fr) et repasse dans la boucle de refresh (prouvé depuis un data/raw/ vide). Les classeurs contiennent un onglet par millésime (2022, 2023, 2024) : le script retient le plus récent commun aux 5, APL 2024 (population 2022), lu dans les fichiers et écrit en colonne apl_millesime ; les libellés des pages et du registre (R/indicator_sources.R) le lisent. Le parquet passe de 34 954 à 34 890 communes (couverture de commune_merged inchangée : 34 848 communes avec APL) ; médiane médecins 2,88 → 2,84 ; part des communes sous le seuil 2,5 : 36,8 % → 38,1 %. Les définitions sont celles de la méthode concertée V2 (mêmes intitulés de colonnes : « APL aux médecins généralistes », ETP pour 100 000 habitants standardisés pour les autres professions) ; la valeur de 2023 reste lisible dans le même classeur.
Rationale : le millésime n'est plus figé dans le code (« APL 2023 » codé en dur dans 4 fichiers) ; une édition ultérieure change l'affichage sans modification de code. Constats DREES à connaître : (i) dans infirmiers.xlsx, l'onglet « APL 2023 » annonce « Millésime : 2024 » et ses valeurs sont celles que ce dépôt affichait jusqu'ici comme « 2023 » pour les infirmières ; le script exige que l'en-tête de l'onglet lu annonce le millésime retenu. (ii) La colonne « médecins ≤ 65 ans » (apl_medecins_jeunes) était lue en 5e position, qui est « 62 ans et moins » dans l'édition de juillet 2026 : les valeurs 2023 affichées jusqu'ici sous « ≤ 65 ans » étaient celles de la variante 62 ans (identiques à 100 % sur les 34 954 communes). Le script repère maintenant la colonne par son intitulé (« de 65 ans et moins »). Cette série change donc de définition en plus de millésime.
Alternatives rejetées : garder APL 2023 (millésime lu dans le même classeur, mais il faudrait le figer dans le code et il serait plus ancien) ; lire les colonnes par position (cause de l'erreur ≤ 62/≤ 65).
[2026-10-15] Decision (15, Agence Bio) : conserver les données 2024 commitées ; ne pas passer à la republication de septembre 2026. Les ressources actuelles du jeu 61a6250d8660681353681fa8 (0b668cd6… surfaces, d8d704fb… opérateurs, 2008-2025, « secretstat ») ont les mêmes intitulés de variables (surfbio = AB + conversion, nb_exp, nboperateur), mais appliquent le secret statistique : en 2024, 61,5 % des lignes commune-année de surface valent « NC » (11 604 sur 18 862), et la somme nationale des surfaces tombe à 1,86 Mha contre 2,71 Mha dans le parquet commité (−31 %) ; en 2025, 61,7 % de lignes masquées. Le nombre d'exploitations (59 402 contre 59 401) et d'opérateurs (87 028 contre 86 958) de 2024 coïncident, mais les surfaces, indicateur central de la page Agriculture, ne sont plus comparables. Le script est rendu robuste (permaliens data.gouv.fr « dernière version », séparateur détecté) et s'arrête sans écrire si plus de 5 % des lignes de surface sont « NC » ou si le millésime n'est plus 2024 (libellé couplé). Vérifié depuis un data/raw/ vide : téléchargement, lecture, arrêt avec message, parquet inchangé (même empreinte). Il reste hors du refresh : dans la boucle set -e un arrêt volontaire ferait échouer tout le job.
Rationale : règle du propriétaire : changer de millésime seulement si les définitions d'indicateur sont identiques. Ici l'intitulé est identique mais pas le contenu (valeurs masquées traitées comme 0 par le calcul, ce qui fausserait cartes, rangs et corrélations). Comparateur : même année (2024), même périmètre (toutes communes), mêmes colonnes, deux publications officielles du même producteur.
Alternatives rejetées : passer à 2025 avec les NC mis à 0 (biais de −31 % non signalé) ou à NA (61 % de communes sans valeur) ; mélanger surfaces 2024 commitées et opérateurs 2025 (deux millésimes dans une même page) ; relever la tolérance MAX_NC pour que le script passe.
[2026-10-15] Decision (m-R1, DVF renumérotées) : cog_rename() écartait toutes les lignes de l'ancien code dès que le nouveau code avait une ligne, quelle que soit l'année ou le type. geo-dvf bascule d'un code à l'autre en cours de série (Orée d'Anjou : 49069 en 2021-2025, 49126 en 2025 seulement), d'où 116 ventes de maisons 2024 perdues et aucun prix de maison pour 49126. dvf_combine_renamed() (scripts/cog_helpers.R) est appliquée une seule fois, en amont, dans 03_dvf_aggregate.R : dvf_aggregated.parquet est donc en COG 2026 et l'Immobilier, le Profil, les Semblables et l'Explorer lisent les mêmes valeurs (premier correctif : fusion dans 05_ seulement, d'où des prix différents entre pages, audit 2026-10-15 MAJOR-2 ; 05_ garde un appel idempotent). La fonction renomme puis fusionne par (code, année, type) : n_transactions sommé, prix médian/q25/q75 = moyenne pondérée par n_transactions, estimation_insuffisante recalculé (n < 5). Seuls 4 couples (année, type) des 4 communes renumérotées sont concernés : 49126 Maison 2024 : aucun prix → 2 185 €/m² sur 116 ventes ; 12218 : 6 → 14 ventes ; 14581 : aucun → 6 ; 69114 : 7 → 19. APPROXIMATION : une moyenne pondérée de médianes n'est pas la médiane du territoire réuni (même convention que PLM). Contrôles : 03 vérifie que la somme des ventes est conservée par la fusion ; 99 vérifie que les paires renumérotées (dérivées de la table COG) n'ont plus aucune ligne sous l'ancien code et que le dvf_n_mai publié = celui de l'agrégat.
Alternatives rejetées : garder la ligne du nouveau code seule (perte de ventes) ; sommer les prix (absurde) ; recalculer la médiane exacte (les transactions individuelles ne sont pas conservées par 03_).
[2026-10-15] Decision (mineurs round 3) : (a) Population du Profil : la colonne ctx_log_pop (log10) est écrite avec 8 décimales (au lieu de 3) pour que 10v arrondi redonne l'effectif exact (avec 3 décimales, Paris s'affichait 2 133 045 au lieu de la population légale 2 133 111 ; 8 décimales redonnent l'effectif exact pour 34 869 communes sur 34 875, les 6 autres étant les communes de population nulle, désormais sans valeur « n.d. » au lieu de « 1 hab. » : ctx_log_pop est NA quand la population est 0). (b) Polygones invalides : 01_geo_boundaries.R répare les 20 polygones invalides (sources Etalab 1 000 m, 3 décimales) par st_make_valid sur la grille d'écriture ; 2 communes (Chêne-Sec, Villeneuve-Frouville) étaient réduites à une ligne d'aire nulle et sont reprises de communes-100m. Avant : 20 invalides ; après : 0 ; 34 917 polygones, mêmes codes, aucun doublon ; aire métropolitaine totale +0,001 % ; 18 communes réparées changent d'aire de 0 à 2,1 % (maximum : 52090). (c) Chiffres figés : la note « Lecture » de la Constellation (seuil de 480 hab., 51 %, 6 %, « 7 communes sans population ») est maintenant calculée par build_constellation() avec l'échelle des cercles ; « 1 176 combinaisons » (Explorer, README) devient la valeur calculée C(n, 2) de R/site_numbers.R ; README : 30 scripts. (d) library(purrr) remonté en tête de 05_ (m17). (e) Ordre de dessin : build_web_assets.R trie les polygones par aire décroissante, de sorte qu'une petite commune incluse dans le tracé généralisé d'une voisine (Chêne-Sec 39140 sous Beauvernois 71028) soit dessinée par-dessus, visible et cliquable. (f) 08, cache : le classeur local est retéléchargé si la taille distante (HEAD) diffère de la taille locale ; HEAD en échec = cache conservé. Un onglet dont l'en-tête (ligne 3) ne correspond pas au millésime fait échouer le script (donc la boucle set -e du refresh) : choix assumé, mieux vaut ne rien publier que publier un millésime mal étiqueté. (g) Santé : le changement de définition de apl_medecins_jeunes (62 → 65 ans) est signalé sur la page. (h) Validateur : paires DVF dérivées de la table COG ; contrôle de apl_medecins_jeunes contre le classeur brut (« [ignoré] » sans data/raw).
Non traités : Reconquête/RDG (02_elections.R, autre branche) ; m2, m3 (deux taux d'accidents : choix de dénominateur à arbitrer), m4, m5 (petites communes non masquées), m8, m18-m21 (déploiement, miniatures), R2 n3, décimales mixtes, permaliens élections 75056/13055 (page élections, autre branche).