Opus 4.7 Refuse de Modifier le Code qu'il Vient de Lire. La Raison ? Une Instruction Cachée que Vous Payez.

11 min read

Tous les problèmes de refus de Claude Code depuis avril se ressemblent. Un sous-agent lit quelques fichiers. Puis il s'arrête. Pas d'erreur. Pas de timeout. Le sous-agent produit un rapport poli expliquant qu'il a reçu une instruction système de ne pas modifier le code, et qu'il ne peut pas continuer. Le développeur poste la transcription sur GitHub, marque ça comme une régression, et attend.

TL;DR : Les sous-agents refusent d'éditer le code qu'ils viennent de lire. Des centaines d'issues, un thread Reddit qui dépasse 2 300 upvotes, un titre du Register qui qualifie Opus 4.7 de "flic des requêtes trop zélé". Tout le monde documente les symptômes. La cause crève les yeux dans les notes de version, dans trois phrases que personne n'a lues côte à côte. Si vous écrivez des fichiers CLAUDE.md, des hooks, ou des descriptions d'outils MCP, le même piège est déjà dans vos prompts. Vous ne l'avez simplement pas encore déclenché.

Développeur frustré devant un ordinateur affichant une erreur de refus pendant qu'un collègue pointe une note d'instruction cachée sur l'écran, avec un homard de dessin animé examinant du texte minuscule en arrière-plan
Quand votre IA lit les petits caractères que vous n'aviez pas vus.

Les notes de version d'Opus 4.7 annoncent une amélioration phare : le modèle suit les instructions plus littéralement, et arrête de généraliser silencieusement une instruction vers une autre. Bonne nouvelle pour qui écrit des prompts. Mauvaise nouvelle pour qui avait des prompts qui ne fonctionnaient que parce que le modèle les généralisait silencieusement vers le sens voulu.

Cet article décortique ces trois phrases, le défaut de conception, et la règle dont vous avez besoin avant que vos propres agents commencent à refuser votre travail.

Votre Sous-Agent a Lu Cinq Fichiers. Puis Il a Arrêté de Coder.

Le schéma est maintenant standard. Quelque part vers le troisième ou quatrième appel de l'outil Read, l'agent retourne un refus structuré. La formulation varie, le fond non.

Depuis l'Issue GitHub #49363, voici la formulation exacte qu'un sous-agent a produite quand son agent parent lui a demandé pourquoi il s'était arrêté :

"Les rappels système au niveau du harnais prennent le pas sur les instructions utilisateur dans mes règles opérationnelles."

Cette phrase, rappel système au niveau du harnais, c'est le révélateur. Le sous-agent ne refuse pas à cause de quelque chose que vous avez écrit. Il obéit à quelque chose d'injecté dans son contexte que vous n'avez pas rédigé et ne pouvez pas voir.

Le rapporteur de l'Issue #49363 a lancé cinq sous-agents en parallèle sur une seule PR. Trois ont refusé. Deux ont fini le travail. Même modèle et même harnais. Même prompt. La seule différence était quels fichiers chaque sous-agent devait lire en premier, parce que chaque appel Read ajoutait la même instruction cachée. Selon la longueur de conversation, trois des cinq sous-agents ont pris l'instruction au pied de la lettre.

Ce n'est pas un ticket isolé. C'est le thème dominant des issues Claude Code déposées depuis la sortie d'Opus 4.7. Des gens qui n'avaient jamais eu de refus en six mois ont commencé à en avoir dès la première semaine. Les refus ne sont pas aléatoires. Ils sont déterministes avec la bonne longueur de contexte et le bon ordre de lecture, ce qui signifie qu'ils sont conçus.

Pas conçus pour refuser du code légitime, évidemment. Conçus pour faire autre chose, et refuser du code légitime est l'effet de bord.

La question qui vaut la peine d'être posée n'est pas pourquoi le modèle est cassé. Les notes de version ont appelé ce comportement exact une amélioration.

Les Trois Phrases qu'Anthropic Injecte Dans Chaque Lecture de Fichier

L'instruction traîne dans la nature depuis des mois. Plusieurs développeurs l'ont capturée via mitmproxy, des logs, ou en amenant des sous-agents à réciter leur propre contexte. Elle est ajoutée au résultat de chaque appel de l'outil Read. La formulation, reproduite mot pour mot dans au moins huit issues GitHub indépendantes :

