Aller au contenu

Un témoin se prouve par mutation, et la mutation est mécanique

StatutEn vigueur, 2026-08-26
ArticleA2 · Un garde est vu rouge sur sa propre mutation
Chantier#4490 (passe 9 de la clôture de #4462)
Vérification certainescripts/adr/verifie_temoins_non_decoratifs.py

Ce qui fait foi aujourd'hui

Complétée le 2026-09-29 par ADR 5572 : sa mutation reste le dispositif de l'article A2 ; la 5572 la relie aux six autres décisions du même défaut, et dit où un verdict se remesure quand aucune mutation ne le couvre.

Amendée le 2026-09-05 par ADR 5257, et l'amendement n'était écrit que de son côté jusqu'à la clôture de #5265. Deux phrases de cette page ne font plus foi. « Exige qu'elle rougisse. Tolérance zéro » : un rouge par plantage ne prouve rien, donc le banc rend trois comptes, tient, non concluant, décoratif, et la tolérance zéro ne porte que sur le dernier. « Un faux positif est bruyant » : mesuré à l'inverse en #5254, un verdict « décoratif » rendu à tort se lit comme une trouvaille et non comme une panne d'outil.

Complétée le 2026-10-06 par ADR 5265 : ce banc n'est plus seul, et ce que les trois ont en commun est ce qu'ils rendent. Sa neutralisation par insertion lit le point d'entrée dans l'arbre depuis #5263, et les gardes qui plantent sous mutation sont nommés dans une table depuis #5743.

Contexte

verifie_scripts.py clôt sur une phrase : « les N scripts chargés détectent leur violation témoin ». Elle affirme davantage que ce que la suite vérifie. Un témoin peut exister, s'exécuter, passer, et ne rien tenir.

Celui du cliquet de longueur d'ADR n'affirmait que isinstance(suspects(), list). Un garde qui aurait cessé de détecter le passait. Le défaut a vécu jusqu'à ce qu'une passe de clôture aille le chercher à la main, et c'est le faux vert que le dépôt refuse partout ailleurs, installé dans le dispositif même qui le refuse.

L'article A2 dit déjà le geste : un garde est vu rouge sur sa propre mutation, et la mutation se refait après toute réécriture. Ce qui manquait n'est pas la règle, c'est qu'elle reposait sur la discipline, et la discipline lâche exactement quand ça va vite.

Décision

La mutation devient mécanique. Pour chaque garde chargée par verifie_scripts.py, verifie_temoins_non_decoratifs.py neutralise ses fonctions de détection, relance la suite, et exige qu'elle rougisse. Tolérance zéro.

La liste se dérive, elle ne s'écrit pas. Les gardes viennent des appels _charge("...") de la suite. Un glob vieillit, et un garde neuf passerait au travers : c'est précisément le défaut que ce script existe pour attraper, et il serait cocasse de l'y poser.

Le sens de la panne est le bon. Si la neutralisation cessait de fonctionner, le garde continuerait de détecter, la suite resterait verte, et le script crierait « témoin décoratif » à tort. Un faux positif est bruyant ; c'est le silence qu'il fallait éviter.

Conséquences

  • Le coût est mesuré, et il a grossi : au 2026-09-01, verifie_scripts.py s'exécute en 132 s et 29 gardes se mutent en 105 s, contre 0,05 s et 23 gardes en 1,2 s à la décision. Le harnais a pris son temps le jour où un cas de couture s'est mis à appeler rapport.collecter(), qui lance tous les gardes ; le corpus, lui, grandit à chaque garde que la suite charge. Rien ne justifie pour autant de refaire ce balayage à la main : c'est trois minutes de machine contre une relecture que personne ne tiendra.
  • Un témoin nouveau est éprouvé dès sa PR, et non à la clôture suivante.
  • L'auto-test du garde prouve le mécanisme dans les deux sens : qu'un témoin solide fait bien rougir la suite sous mutation, et que sans mutation la suite est verte. Sans le second, un script qui répondrait toujours « tout va bien » passerait le premier.

Révision du 2026-09-28 : le préfixe ne distinguait pas la machinerie de la détection

La décision tient, sa mécanique change. « La mutation ne remplace que les fonctions de module non préfixées » définissait une cécité, et en cachait une seconde : un nom ne dit pas si une fonction est de la machinerie ou de la détection. Une détection nommée _completude ou _forge par convention d'interne était hors d'atteinte, et son garde passait pour éprouvé ou décoratif sans que rien de vrai n'ait été mesuré. Le motif « auto » + « test » des deux autres bancs épargnait de même quatre détections.

L'exemption se dérive désormais du graphe d'appel : est machinerie ce que seul le point d'entrée d'auto-test atteint. Le préfixe n'est conservé que comme filtre, ce qui rend le changement monotone.

Mesuré : 119 fonctions entrent dans la portée de la mutation, et verifie_scripts.py sort de la liste ci-dessous, sa détection étant enfin atteinte. Issue #5524.

La cécité déclarée

La mutation ne remplace que les fonctions de module que l'exemption dérivée ci-dessus ne protège pas. Un témoin qui n'éprouverait qu'une constante, une expression régulière ou une classe y survit sans être décoratif pour autant. Le garde ne prononce donc rien sur ceux-là, et il nomme ses exemptions une par une plutôt que de les taire :

Script Ce que son témoin éprouve réellement
resserre_cliquets.py une expression régulière, et la présence d'une fonction plutôt que son effet

Cette liste est la dette de la décision, pas son angle mort : elle est écrite, donc elle se relit.

Alternatives écartées

  • Interdire les témoins structurels. Certains sont légitimes : tenir un corpus, ou la présence d'une passe, se dit structurellement. C'est de les confondre avec une preuve de détection qui trompe.
  • Un glob sur scripts/adr/*.py. Il aurait couvert des scripts sans témoin, que la suite ne charge pas, et rendu du bruit là où le garde doit rendre une liste courte et vraie.
  • Refaire le balayage à chaque clôture. C'est ce qui a été fait une fois, et ce qui a trouvé le défaut. Ce n'est pas ce qui l'aurait empêché.