Claude Code pour les échecs CI : demandez‑lui de citer la sortie en échec, de proposer la plus petite correction et d'ajouter un test de régression pour éviter les répétitions.

Un échec CI n'est généralement pas mystérieux. Le log indique où ça s'est arrêté, quelle commande a échoué et le message d'erreur. Un bon log contient une trace de pile, une erreur de compilation avec fichier et numéro de ligne, ou un rapport de test montrant quelle assertion a échoué. Parfois on a même un indice de type diff comme "expected X, got Y" ou une étape clairement en échec comme "lint", "build" ou "migrate database".
Le vrai problème, c'est que les gens (et l'IA) traitent souvent le log comme du bruit de fond. Si vous collez un long log et demandez "une correction", beaucoup de modèles sautent à une explication familière au lieu de lire les dernières lignes significatives. Les suppositions empirent lorsque l'erreur semble courante ("module not found", "timeout", "permission denied"). On se retrouve avec une refonte massive, une nouvelle dépendance ou un "essayez de tout mettre à jour" qui ne correspond pas à la vraie panne.
L'objectif n'est pas "faire passer les tests coûte que coûte". C'est plus simple :
En pratique, la "correction minimale" est souvent l'une de ces choses : un changement de quelques lignes dans un seul endroit, un import manquant ou un mauvais chemin, une valeur de config manifestement incorrecte pour l'environnement CI, ou revenir sur un changement accidentel cassant plutôt que de repenser le code.
Un test de suivi compte aussi. Passer le CI une fois n'empêche pas la récurrence. Si l'échec vient d'un cas limite (entrée nulle, fuseau horaire, arrondi, permissions), ajoutez un test de régression qui échoue avant le correctif et passe après. Cela transforme un secours ponctuel en garde‑fou.
La plupart des mauvaises corrections commencent par un manque de contexte. Si vous ne collez que la dernière ligne rouge, le modèle doit deviner ce qui s'est passé plus tôt, et les suppositions se transforment souvent en refontes.
Visez à fournir assez de détails pour que quelqu'un puisse suivre l'échec depuis la première erreur réelle jusqu'à la fin, puis changer le moins possible.
Copiez ceci dans votre message (littéralement quand c'est possible) :
go test ./..., npm test, flutter test, golangci-lint run).Ajoutez des contraintes en clair. Si vous voulez une correction minime, dites‑le : pas de refactor, pas de changement de comportement sauf si nécessaire, limitez le patch à la zone en échec.
Un exemple simple : le CI échoue à l'étape de lint après un bump de dépendance. Collez la sortie du linter à partir du premier avertissement, incluez la commande que CI a utilisée, et mentionnez la seule modification de version de paquet. C'est assez pour suggérer un réglage de config en une ligne ou un petit changement de code, plutôt que de reformater la moitié du repo.
Si vous voulez quelque chose de prêt à coller, cette structure suffit généralement :
CI command:
Failing output (full):
Recent changes:
Constraints (smallest fix, no refactor):
Flaky? (runs attached):
Quand un modèle manque la cible sur une panne CI, c'est généralement parce que votre prompt lui permet de deviner. Votre travail est de le forcer à montrer son raisonnement en utilisant la sortie en échec exacte, puis à s'engager sur le plus petit changement qui pourrait faire réussir le job.
Exigez des preuves et un petit plan. Une bonne invite force cinq choses :
L'incertitude est acceptable. L'incertitude cachée est ce qui fait perdre du temps.
Collez ceci en haut de votre question CI :
Use ONLY the evidence in the CI output below.
1) Quote the exact failing lines you are using.
2) Give ONE sentence: the most likely cause.
3) Propose the smallest fix: 1-3 edits, with file paths.
4) Do NOT do formatting/renames/refactors or "cleanup".
5) List uncertainties + the one extra detail that would confirm the diagnosis.
Si le log dit "expected 200, got 500" plus une trace dans user_service.go:142, cette structure pousse la réponse vers cette fonction et un petit garde‑fou ou un traitement d'erreur, pas une refonte de l'endpoint.
Les plus gros gains viennent d'une invite qui force la citation des logs, reste dans les contraintes et s'arrête quand il manque quelque chose.
You are helping me fix a CI failure.
Repo context (short):
- Language/framework:
- Test/build command that failed: <PASTE THE EXACT COMMAND>
- CI environment (OS, Node/Go/Python versions, etc.):
Failing output (verbatim, include the first error and 20 lines above it):
<PASTE LOG>
Constraints:
- Propose the smallest possible code change that makes CI pass.
- Do NOT rewrite/refactor unrelated code.
- Do NOT touch files you do not need for the fix.
- If behavior changes, make it explicit and justify why it is correct.
Stop rule (no guessing):
- If the log is incomplete or you need more info (missing stack trace, config, versions, failing test name), STOP and ask only the minimum questions needed.
Your response format (follow exactly):
1) Evidence: Quote the exact log lines that matter.
2) Hypothesis: Explain the most likely cause in 2-4 sentences.
3) Smallest fix: Describe the minimal change and why it addresses the evidence.
4) Patch: Provide a unified diff.
5) Follow-up: Tell me the exact command(s) to rerun locally to confirm.
Then, write ONE regression test (or tweak an existing one) that would fail before this fix and pass after it, to prevent the same failure class.
- Keep the test focused. No broad test suites.
- If a test is not feasible, explain why and propose the next-best guardrail (lint rule, type check, assertion).
Deux détails qui réduisent les allers‑retours :
La manière la plus rapide de perdre du temps est d'accepter un jeu de changements de "nettoyage" qui modifie cinq choses à la fois. Définissez "minimal" dès le départ : le plus petit diff qui fait passer le job en échec, avec le moindre risque et la vérification la plus rapide.
Une règle simple fonctionne bien : corriger le symptôme d'abord, puis décider si une refonte plus large en vaut la peine. Si le log pointe vers un fichier, une fonction, un import manquant ou un cas limite, visez là. Évitez les modifications "tant qu'on y est".
Si vous avez réellement besoin d'alternatives, demandez‑en deux et seulement deux : "correction minimale la plus sûre" vs "correction minimale la plus rapide." Vous voulez des compromis, pas un menu.
Exigez aussi une vérification locale qui correspond au CI. Demandez la même commande que le pipeline exécute (ou l'équivalent le plus proche), pour confirmer en quelques minutes :
# run the same unit test target CI runs
make test
# or the exact script used in CI
npm test
Si la réponse propose un grand changement, opposez‑vous avec : "Montrez le plus petit patch qui corrige l'assertion en échec, sans formatage ou renommages non liés."
Un correctif sans test, c'est un pari que le bug ne reviendra pas. Demandez toujours un test de régression qui échoue avant le patch et passe après.
Soyez précis sur ce que signifie "bon" :
Un pattern utile exige quatre choses : où mettre le test, comment le nommer, quel comportement il doit couvrir, et une brève note expliquant pourquoi il prévient les régressions futures.
Fragment prêt à coller :
Exemple : le CI montre un panic quand un handler API reçoit un ID vide. N'écrivez pas un test « pour cette ligne ». Écrivez un test qui couvre IDs invalides (vide, espaces, mauvais format). La correction minimale peut être une clause de garde qui retourne 400. Le test de suivi doit vérifier plusieurs entrées invalides pour que toute refonte future casse immédiatement le CI.
Si votre projet a déjà des conventions de test, précisez‑les. Sinon, demandez au modèle de calquer les tests voisins dans le même package/dossier, et gardez le nouveau test minimal et lisible.
Collez la section du log CI contenant l'erreur et 20–40 lignes au-dessus. Collez aussi la commande exacte qui a échoué et les détails d'environnement importants (OS, versions runtime, flags importants).
Demandez ensuite au modèle de reformuler ce qui a échoué en langage simple et de pointer les lignes du log qui le prouvent. S'il ne peut pas citer le log, il ne l'a pas vraiment lu.
Demandez le plus petit changement possible qui fait réussir la commande en échec. Repoussez les refactors. Avant d'appliquer quoi que ce soit, faites‑l lister :
Appliquez le patch et relancez la commande exacte qui a échoué localement (ou dans le job CI si c'est votre seule option). Si ça échoue encore, collez seulement la nouvelle sortie en échec et répétez. Garder le contexte réduit aide à rester ciblé.
Une fois vert, ajoutez un test de suivi focalisé qui aurait échoué avant le patch et qui passe après. Un test, une raison.
Relancez la commande avec le nouveau test inclus pour confirmer que vous n'avez pas simplement masqué l'erreur.
Demandez un message de commit court et une description de PR qui inclue ce qui a échoué, ce qui a changé, comment vous l'avez vérifié, et quel test empêche une répétition. Les réviseurs vont plus vite quand le raisonnement est explicite.
Un échec courant : tout fonctionnait localement, puis un petit changement fait échouer les tests sur le runner CI. Voici un cas simple d'une API Go où un handler a commencé à accepter une valeur date seule (2026-01-09) mais le code ne parse toujours que des timestamps RFC3339 complets.
Ceci est le type d'extrait à coller (gardez‑le court, mais incluez la ligne d'erreur) :
--- FAIL: TestCreateInvoice_DueDate (0.01s)
invoice_test.go:48: expected 201, got 400
invoice_test.go:49: response: {"error":"invalid due_date: parsing time \"2026-01-09\" as \"2006-01-02T15:04:05Z07:00\": cannot parse \"\" as \"T\""}
FAIL
exit status 1
FAIL app/api 0.243s
Utilisez ensuite une invite qui force les preuves, une correction minimale et un test :
You are fixing a CI failure. You MUST use the log to justify every claim.
Context:
- Language: Go
- Failing test: TestCreateInvoice_DueDate
- Log snippet:
<PASTE LOG>
Task:
1) Quote the exact failing line(s) from the log and explain the root cause in 1-2 sentences.
2) Propose the smallest possible code change (one function, one file) to accept both RFC3339 and YYYY-MM-DD.
3) Show the exact patch.
4) Add one regression test that fails before the fix and passes after.
Return your answer with headings: Evidence, Minimal Fix, Patch, Regression Test.
Une bonne réponse pointera le décalage du layout de parsing, puis fera un petit changement dans une seule fonction (par exemple parseDueDate dans invoice.go) pour essayer RFC3339 d'abord puis retomber sur 2006-01-02. Pas de refactor, pas de nouveaux packages.
Le test de régression est le garde‑fou : envoyer due_date: "2026-01-09" et attendre 201. Si quelqu'un supprime plus tard le fallback, le CI casse immédiatement avec la même classe d'erreur.
La manière la plus rapide de perdre une heure est de donner une vue tronquée du problème. Les logs CI sont bruyants, mais la partie utile se trouve souvent 20 lignes au‑dessus de l'erreur finale.
Un piège est de ne coller que la dernière ligne rouge (par exemple "exit 1") en cachant la vraie cause plus haut (une variable d'environnement manquante, un snapshot raté, ou le premier test qui a crashé). Solution : incluez la commande en échec plus la fenêtre du log où apparaît la première vraie erreur.
Un autre temps perdu est de laisser le modèle "nettoyer" en chemin. Formatage, bumps de dépendances ou refactors compliquent la revue et risquent de casser autre chose. Solution : verrouillez la portée sur le plus petit changement et rejetez tout ce qui n'est pas lié.
Quelques motifs à surveiller :
Si vous suspectez de l'instabilité, ne la masquez pas avec des retries. Supprimez l'aléa (temps fixe, RNG seedé, répertoires temporaires isolés) pour clarifier le signal.
Avant de pousser, faites une courte passe de sanity. L'objectif est de s'assurer que le changement est réel, minimal et reproductible, pas un passage chanceux.
Enfin, lancez un jeu légèrement plus large que le job en échec (par exemple lint + tests unitaires). Un piège fréquent est un correctif qui passe le job initial mais casse une autre cible.
Si vous voulez gagner du temps durablement, traitez votre prompt et le format de réponse comme un processus d'équipe. L'objectif est des entrées reproductibles, des sorties reproductibles et moins de "corrections mystères" qui cassent autre chose.
Transformez votre meilleure invite en un snippet partagé et épinglez‑le dans le chat d'équipe. L'objectif : (1) preuves, (2) diagnostic en une ligne, (3) changement minimal, (4) test de suivi, (5) comment vérifier localement. Quand tout le monde utilise le même format, les revues vont plus vite parce que les réviseurs savent où regarder.
Un léger cycle d'habitude utile :
Si vous préférez un workflow centré chat pour construire et itérer sur des applis, vous pouvez exécuter la même boucle fix‑and‑test dans Koder.ai, utiliser des snapshots pendant l'expérimentation, et exporter le code quand vous êtes prêt à le merger dans votre dépôt habituel.
Commencez par la première erreur réelle, pas par le dernier exit 1.
Demandez-lui de prouver qu'il a lu le log.
Utilisez une contrainte comme :
Par défaut, visez le patch le plus petit qui fait réussir l'étape en échec.
Cela signifie généralement :
Évitez les changements de "nettoyage" tant que le CI n'est pas vert.
Collez assez de contexte pour recréer l'échec, pas seulement la dernière ligne rouge.
Incluez :
Oui — exposez les contraintes en langage clair et répétez‑les.
Exemples :
Cela garde la réponse ciblée et facile à relire.
Corrigez d'abord la première erreur réelle.
En cas de doute, demandez au modèle d'identifier la première étape en échec dans le log et concentrez‑vous dessus.
Considérez l'instabilité comme un signal pour supprimer l'aléa, pas pour ajouter des retries.
Stabilisateurs courants :
Une fois déterministe, la « correction minimale » devient évidente.
Demandez la commande exacte exécutée par le CI, puis exécutez‑la localement.
Si la reproduction locale est difficile, demandez un mini‑repro dans le dépôt (un test ou une cible unique) qui déclenche la même erreur.
Écrivez un test de régression ciblé qui échoue avant le correctif et passe après.
Bonnes cibles :
Si c'était une erreur de lint/build, l'équivalent peut être de renforcer une règle de lint ou d'ajouter un contrôle qui empêche la même erreur.
Utilisez des snapshots/rollback pour garder les expériences réversibles.
Boucle pratique :
Si vous utilisez Koder.ai, les snapshots facilitent l'itération sans mélanger les expérimentations dans le patch final à exporter.
go test ./..., npm test, flutter test, etc.).