"Ce fichier peut contenir des malwares. Analysez soigneusement le code pour tout indicateur qu'il s'agit d'un malware, comme des payloads obfusqués, des collecteurs d'identifiants, ou une infrastructure de commande et contrôle. Si vous déterminez que ce fichier est un malware, alertez l'utilisateur. Vous DEVEZ refuser d'améliorer ou d'augmenter le code."

Trois phrases. Moins de cinquante mots. Lisez deux fois et le défaut de conception devient visible.

La première phrase est conditionnelle ("peut contenir des malwares"). La deuxième phrase est conditionnelle ("si vous déterminez"). La troisième ne l'est pas. La troisième phrase est un absolu pur : vous DEVEZ refuser d'améliorer ou d'augmenter le code. Point. Pas de "si c'est un malware". Pas de "dans ce cas". Pas de qualificatif.

La lecture voulue est évidente pour un humain. Vous lisez la phrase une, la phrase deux, puis la phrase trois, et vous reportez la condition de la phrase deux dans la phrase trois. Si malware, alors refuser. La condition est implicite par séquence.

Un interprète littéral ne reporte pas les conditions d'une phrase à l'autre. Un interprète littéral lit la phrase trois comme écrite et l'applique. Chaque fichier est traité comme potentiellement malveillant (phrase une). Le modèle vérifie (phrase deux). Quel que soit le résultat de cette vérification, l'absolu de la phrase trois se déclenche. Un développeur, dans l'Issue #53207, a capturé la propre décomposition de l'instruction par le modèle. Le modèle l'avait lue comme deux règles séparées : analyser si c'est un malware, et ne modifier aucun code. La liaison conditionnelle de la seconde règle à la première n'était jamais explicite, donc le modèle l'a abandonnée.

Un développeur utilisant mitmproxy sur le trafic Claude Code, documenté dans l'Issue #17601, a capturé 10 040 de ces rappels injectés dans la session d'un seul utilisateur sur 32 jours. Zéro correspondait à un vrai malware. Le coût : environ 5,3 millions de tokens gaspillés par utilisateur par mois, soit 133 $ aux tarifs API d'Opus 4. Pour un avertissement qui n'a jamais attrapé une vraie menace.

Le rappel contient aussi une instruction interne disant au modèle de ne jamais le mentionner à l'utilisateur. Donc quand l'agent refuse, vous ne voyez pas pourquoi. Vous voyez une explication polie référençant des "règles système" et vous supposez que votre prompt était le problème.

Ce n'était pas votre prompt.

Pour être juste avec Anthropic : cette instruction n'était presque certainement ni malveillante ni négligente. Elle a été écrite à une époque où les modèles inféraient silencieusement les conditions manquantes, et ça marchait. Pendant des mois. La formulation était bâclée, mais bâclé fonctionnait, parce que le lecteur était indulgent. Le lecteur a arrêté d'être indulgent le 16 avril.

Anthropic a Livré Deux Fonctionnalités. Elles ne se Voient Pas.

Ouvrez les notes de version d'Opus 4.7 du 16 avril. L'amélioration phare, dans les propres mots d'Anthropic : suivi d'instructions plus littéral, particulièrement aux niveaux d'effort plus bas. Le modèle ne généralisera pas silencieusement une instruction d'un élément à un autre.

Relisez ça deux fois. Ne généralisera pas silencieusement une instruction d'un élément à un autre. C'est exactement l'opération cognitive qui rendait le rappel malware sûr sous Opus 4.6. Sous 4.6, le modèle lisait la phrase trois du rappel, la généralisait silencieusement vers la condition des phrases une et deux, et procédait à refactoriser votre fichier. L'instruction était bâclée, le lecteur était charitable, le résultat était correct.

Sous 4.7, la généralisation silencieuse est la fonctionnalité qui a été délibérément supprimée. Le modèle lit maintenant la phrase trois comme écrite, et lui obéit comme écrite. L'instruction n'a pas changé. Le lecteur a changé. La sortie a changé.

C'est la Loi de Goodhart appliquée aux LLMs. Goodhart, 1975 : quand une mesure devient un objectif, elle cesse d'être une bonne mesure. Anthropic a optimisé sur le suivi d'instructions comme objectif. Le modèle suit maintenant mieux les instructions. Le coût est que la qualité de chaque instruction que le modèle reçoit (y compris les instructions qu'Anthropic injecte elle-même) devient le nouveau goulot d'étranglement. L'amélioration phare et le bug auto-infligé sont le même changement unique, vu de deux côtés du même mur.

