Indépendant · Depuis 2009|~750€ / jour
Ce que vos agents de code ignorent sans vous le dire

Ce que vos agents de code ignorent sans vous le dire

Claude Code accepte sans erreur des réglages qu'il n'appliquera jamais : une permission Write(), un hook sur bash, une clé de settings posée dans le mauvais fichier. Cursor et Copilot font pareil avec leurs propres fichiers. deadweight lit la configuration des agents d'un dépôt et signale ce qu'ils ignorent. Je l'ai présenté le 30 septembre. Depuis, il contrôle aussi Cursor, Copilot et AGENTS.md, il est passé à 53 groupes de contrôles, et il confie à un modèle les deux défauts qu'aucun parseur ne voit. Voici ce qui a changé, et comment il est construit.

Le problème : un refus silencieux

Un agent de code ne vous prévient pas quand il ignore une partie de votre configuration. Il n'y a ni erreur ni avertissement : la session démarre, et la règle que vous avez écrite ne compte pas.

Trois exemples côté Claude Code, tous documentés par Anthropic :

  • Une permission Write(src/**) n'est jamais consultée. Les règles de chemin se vérifient contre Edit(...) et Read(...) uniquement : il fallait écrire Edit(src/**).

  • Un hook dont le matcher vaut bash ne se déclenche jamais. Les matchers sont sensibles à la casse, et l'outil s'appelle Bash.

  • Une clé de settings placée dans le mauvais fichier est ignorée. Chaque clé a une portée (projet, utilisateur, géré) : la même ligne qui marche dans l'un est lettre morte dans l'autre.

Aucun de ces problèmes ne fait planter quoi que ce soit. C'est ce qui les rend durables : une configuration qui ignore une partie de ce qu'on a écrit a toujours l'air de marcher.

Claude Code est rarement seul dans le dépôt

Sur 300 dépôts publics configurés pour Claude Code, près d'un sur deux porte aussi les fichiers d'un autre agent : AGENTS.md, Cursor, Copilot. Chacun de ces outils saute en silence un fichier mal nommé ou mal placé, et certains lisent ceux des autres.

Depuis la 0.20, deadweight contrôle donc aussi ces fichiers. Une règle Cursor enregistrée en .md alors que Cursor ne lit que les .mdc. Un fichier d'instructions Copilot sans le suffixe .instructions.md. Un AGENTS.md que Claude Code ne lit pas parce qu'un CLAUDE.md est posé à côté. Et les lignes de CLAUDE.md que seul Claude Code sait suivre : Cursor applique ce fichier à chaque conversation, et une consigne comme « lance /compact » y devient un ordre qu'il ne peut pas exécuter.

Le cas d'AGENTS.md est le plus trompeur. Depuis la version 2.1.277, Claude Code le lit de lui-même, mais seulement quand aucun CLAUDE.md n'existe dans le dossier ou au-dessus. Dès qu'il y en a un, il lit CLAUDE.md à la place, et AGENTS.md ne compte plus, sauf si CLAUDE.md l'importe avec une ligne @AGENTS.md ou si le réglage « Project instructions » demande les deux. Un CLAUDE.local.md compte aussi : le développeur qui en crée un pour ses notes personnelles coupe, sans le savoir, la lecture de l'AGENTS.md de toute l'équipe sur son poste.

Pour Gemini CLI, l'outil ne fournit encore que la documentation, sans contrôle.

D'où vient chaque règle

deadweight classe ses règles en trois origines, et la sévérité en dépend. Une règle tirée de la documentation d'un éditeur est citée entre guillemets avec le nom de la page. Quand elle vient d'une mesure, elle porte sa date et la version de l'outil sur laquelle elle a été vérifiée. Les conventions maison sont marquées comme telles et ne remontent qu'en simple remarque, sauf si le projet choisit de les durcir.

Comment il est construit

L'audit est un paquet Python sans aucune dépendance : un module par famille de contrôles, plus l'analyse des fichiers, le vocabulaire, le rapport et le seuil. Sans appel réseau, il tourne dans n'importe quelle CI, sur Linux, macOS et Windows.

Chaque contrôle reçoit l'état de l'audit en paramètre, et un contrôle qui plante produit un constat « contrôle en échec » au lieu de faire tomber tout le rapport. Le découpage en modules, à la 0.21, a été vérifié sortie contre sortie : identique à l'octet sur 200 dépôts publics re-clonés à leur commit enregistré.

Le script lit lui-même les en-têtes YAML et développe lui-même les globs, pour qu'on n'installe rien. Ces parseurs maison ont coûté cher. Un commentaire en fin de ligne mal retiré produisait 24 faux « modèle inconnu » sur un échantillon. Un tampon mal vidé en a produit 422 sur un seul dépôt public. Les deux sont corrigés, et le code garde la trace de pourquoi.

Le seuil couvre tout le paquet

Le seuil de CI (--set-floor, --check-floor) enregistre l'empreinte de l'auditeur qui l'a mesuré. Depuis la 0.21, cette empreinte couvre tous les modules et plus seulement le point d'entrée. Si l'auditeur change, la comparaison est refusée : deux instruments différents ne produisent pas deux états d'un même projet, et comparer en silence, c'est prendre un changement d'outil pour un progrès.

Comment on sait qu'il a raison

Le premier échantillon, raconté dans l'article précédent, comptait 84 erreurs fausses ou mal classées sur 98. La méthode s'est durcie à partir de là. Sept échantillons de 150 dépôts publics ont été tirés au hasard, avec une graine fixe et sans jamais réutiliser un dépôt. L'instrument est figé avant chaque tirage, rien n'est corrigé pendant la mesure, le seuil de réussite (9 erreurs justes sur 10) est fixé à l'avance, et chaque erreur est relue à la main.

Les échantillons 4 à 7 ont donné les valeurs suivantes :

  • 4e échantillon : 69 erreurs justes sur 82 ;

  • 5e : 126 sur 244, parce qu'un seul dépôt a produit 100 des 112 faux ;

  • 6e : 1 416 sur 1 425, et encore 127 sur 136 une fois le dépôt dominant mis de côté ;

  • 7e : 42 sur 48.

Le seuil de 9 sur 10 n'est pas encore tenu de façon stable. Ce qui converge, ce sont les nouvelles façons de lire un fichier que chaque échantillon révèle : 13, puis 7, puis 1, puis 0.

Les contrôles des autres agents ont suivi la même règle avant leur sortie : 30 alertes justes sur 31, 53 sur 53 et 3 sur 3 selon le contrôle, puis 877 sur 878 sur 513 dépôts jamais vus. Depuis la 0.21, 202 cas de test publics, la plupart nés d'un faux positif trouvé un jour sur un vrai dépôt, sont rejoués à chaque modification sur les trois systèmes.

Ce qu'un parseur ne voit pas

Deux défauts échappent à toute lecture mécanique : deux consignes qui ne peuvent pas être suivies ensemble, et une même règle recopiée dans deux fichiers, qui finiront par diverger. Depuis la 0.21.1, une commande à part les confie à un modèle, appelé par votre propre session Claude Code.

Chaque constat doit citer les deux passages mot pour mot, et chaque citation est vérifiée contre le fichier qu'elle nomme : une citation introuvable fait rejeter le constat. Résultat mesuré : 50 contradictions justes sur 50, 49 doublons justes sur 50. Mais sur 24 défauts que des mainteneurs ont eux-mêmes déclaré corriger dans leurs commits, il n'en retrouve que 4 à leur place, 6 en comptant le même conflit vu dans un autre fichier.

Deux passages successifs ne s'accordent que sur environ trois constats sur quatre. Ce résultat n'entre donc jamais dans le seuil : un chiffre qui bouge d'un passage à l'autre ferait échouer la CI sans que rien n'ait changé.

On ne lui demande pas non plus si une règle est utile. Un modèle qui juge une règle trouve claire et utile celle qu'il aurait suivie de toute façon, donc justement la règle qui ne sert à rien. Ça se mesure en faisant tourner l'agent avec et sans elle, pas en la lisant.

Ce qu'il ne fait pas

deadweight ne corrige rien. Il propose, et le mainteneur tranche : le script n'a volontairement pas d'option --fix, parce qu'une configuration encode des décisions que l'outil ne connaît pas.

Il compte ce qui est sur le disque, pas ce que l'agent a réellement chargé. Pour le savoir, --runtime lit le journal d'un hook InstructionsLoaded que vous posez vous-même : l'outil n'en installe jamais. Enfin, chaque mesure est datée par version de Claude Code : quand Claude Code change, certaines doivent être refaites. L'outil le signale.

L'essayer

claude plugin marketplace add e-xode/deadweight
claude plugin install deadweight@e-xode --scope project

Puis /deadweight:config-auditor dans votre projet. C'est gratuit, sous licence MIT : https://github.com/e-xode/deadweight

Si votre équipe a déployé des agents de code sur plusieurs dépôts et que plus personne ne sait vraiment ce qui se charge, c'est le genre de chantier que je prends : https://www.e-xode.net/fr/contact

Commentaires (0)

Aucun commentaire pour le moment.