docs(spec §11): la mesure d'une charge se lit sur l'appareil, et dit sa source
Constat d'usage de l'agent app, retenu : pour afficher « mesuré » à côté de
« alloué », il fallait désigner une borne comme SON PROPRE compteur dans
meterThingId. Ce n'est devinable par personne, et une note d'écran qui explique
un réglage dit que le défaut est dans le modèle. LM-1105 : quand le Thing piloté
porte lui-même l'état de puissance, le moteur le lit sans configuration.
La règle porte sur le THING, pas sur le mécanisme — certains powerswitch portent
currentPower et RelayRouter sait déjà les sommer ; écrire la règle par mécanisme
y ajouterait la table à maintenir à la main que LM-600 refuse. Et le test se pose
sur la CLASSE, sur TOUS les Things déclarés : interroger les relais actifs ferait
osciller la réponse au palier 0, sur une installation dont rien n'a changé.
Le compteur explicite reste prioritaire — répondu oui, et la raison principale
n'est pas la précision mais qu'un réglage sans effet est pire que pas de réglage.
La priorité porte sur la SOURCE, pas sur la valeur : compteur déclaré injoignable
→ on retombe sur l'appareil, et la charge utile dit lequel a servi.
Le second point de l'agent app décide de la forme, et la vérification l'a rendu
plus tranchant qu'il n'était posé : le moteur porte DÉJÀ trois régimes sous un
seul nom et jette la distinction. evcharger rend une mesure ; relay-router rend
une mesure OU le palier nominal — le booléen `metered` est calculé puis jeté ;
sg-ready rend toujours une puissance DÉCLARÉE, jamais mesurée, délibérément.
Publier ces quatre lignes sous un même measuredW serait faux pour deux d'entre
elles, et un measuredW auto-rempli détruirait au passage la seule information que
le champ portait : sa présence signifiait « un compteur a été posé exprès ».
D'où LM-1106 : le régime se PUBLIE, il ne se déduit pas d'une valeur — C2 de
LM-1009 mot pour mot. measurement {source: meter|device|none, o:powerW}, powerW
absent sous none. `none` est un état POSITIF — C1 de LM-1009 : une capacité
manquante se dit — et c'est lui qui distingue « pas mesurable » de « compteur en
panne ». Sous none, la puissance nominale reste lisible dans mechanism.* : la
faire passer pour une mesure produirait un écart identiquement nul à tous les
cycles, un « tout concorde » permanent, corollaire LM-104.
Ce que la source change au diagnostic, et qui la rend utile plutôt que
décorative : device dit « la charge n'obéit pas » (commande et mesure sortent de
la même boîte) ; meter ouvre trois hypothèses — charge, compteur, câblage — dont
il ne tranche aucune ; none n'autorise rien. L'asymétrie va plus loin : sous
device une CONCORDANCE ne prouve rien, plusieurs wallbox renvoyant leur consigne
en guise de puissance, alors que sous meter elle est une preuve. device détecte
la désobéissance, meter est le seul à pouvoir détecter un mensonge — et c'est ce
qui donne à LM-1104 sa raison d'être : meterThingId reste AUTORISÉ sur une charge
qui publie déjà, à masquer par défaut, pas à interdire.
Ne touche PAS ce que l'arbitre lit : LM-1101 tient, et le recrédit
anti-clignotement continue de lire LoadContext::telemetry.currentPowerW, qui
vient de l'adaptateur et n'a jamais transité par meterThingId. Ce lot déplace ce
qui est PUBLIÉ, pas ce qui décide.
Aucun code. Le contrat bouge (measuredW → measurement), et le brief le dit à
l'app avec son coût : un écran.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015F7G5VeaPVSMeVNjiGj36p
This commit is contained in:
parent
b3abc12c6d
commit
707526191a
@ -832,6 +832,11 @@ portant `energymeter` / `smartmeter` ; la sonde parmi celles portant l'interface
|
||||
Nommer un plugin dans le modèle le rendrait faux au prochain plugin qui rend le même service —
|
||||
et obligerait à maintenir une table à la main, ce que LM-600 refuse déjà pour les mécanismes.
|
||||
|
||||
> ⚠️ **`meterThingId` n'est plus la SEULE source de mesure — voir LM-1105.** Il l'a été, et cela
|
||||
> obligeait l'installateur à désigner une borne comme son propre compteur pour qu'elle affiche
|
||||
> ce qu'elle mesure déjà. Le champ garde tout son sens ; il cesse d'être une corvée de
|
||||
> configuration là où le moteur peut lire l'appareil directement.
|
||||
|
||||
**LM-1101 — Le compteur sert à VÉRIFIER, jamais à décider.** Commandé 3 000 W, mesuré 0 W sur
|
||||
trois cycles consécutifs : la charge ne fait pas ce qu'on lui demande, et c'est **la seule
|
||||
chose** que la mesure autorise à conclure.
|
||||
@ -858,6 +863,9 @@ soupçon. Il se publie comme **diagnostic**, à côté de `faultCode` et sans le
|
||||
> lent et une charge à forte inertie produiraient sinon un diagnostic permanent. Trois cycles
|
||||
> est un point de départ, pas une valeur figée.
|
||||
|
||||
> **Et l'écart ne CONCLUT PAS la même chose selon la source de la mesure** — LM-1106. Un écart
|
||||
> calculé sur une valeur qui n'est pas une mesure ne conclut, lui, rien du tout.
|
||||
|
||||
**LM-1103 — La sonde est en lecture seule, et son vrai usage est différé.** Publiée en
|
||||
télémétrie, **aucun effet** sur les décisions. Deux usages, dont le second est le plus
|
||||
important :
|
||||
@ -879,6 +887,111 @@ compteur de tableau divisionnaire peut couvrir plusieurs charges.
|
||||
`sensorThingId` dans son contrôle d'unicité des Things. Les y ajouter par symétrie avec
|
||||
`relays[]` refuserait des configurations correctes.
|
||||
|
||||
**LM-1105 — Le moteur lit l'appareil qu'il pilote. `meterThingId` cesse d'être la seule
|
||||
source.** *(Constat d'usage de l'agent app, 2026-08-28 ; proposition retenue.)*
|
||||
|
||||
Pour qu'une charge publie ce qu'elle consomme, il fallait la désigner **comme son propre
|
||||
compteur** dans `meterThingId`. Ce n'est devinable par personne : un installateur voit un bloc
|
||||
« compteur dédié » sur une borne qui publie déjà `currentPower`, et n'a aucune raison d'y
|
||||
remettre la borne elle-même. **C'est de la configuration demandée pour compenser ce que le
|
||||
moteur peut déduire** — et une configuration qu'on documente en note d'écran est le signe que le
|
||||
défaut est dans le modèle, pas dans l'app.
|
||||
|
||||
**La règle** : quand le Thing piloté **porte lui-même l'état de puissance**, le moteur le lit,
|
||||
sans configuration. `meterThingId` ne reste nécessaire que là où rien ne mesure.
|
||||
|
||||
> **La règle porte sur le THING, pas sur le mécanisme.** « Les bornes mesurent, les relais
|
||||
> non » est vrai en pratique et faux en droit : certains `powerswitch` portent `currentPower`,
|
||||
> et `RelayRouter` sait déjà les sommer. Écrire la règle par mécanisme y ajouterait la table à
|
||||
> maintenir à la main que LM-600 refuse. Le test est une question posée à la **ThingClass**.
|
||||
>
|
||||
> **Et il se pose sur la CLASSE, jamais sur la valeur ni sur l'instant.** Un `relay-router` au
|
||||
> palier 0 n'a aucun relais actif : interroger les relais *actifs* ferait osciller la réponse
|
||||
> d'un cycle à l'autre, sur une installation dont rien n'a changé. La question est « ces Things
|
||||
> portent-ils l'état ? », posée sur **tous** les Things déclarés de la charge.
|
||||
|
||||
**Le compteur explicite reste PRIORITAIRE, et ce n'est pas d'abord une question de précision.**
|
||||
Un compteur divisionnaire posé exprès mesure mieux qu'un appareil qui se déclare — c'est vrai,
|
||||
et ce n'est pas la raison principale. La raison principale est qu'**un réglage qui n'a pas
|
||||
d'effet est pire que pas de réglage** : si le moteur préférait l'appareil au compteur que
|
||||
l'installateur a pris la peine de désigner, le champ deviendrait décoratif, et le prochain à le
|
||||
lire ne saurait pas s'il sert.
|
||||
|
||||
> **La priorité porte sur la SOURCE, pas sur la valeur.** `meterThingId` renseigné mais Thing
|
||||
> absent, ou Thing sans l'état : on retombe sur l'appareil, et **ce qui est publié dit lequel a
|
||||
> servi** (LM-1106). Ne rien publier au motif que le compteur déclaré est injoignable
|
||||
> perdrait une mesure qu'on a — et le silence se lirait « charge non mesurable », ce qui serait
|
||||
> faux.
|
||||
|
||||
**Ce que LM-1105 ne change PAS** : rien de ce que l'**arbitre** lit. LM-1101 tient mot pour
|
||||
mot — la mesure vérifie, elle ne budgète pas — et le recrédit anti-clignotement continue de lire
|
||||
`LoadContext::telemetry.currentPowerW`, qui vient de l'adaptateur et n'a jamais transité par
|
||||
`meterThingId`. Ce lot déplace **ce qui est publié**, pas ce qui décide. En particulier, il ne
|
||||
rouvre pas la correction B ni l'artefact du banc `.75` (`AGENTS.md`, PLAN 3C).
|
||||
|
||||
**LM-1106 — Ce qui est publié n'est pas un nombre : c'est un couple {valeur, source}.**
|
||||
*(Second point soulevé par l'agent app, et c'est lui qui décide de la forme.)*
|
||||
|
||||
Le moteur porte **déjà** trois régimes sous un seul nom, et il jette la distinction :
|
||||
|
||||
| Adaptateur | Ce que vaut `telemetry().currentPowerW` | Régime |
|
||||
|---|---|---|
|
||||
| `evcharger` | `EvCharger::currentPower()` | **mesuré par l'appareil** |
|
||||
| `etmvariableload` | l'état `currentPowerW` du Thing s'il existe ; sinon la consigne en vol ; sinon 0 | **mesuré**, ou **commandé** |
|
||||
| `relay-router` | somme des relais qui portent `currentPower` ; **sinon le palier NOMINAL** | mesuré ou **nominal** — et le booléen `metered` est calculé, puis jeté |
|
||||
| `sg-ready` | `estimatedPowerW[état]` | **déclaré**, jamais mesuré, délibérément (invariant 8) |
|
||||
|
||||
Publier ces quatre lignes sous le même `measuredW` serait faux pour deux d'entre elles. Et
|
||||
publier un `measuredW` **automatiquement rempli** détruirait au passage la seule information que
|
||||
le champ portait jusqu'ici : sa présence signifiait « un compteur a été posé exprès ».
|
||||
|
||||
**Donc le régime se PUBLIE, il ne se déduit pas d'une valeur.** C'est C2 de LM-1009, mot pour
|
||||
mot, appliqué à la mesure — et pour la même raison qu'en LM-1009 : *un champ absent se voit ; un
|
||||
champ qui s'efface se lit comme un zéro.*
|
||||
|
||||
```
|
||||
o:measurement {
|
||||
source : "meter" | "device" | "none",
|
||||
o:powerW: double // absent si source == "none"
|
||||
}
|
||||
```
|
||||
|
||||
- **`meter`** — un Thing tiers déclaré par `meterThingId`.
|
||||
- **`device`** — l'appareil piloté publie sa propre puissance.
|
||||
- **`none`** — **rien ne mesure cette charge.** État à part entière, et positif : c'est C1 de
|
||||
LM-1009 appliqué ici — une capacité manquante **se dit**. Sans lui, l'app ne peut pas
|
||||
distinguer « pas mesurable » de « compteur en panne », et continue d'afficher un bloc de
|
||||
mesure vide sur un `sg-ready` qui n'en aura jamais.
|
||||
|
||||
> **Sous `none`, aucune valeur n'est publiée sous ce nom.** La puissance *nominale* existe et
|
||||
> reste lisible — `mechanism.stageW`, `mechanism.state`, `mechanism.estimatedPowerW` la portent
|
||||
> déjà, et disent d'où elle vient. La faire passer pour une mesure produirait un écart
|
||||
> commande↔mesure **identiquement nul, à tous les cycles, pour toujours** : un « tout
|
||||
> concorde » permanent, c'est-à-dire le pire des diagnostics. C'est le corollaire LM-104 —
|
||||
> l'hypothèse de prudence devient un masquage de panne.
|
||||
|
||||
**Ce que la source change au DIAGNOSTIC** (LM-1102), et c'est ce qui la rend utile plutôt que
|
||||
décorative :
|
||||
|
||||
| Source | Ce qu'un écart commandé↔mesuré autorise à conclure |
|
||||
|---|---|
|
||||
| `device` | **La charge n'obéit pas.** Commande et mesure sortent de la même boîte : l'écart parle de la charge et d'elle seule — véhicule qui refuse le courant, thermostat ouvert, plafond interne. |
|
||||
| `meter` | **La charge, le compteur, ou le câblage.** Trois hypothèses, l'écart n'en tranche aucune seul. C'est le seul cas où « le compteur ne voit pas cette charge » est sur la table — le défaut ouvert du banc, compteur racine aveugle aux résistances ECS. |
|
||||
| `none` | **Rien.** Aucun écart n'est calculable, et il ne faut surtout pas en fabriquer un. |
|
||||
|
||||
> **L'asymétrie va plus loin que « le compteur mesure mieux », et elle donne à LM-1104 sa
|
||||
> raison d'être.** Sous `device`, une **concordance** ne prouve pas grand-chose : plusieurs
|
||||
> wallbox renvoient leur consigne en guise de puissance, et commandé == mesuré n'y est qu'une
|
||||
> tautologie. Sous `meter`, une concordance est une **preuve**. Autrement dit : `device`
|
||||
> détecte la **désobéissance**, `meter` est le seul à pouvoir détecter un **mensonge**. C'est
|
||||
> pourquoi `meterThingId` doit rester **autorisé** sur une charge qui publie déjà sa puissance
|
||||
> — LM-1104 ne devient pas caduc, il gagne un usage.
|
||||
|
||||
**Conséquence pour l'app, et elle est de présentation, pas de modèle** : le champ « compteur
|
||||
dédié » se **masque par défaut** là où `source` vaut `device`, et se propose en réglage avancé.
|
||||
Il ne doit pas être *interdit* : ce serait fermer le cas ci-dessus, et casser le compteur de
|
||||
tableau divisionnaire couvrant plusieurs charges (LM-1104).
|
||||
|
||||
---
|
||||
|
||||
## §12 — Le plancher de modulation
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user