Aller au contenu

Blog ·

Une exécution qui affichait son échec

La vérification écrivait chaque code de sortie dans un résumé puis DONE quoi qu’il arrive. Une version est partie sur une ligne rouge que personne n’a lue.

Par Provibr

Avant une mise en production, nous exécutons un seul script. Il lance la suite de tests web, les suites des paquets, de la passerelle et des outils, dix contrôles de types, le lint, le contrôle du contenu, le lint du protocole et la génération de code du protocole, et il écrit une ligne par étape dans un fichier de résumé : le nom de l’étape et son code de sortie. Puis il écrit DONE.

Il écrivait DONE même quand certains de ces codes de sortie n’étaient pas zéro.

Le sept septembre, une version est partie alors que le résumé contenait une ligne indiquant bun test packages/gateway/tools exit 1. J’avais lu les compteurs de réussite et d’échec de deux suites et pas de la troisième. Rien n’a cassé : le test en échec était une garde sur les en-têtes des scripts de mesure, le produit n’a donc pas été touché et le client n’a jamais rien vu. Le résultat était bon et la forme était mauvaise, et la forme est la seule partie qui mérite d’être notée.

Les compteurs ne sont pas la barrière

Ce qui rend cela gênant plutôt que simplement malchanceux, c’est que ce mode de défaillance porte un nom dans nos propres notes, et ce nom est vert par vacuité : un contrôle qui n’est relié à aucune décision n’est pas lu, et un contrôle lu à l’œil est lu comme lit une personne, c’est-à-dire en cherchant ce qu’elle s’attend à voir.

Le résumé était conçu pour être parcouru. Chaque suite imprime ses propres totaux quelque part au-dessus, si bien que le mouvement naturel est de regarder « 4515 pass, 0 fail » et de se sentir quitte. Les codes de sortie se trouvaient un écran plus bas, dans un fichier dont la dernière ligne disait DONE.

Le remède fait quatre mots de shell. Après toutes les étapes, le script cherche dans son propre résumé un code de sortie compris entre un et neuf, et s’il en trouve un il ajoute une ligne commençant par FAIL:. La règle qui l’accompagne est qu’un DONE sans FAIL est la barrière, et que les compteurs n’en sont pas une. La seconde moitié de cette règle compte plus que la première : quelqu’un qui dispose d’un signal juste et bon marché cessera de bâtir des habitudes coûteuses autour d’un signal peu fiable.

Il existe une règle compagne : une commande de déploiement ne partage jamais une chaîne de shell avec une vérification qui se contente d’afficher. Si la vérification ne peut pas faire échouer la chaîne, c’est de la documentation.

Ce qui était réellement rouge

La garde qui a échoué appartient à une famille, et elle mérite une description car elle est étonnamment bon marché pour ce qu’elle rapporte.

Le répertoire de la passerelle abrite les scripts de mesure : balayages par navigateur, sondes de mise en page, outils de semis et de nettoyage, tout ce qu’une ronde écrit pour prouver quelque chose et laisse ensuite derrière elle. Il y en a un peu plus de cinq cents aujourd’hui. Ce sont des scripts simples sans contrôle de types, ce qui veut dire que la seule chose qui les sépare du pourrissement est que quelqu’un en exécute un par hasard.

Quatre tamis passent sur l’ensemble dans une suite de tests normale :

  1. Chaque script s’analyse, avec le moteur d’exécution qui le fait vraiment tourner.
  2. Chaque import relatif pointe vers un fichier qui existe. C’est la forme de mort qu’un analyseur ne voit pas : le script est syntaxiquement parfait et s’effondre à la première ligne quand vous le lancez.
  3. Chaque script porte un en-tête avec de la prose dedans. Sans explication, un outil vieux de quatre rondes est indiscernable d’un outil qui compte encore.
  4. Chaque en-tête nomme la ronde dont il vient, sous l’une de deux formes fixes exactement.

C’est le quatrième qui était rouge. Trois scripts de la ronde de documentation avaient des en-têtes, de bons en-têtes, et pas de marqueur de ronde. Voilà tout l’incident : une convention de nommage, attrapée par une garde qui existe pour que cinq cents scripts restent lisibles, posée dans une ligne de résumé que personne n’a lue.

Pourquoi « inconnue » doit coûter une empreinte de commit

Le quatrième tamis accepte deux formes et rien d’autre. Soit l’en-tête donne le nom de la ronde avec une date et l’origine de cette attribution, soit il dit que la ronde est inconnue et porte l’empreinte du premier commit du fichier, avec une date.

Le nom n’a explicitement pas le droit d’être le mot « inconnue ». Sans cette exclusion, « ronde inconnue, 2026-09-04 » est un nom-avec-une-date parfaitement valide, et la branche coûteuse peut être évitée d’un mot. En l’état, avouer que vous ne savez pas vous coûte une empreinte que quelqu’un doit aller chercher, et le temps qu’il l’ait cherchée, il connaît en général la ronde.

La date est obligatoire pour une autre raison. Un nom seul est de la prose, pas un marqueur : une phrase comme « la ronde qui a aussi touché au travail sur les en-têtes » contient un nom de ronde et n’affirme rien sur le fichier où elle se trouve. Avec une date accrochée, elle devient une affirmation sur ce script, faite un jour donné, ce qui est la plus petite chose sur laquelle on puisse tenir quelqu’un.

Une barrière doit pouvoir être à zéro

La question évidente à propos de cinq cents scripts non typés est de savoir pourquoi nous ne les contrôlons pas. Nous l’avons mesuré, et la réponse est instructive.

La configuration existe. C’est un instrument et non une barrière, et elle ne tourne pas dans le script de vérification. Mesuré sur les scripts tels qu’ils étaient :

