From bb15465109e796e34a2839aae6b02a616b3955a6 Mon Sep 17 00:00:00 2001 From: Patrick Schurig Date: Wed, 9 Sep 2026 08:57:49 +0200 Subject: [PATCH] =?UTF-8?q?docs+test:=20le=20contr=C3=B4le=20qui=20dispara?= =?UTF-8?q?=C3=AEt=20avec=20ce=20qu'il=20surveille,=20et=20l'optionnel=20j?= =?UTF-8?q?amais=20exerc=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) Claude-Session: https://claude.ai/code/session_015F7G5VeaPVSMeVNjiGj36p --- docs/DESIGN_PREVISION_PV.md | 29 ++++++++++++++++++++++++++-- tests/auto/simulation/simulation.cpp | 19 ++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/docs/DESIGN_PREVISION_PV.md b/docs/DESIGN_PREVISION_PV.md index 01a441f..db4a056 100644 --- a/docs/DESIGN_PREVISION_PV.md +++ b/docs/DESIGN_PREVISION_PV.md @@ -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. diff --git a/tests/auto/simulation/simulation.cpp b/tests/auto/simulation/simulation.cpp index 97bbe5f..84af2dd 100644 --- a/tests/auto/simulation/simulation.cpp +++ b/tests/auto/simulation/simulation.cpp @@ -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 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)));