Décision de Patrick du 2026-10-17 : un seul vocabulaire. Plan::strategy du rule-based,
GetPlan.strategy et la doc passent de « rule-based » à « rules » (INTERFACE.md, protocole §6).
Les libellés de journal (« repli rule-based ») ne sont pas des valeurs et restent.
Référence decisions régénérée. Preuve AVANT régénération, moteur de e592618 + ce seul
renommage, contre l'ancienne référence : comparateur --strategie (nouvelle option, qui ne tolère
que plan.strategy rule-based → rules) IDENTIQUE HORS STRATÉGIE — 23 792 lignes, 23 728
identiques à l'octet, 64 qui ne diffèrent que par .plan.strategy (décompte indépendant des
chemins JSON : 64 × .plan.strategy "rule-based" → "rules", rien d'autre). 0 rejeu. Le même
build, relu contre la nouvelle référence : IDENTIQUE ; 6 suites vertes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fonctions pures (ni E/S ni horloge, « maintenant » = ctx.timestamp) qui
portent toute la sémantique du plan reçu ; le SocketScheduler les enchaînera.
- valider() : JSON → plan interne ou verdict à code stable. Créneaux à
décalage horaire explicite, ordonnés, sans chevauchement ; loadId connu et
unique ; kind cohérent avec le mécanisme et annoncé dans capabilities.kinds ;
reason non vide ; valeurs dans leur domaine ; validUntil ; créneau courant ;
COUVERTURE Q1 (toute charge disponible nommée). Abstention / expiré /
invalide distingués ; un plan invalide n'est jamais converti en partie.
`force` et champs réservés (annexe F) ignorés et listés.
- motifFiltre() : code hors liste blanche → OPTIMIZER_DECISION sans
paramètres ; sinon seules les clés documentées (optimizerParamKeys, testé
contre le tableau d'INTERFACE.md), valeurs nombre/booléen/code [A-Za-z]+.
Le texte libre reste dans ActionRecue::texte, assaini, jamais dans le motif.
- substituer() : le créneau courant remplace les actions de l'ombre à leur
place ; charges indisponibles → action de l'ombre ; bornes commandées
sorties du proxy (waterfallEvIds) ; budget/draw de l'ombre jamais gardés.
- finaliser() : après dispatch, puissance APPLIQUÉE, niveau unique
« optimizer », financement dérivé de la mesure (surplus puis réseau),
counts cohérents, budget et draw recalculés (Q3, Q4), `clamped`.
LoadAction::clamped ajouté (interne, non publié dans ce lot).
Aucun appelant dans ce commit : le moteur est inchangé.
Tests (loadmodel) : 7 fonctions, dont 31 verdicts data-driven.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>