v0.1.1 : version et dist reconstruit

Patch (AGENTS règle 5 : correction, aucune sortie nouvelle — la quantité d'un
poste passe par `dimension`, qui existait). Étiquette et merge au checkpoint de
la session de pilotage ; montée dans reinnover le même jour (ouvre P1.2b).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tgtn7bJxTLiL2fRCkQMgtR
This commit is contained in:
Jules
2026-10-05 16:39:16 +02:00
co-authored by Claude Fable 5.1
parent 91c755f884
commit 8465bf7204
10 changed files with 213 additions and 40 deletions
+29 -11
View File
@@ -55,22 +55,40 @@ export function finaliseSelection(selection, budget_total, options, postes, inpu
};
let status_final = final_pre.status;
let message_final = final_pre.message;
for (let passe = 0; passe < 2; passe++) {
// Correctif v0.1.1 (SPEC menu §12 n° 2 et 3) : `reajusteBudget` renvoie en
// écho le journal qu'il reçoit ; l'origine le ré-ajoutait à chaque tour (chaque
// FORCE apparaissait deux à quatre fois). Le journal ne s'enrichit que des
// lignes nouvelles de `appliqueCouplages`. La boucle ne se contentait que du
// dépassement : un réajustement qui lâche des accessoires forcés (principal
// retiré ou changé) laissait le total loin sous le budget sans rien recombler.
// Désormais : couplages → dans la bande [−underspend, +overrun] ? fin ;
// sinon réajuste (CAS A ou B) → couplages…, trois tours au plus, et toujours
// une passe couplages en dernier. Si le dernier forçage refranchit le seuil,
// le statut le dit.
const tol_under = (config.tolerances && config.tolerances.budget_underspend_pct) || 15;
const seuil_under = budget_total * (1 - tol_under / 100);
const dans_la_bande = (t) => t <= seuil_over && t >= seuil_under;
const prend = (avec) => {
etat = { axes: avec.axes, couplages_appliques: [...etat.couplages_appliques, ...(avec.couplages_appliques || [])] };
};
for (let passe = 0; passe < 3; passe++) {
// IMPORTANT: appliqueCouplages attend selection = { eau, energie, alim } directement
const avec = appliqueCouplages(etat.axes, options, postes, reglages, false);
etat = {
axes: avec.axes,
couplages_appliques: [...etat.couplages_appliques, ...(avec.couplages_appliques || [])],
};
if (sommeAxes(etat.axes) <= seuil_over)
prend(appliqueCouplages(etat.axes, options, postes, reglages, false));
if (dans_la_bande(sommeAxes(etat.axes)))
break;
const re = reajusteBudget(etat, budget_total, options, postes, inputs, contexte, reglages, false);
etat = {
axes: re.axes,
couplages_appliques: [...etat.couplages_appliques, ...(re.couplages_appliques || [])],
};
etat = { axes: re.axes, couplages_appliques: etat.couplages_appliques };
status_final = re.status;
message_final = re.message;
// Bloqué (rien à ajouter, ou plancher atteint) ou dernier tour : une passe couplages et fin
if (passe === 2 || re.status !== 'OK') {
prend(appliqueCouplages(etat.axes, options, postes, reglages, false));
break;
}
}
if (sommeAxes(etat.axes) > seuil_over && status_final === 'OK') {
status_final = 'BUDGET_INSUFFISANT';
message_final = 'Budget insuffisant : les couplages requis portent le total à ' + sommeAxes(etat.axes) + ' EUR pour un budget de ' + Math.round(budget_total) + ' EUR.';
}
return {
axes: etat.axes,