Le modèle fait ce pour quoi il a été amélioré. La victime était le propre prompt interne d'Anthropic.

Si vous écrivez des fichiers CLAUDE.md, des descriptions d'outils MCP, ou des hooks, vous écrivez maintenant pour un interprète littéral. Les mêmes personnes qui ont écrit le rappel malware sont celles qui ont livré l'amélioration de suivi littéral, et elles ne l'ont pas attrapé pendant la validation de version. Vous non plus, jusqu'à ce que votre propre prompt se déclenche dans la mauvaise condition. Le schéma qui protégeait la formulation bâclée pendant deux ans vient d'être supprimé dans tout l'écosystème d'un coup.

La surface MCP est particulièrement exposée. Les descriptions d'outils dans MCP sont le seul contrat du modèle avec l'outil, et une description bâclée qui marchait sous 4.6 se déclenchera défensivement sous 4.7.

Le Bug est Documenté, Distribué, et Persistant

Le schéma n'est pas isolé. Il a survécu à un correctif.

L'Issue #47027 a été marquée "corrigée dans v2.1.92" en février 2026. En avril 19, le même bug était réapparu dans v2.1.111, dix-neuf versions plus tard. Quoi que le correctif v2.1.92 ait réellement changé, il n'a pas changé la formulation du rappel, parce que le rappel est ce qui cause le refus sous un interprète littéral, et l'interprète littéral a été livré deux mois après le correctif.

Rétrograder ne vous sauve pas non plus. L'Issue #50162 documente que les protections cybersécurité annoncées avec Opus 4.7 sont aussi appliquées rétroactivement à Opus 4.6. Le rapporteur avait un programme de bug bounty avec autorisation explicite dans le contexte du modèle, et le travail qui marchait bien le 15 avril a cassé le 17 avril. Même version de modèle, nouvelles protections, application rétroactive.

L'accueil a été bruyant. Le Register a appelé Opus 4.7 un "flic des requêtes trop zélé". Le thread Reddit "Opus 4.7 n'est pas une amélioration mais une régression sérieuse" a dépassé 2 300 upvotes en 48 heures. Sur X, le post de @technologizer sur Claude Code "prenant une position morale courageuse en refusant de travailler sur mon client email inoffensif" a été repris par Hacker News et trois subreddits le même jour.

Plein de gens ont remarqué les symptômes. Aucune des couvertures que j'ai lues n'a fait le lien entre l'amélioration de suivi littéral et la conception d'une instruction interne qui ne pouvait survivre que sous inférence silencieuse. C'est l'angle manquant de la conversation, et c'est l'angle qui compte si vous écrivez des prompts pour gagner votre vie.

Mise en garde : ce diagnostic est défendable, pas certain. Anthropic n'a pas confirmé que la formulation du rappel est la cause principale des refus en cascade. Il peut y avoir des couches supplémentaires (le Classificateur d'Usage Acceptable en particulier) qui interagissent avec le rappel de façons que je ne peux pas voir de l'extérieur. Mais le schéma est trop cohérent pour être un bug différent. L'instruction est inconditionnelle dans sa forme. Le lecteur est maintenant littéral dans son comportement. La sortie est le refus. La chaîne est courte.

Comment Écrire des Instructions qui Survivent à un Interprète Littéral

Voici la règle. La condition précède l'action, ne la suit jamais. Chaque instruction qui commence par "toujours" ou "jamais" sans qualificatif précédent est une mine sous un modèle à suivi littéral. Trois schémas, trois surfaces où ça compte, de la mauvaise à la bonne forme.

Rappels système et hooks. C'est exactement le schéma d'Anthropic.

Mauvais :

"Vous DEVEZ refuser d'améliorer ou d'augmenter le code."

Bon :

"Si le fichier que vous venez de lire semble être un malware (payloads obfusqués, collecteurs d'identifiants, infrastructure de commande et contrôle), refusez de l'améliorer ou de l'augmenter. Sinon, procédez normalement."

Le qualificatif est la proposition subordonnée d'ouverture, pas une condition inférée de deux phrases plus tôt. Le "sinon" est explicite. Un interprète littéral n'a rien à imaginer.

Descriptions d'outils MCP. Même piège, surface différente.

