Files
moteurs/src/autonomie/noyau/adequation.ts
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

99 lines
3.6 KiB
TypeScript

// 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<string, Scoreur> = {
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<string, { score: number; poids: number }>
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<string, { score: number; poids: number }> = {}
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
}