docs(spec): spec_ecs 0.5.1 — câblage réel 500/1000/1500, les trois consignations s'inversent
La 0.5.0 consignait 500/1000/2000 sur la foi de la consigne d'étape 1. Le
simulateur du banc contredit cette donnée ; arbitrage : le simulateur reflète
l'installation, la donnée était fausse.
Câblage : 500/1000/1500 W, additif, 7 valeurs distinctes de 0 à 3000 W, avec UNE
redondance — 1500 W admet {R1500} et {R500+R1000}.
Trois corrections :
1. ECS-302 est EXERCÉ. Il redevient préalable structurel de l'étape 3 et reprend
son rang devant tout ce qui s'appuiera sur m_relayMapping.
2. ECS-303 SUPPRIMÉ. Le « point dur » 1500→2000 n'est pas une exigence
d'hystérésis, c'est une conséquence directe d'ECS-302 non traité :
relayrouter.cpp:58 retient la première combinaison rencontrée (masque le plus
bas), donc {R500+R1000} pour 1500 W, et jette {R1500}. La transition vers
2000 W = {R500+R1500} demande alors d'ouvrir R1000 et de fermer R1500, avec le
creux qu'impose l'ordre coupure-avant-fermeture. Avec {R1500} pour 1500 W, la
même transition ne coûterait QU'UNE commutation : fermer R500. Aucune entrée
ECS-303 ni ECS-605 de ce côté.
3. 7 valeurs et plafond 3000 W, non 8 et 3500. ECS-305 reste valable, comptes
corrigés : par balayage complet R500 commute 5 fois, R1000 3 fois, R1500 une
seule (vérifié sur l'encodage effectivement retenu par le code actuel).
RÉSERVE INSCRITE : la source est le simulateur (sim/sim_ecs_router.py:38, sommé
dans _power_w(), confirmé en vol sur MQTT), PAS une mesure physique. Ce chiffre a
déjà changé trois fois et il commande désormais l'ordre de l'étape 3 : il doit
être confirmé sur plaque signalétique ou au pince ampèremétrique AVANT
l'ouverture de cette étape. Consigné en §13-3 et en garde-fou sous l'étape 3.
Aucun code touché.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1e80a83df9
commit
1011a6ccd7
@ -1,6 +1,6 @@
|
||||
# SPEC — ECS multi-palier
|
||||
|
||||
Version : 0.5.0
|
||||
Version : 0.5.1
|
||||
Dépôt : `etm-powersync-energy-plugin-etm` (experience-plugin ems)
|
||||
Branche : `feature/beta-rulebased`
|
||||
Contrats faisant autorité : `docs/OPTIMIZER_PROTOCOL.md`, `docs/SAFETY.md`, `AGENTS.md`
|
||||
@ -33,8 +33,13 @@ remonte. Il ne tranche pas seul.
|
||||
>
|
||||
> **0.5.0** — §13-1 et §13-2 **tranchés et consignés** ; l'étape 1 est débloquée.
|
||||
> ECS-412 réduit à `m_lastSwitch` (lecture (b)) et redirigé vers sa cause racine.
|
||||
> Câblage du banc confirmé **500/1000/2000** : ECS-302 n'est plus exercé par ce
|
||||
> matériel, ECS-305 monte, ECS-303 créé pour le point dur 1500→2000 W.
|
||||
>
|
||||
> **0.5.1 — CORRECTION du câblage.** La 0.5.0 consignait 500/1000/**2000** ;
|
||||
> c'était faux. Le câblage réel est **500/1000/1500**. Trois consignations
|
||||
> s'inversent : ECS-302 **est** exercé et redevient préalable structurel de
|
||||
> l'étape 3 ; **ECS-303 est supprimé** (le « point dur » était une conséquence
|
||||
> d'ECS-302 non traité, pas une exigence d'hystérésis) ; 7 valeurs et plafond
|
||||
> 3000 W, non 8 et 3500. Ne pas se fier à une copie 0.5.0.
|
||||
|
||||
---
|
||||
|
||||
@ -159,8 +164,14 @@ unitaire et conditionne l'étape 3.
|
||||
> parle à aucun matériel. L'étape 2 ne sort **aucune** classe de ce genre : elle
|
||||
> extrait le noyau de calcul **interne au mécanisme relais**. Rien à voir.
|
||||
|
||||
**Étape 3 — ECS-302 / ECS-305.** Changement de structure de `m_relayMapping`.
|
||||
Doit précéder tout ce qui s'appuiera dessus.
|
||||
**Étape 3 — ECS-302 / ECS-305.** Changement de structure de `m_relayMapping` :
|
||||
un palier doit pouvoir porter PLUSIEURS combinaisons. **Préalable structurel** —
|
||||
doit précéder tout ce qui s'appuiera dessus. Exercé par le câblage réel
|
||||
(1500 W a deux encodages, §4).
|
||||
|
||||
> **Ne pas ouvrir l'étape 3 avant confirmation physique du câblage** (§13-3) :
|
||||
> c'est lui qui justifie l'ordre de cette étape, et il provient aujourd'hui du
|
||||
> simulateur, pas d'une mesure.
|
||||
|
||||
**Étape 4 — ECS-410** (échec d'écriture). ECS-411 a été **remonté en étape 1**
|
||||
(§13-2). ECS-410 reste ici : il touche le même chemin `applyRelayStage` /
|
||||
@ -250,44 +261,47 @@ fenêtre de verrou active ».
|
||||
|
||||
## §4 — Combinatoire (`RelayRouter`)
|
||||
|
||||
> **Câblage du banc CONFIRMÉ le 2026-08-08 : 500 / 1000 / 2000 W.** Pondération
|
||||
> binaire — huit valeurs distinctes de 0 à 3500 W au pas de 500 W, **aucune
|
||||
> redondance**, un seul encodage par palier.
|
||||
> **Câblage CONFIRMÉ le 2026-08-08 : 500 / 1000 / 1500 W.** Additif (les relais
|
||||
> se somment), **7 valeurs distinctes** de 0 à **3000 W**, avec **une
|
||||
> redondance** : 1500 W a DEUX encodages.
|
||||
>
|
||||
> | Palier | Relais ON | W |
|
||||
> |---|---|---|
|
||||
> | 0 | — | 0 |
|
||||
> | 1 | 500 | 500 |
|
||||
> | 2 | 1000 | 1000 |
|
||||
> | 3 | 500+1000 | 1500 |
|
||||
> | 4 | 2000 | 2000 |
|
||||
> | 5 | 500+2000 | 2500 |
|
||||
> | 6 | 1000+2000 | 3000 |
|
||||
> | 7 | 500+1000+2000 | 3500 |
|
||||
> | W | Encodage(s) |
|
||||
> |---|---|
|
||||
> | 0 | — |
|
||||
> | 500 | R500 |
|
||||
> | 1000 | R1000 |
|
||||
> | **1500** | **R1500** *ou* **R500+R1000** ← deux encodages |
|
||||
> | 2000 | R500+R1500 |
|
||||
> | 2500 | R1000+R1500 |
|
||||
> | 3000 | R500+R1000+R1500 |
|
||||
>
|
||||
> Ceci clôt le point ouvert « 500/1000/1500 ou 500/1000/2000 » et déplace trois
|
||||
> exigences — voir ECS-302, ECS-305 et ECS-303 ci-dessous.
|
||||
> **Source : le simulateur du banc** (`etm-powersync-hems-sim`,
|
||||
> `sim/sim_ecs_router.py:38` — `PALIERS = {1: 500.0, 2: 1000.0, 3: 1500.0}`,
|
||||
> sommés dans `_power_w()`), confirmé en vol sur MQTT (relais 2+3 fermés →
|
||||
> 2500 W publiés, ce qu'une cascade ne produirait pas). **Ce n'est PAS une
|
||||
> mesure physique.** Cette valeur a déjà changé trois fois et elle commande
|
||||
> désormais l'ordre de l'étape 3 : elle DOIT être confirmée sur plaque
|
||||
> signalétique ou au pince ampèremétrique **avant l'ouverture de l'étape 3**.
|
||||
|
||||
**ECS-302 — Encodages équivalents. NON EXERCÉ PAR CE MATÉRIEL.** Avec une
|
||||
pondération binaire il n'y a **rien à arbitrer** : un seul encodage par palier.
|
||||
L'exigence reste valable pour un câblage 1-2-3 ailleurs (deux encodages pour
|
||||
1500 W), mais **le changement de structure de `m_relayMapping` perd sa
|
||||
justification immédiate** : il redescend dans l'ordre de l'étape 3 et **cesse
|
||||
d'être un préalable structurel**. Ne plus le traiter comme tel.
|
||||
**ECS-302 — Encodages équivalents. EXERCÉ PAR CE MATÉRIEL.** 1500 W admet
|
||||
`{R1500}` et `{R500+R1000}` : il y a bien un arbitrage à rendre. L'exigence
|
||||
**redevient un préalable structurel de l'étape 3** et reprend son rang **devant**
|
||||
tout ce qui s'appuiera sur `m_relayMapping`.
|
||||
|
||||
**ECS-303 — Point dur 1500 → 2000 W.** Cette transition bascule **les trois
|
||||
relais d'un coup** (R500 et R1000 s'ouvrent, R2000 se ferme). Avec l'ordre
|
||||
coupure-avant-fermeture d'ECS-402, elle produit un **trou de puissance à chaque
|
||||
franchissement**, en plein milieu de la plage de surplus utile.
|
||||
Ce que fait le code aujourd'hui, et ce que ça coûte : le constructeur retient la
|
||||
**première** combinaison rencontrée, c'est-à-dire le masque le plus bas
|
||||
(`relayrouter.cpp:58`, `if (!byPower.contains(sum))`). Pour 1500 W il retient
|
||||
donc `{R500+R1000}` et **jette `{R1500}`**. Conséquence directe sur la transition
|
||||
1500 → 2000 W (`{R500+R1500}`) : il faut ouvrir R1000, garder R500, fermer
|
||||
R1500 — et comme l'encodage retenu impose de passer par l'ordre
|
||||
coupure-avant-fermeture d'ECS-402, la charge traverse un creux. Avec l'encodage
|
||||
`{R1500}` pour 1500 W, la même transition ne demanderait qu'**une seule
|
||||
commutation** : fermer R500.
|
||||
|
||||
La parade n'est PAS dans la combinatoire — aucun réordonnancement ne supprime le
|
||||
trou, puisque aucun sous-ensemble intermédiaire ne vaut ni 1500 ni 2000 W. Elle
|
||||
est dans un **seuil d'hystérésis élargi à cette frontière précise**. Entrée
|
||||
commune avec ECS-605 (hystérésis paramétrable par charge). **À MESURER au banc
|
||||
avant de coder quoi que ce soit** : c'est le relevé de commutations qui dira
|
||||
quelle largeur donner au seuil.
|
||||
|
||||
**ECS-302 (suite) — Encodages équivalents.** Un palier DOIT pouvoir porter **plusieurs**
|
||||
> **Il n'y a donc pas d'exigence d'hystérésis à ouvrir de ce côté.** Le « point
|
||||
> dur 1500→2000 » qu'envisageait la 0.5.0 est une **conséquence d'ECS-302 non
|
||||
> traité**, pas un phénomène propre au câblage. Aucune entrée pour ECS-303 (créé
|
||||
> puis **supprimé** en 0.5.1) ni pour ECS-605. Un palier DOIT pouvoir porter **plusieurs**
|
||||
combinaisons de relais, et la combinaison retenue DOIT être celle dont le coût de
|
||||
transition depuis l'état courant est le plus faible : d'abord le nombre de relais
|
||||
à basculer, puis le relais dont le compteur de commutations est le moins entamé.
|
||||
@ -301,15 +315,17 @@ rencontrée gagne, c'est-à-dire le masque le plus bas. Sur un câblage
|
||||
porter deux combinaisons. ECS-302 est donc un changement de structure, pas
|
||||
l'ajout d'un critère.
|
||||
|
||||
**ECS-305 — Compteurs de commutations. IMPORTANCE RELEVÉE** par le câblage
|
||||
binaire confirmé. Chaque relais DOIT porter un compteur de commutations, exposé
|
||||
en télémétrie.
|
||||
**ECS-305 — Compteurs de commutations.** Chaque relais DOIT porter un compteur
|
||||
de commutations, exposé en télémétrie.
|
||||
|
||||
Sur un balayage complet des huit paliers, **R500 commute sept fois, R1000 trois
|
||||
fois, R2000 une seule** : le bit de poids faible s'use sept fois plus vite que le
|
||||
bit de poids fort. Le comptage par relais devient **la seule façon de savoir
|
||||
quand le contacteur 500 W arrivera en fin de vie** — la puissance commutée, elle,
|
||||
ne le dit pas.
|
||||
Sur un balayage complet des sept paliers (0 → 3000 W), avec l'encodage retenu
|
||||
aujourd'hui : **R500 commute 5 fois, R1000 3 fois, R1500 une seule**. Le relais
|
||||
de plus faible puissance s'use cinq fois plus vite que le plus gros. Le comptage
|
||||
par relais est **la seule façon de savoir quand le contacteur 500 W arrivera en
|
||||
fin de vie** — la puissance commutée, elle, ne le dit pas.
|
||||
|
||||
\note Ces comptes dépendent de l'encodage choisi : traiter ECS-302 les modifie.
|
||||
Raison de plus pour instrumenter avant d'optimiser.
|
||||
|
||||
**ECS-307 — Grain des temporisations.** `minOn`/`minOff` sont aujourd'hui **par
|
||||
charge** (un unique `m_lastSwitch`, `relayrouter.h:107`), ce qui satisfait
|
||||
@ -446,9 +462,8 @@ mécanique reste **L0**. Perte de sonde → mode sans sonde, pas arrêt d'urgenc
|
||||
|---|---|---|
|
||||
| ECS-306 | simulation | `testEcsBudgetUnderLock` |
|
||||
| ECS-412 | simulation | `testEcsRebuildPreservesLock` |
|
||||
| ECS-303 | banc, puis simulation | relevé de commutations à la frontière 1500/2000 — **mesurer avant de coder** |
|
||||
| ECS-305 | unitaire | `testEcsSwitchCount` — compteur par relais |
|
||||
| ECS-302 | unitaire | `testEcsSwitchCost` — **non exerçable sur le câblage 500/1000/2000** (encodage unique) |
|
||||
| ECS-302 | unitaire | `testEcsSwitchCost` — **exerçable** : 1500 W = `{R1500}` ou `{R500+R1000}` |
|
||||
| ECS-304 | unitaire | `testEcsLevelsPure` |
|
||||
| ECS-410 | simulation | `testEcsPartialFailure` |
|
||||
| ECS-411 | simulation | `testEcsRestartRecovery` |
|
||||
@ -521,7 +536,10 @@ protocole dans le même lot.**
|
||||
| 2026-08-08 | **§13-2 CLOS, lecture (b)** — ECS-412 réduit à `m_lastSwitch` + cause racine (rebuild incrémental) ; ECS-411 remonté en étape 1 |
|
||||
| 2026-08-08 | **Étape 1 OUVERTE** — trois exigences : ECS-306, ECS-411, ECS-412 |
|
||||
| 2026-08-08 | ECS-412 : au démarrage à froid, le verrou est **ARMÉ** (défaut sûr), jamais purgé |
|
||||
| 2026-08-08 | Câblage banc confirmé **500/1000/2000** — ECS-302 non exercé, ECS-305 relevé, **ECS-303 créé** (point dur 1500→2000) |
|
||||
| 2026-08-08 | ~~Câblage 500/1000/2000~~ — **donnée fausse**, corrigée le jour même (cf. ligne suivante) |
|
||||
| 2026-08-08 | **Câblage 500/1000/1500** — 7 valeurs, plafond 3000 W, 1500 W à deux encodages. **Source : le simulateur** (`sim/sim_ecs_router.py:38`), **PAS une mesure** — à confirmer sur plaque ou au pince avant l'ouverture de l'étape 3. Troisième volte-face sur ce chiffre, et il commande désormais l'ordre de l'étape 3 |
|
||||
| 2026-08-08 | **ECS-302 exercé** — redevient préalable structurel de l'étape 3, devant tout ce qui s'appuie sur `m_relayMapping` |
|
||||
| 2026-08-08 | **ECS-303 SUPPRIMÉ** — le « point dur » 1500→2000 est une conséquence d'ECS-302 non traité, pas une exigence d'hystérésis. Aucune entrée ECS-605 de ce côté |
|
||||
|
||||
---
|
||||
|
||||
@ -529,11 +547,13 @@ protocole dans le même lot.**
|
||||
|
||||
1. **ECS-307** — grain des temporisations par relais : nécessaire, ou le compteur
|
||||
de commutations suffit-il ? Le câblage binaire rend la question plus concrète
|
||||
(R500 commute 7× plus que R2000), sans la trancher.
|
||||
2. **ECS-303 / ECS-605** — largeur de l'hystérésis à la frontière 1500/2000 W,
|
||||
et asymétrie montée/descente. **À mesurer au banc avant de coder** : c'est le
|
||||
relevé de commutations qui donne le chiffre.
|
||||
3. **Conflit d'écriture** — `connectIO()` est le mécanisme natif si l'on veut un
|
||||
(R500 commute 5× plus que R1500), sans la trancher.
|
||||
2. **ECS-605** — asymétrie de l'hystérésis montée/descente, à régler à l'usage.
|
||||
Sans rapport avec la frontière 1500/2000 : celle-ci relève d'ECS-302.
|
||||
3. **Câblage à confirmer physiquement** — 500/1000/1500 provient du simulateur,
|
||||
pas d'une mesure. À vérifier sur plaque ou au pince ampèremétrique **avant
|
||||
l'ouverture de l'étape 3**, dont il commande l'ordre.
|
||||
4. **Conflit d'écriture** — `connectIO()` est le mécanisme natif si l'on veut un
|
||||
jour exposer un relais ECS au pilotage manuel de l'utilisateur. Ce serait
|
||||
alors un conflit d'écriture à arbitrer, pas une aide.
|
||||
|
||||
@ -548,8 +568,9 @@ protocole dans le même lot.**
|
||||
ECS-411 remonte en étape 1. L'étape 1 porte donc trois exigences.
|
||||
`testEcsRebuildPreservesLock` couvre obligatoirement « `SetLoadConfig` pendant
|
||||
une fenêtre de verrou active ».
|
||||
- **Câblage du banc** — confirmé **500/1000/2000 W** (cf. §4). ECS-302 n'est pas
|
||||
exercé par ce matériel ; ECS-305 monte en importance ; ECS-303 créé.
|
||||
- **Câblage du banc** — **500/1000/1500 W**, source simulateur (cf. §4, et la
|
||||
réserve : à confirmer physiquement avant l'étape 3). ECS-302 **est** exercé et
|
||||
redevient préalable structurel de l'étape 3.
|
||||
|
||||
**CLOS par l'audit** : le waterfall ne choisit pas entre encodages équivalents
|
||||
(il n'en voit qu'un) ; `ioConnections()`/`connectIO()` est un lien 1↔1
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user