Un refactor n'a pas de symptômes — tu ne vois pas quand Claude se trompe. Trois garde-fous : tests, commits atomiques, clic manuel.
Le refactoring est la tâche où Claude est le plus dangereux. Un bug a des symptômes — bouton qui ne fait rien, valeur undefined, stack trace — tu peux donc dire si le fix de Claude est bon. Un refactor n'en a pas. « Ça tourne encore » peut vouloir dire « les tests passent encore » pendant que le comportement a changé en silence, tu n'as pas vu, et la prod explose une semaine plus tard.
J'ai récemment fait un refactor d'une certaine taille avec Claude sur how2claude : migration des paiements crypto x402 d'un PaymentHandler + FacilitatorClient fait main (139 lignes) vers la gem x402-rails, et en même temps extraction du mapping de champs de Purchase.create! / Subscription.create! — dupliqué dans deux controllers — vers des méthodes de classe sur le model. Un commit, 4 fichiers modifiés, 2 supprimés, 2 ajoutés.
Mon prompt tenait en un mot : « refactor ».
Il pouvait être aussi court parce qu'il y avait des garde-fous autour.
Au moment où la branche en était là, elle avait 221 tests. Tous les chemins critiques du flow de paiement étaient couverts.
Le réflexe par défaut de Claude avant un refactor n'est pas « regarde d'abord les tests ». Alors je lui ai demandé de lancer bin/rails test d'abord, de confirmer que c'était vert, et ensuite de toucher à quoi que ce soit.
Après le refactor, relancer. Toujours vert. Ça ne veut pas dire « aucune régression » — ça veut dire que le comportement connu n'est pas cassé.
Si ton codepath n'a pas de couverture, fais écrire à Claude un test minimal qui fige le comportement actuel. Fais-le tourner, commite. Ensuite refactor. Sinon ce qu'il fait n'est pas un refactor, c'est une réécriture — et tu n'as aucun moyen de vérifier l'équivalence.
Ce refactor, c'était en réalité deux choses :
Purchase / Subscription : controller → méthodes de classe sur le modelCôté frontend, il y avait une troisième : réécrire le flow de signature côté JS avec viem + x402-fetch.
J'ai fait découper Claude selon les frontières naturelles : backend + extraction de model dans un commit (9f3e239), frontend dans un commit séparé (93746d8). Chaque commit porte une description complète, la liste des fichiers, et le pourquoi du changement.
Bénéfices :
- Les diffs restent lisibles. Un commit, une chose.
- Granularité du rollback. Si la prod attrape un bug frontend, git revert 93746d8 n'annule que le frontend, le backend reste.
- L'attention de Claude lui-même reste concentrée. Un commit, une chose — et son attention ne couvre que cette chose-là.
Une fois le refactor terminé, je fais arrêter Claude et je lui demande de me montrer git diff --staged. Pas de tests, pas d'appli lancée, lire le diff d'abord.
Signaux que je scanne :
app/services/x402/payment_handler.rb supprimé entièrement — OK, c'est l'objet de la migration vers la gem. Mais s'il supprime quelque chose que je ne lui ai pas demandé de toucher, je m'arrête et je demande.Purchase.create!(wallet_address: verify_result["payer"], ...) → Purchase.record_x402!(payment:, settlement:) lit maintenant payment[:payer]. La source a changé (request.env de la gem vs valeur de retour de l'ancien client), mais les champs doivent se correspondre un à un.Piège 1 : les Stimulus controllers de la gem n'ont pas été chargés, en silence
La gem x402-rails embarque ses propres Stimulus controllers. Claude a écrit le code, les tests sont passés au vert. J'ai cliqué à la main sur le bouton de paiement — rien.
Raison : dans config/importmap.rb, le pin pour @hotwired/stimulus pointait vers un fichier vendor inexistant, et importmap a silencieusement supprimé ce pin. Les controllers de la gem ne se sont jamais chargés. Les tests ne peuvent pas attraper ça parce que bin/rails test n'exécute pas le JS.
Piège 2 : YAML a parsé 0x... comme un entier
wallet_address: 0x833589... — sans guillemets. YAML a vu le préfixe 0x, l'a lu comme un entier hexadécimal. Le facilitator a reçu une non-chaîne et a refusé. Claude ne s'est pas arrêté pour penser aux règles de parsing YAML en écrivant la config.
Les deux pièges ont été attrapés parce que j'ai cliqué sur le vrai bouton. Tests au vert ≠ feature qui marche. La vérification manuelle après un refactor n'est pas optionnelle.
Le refactoring est le scénario « laisser Claude conduire » à plus haut risque. Les garde-fous ne sont pas pour Claude. Ils sont pour toi — pour que quand Claude se trompe, tu l'attrapes en 5 minutes plutôt que dans un incendie de prod.