Blog ·
Une date future n’est pas un calendrier
Vingt-quatre articles en ligne affirmaient n’être pas encore parus. La solution n’a pas été un planificateur mais une compilation qui refuse ces dates.
Par Provibr
Chaque article de ce site porte une date de publication dans son en-tête. Elle s’affiche sous le titre, elle entre dans les données structurées que lit un moteur de recherche, et c’est la seule date que le plan du site imprime jamais. Elle est censée être un fait.
Pendant un temps, vingt-quatre d’entre elles ne l’étaient pas. Elles portaient des dates réparties sur les six jours suivants, parce que la personne qui les a écrites avait un rythme de publication en tête et l’a inscrit dans le fichier. Neuf langues chacune, soit deux cent seize fichiers. Chacune de ces pages était en ligne, explorable et indexée, et chacune racontait à un robot, sous forme lisible par machine, qu’elle était parue un jour qui n’avait pas encore eu lieu.
Rien n’était au rouge. La compilation était verte, les tests étaient verts, les pages s’affichaient. La seule chose capable de voir la contradiction était une machine lisant la page, et les machines ne déposent pas de rapports.
Ce que disait l’historique
La première chose à établir était laquelle des deux dates était vraie. Cela tient en une commande : demander à git quand chaque fichier a été ajouté pour la première fois. Les vingt-quatre ont été ajoutés le même jour, en trois livraisons, par trois séries du même travail de nuit. Il n’y a pas eu de déploiement sur six jours. L’étalement était une intention inscrite dans un champ réservé aux observations.
Cette distinction fait tout l’article. Un champ qui consigne ce qui s’est produit ne peut pas exprimer en plus ce que vous prévoyez, car un lecteur ne sait pas distinguer les deux, et un robot pas davantage.
Pourquoi le planificateur n’a pas été construit
La réparation évidente consiste à rendre les dates vraies en faisant respecter par le site : masquer un article jusqu’à ce que sa date arrive. C’est ici la mauvaise réparation pour deux raisons indépendantes, et il vaut la peine de détailler les deux car la première se rate facilement.
Ce site est généré statiquement. Les pages sont rendues une fois, pendant la compilation, et servies comme fichiers. Une porte sur la date est donc évaluée au moment de la compilation et plus jamais ensuite. À minuit, rien n’apparaît ; cela apparaît quand quelqu’un compile. Une porte de date ne produit donc pas un calendrier de publication, mais un ensemble de pages absentes jusqu’à ce qu’un déploiement sans rapport se produise par hasard.
La seconde raison est pire. Ces deux cent seize adresses étaient déjà explorées. Les masquer jusqu’à leur date nominale revient à servir une 404 pendant jusqu’à six jours sur des pages qu’un moteur de recherche a déjà vues et indexées. Une 404 sur une adresse déjà indexée n’est pas un « revenez plus tard », c’est un signal de retrait, et s’en remettre coûte bien davantage que l’inexactitude corrigée.
Les dates ont donc été corrigées vers le jour où le travail a réellement atterri, en ne touchant que cette ligne dans chacun des deux cent seize fichiers, et c’est la possibilité d’écrire une date future qui a été retirée à la place.
La porte est à la source et n’a pas d’échappatoire
La compilation de contenu refuse désormais toute date d’en-tête postérieure au jour où elle compile. Pas un avertissement : une compilation en échec, avec le nom du fichier et les deux dates dans le message.
Deux petites décisions à l’intérieur méritent d’être nommées. Elle compare avec le jour courant dans le fuseau horaire du projet et non avec UTC, car un article paru ici à minuit et demi porte la date d’ici, et une comparaison avec UTC rejetterait un fichier le jour même de sa parution. Et il n’y a volontairement aucune dérogation : pas de variable d’environnement, pas d’option. Une échappatoire sur une règle pareille sert une fois pour une bonne raison puis définitivement, et un calendrier appartient à une liste de tâches et non à l’en-tête d’un fichier déjà livré.
Une seconde porte existe plus loin, dans le registre qui assemble les articles publiés, et elle écarte tout article dont la date de publication est encore à venir. C’est un filet pour les chemins qui ne passent pas par la compilation : un fichier modifié à la main, une fusion qui mêle deux générations, une sauvegarde restaurée. Elle ne contrôle que la date de publication et pas celle de modification, car une faute de frappe dans un champ de date ne doit pas faire disparaître une page déjà indexée.
Et cette seconde porte est évaluée une fois, au chargement du module pendant la compilation. C’est écrit dans un commentaire à côté, car un lecteur qui supposerait autre chose finirait par écrire le planificateur contre lequel cette section argumente.
Une date que vous ne pouvez pas déduire, mieux vaut l’omettre
La même série a dû décider quelle date, s’il en fallait une, revient aux pages de documentation, qui n’ont pas d’en-tête du tout. Trois candidates se présentaient, et les trois sont fausses.
| Candidate | Pourquoi elle est fausse |
|---|---|
| La date git du composant de page | Change quand un nom de classe change et ne change pas quand le texte part dans un fichier de traduction |
| La date git du catalogue de traduction | Un fichier contient des milliers de textes sans rapport et change donc sans cesse pour des raisons étrangères à cette page |
| La date de compilation | Dit chaque jour que chaque page a été écrite aujourd’hui |
Les pages de documentation ne portent donc aucune date de publication dans leurs données structurées. Rien vaut mieux qu’un chiffre plausible, car un chiffre plausible est celui que personne ne vérifie.
Le même raisonnement gouvernait déjà le plan du site. Les routes fixes ne portent aucune date de modification, et la raison n’est pas la paresse : leur contenu est du code et leur texte vit dans neuf catalogues de traduction, toute date calculable suivrait donc autre chose que ce que voit le lecteur. Un moteur qui récupère trois fois une page « modifiée » et la trouve inchangée apprend à ignorer le champ, et alors le champ est pire qu’absent sur les pages où il est réel. Les articles en portent bien une, car elle est dans l’en-tête à côté du titre, là où la personne qui réécrit le texte la voit vraiment.
Après ce travail, la couverture n’a pas bougé du tout : les adresses d’articles portent une date de modification, tout le reste n’en porte pas, exactement comme avant. Ce qui a changé, c’est que deux cent seize de ces dates étaient dans le futur, et qu’aucune ne l’est plus.
Une contradiction de plus, réglée par l’identité
En relisant les données structurées, une version plus discrète du même problème est apparue : sur certaines pages, l’auteur et l’éditeur étaient deux entités distinctes sans relation déclarée. Lues à la lettre, ces pages affirmaient que l’article avait été écrit par une entreprise et publié par une autre. Les deux pointent désormais vers le même identifiant. Personne ne s’en serait plaint, et c’était tout de même une affirmation de notre part qui était fausse.
Ce que nous noterions
- Ne mettez jamais une intention dans un champ qui consigne une observation. Un lecteur ne peut pas les séparer, une machine non plus.
- Confrontez l’affirmation à l’historique. Une commande sur l’historique des fichiers a tranché laquelle des deux dates était la vraie, et elle contredisait les vingt-quatre fichiers.
- Une porte de date sur un site généré statiquement n’est pas un calendrier. À minuit rien n’apparaît ; cela apparaît à la compilation suivante.
- Ne masquez pas des adresses déjà indexées. Une 404 sur une page explorée est un signal de retrait, et le remède coûte plus cher que le mal.
- Placez la porte là où la faute se commet, faites échouer la compilation, et n’ajoutez pas de dérogation. Placez une seconde porte plus loin pour les chemins qui sautent la première.
- Omettez une date que vous ne pouvez pas déduire honnêtement. Trois sources plausibles, fausses toutes les trois, signifient que la sortie honnête est aucune.
Pour être clair sur ce dont il s’agit : ceci est de l’entretien sur un site public, pas une fonction produit, et cela n’a changé aucun comportement payé par qui que ce soit. Une part reste non prouvée. Les données structurées ont été validées contre leur propre schéma et relues à la main, pas par un vrai robot ni par une vraie carte de prévisualisation. Rien n’a été mesuré contre l’index d’un moteur de recherche, car cette mesure prend des semaines et personne ne devrait l’attendre avant de retirer une inexactitude.
Issu du travail sur le site de Provibr. Ce que coûte le maintien de seize mille textes justes en neuf langues est dans seize mille clés, neuf langues, et comment une collision de numéros de champ dans un protocole est restée cachée est dans deux chantiers, un seul numéro de champ.