Six appels à `update(QDateTime::currentDateTime())` manquaient la garde
ENERGY_SIMULATION que leurs voisins ont (l.124, l.288) :
setPhasePowerLimit, setAcquisitionTolerance, et trois dans
onActionExecuted — qui partent sur toute action manuelle appliquée à une
borne.
Un cycle d'arbitrage complet partait donc à l'horloge MURALE au milieu
d'une suite qui injecte un temps simulé. Les deux horloges se mélangeaient
dans les verrous : l'armement paresseux (ECS-412) figeait m_lastSwitch sur
l'heure qu'il était, et un scénario daté en dur se déroulait « avant » son
propre armement — elapsed négatif, verrou jamais ouvert.
Ce n'est pas un défaut de production : il n'y a là-bas qu'une seule horloge.
C'est une faille de REPRODUCTIBILITÉ, et elle touchait tout test de
simulation réglant une limite de phase, une tolérance d'acquisition, ou
exécutant une action manuelle sur une borne.
PREUVE DU CORRECTIF : la garde rendue, testL4ShedsAPacAndSaysItForcedTheLock
repasse avec une DATE FIXE, trois fois sur trois — ce qu'il ne pouvait pas
faire. L'ancrage sur l'horloge réelle, posé la veille faute d'avoir la
cause, était un contournement ; il est retiré, et la date fixe revient parce
qu'elle rend les journaux reproductibles.
tools/check-simulation-clock.py, câblé en 4/4 de ci-quality.sh, et vérifié
mordant : garde retirée, il nomme la ligne exacte. Il a trouvé trois des six
déclencheurs dès son premier passage.
Pourquoi une vérification STATIQUE et pas un test : la suite ne peut pas
dire d'elle-même que son verdict dépend de l'heure, puisque c'est le verdict
qui ment. Le défaut n'a été trouvé que parce qu'il échouait cinq fois sur
cinq à code identique — une fenêtre de nuisance plus étroite ne basculerait
qu'une fois sur vingt, passerait pour une fragilité de temporisation, et
serait relancée jusqu'à ce qu'elle passe. C'est la famille de la semaine
sous une forme de plus : après l'instrument dont le silence ressemble à un
résultat, l'instrument dont le VERDICT ment selon l'heure.
Suite complète : simulation 54/54, charging 48/48 identique à la référence
ligne à ligne, loadmodel 21/21, spotmarket 32/32, doxygen 0 avertissement.
Aucun test ne dépendait de ces cycles.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015F7G5VeaPVSMeVNjiGj36p
Étape 4 du chantier de documentation. tools/ci-quality.sh porte les trois
vérifications qui se posent au même endroit — elles partagent la même sortie
(doc-generated/) et la même commande de réparation, les séparer ferait trois jobs
qui régénèrent trois fois la même chose :
1. l'index des règles est VRAI (code de retour de gen-rules.py) ;
2. la doc Doxygen est complète — 0 avertissement, DoD §5 ;
3. l'index est REPRODUCTIBLE : deux passes, un seul résultat.
PAS EN SERVICE, et l'extension le garantit : ci/gitea-workflow.yml.disabled ne
déclenche rien tant qu'il n'est pas déplacé dans .gitea/workflows/. La raison est
datée dans le fichier — forge muette, plus de trente commits en attente ici et
plus de soixante côté app ; un job activé à l'aveugle échouerait au moment précis
où tout le monde pousse, et le premier réflexe serait de le désactiver.
CHAQUE ÉCHEC DONNE LA COMMANDE À LANCER. Un job qui annonce « l'index est
périmé » sans dire quoi faire se contourne en le désactivant : c'est le chemin de
moindre effort, et il gagne toujours.
VÉRIFIÉ AVANT D'ÊTRE DÉCLARÉ PRÊT, et ça ne passait pas du premier coup.
— Les 26 avertissements Doxygen de ce matin sont CORRIGÉS, pas contournés par un
cliquet sur un compte de référence : c'était de la dette DoD-5 (retours et
paramètres non documentés dans relayrouter.h, energyarbitrator.h, loadconfig.h,
les trois clearFault(), ILoadAdapter::updateSoftConfig), plus deux que j'avais
introduits — un \rule{} dans un titre \par, et un \param energyLogs qui ne
correspond à aucun argument. Le seuil est donc ZÉRO, le seul qui ne rote pas.
— Et le script lui-même échouait sur un dépôt SAIN : `grep -c ... || echo 0`
affiche 0 PUIS sort en 1 quand il ne trouve rien, si bien que le « || » empile
un second zéro et que le test entier casse. Corrigé ici et dans gen-doc.sh, qui
portait le même piège. Une commande de mesure dont l'échec produit une lecture
fausse — le motif de la semaine, appliqué à l'outil.
CE QUI N'EST PAS VÉRIFIÉ, et pourquoi : « régénérer et refuser si ça diffère de
ce qui est commité » n'a rien à comparer, doc-generated/ étant dans .gitignore.
Le risque qu'un tel diff attraperait — un artefact commité qui dérive de sa
source — a été SUPPRIMÉ en ne le commitant pas, pas déplacé. Ce qui reste à
garantir est que l'index soit vrai (contrôle 1) et déterministe (contrôle 3).
État au 2026-08-29 : ./tools/ci-quality.sh → RC=0, 113 règles, 0 avertissement.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015F7G5VeaPVSMeVNjiGj36p