Déploiement vérifié SUR MACHINE et non déduit du script : version relue, nymead actif, arbitre initialisé, et les quatre motifs du §10 présents dans le binaire posé. Piège de vérification noté au passage : authorisedW, perPhaseBound et binding sont des QStringLiteral, donc stockés en UTF-16 et invisibles à `strings` par défaut. Un premier relevé les donnait absents — j'ai failli les rapporter manquants. `strings -el` les trouve. Vérifier une chaîne dans un binaire demande de savoir comment elle y est encodée. Et le design du premier constat de l'app, ouvert plutôt qu'attaqué au code. Trois choses qu'il établit, toutes mesurées : Le titre est trop étroit. « Réappliquer la commande de l'arbitre » ne décrit pas le cas : en mode manuel l'arbitre NE COMMANDE PAS. Ce qui s'est passé est qu'une écriture du proxy a échoué pendant l'indisponibilité, que personne ne l'a rejouée, et que l'organe est resté sur une consigne dont plus aucun commandeur ne se réclame. La pièce qui manque est là où le constat porte : l'EvAdapter ne garde PAS sa dernière consigne, là où les adaptateurs en watts la gardent. Ils en ont besoin pour l'écrêtage de verrou ; la borne était pilotée par le proxy, qui n'a jamais eu à se relire. Le vrai coût n'est pas l'affichage. draw.committedW à 0 pendant que 4,4 kW sont tirés veut dire que le budget de surplus est calculé sans ces watts : le moteur alloue de l'énergie qui n'existe pas. Le délestage, lui, protège — il agit sur la marge MESURÉE, qui les inclut. C'est le budget qui ment. Quatre décisions posées, dont la principale : signaler toujours, réappliquer jamais telle quelle. Rejouer une consigne vieille de plusieurs minutes, c'est décider avec des données mortes — ce que le mode dégradé L2 refuse déjà de faire. Ce qui manque n'est pas le rejeu, c'est que l'écart soit DIT tant qu'il dure, et il dure indéfiniment quand personne ne reprend la main. Ordre de travail : mémoire de la commande, puis écart publié sans décider dessus, puis comptabilité corrigée, et la reprise en main EN DERNIER — c'est la seule étape qui commande du matériel, et on saura alors combien de fois le cas se produit vraiment. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015F7G5VeaPVSMeVNjiGj36p
6.3 KiB
DESIGN — la commande perdue, et l'écart que personne ne mesure
(Ouvert le 2026-09-01, sur le premier constat de RELEVE_APP_20260831.md. Le design avant le
code, comme pour le délestage et le §10.)
1. Le fait, tel qu'il a été mesuré
Coupure Modbus. La box journalise Restoring manual values of false 6 A trois secondes après.
La borne, elle, reste à power: true, 7 A — la consigne que l'arbitre lui avait donnée au
cycle d'avant. Le lien revient : rien ne réapplique. En mode manuel personne ne commande,
donc l'écart est permanent.
4,4 kW réellement tirés, draw.committedW à 0, un budget de surplus de 2 349 W qui ignore ces
watts.
2. Ce que le fait dit vraiment — et il est plus large que son titre
« Réappliquer la commande de l'arbitre » ne décrit pas le cas : en mode manuel, l'arbitre ne commande pas. Ce qui s'est passé est autre chose, et c'est pire :
- Le proxy amont a voulu restaurer des valeurs manuelles (
false 6 A) ; - l'écriture a échoué pendant l'indisponibilité ;
- personne ne l'a rejouée ;
- l'organe est resté sur une consigne dont plus aucun commandeur ne se réclame — ni l'arbitre, qui ne commande plus, ni le mode manuel, dont la consigne n'a pas atterri.
La troisième forme de la même famille. Après la télémétrie qui ne distinguait pas une issue de son contraire (
ECS-111) et la valeur de retour qui faisait passer un refus pour un succès (ECS-415), voici l'exécution : une écriture perdue, un état sain en apparence,availableà vrai, et personne pour savoir que la commande n'a jamais atterri.
3. Ce que le moteur a déjà — et ce qui manque
| Pièce | État |
|---|---|
| Dernière consigne écrite, charges en watts | existe — m_currentSetpointW, m_currentStage |
| Dernière consigne écrite, bornes VE | MANQUE — EvAdapter ne garde que m_lastActionAt |
| Ce que l'organe FAIT | existe — EvCharger::maxChargingCurrent(), états du Thing |
| Ce que l'organe MESURE, et ce que ça vaut | existe — deviceMeasurement(), measurement.source (LM-1105/LM-1106) |
| Détection de la FIN d'une indisponibilité | MANQUE — le seul chemin est clearFault(), actionné par l'opérateur |
| Comparaison commandé / constaté | MANQUE — nulle part |
Le constat porte sur les bornes, et c'est précisément là que la mémoire de la commande manque. Ce n'est pas un hasard : les adaptateurs de charges en watts gardent leur consigne parce qu'ils en ont besoin pour l'écrêtage de verrou ; la borne, elle, était pilotée par le proxy amont, qui n'a jamais eu à se relire.
4. LES DÉCISIONS
4.1 — Réappliquer, ou signaler ? Réappliquer automatiquement une consigne vieille de plusieurs minutes est un geste dangereux : le monde a changé pendant l'indisponibilité — le surplus, l'heure, l'échéance. Rejouer une décision périmée, c'est décider avec des données mortes, exactement ce que le mode dégradé L2 refuse de faire.
Recommandation : SIGNALER toujours, RÉAPPLIQUER jamais telle quelle. Au retour de disponibilité, le cycle normal reprend la main et décide sur des données fraîches — c'est déjà le bon comportement. Ce qui manque n'est pas le rejeu, c'est que l'écart soit dit tant qu'il dure. Et il dure indéfiniment quand personne ne reprend la main, ce qui est le cas du relevé.
4.2 — Que publie-t-on, et sous quelle forme ?
Un écart n'a de sens que rapporté à ce qu'on sait de l'organe. Proposition : un objet command
au niveau de la charge, publié seulement quand la comparaison est possible —
"command": { "expectedW": 1380, "observedW": 4400, "divergent": true, "since": "…" }
measurement.source conditionne ce que vaut cette comparaison, et doit donc la gouverner :
contre none, il n'y a rien à comparer et l'objet est absent — pas divergent: false, qui
affirmerait la concordance qu'on ne peut pas constater. Même règle que partout ailleurs ici.
4.3 — Et la COMPTABILITÉ, qui est le vrai coût.
draw.committedW à 0 pendant que 4,4 kW sont tirés n'est pas un défaut d'affichage : le budget
de surplus est calculé sans ces watts, donc le moteur alloue de l'énergie qui n'existe pas.
Une charge que l'arbitre ne commande plus mais qui consomme est de la consommation fixe, au
même titre que la base de la maison — c'est exactement le raisonnement d'ECS-410 pour une
charge gelée, appliqué à une cause nouvelle.
Recommandation : la retrancher du budget, sans l'allouer. Elle n'est pas servie, elle est subie. La compter comme allouée serait prétendre l'avoir décidée.
Sur 18 kVA c'est invisible ; sur 6 kVA c'est le disjoncteur. Et le délestage ne rattrape pas ce cas : il agit sur la marge MESURÉE, qui inclut bien ces 4,4 kW — donc il protège. Ce qui reste faux est le budget, qui promet un surplus déjà consommé.
4.4 — Faut-il un état « commande en vol perdue » distinct d'un défaut ?
ECS-410/ECS-414 couvrent l'écriture qui échoue trois fois → défaut. Ici l'écriture a échoué
pendant une indisponibilité, et la charge est ensuite redevenue disponible : le défaut se
lève, la divergence reste. À trancher : est-ce un faultCode de plus, ou un état orthogonal ?
5. ORDRE DE TRAVAIL — deux étapes à comportement constant d'abord
Étape 1 — la MÉMOIRE de la commande, sans rien en faire. EvAdapter retient sa dernière
consigne appliquée, comme les autres adaptateurs le font déjà. Publication seule, comportement
constant. Sans cette pièce, aucune des suivantes n'est calculable.
Étape 2 — l'ÉCART publié, sans décider dessus. L'objet command, gouverné par
measurement.source. C'est la moitié qui rend le défaut visible, et elle ne change aucune
décision — même stratégie qu'à l'étape C du §10, où publier le régime a précédé de décider avec.
Étape 3 — la COMPTABILITÉ corrigée. La conso subie sort du budget. C'est ici que le comportement change, et c'est la seule étape qui le fasse.
Étape 4 — la reprise en main, si elle est jugée nécessaire après avoir vu les traces des étapes 2 et 3. Délibérément en dernier : c'est la seule qui commande du matériel, et on saura alors combien de fois le cas se produit réellement.