// pondere-axes.ts — Étape 1 : pondération des axes selon contexte // Spec: V2-algo-spec.md §Étape 1 — origine calculs/src/lib/autonomie/pondere-axes.js. // Correction LOT P1.0 : `config` en paramètre (plus de getConfig()). export function pondereAxes(inputs, contexte_derived, config, debug = false) { const base = config.poids_axes_base ?? { eau: 40, energie: 40, alim: 20 }; const mod = (config.modulateurs ?? {}); const poids = { eau: base.eau, energie: base.energie, alim: base.alim }; const log = debug ? [] : null; // SI surface_toit < seuil → poids_energie -= 15, redistribuer eau+5 alim+10 const toit_seuil = mod.toit_petit_seuil_m2 ?? 30; if ((inputs.surface_toit_m2 ?? 0) < toit_seuil) { const delta = mod.toit_petit_delta ?? { energie: -15, eau: 5, alim: 10 }; poids.energie += delta.energie ?? 0; poids.eau += delta.eau ?? 0; poids.alim += delta.alim ?? 0; if (log) log.push(`toit < ${toit_seuil}m² → Δenergie${delta.energie}, Δeau+${delta.eau}, Δalim+${delta.alim}`); } // SI surface_toit > 100 m² → poids_energie += 5 if ((inputs.surface_toit_m2 ?? 0) > 100) { poids.energie += 5; if (log) log.push('toit > 100m² → Δenergie+5'); } // SI nb_personnes >= 5 → poids_eau += 10, poids_alim += 5, poids_energie -= 15 const famille_seuil = mod.famille_grande_seuil ?? 5; if ((inputs.nb_personnes ?? 0) >= famille_seuil) { const delta = mod.famille_grande_delta ?? { eau: 10, alim: 5, energie: -15 }; poids.eau += delta.eau ?? 0; poids.alim += delta.alim ?? 0; poids.energie += delta.energie ?? 0; if (log) log.push(`nb_pers >= ${famille_seuil} → Δeau+${delta.eau}, Δalim+${delta.alim}, Δenergie${delta.energie}`); } // SI zone_biogeo == 'MED' → poids_eau += 10 if (contexte_derived.zone_biogeo === 'MED') { const delta = mod.biogeo_med_delta ?? { eau: 10 }; poids.eau += delta.eau ?? 0; if (log) log.push(`zone MED → Δeau+${delta.eau}`); } // SI pluviometrie_mm < 600 → poids_eau += 5 const pluvio_seuil = mod.pluvio_basse_seuil_mm ?? 600; if ((contexte_derived.pluviometrie_mm ?? 800) < pluvio_seuil) { const delta = mod.pluvio_basse_delta ?? { eau: 5 }; poids.eau += delta.eau ?? 0; if (log) log.push(`pluvio < ${pluvio_seuil}mm → Δeau+${delta.eau}`); } // SI surface_parcelle < 300 m² → poids_alim = 0 const parcelle_petite = mod.parcelle_petite_seuil_m2 ?? 300; if ((inputs.surface_parcelle_m2 ?? 0) < parcelle_petite) { poids.alim = 0; if (log) log.push(`parcelle < ${parcelle_petite}m² → alim=0`); } // SI surface_parcelle >= 1000 m² ET temps_dispo == 3 → poids_alim += 10 const parcelle_grande = mod.parcelle_grande_seuil_m2 ?? 1000; if ((inputs.surface_parcelle_m2 ?? 0) >= parcelle_grande && inputs.temps_dispo === 3) { const delta = mod.parcelle_grande_temps3_delta ?? { alim: 10 }; poids.alim += delta.alim ?? 0; if (log) log.push(`parcelle >= ${parcelle_grande}m² + temps=3 → Δalim+${delta.alim}`); } // Axes explicitement désactivés par l'utilisateur (V3 toggles d'axes) : // marqueur posé par axes-actifs.ts (configPourAxes). Les modulations // hardcodées ci-dessus (ex : toit > 100 m² -> energie +5) ne doivent pas // réactiver un axe éteint. Absent = comportement historique inchangé. const desactives = config._axes_desactives || []; for (const axe of desactives) { if (axe in poids && poids[axe] !== 0) { poids[axe] = 0; if (log) log.push('axe ' + axe + ' désactivé (toggle UI) -> poids 0'); } } // Normalisation : somme = 100 const total = poids.eau + poids.energie + poids.alim; if (total !== 100 && total > 0) { poids.eau = Math.round((poids.eau / total) * 100); poids.energie = Math.round((poids.energie / total) * 100); poids.alim = 100 - poids.eau - poids.energie; // garantie somme exacte } // Garde-fou : pas de poids négatif poids.eau = Math.max(0, poids.eau); poids.energie = Math.max(0, poids.energie); poids.alim = Math.max(0, poids.alim); if (debug) return { poids, log: log ?? [] }; return poids; }