docs+test: le contrôle qui disparaît avec ce qu'il surveille, et l'optionnel jamais exercé

DEUX CLASSES GRAVÉES DANS AGENTS.md.

1. LE CONTRÔLE QUI DISPARAÎT AVEC CE QU'IL SURVEILLE. Un balayage assis sur la
DÉCLARATION passait au vert quand la déclaration disparaissait : le défaut ne
trompait pas le détecteur, il le SUPPRIMAIT. Il occupe une place vide dans la
famille — la contre-épreuve qui ne mord pas est là mais ne peut pas échouer ;
l'identité qui se referme est vraie par construction ; la mesure qui porte à
côté vise une grandeur voisine ; celui-ci n'est PLUS LÀ, et son absence est
silencieuse.

Remède général : ancrer le critère sur ce qui SUBSISTE quand la référence
disparaît. Ici, la réponse plutôt que la déclaration. Et la seule façon de s'en
apercevoir est de REJOUER le défaut — la relecture donne toujours raison à qui a
écrit.

2. UN PARAMÈTRE OPTIONNEL QU'AUCUN TEST N'EXERCE EST UN PARAMÈTRE QU'ON PEUT
PERDRE. Aucun appel nominal ne l'utilise, donc sa disparition ne casse rien de
visible ; elle ne manquera qu'au client qui s'en sert, et le symptôme sera chez
lui. Ce qui n'est jamais exercé n'est pas « peu testé » : c'est indistinguable
d'absent, alors qu'un client lit les optionnels dans l'introspection et les
croit disponibles.

Fermé plutôt que noté : le balayage fait un SECOND PASSAGE avec les optionnels
renseignés. Contre-épreuve vérifiée — retirer o:knownAt fait sortir « Invalid
params: Invalid key: knownAt ».

AU CONTRAT : lire le STATUT avant la charge utile. Un appel refusé et un appel
qui ne rend rien se ressemblent et n'accusent pas le même — un client qui ne lit
que `params` conclut que le moteur est muet et accuse un code qui n'a pas tourné.

ET UNE NON-OBSERVATION, écrite comme telle : le cycle de 09:20 ne prouvera rien
de mon côté. Il ne reste qu'un plan depuis le retrait de 08:11:36, et une garde
qui compare deux plans ne s'exerce pas sur un seul. Un silence signifie « rien à
comparer », pas « les plans sont alignés » — les deux produisent la même trace,
aucune ligne. Le seul relevé exploitable reste celui de 08:08, obtenu par le
chemin forcé et non par la boucle horaire.

simulation 70/70, ci-quality 4/4, build 0 erreur 0 warning.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015F7G5VeaPVSMeVNjiGj36p
This commit is contained in:
Patrick Schurig 2026-09-09 08:57:49 +02:00
parent c02807c56d
commit bb15465109
2 changed files with 46 additions and 2 deletions

View File

@ -1177,5 +1177,30 @@ n'avait fait, parce que le symptôme était compatible avec deux causes.
- **La FORME des valeurs** : on vérifie qu'une clé est là, pas que son contenu est du bon type
ni qu'il a du sens. `forecastPoints: []` passe — et c'est correct, une table vide est un état
légitime.
- **Les paramètres OPTIONNELS** : `o:knownAt` n'est jamais exercé. Une déclaration optionnelle
supprimée ne serait pas vue.
- ~~**Les paramètres OPTIONNELS**~~ — **fermé le 2026-09-09**. Le balayage fait un **second
passage** avec les optionnels renseignés, et la contre-épreuve mord : retirer `o:knownAt` fait
sortir `Invalid params: Invalid key: knownAt`. C'était une classe et non un cas — *ce qui n'est
jamais exercé n'est pas « peu testé », c'est indistinguable d'absent*, alors qu'un client lit
les optionnels dans l'introspection et les croit disponibles.
---
## 25. Alignement des plans — NON OBSERVÉ, et il faut le dire ainsi
Le producteur confirme son correctif au cycle de 09:20. **Ce cycle ne prouvera rien de mon
côté** : le plan de test a été retiré à 08:11:36, il n'en reste **qu'un**, et une garde qui
compare deux plans ne s'exerce pas sur un seul.
> **À noter comme NON OBSERVÉ, jamais comme validé.** Un silence de la garde signifie ici « rien
> à comparer », pas « les plans sont alignés ». Les deux produisent exactement la même trace :
> aucune ligne.
C'est le mode d'érosion de l'instrument dont le silence ressemble à un résultat, dans sa forme la
plus banale — et il aurait été facile de conclure de travers, puisque le résultat attendu et
l'absence de mesure ont la même apparence.
**Ce qu'il faudra pour l'observer** : deux plans réels et durables sur un site, ou une fenêtre
d'observation pendant laquelle un second plan existe. Le seul relevé exploitable à ce jour reste
celui de 08:08 — deux plans, même `issuedAt`, même `t0`, somme correcte — et il a été obtenu par
le chemin **forcé**, pas par la boucle horaire naturelle.

View File

@ -7038,6 +7038,15 @@ void Simulation::testEveryGetterReturnsWhatItDeclares()
{ QStringLiteral("NymeaEnergy.GetPvForecast"),
{{"from", "2026-09-09T00:00:00Z"}, {"to", "2026-09-10T23:00:00Z"}} },
};
// LES OPTIONNELS AUSSI, et c'est une classe à part : aucun appel nominal ne les utilise,
// donc leur disparition ne casse rien de visible. Ce qui n'est jamais exercé n'est pas
// « peu testé » — c'est indistinguable d'absent, alors qu'un client les lit dans
// l'introspection et les croit disponibles.
const QHash<QString, QVariantMap> optionnels {
{ QStringLiteral("NymeaEnergy.GetPvForecast"),
{{"from", "2026-09-09T00:00:00Z"}, {"to", "2026-09-10T23:00:00Z"},
{"knownAt", "2026-09-09T12:00:00Z"}} },
};
int verifies = 0;
QStringList muettes;
@ -7086,6 +7095,16 @@ void Simulation::testEveryGetterReturnsWhatItDeclares()
}
}
// SECOND PASSAGE : les mêmes méthodes, avec leurs paramètres OPTIONNELS renseignés. Un
// optionnel supprimé de la déclaration ferait ici « Invalid params », comme les requis.
for (auto it = optionnels.constBegin(); it != optionnels.constEnd(); ++it) {
const QVariantMap brut = injectAndWait(it.key(), it.value()).toMap();
if (brut.value(QStringLiteral("status")).toString() != QLatin1String("success"))
muettes << QStringLiteral("%1 (avec optionnels) → statut « %2 » (%3)")
.arg(it.key(), brut.value(QStringLiteral("status")).toString(),
brut.value(QStringLiteral("error")).toString());
}
QVERIFY2(verifies >= 5,
qUtf8Printable(QStringLiteral("seulement %1 getter(s) parcouru(s) — le balayage "
"ne prouve rien s'il ne balaie rien").arg(verifies)));