- OPTIMIZER_DECISION : code générique d'une action d'optimiseur dont le reasonCode est
absent, inconnu ou hors liste blanche ; sans paramètres ni texte (invariant 12).
- PRICE_SLOT (priceCtkWh, o:setpointW) : décision prise sur le prix du créneau, demandée par
l'app (exigence 5). Aucun émetteur interne — le rule-based ne lit pas le prix (§11).
EV_SPOT_MARKET ne convenait pas : il nomme un fournisseur hors du build et ne vaut que
pour une borne.
- DecisionCode::knownCodes() : la liste énumérable du catalogue (« connu » se lit ici).
- DecisionCode::optimizerEmittableCodes() / optimizerMayEmit() : liste blanche E14 —
SURPLUS_SETPOINT, SURPLUS_INSUFFICIENT, BELOW_MIN_POWER, EV_DEADLINE, SG_FORCED,
SG_RECOMMENDED, SG_NORMAL, ECO_FLOOR_GRID, PRICE_SLOT, OPTIMIZER_DECISION. Jamais la
sécurité, les verrous, l'indisponibilité, le plafond, la réserve, la dérogation ni les
états du moteur.
- renderFr : deux branches ; INTERFACE.md : les deux lignes (libellés FR/DE/EN proposés
pour l'app) et l'encadré de la liste blanche.
Rien n'appelle ces fonctions : sans endpoint, aucun effet.
Tests (loadmodel) : anti-dérive — knownCodes() confronté aux constantes de l'EN-TÊTE lu par
le test, chacune avec un rendu autre que « motif inconnu » ; liste blanche ⊂ catalogue et
sans aucun code moteur. Contre-épreuves : constante ajoutée sans entrée, branche SG_NORMAL
retirée → échec.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>