LOT P1.0 : paquet @transformer/moteurs v0.1.0

Extraction du cœur autonomie de calculs.trans-former.fr (12 modules, sans
singleton, couplages sans mutation, console derrière debug), découpage en trois
moteurs d'axe + intégrateur (mode global = calculs, mode par_axe = plateforme),
moteurs commun.contexte (Corse 2A/2B, DOM 97x corrigés) et commun.geometrie,
table des coefficients harmonisés (docs/CONSTANTES.md pour Jules, R-7),
validation structurelle des données (schemas/), tests hors ligne : 28 assertions
d'origine + épingle générée depuis le code d'astro-pro + écarts d'harmonisation
figés + contrat des moteurs. dist/ committé.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019UBHYPdeQYy2m1GVJp6b12
This commit is contained in:
Jules
2026-09-28 17:06:49 +02:00
co-authored by Claude Fable 5.1
commit 69809df5d1
123 changed files with 13225 additions and 0 deletions
+160
View File
@@ -0,0 +1,160 @@
// coefficients.ts — chaque grandeur physique UNE fois, avec source et date.
//
// Règle : le document de recherche l'emporte sur le code quand ils divergent
// (SPEC phase 1 §4.1, LOT P1.0 point 5). La table lisible par Jules est
// docs/CONSTANTES.md (une ligne par grandeur : ancienne(s) valeur(s) →
// retenue, source, date). Le jeu de coefficients d'ORIGINE (valeurs du code
// de calculs.trans-former.fr au 28/09/2026) vit dans
// fixtures/coefficients-2026-05.json et sert au test de non-régression.
//
// Les poids d'axes, modulateurs, matrices d'adéquation et tolérances de
// algo-config.json ne sont PAS ici : ce sont des heuristiques de conception,
// non sourcées, livrées comme données (fixtures/algo-config.json) et injectées.
const D_RECHERCHE = '2026-04-28';
const D_LOT = '2026-09-28';
const S_EAU = '1 PROJETS/DEV/Simulateur autonomie V2/01-recherche-eau.md';
const S_ENERGIE = '1 PROJETS/DEV/Simulateur autonomie V2/02-recherche-energie.md';
const S_BRIEF = '1 PROJETS/DEV/Simulateur autonomie V2/99-brief-atis-dev.md';
const S_V1 = 'calculs.trans-former.fr, simulateur autoconstruction V1 (public/simulateurs/autoconstruction/app.js, calcSurfaces)';
/** Table harmonisée (LOT P1.0, 28/09/2026). Référence tant que Jules ne met pas de veto (R-7). */
export const COEFFICIENTS = {
captage_rendement: {
valeur: 0.8,
source: `${S_EAU} §3 « Captable max » et §7 n°6 (NF EN 16941-1, recueil Nény p.16)`,
date: D_RECHERCHE,
note: 'fourchette 0,75 (zone sèche) à 0,85 (zone humide, gouttières optimisées) ; le code portait 0,7 (scoreurs), 0,8 (taux) et 0,85 (V1 bioclimatique)',
},
captage_rendement_par_toiture: {
valeur: { tuile: 0.85, ardoise: 0.85, gravillonnee: 0.5, vegetalisee: 0.3 },
source: `${S_EAU} §7 n°6 (ADEME, réf. NF EN 16941-1)`,
date: D_RECHERCHE,
note: 'à brancher quand le formulaire demande le type de toiture ; non utilisé en v0.1',
},
besoin_eau_l_j_pers: {
valeur: 150,
source: `${S_EAU} §3 « Besoin eau » (INSEE / Eau France 2024) ; ${S_BRIEF} §7.1`,
date: D_RECHERCHE,
note: '54 750 L/an/personne ; le V1 comptait 46,5 m³/an',
},
part_eau_substituable: {
valeur: 0.7,
source: `${S_EAU} §3 ; ${S_BRIEF} §7.1 (WC 30 + douche 60 + lessive 30 + jardin 25 L/j sur 150)`,
date: D_RECHERCHE,
note: 'le V1 comptait 32 % (15 m³ sur 46,5)',
},
orientation_pv: {
valeur: { sud: 1, 'sud-est': 0.95, 'sud-ouest': 0.95, est: 0.8, ouest: 0.8, nord: 0.6 },
source: `${S_ENERGIE} §3.2 « Variantes orientation toiture »`,
date: D_RECHERCHE,
note: 'source : SE/SO 95 %, E/O 80-85 %, N 60-65 % (bas de fourchette retenu) ; le brief §7.2 prenait les milieux 0,82 et 0,62 ; le code portait 0,93 / 0,78 / 0,40',
},
productible_pv_kwh_kwc: {
valeur: {
par: 'zone_rt',
table: { H1a: 1000, H1b: 1050, H1c: 1200, H2a: 1100, H2b: 1200, H2c: 1250, H2d: 1300, H3: 1400 },
defaut: 1100,
},
source: `${S_ENERGIE} §3.2 (PVGIS, sud 30°, pertes 14 %)`,
date: D_RECHERCHE,
note: 'H1a : moyenne Lille 950 / Paris 1 050 ; H2d : interpolé entre H2c et H3 par la MOE, non sourcé (déclaré en avertissement) ; défaut = H2a ; le code portait une table par zone biogéographique allant jusqu\'à 1 550, au-dessus du maximum de la source',
},
autoconso_sans_batterie: {
valeur: 0.3,
source: `${S_ENERGIE} §3.2 ; ${S_BRIEF} §7.2`,
date: D_RECHERCHE,
note: 'absent du code : la couverture énergie comparait la production brute au besoin',
},
autoconso_avec_batterie_10kwh: {
valeur: 0.7,
source: `${S_ENERGIE} §3.2 ; ${S_BRIEF} §7.2`,
date: D_RECHERCHE,
note: 'entre 0 et 10 kWh de batterie, le moteur interpole linéairement (choix MOE, non sourcé)',
},
besoin_elec_kwh_pers_an: {
valeur: 1000,
source: `${S_ENERGIE} §3.1 (ADEME 2023, RTE 2024) ; ${S_BRIEF} §7.2`,
date: D_RECHERCHE,
note: 'fourchette 900 à 1 200 ; hors chauffage électrique, ECS et véhicule',
},
dju_defaut_par_classe_rt: {
valeur: { H1: 2800, H2: 2200, H3: 1500 },
source: 'heuristique de conception V2 (calibrage.js et algo-config.json), non sourcée',
date: '2026-05-01',
note: 'repli seulement : la table france_climat porte un DJU par département',
},
ml_haie_par_pers: {
valeur: 25,
source: `${S_BRIEF} §7.3 (correction Jules du 28/04/2026) ; 03-recherche-alimentation.md §5`,
date: D_RECHERCHE,
note: '50 ml/personne pour un excédent transformable',
},
contexte_defaut: {
valeur: { zone_rt: 'H2a', zone_biogeo_code: 4, pluviometrie_mm: 800, dju: 2200 },
source: 'heuristique de conception V2 (algo.js deriveContexte, simulation.js), non sourcée',
date: '2026-05-01',
note: 'appliqué seulement si le département est absent de france_climat ; toujours déclaré en avertissement',
},
geometrie_ratio_shab_emprise: {
valeur: 0.8,
source: 'heuristique MOE (murs extérieurs ~0,3 m, refends, escalier), non sourcée',
date: D_LOT,
note: 'hypothèse porteuse du P1.2 : à confronter à la surface DPE des adresses A et B (écart visé < 20 %)',
},
geometrie_ratio_vitrage_shab: {
valeur: 1 / 6,
source: `${S_V1} (vit = S/6) ; règle RT 2012 (baies ≥ 1/6 de la SHAB)`,
date: '2025-01-01',
note: 'la SPEC §4.1 écrit « 15 % » ; 1/6 = 16,7 %',
},
geometrie_hauteur_etage_m: {
valeur: 2.5,
source: 'heuristique MOE (hauteur sous plafond courante), non sourcée',
date: D_LOT,
},
geometrie_facteur_perimetre: {
valeur: 1.3,
source: `${S_V1} (perimetre = √(S × 1,3) × 4)`,
date: '2025-01-01',
},
geometrie_part_mur_mitoyen: {
valeur: 0.25,
source: 'heuristique MOE (un côté mitoyen = un quart du périmètre), non sourcée',
date: D_LOT,
},
geometrie_majoration_toiture: {
valeur: 1.05,
source: `${S_V1} (toiture = S / cos α × 1,05)`,
date: '2025-01-01',
},
geometrie_pente_defaut_deg: {
valeur: 30,
source: 'heuristique MOE (pente courante des toitures à deux versants), non sourcée',
date: D_LOT,
},
};
/** Clés de la table, pour valider un jeu de coefficients injecté (fixture, veto). */
export const CLES_COEFFICIENTS = Object.keys(COEFFICIENTS);
/**
* Vérifie qu'un objet a la forme d'une table de coefficients (toutes les clés,
* chaque entrée avec valeur, source et date). Renvoie la liste des défauts.
*/
export function verifieTableCoefficients(table) {
const erreurs = [];
if (!table || typeof table !== 'object')
return ['table absente ou non objet'];
const t = table;
for (const cle of CLES_COEFFICIENTS) {
const c = t[cle];
if (!c || typeof c !== 'object') {
erreurs.push(`${cle} : absent`);
continue;
}
if (!('valeur' in c))
erreurs.push(`${cle} : valeur absente`);
if (typeof c.source !== 'string' || !c.source)
erreurs.push(`${cle} : source absente`);
if (typeof c.date !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(c.date))
erreurs.push(`${cle} : date absente ou non AAAA-MM-JJ`);
}
return erreurs;
}