17 septembre 2026
en cours
en cours
Ce qui se repetait, ce qui se taisait, et ce qui mentait
- L’audit repetait les memes 61 pages, et le disait autrement.Un passage explore soixante pages, plus l’accueil. Le code affirmait — et l’ecran l’affichait — que les autres « passeront aux prochains audits ». C’etait faux : la file repartait de la tete du sitemap a chaque fois. Mesure sur un site de 1 279 adresses : deux audits consecutifs, 61 pages chacun, **61 en commun sur 61**. Les 1 218 autres n’avaient jamais ete vues et ne l’auraient jamais ete. Chaque passage est desormais coupe en deux : la moitie pour relire les pages qui avaient un defaut — une page reparee est donc revue au passage suivant, et non au vingtieme — l’autre moitie pour decouvrir. Verifie apres deploiement : 28 pages en commun au lieu de 61, et 154 adresses distinctes vues au lieu de 61.
- Un sitemap declare ailleurs est un sitemap.Un site declarait le sien sur une fonction hebergee chez un tiers. On ecartait tout sitemap qui n’etait pas sur le domaine audite : on sautait donc le seul sitemap du site, puis on concluait « aucun sitemap trouve, ni declare dans le robots.txt » — a cote d’un autre constat qui disait « ton robots.txt declare un sitemap ». Deux verdicts contraires sur le meme ecran, et c’est celui qui accuse qu’on croit. Declarer un sitemap dans son robots.txt EST l’autorisation de le lire la ou il est. Et quand rien n’est declare, on essaie aussi `sitemap_index.xml` et `wp-sitemap.xml`, que posent les deux outils les plus installes du web.
- La passe de preuve sondait plus de domaines que sa borne.Un test tombait une fois sur trois, jamais seul. On l’a reecrit trois fois en accusant l’ordre des fichiers, puis la portee de l’assertion. Le symptome n’avait pourtant jamais bouge : trois lignes rendues pour une borne a deux. La sous-requete d’un `IN` peut etre **re-executee** par PostgreSQL, une fois par ligne examinee ; chaque re-execution applique bien la borne, mais pas sur les memes lignes, parce que l’ordre laissait des ex aequo. La correction tient en deux parties dont aucune ne suffit : une CTE `MATERIALIZED`, et un tri qui ferme les ex aequo. Ce que ca protegeait : cette passe sonde des serveurs qui ne sont pas les notres, et depasser sa borne c’est frapper plus fort que promis chez quelqu’un d’autre.
- Bloquer un robot qui cite et un robot qui entraine n’est plus la meme nouvelle.Un utilisateur a mesure, sur son site, que deux robots d’entrainement recevaient un 403 de son CDN pendant que les quatre robots de citation passaient. Notre audit annoncait « serieux » — et l’urgence n’existait pas : il ne perdait aucune citation ce jour-la, il perdait sa presence dans les corpus des prochains modeles. « Nous avons failli courir », a-t-il ecrit. Une alerte qui fait courir pour rien apprend a ne plus courir, et c’est celle d’apres qui se paie. Citer refuse reste serieux ; entrainer seul refuse devient une attention, avec le moyen de la faire taire si c’est un choix. On sonde cinq robots au lieu de trois, dont trois qui citent : sans eux, la distinction n’etait pas mesurable.
- Une tache qui n’a jamais demarre se signale. Une fois.Depuis qu’une tache surveillee n’alerte plus tant qu’aucun battement n’est arrive, en creer huit d’un coup ne coute plus une alerte. Mais un cablage faux la laissait en attente **pour toujours**, dans un silence parfaitement paisible : le module dont le metier est de detecter le silence etait le seul a ne pas voir celui-la. C’est l’utilisateur qui l’a vu, pas nous. Trois echeances manquees sans le moindre battement, et un message au libelle distinct — « n’a jamais demarre », pas « ne donne plus signe de vie ». Ce ne sont pas les memes nouvelles : l’une fait relire les journaux du serveur, l’autre la cle de battement.
- Un essai a blanc pour eprouver un cablage sans laisser de trace.`?essai=1` sur l’adresse de battement repond exactement comme un vrai battement — 200, 404, 429 — et n’ecrit rien. Le mode « execute » avait son essai depuis longtemps ; « monitor », qui demande pourtant le plus de cablage, n’avait rien. Un utilisateur a donc fait la seule chose possible : pinguer une tache en pause. Nous l’avons armee, et son essai a laisse dans l’historique une ligne qui ressemble a une vraie execution.
- Sortir de pause recalcule l’echeance.Elle restait figee a sa valeur du moment de la mise en pause. Mesure par un utilisateur : une tache horaire relancee a 14 h 12 annoncait encore une prochaine execution a 8 h 07, six heures et demie dans le passe. En mode « execute » le worker rattrape ; en « monitor » personne ne rattrape, et c’est nous qui comparons une heure attendue a une heure reelle. Le module dont le metier est de juger un retard se trompait de reference.
- L’audit passe de neuf secondes a deux et demie.Soixante et une pages lues l’une apres l’autre font neuf secondes, pendant lesquelles le bouton ne repond pas et on reclique. Quatre pages a la fois, pas quarante : on lit le site de quelqu’un d’autre, et soixante requetes simultanees sur un mutualise peuvent le faire tomber — on serait alors la panne qu’on pretend mesurer. Et tous les boutons du produit portent desormais un disque de chargement, en six lignes de JavaScript qui se dégradent proprement : sans lui, il ne se passe rien de plus qu’avant.
- LeTock mesure enfin sa propre machine.Il surveillait les serveurs de ses clients et pas le sien. L’ecran d’exploitation repondait a « quand faudra-t-il grandir » par un calcul de cout — exact, et dans une unite qui n’est pas celle de la question : on ne sait pas si cinq euros de volume font transpirer deux coeurs. Charge, memoire, disque et taille de base sont relevees **chaque seconde** et gardees chaque minute, en gardant le maximum et non la valeur de l’instant, qui raterait un pic de trois secondes. Trois fenetres, trois questions : une heure a la seconde pour la forme d’un pic, vingt-quatre heures a la minute pour savoir a quelle heure ca travaille, sept jours a l’heure pour savoir si ca monte.
- La jauge « la plus pleine » n’en designait aucune.La tuile annoncait « runs d’agents — 1 % du quota » quand la plus pleine etait « audits de pages — 5 % ». Deux defauts empiles, dont le premier est invisible a la lecture : `compte::text AS compte … ORDER BY compte` fait trier PostgreSQL sur le **texte**, parce qu’un nom d’ORDER BY se resout sur les alias de sortie avant les colonnes. En ordre lexicographique, « 93 » passe devant « 2310 ». Et meme trie juste, « le plus gros compte » n’est pas « la plus pleine jauge » : les plafonds varient d’un facteur cent d’un poste a l’autre.
- L’exploitation prend les formes des stats.Elle posait ses chiffres en liste et ses trente jours en barres, pendant que le module Stats — qui repond aux memes questions sur un site au lieu de tous — avait un bandeau de tete, une courbe d’aire, un anneau et un tableau trie. Deux grammaires visuelles pour une seule idee : savoir lire un ecran n’aidait pas a lire l’autre. La jauge de quota n’utilise volontairement pas le composant Jauge : il colore en vert ce qui approche de cent pour cent, parce qu’il a ete ecrit pour des scores — et un quota a 91 % est l’inverse d’une bonne nouvelle.
- Le site parle anglais.Le francais reste a la racine, l’anglais vit sous `/en` : aucun lien existant ne casse, aucune redirection, aucun classement perdu. Le francais est la **langue de reference** et non une traduction — son catalogue definit le type, et toute autre langue doit le satisfaire, donc une cle oubliee est une erreur de compilation qui nomme le fichier, pas un trou a l’ecran decouvert par un visiteur. Chaque page porte son canonique dans sa langue et les liens vers les autres ; sans eux, un moteur voit deux adresses voisines, en choisit une, et l’autre disparait.
- Un selecteur, un domicile.Onze selecteurs de la feuille de style etaient declares deux fois au meme niveau. La seconde gagne, et personne ne le sait en lisant la premiere : on lisait « cette liste est une rangee » et l’element etait une grille, parce que quatre mille lignes plus bas quelqu’un avait reecrit la regle. Du code mort qui a l’air vivant est pire que du code mort — il repond a la question qu’on se pose, et il repond faux. Et quatre classes d’evolution — « +18 % », « −12 % », « = », « nouveau » — n’avaient aucun style du tout.
Ce que ça change pour ton coderupture
- Un alias de chemin `@/` remplace 609 imports relatifs vers `src/`, qui vivaient a six profondeurs differentes. Sans lui, toute reorganisation se fait a l’arithmetique de « ../ » — exactement le genre de reecriture qui casse une ligne sur cinquante sans qu’aucun test ne le voie.
- Rupture. `POST /api/v1/taches` accepte `projet` — par nom, par domaine ou par identifiant — et `GET /api/v1/taches?projet=` filtre. Le champ etait accepte et jete en silence depuis des mois : la colonne existait, elle n’etait ecrite nulle part.
- La creation de tache rend `avertissements` : nuits de changement d’heure sautees ou doublees, mois sans declenchement, et le fuseau laisse implicite. `/api/v1/analyser` les calculait depuis toujours et la creation n’en disait rien — poser une tache sure demandait deux appels, dont un que personne ne fait.
- Le cout d’un audit passe de sept a neuf requetes : deux sondes d’identite de plus, pour distinguer les robots qui citent de ceux qui entrainent.
- La suite de tests refuse de tourner a deux exemplaires sur la meme base : un verrou consultatif le dit au lieu de laisser deux executions se vider les tables mutuellement. Mesure une fois le soupcon venu — 263 tests rouges a deux suites, 1703 verts seul.