// adequation.ts — adequation_contexte(typo, inputs, poste, contexte_derived) → [0..1] // Spec: V2-algo-spec-FONCTIONS.md §1 — origine calculs/src/lib/autonomie/adequation.js. // Correction LOT P1.0 : `reglages` en paramètre (plus de getConfig()) ; le // console.warn de debug devient un champ `avertissement` du retour debug. import { clamp01 } from './calibrage.js' import { score_pluviometrie, score_climat_chauffage, score_climat_meridional, score_taille_foyer, score_surface_toit, score_orientation_toit, score_surface_parcelle, score_temps_dispo, score_metres_haie, score_couplage_disponible, } from './scoreurs.js' import type { Autodiag, Contexte, Option, Poste, Reglages } from './types.js' type Scoreur = (typo: Option, inputs: Autodiag, contexte: Contexte, poste: Poste, sel: string[], reglages: Reglages) => number // Catalogue de dispatch des scoreurs par nom de critère const SCOREURS: Record = { pluviometrie: score_pluviometrie, climat_chauffage: score_climat_chauffage, climat_meridional: score_climat_meridional, taille_foyer: score_taille_foyer, surface_toit: score_surface_toit, orientation_toit: score_orientation_toit, surface_parcelle: score_surface_parcelle, temps_dispo: score_temps_dispo, metres_haie_possibles: score_metres_haie, couplage_disponible: score_couplage_disponible, } export interface AdequationDebug { score: number scoreurs: Record avertissement?: string } /** * Calcule le score d'adéquation contextuelle d'une typologie [0..1]. * * @param typologies_selectionnees — sélections déjà faites (pour score_couplage_disponible) * @returns score ∈ [0..1] ; en debug, { score, scoreurs } */ export function adequation_contexte(typo: Option, inputs: Autodiag, poste: Poste, contexte_derived: Contexte, reglages: Reglages, typologies_selectionnees?: string[], debug?: false): number export function adequation_contexte(typo: Option, inputs: Autodiag, poste: Poste, contexte_derived: Contexte, reglages: Reglages, typologies_selectionnees: string[], debug: true): AdequationDebug export function adequation_contexte( typo: Option, inputs: Autodiag, poste: Poste, contexte_derived: Contexte, reglages: Reglages, typologies_selectionnees: string[] = [], debug = false, ): number | AdequationDebug { const matrix = reglages.config.adequation_weights?.[poste.code] if (!matrix) { if (debug) return { score: 0.5, scoreurs: {}, avertissement: `[adequation_contexte] Pas de matrice pour poste "${poste.code}" — fallback 0.5` } return 0.5 } let weighted_sum = 0 let total_weight = 0 const debug_scores: Record = {} for (const [critere, poids] of Object.entries(matrix)) { if (poids === 0 || !SCOREURS[critere]) continue const scoreur = SCOREURS[critere] let s: number if (critere === 'couplage_disponible') { s = scoreur(typo, inputs, contexte_derived, poste, typologies_selectionnees, reglages) } else { s = scoreur(typo, inputs, contexte_derived, poste, [], reglages) } weighted_sum += s * poids total_weight += poids if (debug) debug_scores[critere] = { score: +s.toFixed(3), poids } } let score = total_weight > 0 ? weighted_sum / total_weight : 0.5 // §1.4 Bonus / malus globaux if (typo.flag_diy && inputs.temps_dispo === 3) score *= 1.3 if (typo.complexite_pose === 3 && inputs.temps_dispo === 1) score *= 0.5 if (!typo.accessible_fr) score *= 0.6 score = clamp01(score) if (debug) { return { score, scoreurs: debug_scores } } return score }