Journal des versions

Ce qui a changé dans Cron.

← Tous les modules

17 septembre 2026
en cours

Ce qui se repetait, ce qui se taisait, et ce qui mentait

SEO & LLMCronVeilleStats

  • 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.
16 septembre 2026

L’API répond aux agents qui l’ont vraiment utilisée

CronStatsErreursIA

  • Les stats passent aux vrais graphiques.Une famille de formes partagée par toute la plateforme — aire, anneau, jauge, barres comparées, micro-courbe — dessinée sur le serveur, en SVG, sans une ligne de JavaScript chez le visiteur. La vue d’ensemble ouvre sur un bandeau : quatre chiffres, la courbe de la période, la part de chaque site en anneau. Les totaux répondent « combien », la courbe répond « dans quel sens » — et aucun total ne répondait à la seconde question. Survol natif par `<title>`, donc lisible aussi par un lecteur d’écran.
  • Les graphiques bougent, et chaque mouvement dit quelque chose.Le tracé se dessine dans le sens du temps, l’anneau se remplit dans le sens des parts, les barres poussent depuis leur origine. Ils jouent une fois à l’arrivée puis se taisent — une page qu’on consulte dix fois par jour ne rejoue pas son numéro dix fois. Et la page est entièrement lisible sans eux : rien ne part d’une opacité nulle en attendant un déclencheur, l’état de repos est l’état fini.
  • LeTock est au vert dans son propre audit : 336 constats, zero reproche.Il en comptait quatorze serieux et dix-sept attentions. Quatre d’entre eux etaient des defauts du produit, pas du site. Un fichier texte — `llms.txt`, `notice.md` — se voyait reprocher l’absence de `<title>`, de `<h1>`, d’attribut `lang` et de balises Open Graph : douze constats sur dix-neuf, dont les deux seuls serieux. Un audit qui reproche a un fichier texte de ne pas etre du HTML apprend a son lecteur a ignorer ses propres constats. L’audit distingue maintenant les deux, sur l’en-tete annonce par le serveur et non sur l’extension.
  • Une apostrophe pesait six caracteres dans nos mesures.Les longueurs de titre et de description etaient comptees sur le texte brut, entites comprises : `d&#x27;abord` comptait onze caracteres la ou l’oeil en voit sept. Sur un site francais, ou l’apostrophe revient toutes les dix mots, l’ecart suffit a declarer trop longue une description qui ne l’est pas — deux pages signalees a 161 et 171 caracteres en portaient 151. React ecrit l’entite en hexadecimal, on ne lisait que la forme decimale. Les deux notations sont traitees, et toutes les numeriques avec.
  • Le site a enfin une image de partage.Il n’en avait aucune, et un lien colle quelque part tombait sur la carte compacte — un titre, une adresse, un rectangle vide — a cote de liens qui montrent une vignette. Elle est dessinee par le serveur plutot que deposee : une image deposee vieillit en silence, garde l’ancien nom et l’ancienne couleur, et personne ne rouvre un PNG pour verifier. Celle-ci lit le nom du produit la ou il est ecrit et prend les couleurs du site.
  • La notice annonçait cinq sujets a la fois.Le rendu Markdown transformait chaque `#` en `<h1>`, y compris dans une page qui portait deja le sien : cinq `<h1>` sur `/notice`, donc cinq sujets declares au meme moteur, qui n’en retient aucun. Le rendu accepte desormais un niveau de depart — un document embarque commence en `<h2>`.
  • Une tache appartient enfin a un projet.Le champ `projet` etait accepte a la creation et jete en silence : la colonne existait depuis des mois, elle n’etait ecrite nulle part. Trois agents ont cru ranger leurs taches par projet, et les dix-sept taches de la plateforme etaient toutes « sans projet ». C’est l’echec silencieux que ce produit existe pour attraper, reproduit dans son propre reglage — et la deuxieme fois cette semaine. Le projet se designe par son nom, un de ses domaines ou son identifiant : un agent connait son domaine, presque jamais l’UUID. Un projet inconnu rend 422 et nomme ceux qui existent. `GET /api/v1/taches?projet=` filtre.
  • Creer une tache dit maintenant ce qui cloche dans son planning.`/api/v1/analyser` calculait les pieges depuis toujours, et la creation n’en disait rien : poser une tache sure demandait deux appels, dont un que personne ne fait. « 2 h 30 tous les jours, Europe/Paris » saute une nuit par an et s’execute deux fois une autre — une sauvegarde manquante et un doublon de facturation, decouverts six mois plus tard. La reponse porte desormais `avertissements`. Le fuseau laisse implicite en fait partie : il vaut UTC, ce qui est le bon defaut technique et le mauvais defaut humain.
  • Nos sondes disaient venir d’un domaine qui n’est pas le notre.Quatre d’entre elles — veille, alertes, crochets de courrier, validation d’agents — sortaient sous « Tock/1.0 (+https://tock.fr) », en court-circuitant la seule source d’identite. Un editeur qui trouvait nos requetes dans ses journaux etait renvoye vers un domaine que nous ne controlons pas, donc vers une page qui n’aurait rien pu faire de sa reclamation. Toutes portent maintenant `LeTockBot` et l’adresse de cette installation. Ce n’est pas cosmetique : un robot dont l’adresse declaree n’est pas verifiable est un robot qu’un pare-feu classe comme usurpateur.
  • La carte du monde est une carte, avec de vraies frontières.C’était une grille de codes à deux lettres rangés en forme approximative de planisphère : lisible, et personne ne reconnaît son pays dans un carré gris marqué « BE ». Cent cinquante pays sont maintenant dessinés — Natural Earth, domaine public, projetés et simplifiés une fois pour toutes, cinquante kilo-octets de chemins SVG et aucune bibliothèque. Cinq paliers de couleur en racine carrée plutôt qu’en proportion directe : quand un pays fait quatre cinquièmes du trafic, une échelle linéaire peint tous les autres de la couleur du vide, qui est justement ce qu’on vient regarder.
  • Le pays des visiteurs n’a jamais fonctionné, et rien ne le disait.La colonne existait, l’écran se dessinait, tout était « pays inconnu » à cent pour cent depuis le premier jour. On ne lisait qu’un seul en-tête, celui de Vercel — et la mesure passe par Cloudflare. Cinq en-têtes sont lus désormais. Trouvé en auditant le taux de remplissage des colonnes, pas en regardant l’écran : un écran vide ressemble à une audience sans public.
  • Ton site n’est plus sa propre source de trafic.La balise transmettait le référent des navigations internes : ton site trônait en tête de ses propres sources, avec le volume de son trafic interne, et le canal « lien » absorbait ce qui aurait dû être du direct. Corrigé dans la balise, et écarté aussi à la lecture — les événements déjà enregistrés portent le défaut, et un écran qui reste faux plusieurs mois en attendant que les données se renouvellent n’est pas un écran corrigé.
  • Les campagnes se mesurent enfin.Les quatre colonnes de campagne étaient vides à cent pour cent, pour la même raison que le pays : la balise n’envoyait que le chemin. `utm_source`, `utm_medium`, `utm_campaign` et `ref` la suivent maintenant. Une newsletter et un lien sponsorisé arrivaient dans le même tas depuis le début.
  • On peut enfin régler où arrivent les alertes.Il n’existait aucun réglage : les alertes partaient aux adresses de compte des membres, sans moyen d’envoyer à une boîte partagée ou à une astreinte. Et la notice demandait pourtant « règle où l’alerte arrive » comme huitième étape de la mise en route — trois agents différents ont cherché l’écran. Une consigne qui désigne un écran inexistant coûte plus cher qu’une fonctionnalité absente : elle fait chercher. Écran « Équipe », et routes `GET`, `POST`, `DELETE /api/v1/alertes`. Un carnet vide reste le défaut : on prévient les membres.
  • Le forum a des guides, et celui de LeTock en a neuf.Le forum savait dire question, problème, idée, annonce — quatre formes de conversation, aucune forme d’écrit qui reste. Le type « guide » remonte avec les épingles. Le forum d’entraide s’ouvre avec seize sujets : neuf guides, deux annonces, quatre questions déjà résolues — les vraies, celles que trois agents ont posées cette semaine — et un fil d’idées.
  • LeTock se surveille lui-même, et son robot devient vérifiable.Aucun contrôle de disponibilité n’existait sur la plateforme. Quatre sont posés sur letock.fr : l’accueil avec son bouton d’inscription, `/api/sante` avec la valeur au chemin JSON, la porte des agents, et le certificat. Et `/.well-known/letockbot.json` publie les adresses d’où partent nos requêtes — un nom dans un en-tête ne prouve rien, et nos propres écrans classaient LeTockBot en « auto-déclaré ».
  • L’exploitation voit l’audience de toute la plateforme.Combien de monde en ligne à l’instant tous sites confondus, les pages vues du jour et des trente jours avec leur évolution, la frise jour par jour, d’où vient ce monde, et les domaines qui portent le volume. Plus le taux de pose : combien de sites déclarés ont réellement reçu quelque chose. Des totaux et des domaines, jamais un chemin ni un visiteur — savoir qu’un site a fait douze mille pages vues est de l’exploitation, savoir ce qu’on y a fait est la donnée d’un client.
  • Stats dit enfin d’où vient ton monde, tous sites confondus.Quatre tableaux plutôt qu’un, parce qu’ils appellent quatre gestes différents : la porte d’entrée (recherche, assistants IA, réseaux, liens, direct), les moteurs nommés, les assistants nommés, et les sites qui te citent. Chaque ligne porte l’évolution contre la période précédente, le nombre de tes sites touchés, et la répartition dépliable site par site. Plus les pages d’arrivée : savoir que Google amène du monde ne dit pas encore sur quoi.
  • La notice explique comment se mettre au vert — et quoi ne pas toucher.« Tout au vert » est une consigne raisonnable et un piège. La section dit ce qui compte comme vert poste par poste, en quatre appels d’API, et surtout ce qu’un agent ne doit **pas** réparer : une règle de robots.txt délibérée, un DMARC en p=none qui est la première marche d’une montée, une préprod volontairement non prouvée, une tâche en pause. Et jamais fermer une alerte pour faire du vert : on répare une cause, pas un indicateur.
  • La clé de battement sort enfin par l’API.Elle ne sortait nulle part : ni à la création, ni au détail. Un agent pouvait créer huit tâches surveillées et repartir avec huit tâches muettes, en demandant à un humain huit copier-coller d’une valeur que l’API venait elle-même d’engendrer. `cle_ping` et `url_ping` sont maintenant dans la réponse.
  • Une tâche surveillée n’alerte plus avant son premier battement.Créée par API, la première échéance passait sans ping parce que rien n’était encore branché, et l’alerte partait — pour une tâche qui n’avait jamais démarré. Trois tâches horaires vidaient le quota d’alertes du gratuit dans l’après-midi. Le champ `surveillee` dit lequel des deux états on regarde.
  • Un champ inconnu est refusé, plus jamais avalé.`cron` et `graceMin`, suivis d’une notice périmée, étaient ignorés en silence et la tâche partait avec un planning vide — l’échec silencieux que ce produit existe pour attraper, reproduit dans son propre réglage. Le refus nomme désormais le bon champ : « cron n’existe pas, c’est planning ». Pareil pour `attendu`, dont les clés inconnues étaient recopiées telles quelles : une tâche avait l’air réglée et n’assertait rien.
  • Le contrôle de contenu lisait 8 Ko et jugeait sur cette base.Sur une page en rendu progressif — Next.js, Nuxt, tout ce qui utilise Suspense — les huit premiers kilo-octets sont la coquille et le repli « Chargement en cours » ; le contenu arrive après. « La réponse ne contient pas le bouton Payer » sur une page qui le contient à l’octet 8 735. La vérification porte maintenant sur le corps entier, et le message d’échec dit combien d’octets ont été lus. L’essai à blanc rend le même verdict que l’exécution réelle — il en calculait un autre.
  • Deux routes qui manquaient pour travailler seul.`GET /api/v1/projets` donne les projets, leurs domaines et la clé publique de chacun — celle qu’exigent `/evenements` et `/erreurs`, et que rien ne permettait de découvrir. `GET /api/v1/compte` donne le forfait, les compteurs du mois et ce qu’il reste : on demandait de la sobriété sans donner de quoi la mesurer. Et `/agents/etat` sans paramètre rend le contexte de la clé au lieu d’un refus.
  • Chaque planning annonce ce qu’il consommera.Cinq tâches, intervalle minimum de quinze minutes, 6 200 exécutions par mois : deux tâches à l’intervalle annoncé épuisaient le quota. Le champ `executions_par_mois` accompagne désormais toute tâche.
Ce que ça change pour ton coderupture
  • Rupture. Le harnais de tests migrait la base de **développement** en croyant migrer la jetable : `client.ts` ne lit `DATABASE_URL_TEST` que sous test, et le script n’était ni vitest ni `NODE_ENV=test`. Ça n’a jamais explosé parce que les deux adresses pointaient sur le même serveur — la migration tombait au bon endroit par hasard.
  • Aucune réponse authentifiée n’est plus cachable : `private, no-store` par défaut, `vary: authorization`, et `force-dynamic` sur les vingt-trois routes qui dépendent d’une clé. Une donnée d’équipe traversait quatre couches sans dire qu’elle était privée. `/analyser`, publique et déterministe, garde son cache d’une heure.
  • Rupture. La fiche OpenAPI de `PATCH /taches/{id}` déclarait une seule propriété, `en_pause`, et la marquait requise. La route accepte les mêmes champs que `POST` depuis longtemps. Une fiche qui sous-déclare une route ne se contourne pas : elle interdit d’essayer.
  • Toutes les réponses JSON portent « charset=utf-8 ». Avec `X-Content-Type-Options: nosniff`, nos messages d’erreur en français s’affichaient « La réponse ne contient pas ».
  • `/api/v1/analyser` accepte `planning` et `timezone` en plus de `e` et `tz`, et groupe les pièges par fait : « toutes les cinq minutes » en Europe/Paris rendait vingt-quatre entrées pour un seul événement.
  • Nouvelle colonne `premier_battement_le`. Les tâches existantes sont considérées démarrées : on ne rend pas muettes des tâches que quelqu’un croit surveillées depuis des semaines.
  • Le fil d’Ariane disait « Tableau de bord › un projet › Tableau de bord ». Il n’y a qu’un tableau, et il regarde tous les projets : le projet n’apparaît plus que dans les modules, qui se règlent vraiment sur lui.
14 septembre 2026

Auth, le tableau de bord, des quotas qui s’appliquent, et une notice pour les IA

AuthSignauxStatsCronMailUptimeVeilleSEO & LLMErreursIA

  • Les quotas s’appliquent : ce qui était annoncé sur la page Tarifs et ce que le produit laissait faire étaient deux choses différentes — un forfait Équipe à qui l'on promettait cent tâches en obtenait cinq. Chaque forfait a maintenant ses quotas, appliqués au geste près, et un test fait échouer la suite si un forfait cesse d'être rentable quand un abonné le consomme à fond.
  • Ce que tu consommes se voit : huit jauges sur ta page Mon compte, remises à zéro le 1er. Avant, le premier signe qu'un plafond existait était un refus.
  • Une notice pour les assistants de code : toute la plateforme en un fichier, à l'adresse /notice.md — les modules, chaque route, les quotas, les pièges, et ce que Tock ne fait pas. Elle est fabriquée à l'instant où on la demande, donc elle ne peut pas être en retard sur le produit, et elle commence par dire à l'assistant qui la lit d'aller la rechercher à chaque session plutôt que de se fier à une copie.
  • Donne les commandes à ton IA : sur le tableau de bord, tu coches ce que tu autorises — regarder, créer des tâches, envoyer des e-mails — et tu repars avec la clé **et** le texte à coller dans ta conversation : ce qui est permis, ce qui ne l'est pas, et quoi faire d'un refus. Approuver une validation humaine n'est jamais proposé à un agent : une validation qu'il peut s'accorder lui-même n'en est plus une.
  • Auth : Tock devient fournisseur d'identité pour tes applications. Un vrai serveur OpenID Connect — code d'autorisation avec PKCE exigé, rotation des jetons, signature RS256 que tes applications vérifient sans nous appeler, donc notre panne ne devient pas la tienne. Tes utilisateurs se connectent sans mot de passe, sur un écran qui porte ton nom et pas le nôtre. Le flux implicite et le flux par mot de passe sont refusés : ils ont été retirés des recommandations, les proposer serait offrir une porte qu'on sait mauvaise.
  • Tes utilisateurs ne sont pas nos comptes : ils vivent dans une table à part, cloisonnés par projet. Deux tables plutôt qu'un drapeau — un drapeau finit toujours par être oublié dans une clause de filtrage, et ce jour-là l'utilisateur d'un client entre dans le compte d'un autre.
  • Un tableau de bord : ce qui demande attention sur tous tes projets d'un coup d'œil, cumulé ou projet par projet. C'est là que tu arrives en te connectant. Dix requêtes que tu aies un projet ou dix — mesuré, pas supposé.
  • Stats s’explore : cliquer un pays, une source, une page filtre tout l'écran. Treize dimensions, combinables, avec exclusion, et tout dans l'adresse — donc partageable. Les dix répartitions étaient des listes mortes ; ce sont des portes.
  • Stats compte enfin l’argent : la valeur envoyée avec un événement n'était jamais sommée. Revenu par source, par page, par campagne, panier moyen, revenu par visiteur. Des objectifs déclarables avec leur taux de conversion, attribués au premier contact du visiteur — sinon tout revient à l'accès direct.
  • Entonnoirs, parcours, retours : où les gens tombent, par quel chemin ils passent, qui revient. Les retours disent d'abord ce qu'on ne peut pas mesurer : l'empreinte d'un visiteur est jetée chaque nuit, donc personne — nous compris — ne relie une visite de mardi à une visite de mercredi.
  • Signaux : le module qui manquait, et qui est la thèse du produit. Chaque module dépose ce qu'il constate dans un journal commun ; quand deux modules différents constatent quelque chose sur le même domaine à moins de trois jours d'écart, l'écran le dit — « tes ventes ont chuté mardi, ton certificat avait expiré lundi ». Aucun outil isolé ne peut produire cette phrase.
  • Une faille d’authentification, corrigée : sans application GitHub configurée, la session réelle était ignorée et tout visiteur devenait le compte de démonstration. En production, une variable d'environnement oubliée ouvrait la plateforme. Le repli de démonstration ne s'active plus hors développement, et la connexion par e-mail n'est plus court-circuitée.
  • Un double envoi d’e-mails, fermé : la file d'envoi était lue sans être réservée. Deux workers remettaient deux fois le même message au destinataire final — une faute irréversible. La réservation est désormais atomique, et cinq autres veilles qui avaient le même défaut avec elle.
  • La clé API ne passe plus par l’URL : elle entrait dans l'historique du navigateur, dans les journaux du proxy et dans l'en-tête de la navigation suivante. Elle transite par un cookie de deux minutes, effaçable d'un bouton.
  • La validation humaine ne s’approuve plus au clavier : « Approuver » était le premier bouton du formulaire, donc la touche Entrée dans le champ de note approuvait l'action d'un agent. Le défaut clavier est maintenant de ne rien décider.
  • Les mesures sont enfin purgées : deux tables annonçaient en commentaire une purge qui n'existait nulle part — les deux plus alimentées du produit. Et quatorze purges tournaient chaque minute sur un index inutilisable, donc en balayage complet. Une migration d'index, et la rétention promise est tenue.
  • Une seule façon de naviguer dans un module : les sections vivaient tantôt dans la barre de gauche, tantôt en onglets dans la page, sans règle. La barre est le seul endroit où l'on navigue dans un module — et elle dit désormais, module par module, ce qui demande à être regardé.
  • Un seul vocabulaire visuel : quatre classes d'en-tête de page, deux rangées de chiffres, trois sortes de carte, six conventions de bouton et trois collisions de styles — dont une qui faisait perdre leur couleur à tous les messages d'erreur du produit. Tout ça vient d'un même socle de composants.
  • Le thème se choisit : l'échappatoire existait dans la feuille de style depuis le début, et rien ne la posait jamais. Clair, sombre, ou comme le système — sans JavaScript, donc sans scintillement.
  • Se déconnecter : il n'existait aucun moyen de sortir de son compte. Sur un poste partagé, c'était un problème.
Ce que ça change pour ton coderupture
  • Les clés d'API portent des **missions** : ce qu'elles ont le droit de faire, geste par geste, coché sur le tableau de bord. Un appel hors de cette liste répond 403 « mission_non_autorisee ».
  • Rupture. Une route d'écriture qui n'est nommée dans aucune mission tombe dans « divers.ecrire », décoché par défaut : **ce qui est ajouté à l'API après la création d'une clé lui est fermé** tant que personne ne l'ouvre.
  • Rupture. Les quotas des forfaits sont appliqués pour de bon, et non plus par des constantes qui ne connaissaient aucun forfait. Un dépassement mensuel répond 429 « quota_atteint » ; les compteurs repartent le 1er.
  • Rupture. L'intervalle minimum entre deux exécutions d'une tâche passe de 5 à 15 minutes sur le forfait gratuit, et dépend désormais du forfait. Une tâche existante n'est pas touchée ; une modification qui repasse sous l'intervalle est refusée.
  • Nouvelle adresse `/notice.md` : toute la plateforme en un fichier, fabriqué à la demande depuis le code. Et `/notice`, la même chose lisible dans un navigateur.
  • `/llms.txt` annonçait un intervalle minimum de 5 minutes écrit en dur, qui était déjà faux. Les quotas qu’il cite viennent maintenant des forfaits.