Files
moteurs/dist/autonomie/noyau/pondere-axes.js
T
JulesandClaude Fable 5.1 69809df5d1 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
2026-09-28 17:06:49 +02:00

92 lines
4.3 KiB
JavaScript

// 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;
}