From 002d1ef40bddf2620c3960b8a26b6c72604f941b Mon Sep 17 00:00:00 2001 From: Patrick Schurig Date: Sun, 30 Aug 2026 09:17:12 +0200 Subject: [PATCH] =?UTF-8?q?test:=20l'absence=20de=20`draw.authorisedW`=20e?= =?UTF-8?q?st=20=C3=89PINGL=C3=89E,=20plus=20seulement=20=C3=A9crite?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit « C'est le genre de champ qu'on ajoute pour compléter, six mois plus tard, sans se rappeler pourquoi il manquait. » — et un contrat ne fait échouer aucune compilation. L'absence était défendue en prose dans INTERFACE.md, dans le changelog et dans un commentaire de code : trois endroits qui n'arrêtent personne. testLoadTelemetryRpc épingle désormais la FORME de `draw` : exactement une clé, `committedW`. Les quatre du §14a — authorisedW, remainingW, binding, perPhaseBound — sont absents, et leur ajout casse le test avec la raison. VÉRIFIÉ EN L'AJOUTANT : `draw.insert("authorisedW", 0.0)` « pour compléter l'objet » fait échouer le test — 2 clés au lieu d'1. C'est la contre-épreuve qui compte ici : un test d'absence qui ne casserait pas sur l'ajout ne protégerait rien. Le commentaire dit quoi faire quand il casse, parce que le premier réflexe devant un test rouge est de corriger le test : ce n'est pas lui qu'il faut changer, c'est le champ ajouté qui doit arriver AVEC son transport §14a et une valeur vraie — jamais à zéro. Un `authorisedW: 0` assorti d'un `binding` par défaut afficherait un plafond de soutirage qui n'existe pas, avec sa source. Épinglé aussi en mode dégradé : `draw` y est absent comme `budget`, pour la même raison — sans plan, il n'y a pas de soutirage DÉCIDÉ, et un `committedW: 0` s'y lirait « ce cycle n'a rien acheté » alors qu'il n'y a pas eu de cycle. Aucun changement de comportement. simulation 33/33. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_015F7G5VeaPVSMeVNjiGj36p --- tests/auto/simulation/simulation.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/auto/simulation/simulation.cpp b/tests/auto/simulation/simulation.cpp index 4caaa0f..d995460 100644 --- a/tests/auto/simulation/simulation.cpp +++ b/tests/auto/simulation/simulation.cpp @@ -4285,6 +4285,20 @@ void Simulation::testLoadTelemetryRpc() QCOMPARE(qRound(budget.value("evReservedW").toDouble()), 0); QCOMPARE(qRound(budget.value("allocatedW").toDouble()), 5600); QCOMPARE(qRound(budget.value("remainingW").toDouble()), 1400); + // ---- L'ABSENCE de `draw` se défend, parce que rien ne casse quand on la comble ----------- + // + // `draw` ne porte qu'un champ : `committedW`. Les quatre autres du §14a — authorisedW, + // remainingW, binding, perPhaseBound — sont ABSENTS, jamais à 0. Le contrat le dit, mais un + // contrat ne fait échouer aucune compilation : le jour où quelqu'un ajoutera `authorisedW: + // 0` « pour compléter l'objet », six mois plus tard, rien ne le retiendra — et l'app + // affichera un plafond de soutirage qui n'existe pas, avec sa source, faute d'avoir un + // moyen de distinguer « pas de plafond » de « plafond nul ». + // + // Ce test est ce moyen. S'il casse, ce n'est pas lui qu'il faut corriger : c'est le champ + // ajouté qui doit arriver AVEC son transport §14a et une valeur vraie, pas à zéro. + const QVariantMap draw = notif.value("draw").toMap(); + QCOMPARE(draw.keys(), QStringList{QStringLiteral("committedW")}); + // Le relais tire déjà ses 1000 W depuis le cycle précédent : ils lui sont RECRÉDITÉS avant // arrondi (anti-clignotement). Sans ce terme publié, l'identité serait fausse ici même. QCOMPARE(qRound(budget.value("recreditedW").toDouble()), 1000); @@ -4442,6 +4456,10 @@ void Simulation::testLoadTelemetryRpc() // budget ABSENT : la planification est suspendue, il n'y a pas de budget pour ce cycle. // Publier des zéros se lirait « arbitrage exécuté, rien à allouer » — l'inverse du vrai. QVERIFY2(!dgr.contains("budget"), "budget publié en mode dégradé (planification suspendue)"); + // Et `draw` avec lui, pour la même raison : sans plan, il n'y a pas de soutirage DÉCIDÉ. + // Un `committedW: 0` s'y lirait « ce cycle n'a rien acheté », alors qu'il n'y a pas eu de + // cycle du tout. + QVERIFY2(!dgr.contains("draw"), "draw publié en mode dégradé (aucun soutirage décidé)"); QVERIFY(!dgr.value("loads").toList().isEmpty()); QVariantMap dgrParId; for (const QVariant &v : dgr.value("loads").toList()) {