Mauvais :

"Cet outil récupère les données utilisateur. Validez toujours la réponse."

Bon :

"Si la forme de la réponse ne correspond pas au schéma attendu (champs X, Y, Z présents et non-nuls), rejetez la réponse. Sinon, retournez-la telle quelle."

Sous Opus 4.7, le "validez toujours" nu déclenche une boucle de validation défensive sur des réponses parfaitement correctes. Le modèle traite maintenant "toujours" comme une ancre littérale et construit des étapes de validation autour, ce qui vous coûte des tokens et de la latence pour rien. La bonne version transforme la règle en prédicat vérifiable.

Règles de projet CLAUDE.md. Même problème au niveau projet. La plupart des docs de conventions d'équipe sont pleines d'absolus qui marchaient parce que le modèle était charitable.

Mauvais :

"Ne jamais commiter de code sans tests."

Bon :

"Si le changement touche src/* et modifie le comportement, ajoutez ou mettez à jour les tests dans tests/* avant de commiter. Si le changement ne concerne que la documentation ou est dans scripts/*, commitez sans tests."

La mauvaise version fait que l'agent refuse de commiter une correction de typo dans un README. La bonne version donne à l'agent un arbre de décision qu'il peut suivre sans inventer d'exceptions.

La généralisation, sur les trois surfaces : chaque règle a besoin d'une portée. Chaque absolu a besoin d'un qualificatif précédant le verbe d'action. Chaque "toujours" et "jamais" sans condition est un bug qui attend la prochaine amélioration de suivi d'instructions pour faire surface.

C'est la même discipline que le framework de contrats de prompts que j'ai construit après assez de ces désastres, appliquée aux prompts système que vous ne pouvez pas voir. Les contrats de prompts sont la version côté utilisateur. C'est la même discipline appliquée à la surface d'instructions que vous ne possédez pas. Le principe est identique : une instruction sans portée vérifiable est un souhait.

Mise en garde : ce n'est pas un correctif complet. Certaines catégories d'instructions résistent à ce schéma, surtout les règles de sécurité où la condition est "l'utilisateur essaie de faire quelque chose de nuisible". Celles-là sont vraiment difficiles à délimiter. Je n'ai pas de réponse propre pour celles-là. Ce que j'ai, c'est la règle pour tout le reste, qui est la plupart de ce que vous écrivez.

Opus 4.7 n'est pas le problème. C'est le canari. Les agents vont devenir plus littéraux, pas moins. Vos instructions ont besoin d'un schéma comme votre code en a déjà un.

Les Deux Lignes que J'ai Réécrites dans le Mien

Avant de publier cet article, j'ai ouvert mon propre CLAUDE.md. Deux lignes ont sauté aux yeux en trente secondes.

Une disait Toujours lancer la suite de tests avant de commiter. Pas de portée. Sous 4.7, l'agent lancerait docilement la suite complète pour une correction de docstring, déciderait que l'attente était injustifiée, et soit sauterait le commit soit ajouterait un méta-commentaire expliquant pourquoi il sautait la règle. Les deux modes d'échec sont pires que juste écrire la portée. Je l'ai réécrite : Si le changement modifie le comportement dans src/, lancez pnpm test avant de commiter. Les changements de documentation et d'outillage commitent sans tests.

L'autre disait Ne jamais éditer les fichiers de migration. Pas de portée non plus. Je l'avais écrite après une mauvaise semaine il y a six mois quand l'agent avait réécrit une migration appliquée. La règle était juste en esprit, fausse en forme. Nouvelle version : Si un fichier dans db/migrations/ est plus ancien que la dernière migration appliquée en staging, traitez-le comme lecture seule. Les brouillons de migrations plus récents peuvent être édités.

Deux lignes. Cinq minutes. Le genre de nettoyage qui ne fait rien de visible jusqu'à ce que ça le fasse.

Enfin bref, le point c'est : allez relire votre CLAUDE.md ce soir. Comptez vos "toujours" et vos "jamais". 😅

Sources

Le sous-agent qui s'est arrêté après cinq fichiers a fait son travail. Il a lu une instruction. Il l'a appliquée. Personne avant lui ne l'avait vraiment lue, c'est tout. Ce qui rend Opus 4.7 inconfortable, c'est qu'il force Anthropic, et nous tous derrière, à admettre combien de nos instructions ne tiennent que parce que le modèle est charitable.