docs(R3): counts retenu — et sur un niveau mixte, ni omission ni « mixed » publié
Arbitrage rendu au moteur avant qu'il n'écrive R3. La forme proposée est prise telle quelle : `funding` reste, `counts` s'ajoute, `Σ counts == targetW` toujours, publié même à une seule destination. L'exception `EV_GRID_START` disparaît du contrat, remplacée par une règle vérifiable par niveau. Trois apports de notre côté : - « approximation » est le mauvais mot et coûterait le champ : quelqu'un voudrait le rendre exact, et un libellé par part dominante basculerait d'un cycle à l'autre sur 900/480. Règle demandée : **`grid` l'emporte dès qu'un watt est acheté** — déterministe, et vraie sans nouvelle décision pour le plancher éco du §10 ; - `"mixed"` publié est refusé, et c'est notre propre code qui le dit : une troisième valeur tombe dans la branche par défaut de tout client — « surplus » — donc reproduit la panne de l'omission, avec un champ présent en plus pour faire croire le contraire. Et il serait dérivable de `counts`, donc supprimé un jour à juste titre. Notre `mixed` reste dérivé, local, jamais transporté ; - ce que l'app promet : clés de `counts` traitées comme identifiants opaques, une clé inconnue dit « destination inconnue de cette version », jamais zéro. Contrat, pas feuille de route : `CLAUDE.md` et `surplusShareW` gardent l'exception écrite tant que la sonde ne l'a pas vue disparaître de la box. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
This commit is contained in:
parent
5c06e65a0e
commit
1d0112a6e4
@ -2,6 +2,98 @@
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-30 — R3 : `counts` est retenu, et `funding` sort de la réconciliation
|
||||
|
||||
**Réponse à la question du moteur sur le niveau mixte.** La forme proposée est prise telle
|
||||
quelle : `funding` reste, `counts` s'y ajoute, `Σ counts == targetW` toujours, et `counts`
|
||||
est publié même à une seule destination.
|
||||
|
||||
### Le code unique l'emporte — et l'argument contre l'omission est vérifiable, pas seulement juste
|
||||
|
||||
L'omission n'est pas neutre **dans le code qui tourne aujourd'hui** : `resolvedFunding` rend
|
||||
`null` quand rien n'est publié, et `isSurplusFunded` rend alors `true`
|
||||
(`lib/models/load_telemetry.dart`). Un niveau mixte sans `funding` serait donc rangé **avec
|
||||
les charges du soleil**, en silence. L'omission porterait déjà une affirmation — et la pire
|
||||
des deux.
|
||||
|
||||
### Mais « approximation » est le mauvais mot, et le garder coûterait le champ
|
||||
|
||||
Tant que `funding` est décrit comme approximatif, quelqu'un finira par vouloir le rendre
|
||||
exact : part dominante, seuil de majorité. Ce serait un libellé qui **bascule d'un cycle à
|
||||
l'autre** sur 900/480, sans qu'aucune décision n'ait changé.
|
||||
|
||||
**La règle que nous demandons d'écrire à sa place : `grid` l'emporte dès qu'un watt est
|
||||
acheté.** Déterministe, indépendante des proportions, et alignée sur ce qu'un humain doit
|
||||
savoir — l'achat est le fait actionnable, le surplus est l'ordinaire. Elle vaudra telle
|
||||
quelle pour le plancher éco acheté au réseau (§10) sans nouvelle décision à prendre.
|
||||
|
||||
### Ce qui rend l'ensemble soutenable : `funding` sort de la comptabilité
|
||||
|
||||
Avec `counts` **toujours** publié, `funding` ne participe plus à aucun calcul de
|
||||
réconciliation. Il ne dit plus que : *faut-il en parler ?* — et `counts` dit *combien, et
|
||||
où*. Aucun des deux ne se dérive de l'autre, et l'approximation qui reste n'entre plus dans
|
||||
un total. Côté écran, la carte d'un niveau mixte dira **« en partie achetée — 480 W sur
|
||||
1 380 »** : `funding` déclenche la phrase, `counts` la chiffre.
|
||||
|
||||
### Et `"mixed"` publié ? Non — et c'est notre propre code qui le dit
|
||||
|
||||
C'est bien la troisième voie, elle mérite d'être posée, et nous la refusons. Trois raisons,
|
||||
dans l'ordre de force :
|
||||
|
||||
**1. Il reproduirait EXACTEMENT la panne de l'omission, sur le même chemin de code.** Tout
|
||||
client qui teste `funding == 'grid'` a une branche par défaut, et cette branche est
|
||||
« surplus » — la nôtre l'était encore ce matin (`isSurplusFunded => funding != 'grid'`).
|
||||
Une troisième valeur y tombe **sans erreur**, et range au soleil un niveau dont une part est
|
||||
achetée. C'est le défaut que l'omission produisait, avec un champ présent en plus pour faire
|
||||
croire le contraire.
|
||||
|
||||
**2. Il serait dérivable — donc il violerait votre propre règle.** `"mixed"` ⟺ `counts` a
|
||||
plus d'une destination non nulle. Un champ publié qui se recalcule depuis un autre est
|
||||
précisément celui que quelqu'un supprimera un jour comme redondant, et il aura raison.
|
||||
|
||||
**3. Il ne répond pas à la question que `funding` pose.** `funding` dit *d'où viennent ces
|
||||
watts* ; `"mixed"` dit *qu'il y a deux réponses* — une réponse sur la question, pas sur les
|
||||
watts. Et l'information actionnable qu'elle promet (**combien** est acheté) est déjà dans
|
||||
`counts`, en clair.
|
||||
|
||||
**La ligne qui sépare nos deux `mixed`** : le nôtre est **dérivé, local, jamais transporté**
|
||||
— `resolvedFunding` le fabrique pour une CHARGE dont les niveaux divergent, uniquement pour
|
||||
empêcher une carte d'affirmer une origine unique là où il y en a deux. Il est légitime parce
|
||||
qu'il est dérivable ; le vôtre serait illégitime pour la même raison. **On publie ce qui ne
|
||||
se dérive pas, on dérive ce qui se dérive** — et cette règle range `funding`, `counts` et
|
||||
`mixed` chacun à sa place sans qu'aucun ne soit redondant.
|
||||
|
||||
### Trois choses en échange, et elles sont de notre champ
|
||||
|
||||
**a. Une clé inconnue ne doit jamais disparaître.** Nous traiterons les clés de `counts`
|
||||
comme des **identifiants opaques**, jamais comme des chemins à parser. Si `draw.committedW`
|
||||
arrive sur une box plus récente que l'app, elle vérifiera quand même `Σ counts == targetW`
|
||||
— la règle ne dépend pas du sens des clés — mais dira **« destination inconnue de cette
|
||||
version »**, jamais zéro. Corollaire pour vous : **ne réutilisez jamais une clé existante
|
||||
pour un sens nouveau**. C'est le seul cas qu'aucun client ne peut détecter.
|
||||
|
||||
**b. Publiez `counts` même à zéro, avec sa destination.** Mesuré sur `.75` ce matin (cycle
|
||||
06:14) : un niveau `targetW: 0` **est** publié, avec le motif qui dit pourquoi. Un
|
||||
`counts: {}` y satisferait l'identité (0 == 0) tout en perdant la destination — un trou
|
||||
exactement sur le cas le plus fréquent, et de la même famille que celui que `counts` vient
|
||||
fermer. Une clé, valeur 0.
|
||||
|
||||
**c. Dites qui fait foi entre `counts` et les params d'`EV_GRID_START`.** Les deux porteront
|
||||
le même partage (`budgetW` / `gridW`). Notre lecture : **`counts` fait foi pour la
|
||||
comptabilité**, les params restent pour la **phrase** du motif — catalogue fermé, testé sur
|
||||
le texte. Si vous les gardez, dites-le ; s'ils divergent un jour, c'est `counts` que nous
|
||||
croirons.
|
||||
|
||||
### Ce que ça change pour nous, et quand
|
||||
|
||||
R3 devient vérifiable **par niveau**, sans connaître le sens des compteurs — c'est plus fort
|
||||
que ce que nous demandions. L'exception `EV_GRID_START` disparaîtra du contrat **le jour où
|
||||
la sonde la verra disparaître de la box** : d'ici là elle reste écrite dans `CLAUDE.md` et
|
||||
traitée dans `surplusShareW`, et nous ne touchons ni l'un ni l'autre. Contrat, pas feuille
|
||||
de route — comme pour `levels[]`.
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-29 — RÉPONSE au §9 : les deux passes du §10, vues de l'écran
|
||||
|
||||
**Maquette : `docs/mockups/deux_passes_eco_confort_mockup.html`** — trois écrans, un catalogue
|
||||
|
||||
@ -611,6 +611,8 @@
|
||||
<li>Un <b>second classement</b> à régler.</li>
|
||||
<li>Un écart entre <b><code>Σ targetW</code> et <code>allocatedW</code></b> : ils sont égaux par
|
||||
construction. Cherché là, l'arrondi est invisible et l'écran se tait sans se tromper.</li>
|
||||
<li>Une <b>exception de réconciliation</b> : avec <code>counts</code>, il n'y en a plus une seule.
|
||||
Un écart qui subsiste est un défaut, et il se dit.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@ -643,7 +645,10 @@
|
||||
<span class="k">"levels"</span>: [ <span class="c">// AJOUT — un élément par passe RÉELLEMENT parcourue</span>
|
||||
{ <span class="k">"level"</span>: <span class="s">"eco"</span>,
|
||||
<span class="k">"targetW"</span>: <span class="n">1400</span>, <span class="c">// la part de ce décidé qui revient à ce niveau</span>
|
||||
<span class="k">"funding"</span>: <span class="s">"grid"</span>, <span class="c">// le financement descend au NIVEAU</span>
|
||||
<span class="k">"funding"</span>: <span class="s">"grid"</span>, <span class="c">// L'ORIGINE — « ces watts sont achetés ». Livré en +etm30.</span>
|
||||
<span class="k">"counts"</span>: { <span class="k">"draw.committedW"</span>: <span class="n">1400</span> }, <span class="c">// LE REGISTRE — « ils sont comptés ici ».</span>
|
||||
<span class="c">// Σ counts == targetW, toujours. Publié même à une seule</span>
|
||||
<span class="c">// destination, et même à zéro, avec sa destination.</span>
|
||||
<span class="k">"decision"</span>: { <span class="k">"code"</span>: <span class="s">"ECO_FLOOR_GRID"</span>,
|
||||
<span class="k">"params"</span>: { <span class="k">"deliveredWh"</span>: <span class="n">2100</span>, <span class="k">"targetWh"</span>: <span class="n">3000</span>, <span class="k">"gridW"</span>: <span class="n">1400</span> } },
|
||||
<span class="k">"progress"</span>: { <span class="k">"regime"</span>: <span class="s">"measured"</span>, <span class="c">// measured | estimated | unmeasurable</span>
|
||||
@ -681,13 +686,29 @@
|
||||
<p><span style="color:var(--green)"><b>Parti le 2026-08-29</b></span> — l'argument de coût a emporté la
|
||||
priorisation. C'est la première des huit à être écrite.</p></div>
|
||||
|
||||
<div class="req hard"><b><u>R3</u>Chaque watt publié tombe dans exactement un compteur, et le mapping est publié</b>
|
||||
<p>Trois destinations coexisteront : <code>budget.allocatedW</code> (surplus), <code>budget.evReservedW</code>
|
||||
(réseau, proxy VE) et <code>draw.committedW</code> (réseau, plancher éco). <b>Dites où va chaque
|
||||
(niveau, financement)</b> — l'app ne doit pas le deviner, sinon deux clients afficheront deux bilans
|
||||
différents du même cycle. C'est la leçon d'<code>EV_GRID_START</code>, qui partage une allocation entre deux
|
||||
compteurs et qui aurait cassé notre réconciliation en silence. <b>Tranché le 2026-08-29</b> : les compteurs
|
||||
comptent le <b>décidé</b> — reste à publier la destination de chaque couple (niveau, financement).</p></div>
|
||||
<div class="req"><b><u>R3</u>Chaque watt tombe dans un compteur nommé — <span style="color:var(--green)">✔ résolu par `counts`</span></b>
|
||||
<p><b>La forme du moteur est prise telle quelle</b> (2026-08-30) : à côté de <code>funding</code>, un
|
||||
<code>counts</code> qui nomme les registres, avec <code>Σ counts == targetW</code> <b>toujours</b>, publié
|
||||
même à une seule destination. L'identité devient calculable <b>sans exception</b> et <b>par niveau</b> :
|
||||
l'exception <code>EV_GRID_START</code>, qui partageait une allocation entre deux compteurs, disparaît —
|
||||
remplacée par une règle vérifiable qui vaudra telle quelle quand <code>draw.committedW</code> arrivera.</p>
|
||||
<p><b>Les deux champs ne se dérivent pas l'un de l'autre</b>, et c'est ce qui empêchera qu'on en supprime un :
|
||||
<code>funding</code> dit <b>l'origine</b> (« ces watts sont achetés » — voisin du motif), <code>counts</code>
|
||||
dit <b>le registre</b> (« ils sont comptés ici » — une comptabilité).</p>
|
||||
<p><b>Sur un niveau mixte, un code unique : <code>"grid"</code></b> — et la règle demandée n'est pas « une
|
||||
approximation » mais <b>« grid l'emporte dès qu'un watt est acheté »</b>. Déterministe, indépendante des
|
||||
proportions (un libellé qui bascule sur 900/480 serait pire que faux), et alignée sur ce qu'un humain doit
|
||||
savoir : l'achat est le fait actionnable. Elle vaudra sans nouvelle décision pour le plancher éco du §10.
|
||||
<b>Ni omission</b> (notre <code>isSurplusFunded</code> range alors le niveau au soleil, en silence)
|
||||
<b>ni <code>"mixed"</code> publié</b> : une troisième valeur tomberait dans la branche par défaut de tout
|
||||
client — « surplus » — donc reproduirait la panne de l'omission, et elle serait <b>dérivable de
|
||||
<code>counts</code></b>, donc supprimée un jour à juste titre.</p>
|
||||
<p><b>Ce que l'app promet en échange</b> : les clés de <code>counts</code> sont traitées comme des
|
||||
<b>identifiants opaques</b>, jamais comme des chemins. Une clé inconnue d'une version ancienne n'est pas
|
||||
perdue : l'identité <code>Σ counts == targetW</code> reste vérifiable sans connaître le sens des clés, et
|
||||
l'écran dit « destination inconnue de cette version », <b>jamais zéro</b>. Corollaire pour le moteur : ne
|
||||
jamais réutiliser une clé existante pour un sens nouveau — c'est le seul cas qu'aucun client ne peut
|
||||
détecter.</p></div>
|
||||
|
||||
<div class="req"><b><u>R4</u>`Σ targetW == allocatedW` — une identité, pas un écart <span style="color:var(--green)">✔ tranché</span></b>
|
||||
<p><b>Corrigé le 2026-08-29 : notre prémisse était fausse.</b> <code>allocatedW</code> publie le
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user