ADR-0001 — Langage : Rust
Accepté · 2026-06-14
carbon-fr doit être à la fois un service (API auto-hébergeable, robuste, économe) et une bibliothèque embarquable (le cœur réutilisable hors du service). Le projet vise explicitement un trou de l'écosystème : des wrappers de l'API carbone existent en Python, JS, Rust… côté britannique, mais rien d'équivalent pour la France. Le projet s'inscrit aussi dans la cohérence technique de Kovelt (souveraineté, contrôle, performance).
ADR-0002 — Architecture hexagonale + workspace
Accepté · 2026-06-14
Plusieurs forces propres à ce projet rendent le couplage à l'infrastructure dangereux :
ADR-0003 — Périmètre national+régional & source ODRÉ
Accepté · 2026-06-14
La donnée carbone française est publiée par RTE dans éCO2mix, exposée en open data via ODRÉ :
ADR-0004 — Stockage : PostgreSQL natif (sans extension)
Accepté (partitionnement : mesuré le 2026-09-25, non retenu pour l'instant — seuils de déclenchement fixés, cf. addendum) · 2026-06-14
On stocke une série temporelle au pas quart d'heure, sur le national + 12 régions, avec un historique remontant à 2012/2013 — soit de l'ordre de 5 à 6 millions de lignes (~1 Go). Besoins : servir le temps réel et l'historique, et produire des rollups (horaire/journalier) pour les statistiques et le futur modèle de prévision. Le projet est OSS, souverain, auto-hébergeable, avec un éventuel tier hébergé.
ADR-0005 — Méthodologie carbone
Accepté · 2026-06-14
L'intensité carbone n'est pas un chiffre absolu : elle dépend de choix méthodologiques explicites. Deux projets peuvent annoncer des valeurs très différentes pour le même réseau selon qu'ils :
ADR-0006 — Cycle de vie & révision des données (millésime + upsert)
Accepté · 2026-06-14
Les données éCO2mix ne sont pas figées. RTE les révise dans le temps :
ADR-0007 — Topologie de déploiement (API sur VPS, site statique, sous-domaine Kovelt)
Accepté · 2026-06-14
Le projet comprend deux composants aux besoins d'hébergement radicalement différents :
ADR-0008 — Méthodologie cycle de vie (acv-ademe) & intensité régionale
Accepté · 2026-06-14
ADR-0009 — Modèle de prévision d'intensité (climatology@1)
Accepté · 2026-06-15
La phase 3 ouvre la prévision d'intensité carbone : répondre à « quand, dans les prochaines heures, l'électricité sera-t-elle la moins carbonée ? » (décaler une recharge, un lave-vaisselle, un batch de calcul). L'échafaudage du domaine existe déjà :
ADR-0010 — Méthodologie acv-ademe (cycle de vie + imports, consumption-based)
Accepté (mise en œuvre engagée — domaine pur + endpoints de vérifiabilité livrés ; source d'import ENTSO-E branchée et validée live, ingestion poller + service @2 à la lecture livrés ; cf. § État d'implémentation) · 2026-06-15
Tranche A — domaine pur + vérifiabilité : livrée. Le calcul consumption-based est entièrement spécifié et testé sans IO :
ADR-0011 — Contrat de prévision : ForecastPoint (intervalles) + StatForecaster
Accepté (contrat implémenté ; raffinements de modèle/intervalle restants — cf. État) · 2026-06-15
Contrat livré : type domaine ForecastPoint (expected/lower/upper, ModelVersion, sans vintage, invariant lower ≤ expected ≤ upper garanti à la construction) ; port ForecastModel et greenest_window retypés ; climatology@1 produit des ForecastPoint ; /v1/intensity/forecast expose expected/lower/upper/model ; greenest-window gagne le sélecteur ?estimator=central|prudent.
ADR-0012 — Modèle de prévision ML : GbdtForecaster (tout-Rust) + features météo
Accepté (mise en œuvre engagée — store météo + framework GBDT + bin/train + GbdtForecaster livrés ; mesuré, gbdt@1 ne bat pas climatology@1 → non servi par garde de promotion ; gain ML = itération ouverte) · 2026-06-15
Tranche 1 — store de prévision météo (§5/§6) : livré. Port WeatherForecastSource + adapter carbonfr-adapter-meteo (Open-Meteo, sans clé, FR/EU — vent à 100 m + irradiance, agrégés sur 7 points de métropole). Store WeatherRepository (table weather_forecast) daté (run_at, valid_at) pour l'anti-fuite : on conserve l'historique des run_at afin de n'entraîner/inférer que sur la prévision telle qu'elle était disponible. Le poller l'ingère à chaque cycle. Le crate gbdt (GBDT pur Rust, Apache-2.0, compatible cargo-deny) est confirmé pour la suite. ENTSO-E (prévisions de génération vent/solaire, souveraines mais sous token) reste l'upgrade prévu, derrière le même port.
ADR-0013 — Prévision acv-ademe : prévoir les entrées, puis appliquer le calculateur
Accepté (mise en œuvre engagée — pipeline + baseline climatologique livrés ; ML & day-ahead à venir) · 2026-06-15
Tranche A — pipeline « prévoir les entrées → appliquer le calculateur » + baseline climatologique : livrée. C'est exactement le baseline du §7 (mix saisonnier + imports climatologiques), et la preuve du pipeline §1-2.
ADR-0014 — Usage : primitives carbon-aware + livraison live par SSE
Accepté (mis en œuvre — primitives de scheduling et SSE livrés ; webhooks reportés) · 2026-06-15
Tranche A — primitives de scheduling (§1) : livrée. Fonctions pures du domaine (crates/core/src/domain/schedule.rs), zéro nouveau port, réutilisant le sélecteur central/prudent :
ADR-0015 — Tier hébergé : clés API en couche de bord, anonyme par défaut
Accepté (mise en œuvre engagée — auth par clé + quota livrés ; webhooks débloqués puis livrés par l'ADR-0016 ; métering persistant à venir) · 2026-06-15
Tranche A — clés API + quota au bord, opt-in : livrée. core strictement intact (aucun cas d'usage, aucun type carbone touché — le seul ajout est un port sortant ApiKeyRepository + ses value objects ApiTier/ApiKeyRecord, qui vivent avec le port, pas dans le domaine carbone).
ADR-0016 — Webhooks : notification sortante signée, gardée par l'ownership de clé
Accepté (implémenté — fondation de sécurité, store, livraison, watcher, endpoints) · 2026-06-16
Livré de bout en bout, sécurité d'abord.
ADR-0017 — Endpoint public des échanges transfrontaliers
Accepté (implémenté — GET /v1/exchanges + GET /v1/exchanges/date) · 2026-06-16
Le poller ingère déjà, toutes les 15 min, le contexte d'import transfrontalier (ENTSO-E) : pour chacune des 6 frontières métropolitaines, le flux net signé FR↔voisin et l'intensité carbone (cycle de vie ADEME) du voisin, alignés au pas quart d'heure (ADR-0010, store cross_border_flow). Cette donnée n'alimentait jusqu'ici que le calcul acv-ademe@2 consumption-based, sans être exposée.
ADR-0018 — Dérivation renouvelable : météo → production éolien/solaire
Accepté, engagé (calculateur + backtest + exposition /v1/renewable livrés ; prévision d'intensité météo-pilotée écartée, gate non franchi — cf. addendum) · 2026-06-16
La météo (vent à 100 m, irradiance) est déjà ingérée (ADR-0012) mais n'alimentait qu'un GBDT bout-en-bout météo → intensité qui ne battait pas la climatologie (les arbres n'extrapolent pas). Le levier différenciant — dev-first FR/EU, que personne n'expose — est la couche de dérivation métier : décomposer le problème en un intermédiaire physique explicable, plutôt qu'un modèle opaque.
ADR-0019 — Politique de versionnement (quatre axes découplés)
Accepté, engagé (axe applicatif livré : version de workspace + exposition au démarrage + image Docker taguée sur v*) — amendé par ADR-0030 (2026-09-23, 5ᵉ axe : versions crates.io) · 2026-06-17
carbon-fr n'a pas un versionnement mais plusieurs, qui ne bougent pas au même rythme. Trois étaient déjà décidés implicitement, un manquait :
ADR-0020 — Politique de dépréciation (préavis, en-têtes, fenêtre de retrait)
Accepté · 2026-06-17
carbon-fr est une API publique. Ses consommateurs (SDK, scripts carbon-aware, intégrations tierces) ne peuvent pas être prévenus individuellement : le seul canal fiable est la réponse HTTP elle-même et la documentation. ADR-0019 acte que /v1 et /v2 coexistent en cas de rupture, mais ne dit rien de :
ADR-0021 — Format d'erreur : Problem Details (RFC 9457)
Accepté · 2026-06-17
L'API renvoyait ses erreurs sous une forme maison : {"error": "<code>", "message": "<texte>"} en application/json. C'était cohérent en interne, mais :
ADR-0022 — Observabilité : exposition Prometheus /metrics
Accepté · 2026-06-17
L'API est déployée et publique. On avait les logs (tracing, format JSON en prod) et deux sondes (/health, /health/ready), mais aucune métrique numérique scrutable. Or les questions d'exploitation les plus importantes sont chiffrées :
ADR-0023 — Affichage du prix de l'électricité : décomposition ancrée sur le TRV
Un retour de communauté (forum énergie) a fait émerger une demande récurrente : afficher le « prix réel » de l'électricité en regard de ce que paie le consommateur. La formulation spontanée des utilisateurs (« le coût de production du nucléaire vs le prix sur la facture ») mélange en réalité trois notions distinctes :
ADR-0024 — Couche comparative LCOE (coût de production) : cadre de neutralité
L'ADR-0023 a écarté le LCOE (coût de production par source) comme ancrage du « prix réel de l'énergie », au profit de la composante énergie spot (factuelle). Le LCOE reste néanmoins demandé par la communauté comme comparatif pédagogique : « combien coûte réellement à produire » en regard de « combien se vend l'énergie sur le marché ».
ADR-0025 — Extension au vecteur hydrogène : couche carbon-aware « électrolyseur » et cadres d'éligibilité RFNBO / bas-carbone
Accepté — couche A implémentée (méthodologie détaillée : ADR-0026) · 2026-06-20
Une idée issue de la communauté propose d'étendre carbon-fr aux vecteurs énergétiques alternatifs, l'hydrogène en tête, sur le modèle de la carte interactive production/consommation d'électricité.
ADR-0026 — Méthodologie des overlays d'éligibilité électrolyseur (RFNBO / bas-carbone)
Accepté · 2026-06-20
L'ADR-0025 acte la couche A « électrolyseur » : un overlay d'éligibilité au niveau réseau par créneau, sous deux cadres neutres (rfnbo renouvelable, low-carbon bas-carbone inclusif), au-dessus de la donnée régionale horodatée et de /greenest-window. Il renvoie à un ADR de méthodologie pour figer la paramétrisation. C'est cet ADR.
ADR-0027 — Politique de contribution et verrouillage de branche
Accepté · 2026-06-20
carbon-fr est destiné à s'ouvrir aux contributions externes. Le projet porte des invariants forts qu'une contribution bien intentionnée peut violer sans le savoir :
ADR-0028 — Prévision de la part renouvelable pour l'éligibilité (share-clim@1)
Accepté (GATE de backtest franchi le 2026-07-03 ; GATE de neutralité re-joué et GREEN le 2026-07-03, cf. 0026-revue-neutralite.md §6 — servi) · 2026-07-03
La couche A « électrolyseur » (ADR-0025/0026) sert le pilier renewable-share du cadre rfnbo au nowcast uniquement (décision 9 d'ADR-0026, « D4 ») : au-delà de la dernière observation, la part renouvelable est None → signal Indeterminate. La revue de neutralité du 2026-07-03 a mesuré l'ampleur réelle de cette limite : 100 % des créneaux de l'endpoint prévisionnel sont indéterminés sur ce pilier (constat C4, réfuté comme choix documenté, mais noté « le chantier qui le lèvera est MixForecast »). C'est le chantier H4 de la roadmap hydrogène.
ADR-0029 — Carte « électrolyseurs × carbone live » (couche B-light)
Accepté, implémenté · 2026-07-03
L'ADR-0025 réserve la couche B-light : une page carte « électrolyseurs FR/UE × intensité carbone live », fusion d'une donnée structurelle à cadence lente et de la donnée temps réel de carbon-fr — présentée comme le différenciateur du produit (ni l'Observatoire européen ni h2inframap n'ont la couche carbone temps réel), sans API structurelle à maintenir. Chantier H6 de la roadmap hydrogène.
ADR-0030 — Politique de publication crates.io
Accepté (la fusion de la PR vaut acceptation par Morgan) · 2026-09-23
carbon-fr porte une contradiction non résolue depuis son origine. ADR-0001 (2026-06-14) décide : « Le core est conçu pour être publiable sur crates.io comme bibliothèque indépendante. » ADR-0019 (2026-06-17), en Contexte, affirme l'inverse : « les crates carbonfr-* ne sont pas publiées séparément sur crates.io — le service se distribue en image Docker […]. Les versionner individuellement n'a donc aucun intérêt. » (docs/adr/0019-politique-de-versionnement.md:16), et l'inscrit en Conséquences : « Ne nous engage pas à du SemVer par crate ni à de la publication crates.io […] les crates restent publish = false. » (:47). Cet ADR tranche en faveur d'ADR-0001 et amende ADR-0019 (addendum séparé, même date, symétrique de la mention déjà présente en tête d'ADR-0019 quand un ADR ultérieur en amende un antérieur).
ADR-0031 — Conception du SDK Rust (carbonfr-sdk)
Accepté · 2026-09-23
Le SDK TypeScript @carbon-fr/sdk 0.2.0 (publié le 2026-09-23, npm, Trusted Publishing) couvre 26 des 28 opérations de l'OpenAPI 3.1.0 servi (health/health_ready exclues, infra) — sdk/typescript/src/client.ts:79-493. docs/plan-iterations.md (I3, I6) prévoit un équivalent Rust, carbonfr-sdk, publié sur crates.io après carbonfr-core/carbonfr-eligibility (I5). Aucune ligne de code SDK Rust n'existe : ni crate, ni emplacement dans [workspace] members (Cargo.toml racine, 11 membres, aucun sdk).
ADR-0032 — Génération des types du SDK TypeScript et publication de la doc rustdoc des crates internes
Accepté (la fusion de la PR vaut acceptation par Morgan) — 2 points à confirmer par Morgan, cf. encadrés · 2026-09-25
Itération I7 du plan (docs/plan-iterations.md, §I7) laisse deux questions ouvertes, décisionnelles, sans ligne de code hors docs/ :
ADR-0033 — Index qualitatif d'intensité carbone (index : very-low → very-high)
Accepté le 2026-10-20 — Morgan a retenu la proposition telle quelle (« garde les seuils proposés »), les quatre points de l'encadré ci-dessous compris ; le premier commit d'implémentation n'arrive qu'après cette acceptation (principe 3 du plan I9) ; implémenté le 2026-10-20 (PR #156) · 2026-10-20
Le besoin (PROD-API-1, état des lieux du 2026-09-26) : carbon-fr sert des gCO₂eq/kWh, jamais une lecture qualitative. carbonintensity.org.uk (NESO, Grande-Bretagne) expose depuis 2017 un champ intensity.index à cinq valeurs — very low, low, moderate, high, very high — qui est le champ repris par le grand public, les outils no-code (Home Assistant, Node-RED, IFTTT : « si l'index est very low, lancer la charge ») et les tableaux de bord, parce qu'un libellé se lit sans connaître l'unité ni l'ordre de grandeur. Le plan I9 en fait le premier différenciateur de l'itération, ADR d'abord : des seuils se discutent (neutralité perçue), ils ne se glissent pas dans une PR de code.