core/ strictement ERP-agnostique
Contexte
Le sous-package electricore/core/ a été pensé dès le départ comme couche métier portant les calculs énergie purs (périmètre, abonnements, énergie, TURPE, accise, facturation Enedis). En pratique, cette intention a glissé : electricore/core/loaders/odoo/ et electricore/core/writers/odoo.py (depuis migrés vers integrations/odoo/) ont été introduits parce qu'au démarrage seule l'instance EDN existait, et Odoo était le seul ERP en jeu. Aucun ADR n'avait inscrit la règle, donc le code l'a discrètement érodée.
Le coût de cette dérive devient lisible maintenant que l'instance Enargia (cf. ADR-0015) consomme core/ depuis des notebooks hébergés hors de ce dépôt pour ses propres calculs métier — sans Odoo direct. Côté EDN, les orchestrations qui rapprochent Enedis et Odoo (cf. ADR-0014, ADR-0013) sont par nature instance-spécifiques mais elles vivent aujourd'hui à côté des pipelines purs, ce qui brouille le contrat.
Décision
core/ ne dépend que de Polars, DuckDB, Pandera, et de la stdlib Python. Aucune dépendance d'intégration ERP (Odoo, Haulogy, autre) ne traverse son interface ni ses imports.
Concrètement :
- Nouveau sous-package electricore/integrations/ qui accueille les adaptateurs vers les ERP et systèmes externes. Premier occupant :
integrations/odoo/. core/loaders/odoo/→integrations/odoo/loaders/(les query buildersOdooReader,OdooQueryet leurs helpers).core/writers/odoo.py→integrations/odoo/writers.py.- Les orchestrations qui composent du métier core et de l'ERP (par ex.
facturation_du_mois,accise_du_trimestre, le rapprochementrapprocher_facturation_mensuelle) vivent dansintegrations/odoo/— elles sont EDN-shaped aujourd'hui et serviront de prototype pour un futur module Odoo libre. - Les modèles Pandera qui décrivent des objets Odoo (
core/models/odoo/) suivent dansintegrations/odoo/models/. - Test d'imports en CI :
tests/architecture/test_core_purity.pyparse tous les fichierselectricore/core/**/*.pyet échoue si l'un d'eux importeelectricore.integrations,electricore.api,electricore.bot, ou une lib ERP (odoorpc, etc.). C'est la garantie exécutable que le contrat ne se ré-érode pas silencieusement.
api/services/ se réduit au binding HTTP + à la sérialisation (XLSX/Arrow/ZIP, factorisée). Les services importent désormais à la fois core/ et integrations/odoo/, et c'est attendu — l'API est le hub (cf. ADR-0009).
Raison
Trois facteurs cumulés :
- Le seam est earning its keep aujourd'hui. Enargia est un consommateur réel de
core/qui n'a pas Odoo dans la boucle. Garder Odoo danscore/rend le module impossible à utiliser pour ce cas — ce n'est plus une pureté esthétique, c'est un blocage. - L'horizon ERP libre. Le projet vise à émerger comme support des fournisseurs alternatifs/anticapitalistes, avec un futur module Odoo couplé à ElectriCore. La règle «
core/= énergie pure,integrations/<erp>/= colle métier » trace dès maintenant l'arborescence dans laquelle ce module pourra atterrir sans refactor. - Le test d'imports rend la règle exécutable. Une convention écrite seule dans CONTEXT.md se contourne sous pression. Un test CI qui échoue est lisible par tout futur contributeur — humain ou agent.
Alternatives écartées :
- Acter qu'Odoo est in-core, écrire l'ADR «
core/est Odoo-aware ». Rapide, mais ferme la porte à Enargia et à l'évolution multi-instance. Le coût de la migration aujourd'hui (~30 fichiers, imports à mettre à jour) est inférieur au coût futur de refactor sous contrainte de production. - Introduire un seam ERP générique (
ERPAdapterinterface, Odoo et Haulogy comme adaptateurs). Hypothétique aujourd'hui : Haulogy est lui-même basé sur Odoo et le second consommateur ERP n'est pas en prod ici. Un adapter = seam hypothétique — on attend qu'il devienne réel pour le nommer.
Conséquences
- ADRs à mettre à jour :
- ADR-0007 (query builders) —
OdooQueryn'est plus encore/mais enintegrations/odoo/. Reformuler la note d'uniformité d'API (un caller à chevalcore/integrationsreste légitime via l'API ou via les services). - ADR-0009 (API-centrique) — la phrase « DuckDB, les pipelines Polars et
OdooReader/Writersont des composants internes consommés via l'API » devient « DuckDB et les pipelines Polars (core) + les adaptateurs (integrations) sont consommés via l'API ». - ADR-0012 (API read-only Odoo) — chemins d'import à mettre à jour, principe inchangé.
-
ADR-0013 (renommage Périmètre → Historique) — pas d'impact structurel, mention résiduelle d'Odoo à reformuler si présente.
-
CONTEXT-MAP.md : ajouter
electricore/integrations/comme contexte au même titre quecore,etl,api,bot. Glossaire dédiéintegrations/odoo/CONTEXT.mdaccueillant les termes Odoo-spécifiques (sale.order, account.move, x_invoicing_state, RSC côté écriture). Le glossairecore/CONTEXT.mdgarde les concepts métier neutres (Historique, Périmètre, Abonnement, RSC en tant que concept Enedis) ; les sections « Intégration Odoo » et « Rapprochement PDL ↔ RSC » migrent versintegrations/odoo/CONTEXT.md. -
Documentation : README, CLAUDE.md,
docs/odoo-query-builder.md— mise à jour des imports et de l'arborescence. -
Notebooks : les imports
from electricore.core.loaders import OdooReader, OdooQuery, ...deviennentfrom electricore.integrations.odoo import OdooReader, OdooQuery, .... Aucun changement de signature.
Limites à connaître avant un changement d'échelle
- Pas de seam ERP-générique aujourd'hui. Si une seconde intégration ERP (Haulogy ou autre) entre en prod, on aura deux adaptateurs réels — c'est alors le moment de nommer le seam (interface
ERPAdapterou équivalent). Tant qu'on en a un seul, la duplication éventuelle entreintegrations/odoo/et un futurintegrations/<x>/reste préférable à une abstraction prématurée. - Le bot Telegram reste Odoo-couplé. Plusieurs commandes du bot (
/check odoo, exports facturation/taxes) supposent un ERP Odoo configuré. Avant de poser un seam ERP, étape intermédiaire à prévoir : rendre le bot fonctionnel sur une instance sans ERP connecté, au minimum pour les commandes ETL et exports flux Enedis. Issue à ouvrir après les PR de migration. - La règle ne couvre pas
etl/. Le sous-package ETL ingère les flux Enedis (XML/CSV via SFTP, déchiffrement AES) et reste non-Enedis-agnostique — c'est sa raison d'être. Le contrat « pas d'ERP » s'applique uniquement àcore/.