ConfigurationErreurs
Avec les réglages stricts de cet espace de travail3180
Sans le mode strict398
Sans le mode strict, après avoir rendu typable un fichier partagé159

Une barrière doit se tenir à zéro, et ces 159 restantes ne sont pour la plupart pas des défauts. Deux familles ont été parcourues et toutes deux se sont révélées être des artefacts du typage de code non typé : un paramètre sans valeur par défaut qui tombe de la forme inférée, et une boucle de déstructuration sur un tableau mixte qui s’élargit en une union. Vingt-sept d’entre elles sont un seul et même diagnostic, à propos de l’import d’un fichier TypeScript depuis un script qui tourne sous un chargeur qui le gère parfaitement.

Ce que l’instrument a rapporté, c’est le passage de 398 à 159. Une seule ligne dans un utilitaire de navigateur partagé, un constructeur qui affecte ses arguments en bloc sur l’instance, maintenait 239 erreurs en vie, car chaque accès à une propriété de cet objet, dans chaque script, était impossible à résoudre. Une réparation, 239 erreurs disparues. C’est un bon rendement pour une mesure qui a le droit d’être non nulle, et c’est exactement le rendement que l’on n’obtient pas d’une barrière, car une barrière que l’on ne peut pas satisfaire finit éteinte.

Le contrôle qui mesurait son propre moteur d’exécution

Faire marcher le contrôle d’analyse a demandé deux tentatives, toutes deux ratées d’une manière qui ressemblait à des problèmes de produit.

La première version demandait au moteur d’exécution courant de vérifier chaque fichier. Sous notre lanceur de tests, le moteur courant n’est pas celui sous lequel tournent les scripts, et son drapeau de vérification veut dire tout autre chose. Le résultat a été 301 signalements de fichiers syntaxiquement cassés, avec des lignes de source citées en guise de texte d’erreur. Tous allaient très bien.

La deuxième version nommait explicitement le bon moteur et échouait quand même, autrement : le lanceur de tests récolte les processus enfants appartenant à un test, et à partir de la moitié de la liste environ, chaque appel revenait avec un statut nul. Tué par un signal, pas une erreur d’analyse. Une garde qui passe au rouge au hasard n’est pas une garde.

La version qui marche lance un seul processus enfant qui vérifie lui-même les fichiers, huit à la fois, en environ neuf dixièmes de seconde au moment de la mesure. Ce qui est affirmé n’a pas changé : le moteur qui fait tourner ces scripts va-t-il les accepter.

Le parallélisme n’est pas non plus un confort. En série, le contrôle dépassait la limite de temps par test, et une garde qui expire se lit comme une garde cassée plutôt que comme une garde lente.

La borne inférieure que personne ne demande

Il y a dans ce fichier un cinquième test qui affirme seulement qu’il y a plus de cinquante scripts à vérifier.

Un parcours de répertoire qui ne trouve rien rend trivialement vraie chaque affirmation qui le suit. Renommez le répertoire, changez le filtre d’extension, cassez le parcours, et quatre tamis verts rendent compte d’une liste vide. La borne inférieure est délibérément très en dessous du nombre réel, car le but n’est pas d’empêcher le nettoyage ; il est de rendre visible la différence entre « rien ne va mal » et « rien n’a été examiné ».

Le même fichier de test est honnête sur ses limites, et cette honnêteté fait partie de la conception. Aucun des quatre tamis ne prouve qu’un script mesure encore ce qu’il prétend. Un sélecteur qui n’existe plus, une route qui a bougé, une colonne qui a été supprimée : les quatre contrôles passent. C’est un plancher, pas un contrôle de types, et le dire dans le fichier empêche la personne suivante de prendre une exécution verte pour plus qu’elle n’est.

Ce que nous noterions

  1. Une vérification qui se contente d’afficher n’est pas une barrière. Elle doit pouvoir faire échouer ce qui vient après elle.
  2. Écrivez la ligne d’échec, pas seulement les codes de sortie. La barrière est un mot que l’on peut chercher, à un endroit fixe, pas un nombre qu’il faut remarquer.
  3. N’enchaînez jamais un déploiement derrière un contrôle qui ne peut pas l’arrêter. La chaîne est la promesse.
  4. Les compteurs sont un résumé, pas un verdict. Les gens lisent le nombre qu’ils s’attendent à voir.
  5. Une barrière doit pouvoir se tenir à zéro. Si une mesure ne le peut pas, gardez-la comme instrument et dites-le, sinon elle sera désactivée puis oubliée.
  6. Rendez coûteuse l’échappatoire bon marché d’une règle. Si avouer son ignorance tient en un mot, tout le monde écrit le mot.
  7. Un contrôle qui échoue au hasard n’est pas un contrôle. Courez après l’instabilité avant de faire confiance au signal.
  8. Affirmez une borne inférieure sur ce que le parcours a trouvé. Quatre contrôles verts sur une liste vide ressemblent exactement à quatre contrôles verts.

Pour être clair : la ligne d’échec est dans le script qui se trouve dans le dépôt, et elle a depuis tourné sur des fusions qui étaient vertes. Elle n’a pas encore été prouvée par une exécution rouge en usage réel, seulement par le résumé contre lequel elle a été écrite. Les chiffres de typage viennent d’une mesure faite un jour donné et le nombre de fichiers bouge chaque nuit.

Issu du travail de plateforme sur Provibr. Une autre garde qui a dû prouver son propre zéro est dans une exception d’accessibilité qui se mesure, et un champ qui portait discrètement une intention au lieu d’un fait est dans une date future n’est pas un calendrier.

Commencez avec un hôte et un agent

Créez un compte, installez l’agent avec une seule commande et connectez votre premier hôte Proxmox. La période d’essai dure 14 jours et ne demande aucune coordonnée de paiement.