// pin-origine.mjs — génère fixtures/sorties-origine-.json DEPUIS LE CODE // D'ORIGINE (clone astro-pro, src/lib/autonomie), pas depuis ce paquet : c'est // ce qui fait du test de non-régression une vraie épingle. // // Rejouable seulement avec un clone d'astro-pro à la révision d'origine // (master c628cf9 au 2026-09-28) : ASTRO_PRO_DIR=~/dev/astro-pro par défaut. // Usage : node scripts/pin-origine.mjs [AAAA-MM-JJ] import { readFileSync, writeFileSync } from 'node:fs' import { homedir } from 'node:os' import { join } from 'node:path' import { pathToFileURL } from 'node:url' const ASTRO = process.env.ASTRO_PRO_DIR ?? join(homedir(), 'dev', 'astro-pro') const date = process.argv[2] ?? new Date().toISOString().slice(0, 10) const lib = (f) => pathToFileURL(join(ASTRO, 'src', 'lib', 'autonomie', f)).href const { selectionner } = await import(lib('algo.js')) const { configPourAxes } = await import(lib('axes-actifs.js')) const { initConfig } = await import(lib('calibrage.js')) const fx = new URL('../fixtures/', import.meta.url) const lire = (f) => JSON.parse(readFileSync(new URL(f, fx), 'utf8')) const options = lire('options.json') const postes = lire('postes.json') const climat = lire('france_climat.json') const config = lire('algo-config.json') const profils = lire('profils-reference.json') initConfig(config) const AXES = ['eau', 'energie', 'alim'] const resume = (r) => ({ total_eur_ht: r.total_eur_ht, status: r.status, ecart_budget_pct: r.ecart_budget_pct, axes: Object.fromEntries( AXES.map((a) => [ a, { budget_alloue: r.axes[a]?.budget_alloue ?? 0, poids: r.axes[a]?.poids ?? 0, sous_total_eur_ht: r.axes[a]?.sous_total_eur_ht ?? 0, postes: (r.axes[a]?.postes ?? []).map((p) => ({ poste_id: p.poste_id, typologie_choisie: p.typologie_choisie, dimension: p.dimension ? { valeur: p.dimension.valeur, unite: p.dimension.unite } : null, cout_eur_ht: p.cout_eur_ht, force_par_couplage: !!p.force_par_couplage, })), }, ]), ), couplages: r.couplages, }) const sortie = { _commentaire: `Sorties de selectionner() D'ORIGINE (astro-pro src/lib/autonomie, coefficients du code) sur les trois profils de référence, générées le ${date} par scripts/pin-origine.mjs. 'global' = pipeline complet ; 'par_axe' = mode un seul axe actif (configPourAxes) avec le budget que le pipeline global avait alloué à cet axe.`, date, profils: {}, } for (const profil of profils) { const global = selectionner(profil.inputs, options, postes, climat, config, false) const par_axe = {} for (const axe of AXES) { const budget = global.axes[axe]?.budget_alloue ?? 0 const actifs = Object.fromEntries(AXES.map((a) => [a, a === axe])) const r = selectionner({ ...profil.inputs, budget_eur: budget }, options, postes, climat, configPourAxes(config, actifs), false) par_axe[axe] = { budget_axe: budget, ...resume(r) } } sortie.profils[profil.nom] = { inputs: profil.inputs, global: resume(global), par_axe } } const cible = new URL(`sorties-origine-${date}.json`, fx) writeFileSync(cible, JSON.stringify(sortie, null, 2) + '\n', 'utf8') console.log(`écrit : fixtures/sorties-origine-${date}.json`) for (const [nom, p] of Object.entries(sortie.profils)) { console.log(`${nom} : total ${p.global.total_eur_ht} (${p.global.status})`, AXES.map((a) => `${a}=${p.global.axes[a].postes.map((x) => x.typologie_choisie).join('+')}`).join(' | ')) }