Aller au contenu
14 août 2026·8 min de lecture

Comment relire du code généré par IA impossible à lire

Apprenez à relire du code généré par IA à grande échelle avec tests de propriétés, tests différentiels, invariants et inspection humaine ciblée.

Comment relire du code généré par IA impossible à lire

Un modèle peut produire en un après-midi plus de code qu'une équipe compétente ne peut en examiner en une semaine. Ajouter des relecteurs pour conserver l'ancien rituel ne résout pas ce décalage. Cela crée une file d'attente, favorise les approbations superficielles et laisse encore passer des défauts répartis dans des centaines de fonctions qui, prises séparément, semblent plausibles.

La norme praticable repose sur les preuves, pas sur une couverture visuelle complète. Les relecteurs doivent démontrer que le nouveau système conserve le comportement requis, respecte les règles qui doivent toujours tenir et ne prend aucune décision inacceptable aux rares endroits où le jugement humain ne peut pas être automatisé. La lecture compte toujours, mais elle se concentre sur les endroits où une ligne peut modifier une autorisation, de l'argent, des données ou une reprise.

Classer le risque avant de choisir la méthode de revue

La quantité de code ne dit presque rien sur la quantité de revue nécessaire. L'effort doit suivre la conséquence d'une mauvaise décision et la facilité avec laquelle les tests peuvent l'observer. Un analyseur généré à partir d'une grammaire précise peut mériter davantage de cas automatisés et moins de lecture ligne par ligne qu'une courte fonction d'autorisation dont l'intention se trouve dans des politiques et leurs exceptions.

Commencez par diviser la modification en surfaces comportementales. Une surface regroupe des entrées, un état et des sorties testables comme un seul contrat: calcul de facture, éligibilité d'un compte, conversion de fichier, évaluation d'un droit, reprise d'un traitement par lots ou migration de base de données. Ne divisez pas le travail selon le nombre de fichiers générés. Les modèles répartissent souvent une décision entre adaptateurs, fonctions auxiliaires et types, tandis qu'un grand convertisseur de données généré peut ne contenir presque aucune décision indépendante.

Pour chaque surface, notez quatre faits: la conséquence d'un échec, le comportement de référence disponible, les invariants applicables et les emplacements du code qui exercent une autorité. La conséquence détermine la quantité de preuves indépendantes nécessaire. La référence indique si un test différentiel est possible. Les invariants trouvent des défauts même si l'ancienne implémentation les partage. Les points d'autorité montrent où une lecture humaine s'impose.

Une matrice de revue utile ressemble à ceci:

  • Calcul fiscal: comparer l'ancien service aux exemples approuvés, rejouer des cas, vérifier la conservation et examiner l'arrondi ainsi que le choix du taux.
  • Import CSV: utiliser la spécification du format et des échantillons de production, générer des entrées incorrectes et examiner les erreurs ainsi que les limites de ressources.
  • Contrôle de rôle: construire une table de décision à partir des politiques, tester les refus et lire chaque chemin qui autorise.
  • Reprise d'un lot: rejouer l'historique enregistré, injecter des pannes, vérifier l'idempotence et examiner les limites transactionnelles.

Cette classification répond aussi à la question de savoir si le code écrit par un modèle peut être fusionné sans danger. Il est suffisamment sûr uniquement quand les preuves correspondent aux conséquences d'un échec et que chaque écart non résolu a un responsable. Aucun score du modèle, nombre de tests ou sentiment de confiance ne remplace cette décision. Un formateur à faible risque peut passer avec des propriétés et des échantillons. Un chemin de paiement ou d'autorisation exige des spécifications indépendantes, des cas défavorables et une inspection directe.

Écrire le contrat observable avant de lire l'implémentation

Un relecteur a besoin d'une description externe du bon comportement avant d'ouvrir le code généré. Sinon, l'implémentation devient discrètement sa propre spécification et une structure plausible est prise pour une intention correcte. Le contrat doit décrire ce que les appelants peuvent observer, notamment les valeurs renvoyées, les changements d'état, les erreurs, les limites temporelles pertinentes et les effets externes.

Tirez ce contrat de sources antérieures à la génération: définitions d'interface, procédures d'exploitation, requêtes et réponses de production, contraintes de base de données, jeux d'essai acceptés, réglementations et entretiens avec les personnes qui traitent les exceptions. L'ancien code est une source, pas la seule. Les commentaires peuvent être périmés, les tests peuvent figer des accidents et les opérateurs peuvent dépendre d'un comportement jamais documenté.

Écrivez explicitement les cas gênants. Que se passe-t-il avec une entrée vide? Quel fuseau horaire régit une date limite? Une nouvelle tentative renvoie-t-elle un courriel ou réutilise-t-elle le résultat précédent? Un champ absent diffère-t-il d'une valeur nulle? Quelle règle décimale s'applique exactement entre deux montants représentables? L'ordre porte-t-il un sens alors que l'API prétend le contraire? Ces questions causent plus d'échecs de migration que les erreurs de syntaxe ou de type.

Le contrat doit aussi indiquer les changements permis. Certaines réécritures doivent conserver une sortie identique octet pour octet. D'autres peuvent normaliser les espaces, remplacer un identifiant interne ou renvoyer une erreur plus claire tout en gardant sa catégorie. Sans relation d'équivalence définie, l'outil de comparaison signale du bruit inoffensif ou, pire, normalise un vrai défaut jusqu'à le faire disparaître.

Formulez des clauses testables. «Traite correctement les factures» ne sert à rien. «Pour une facture acceptée, le débit comptabilisé égale la somme des crédits dans la devise du grand livre» peut devenir une propriété. «Les nouvelles tentatives sont sûres» reste vague. «Répéter le même identifiant de requête ne produit aucun effet externe supplémentaire» donne une mesure au banc d'essai.

Faites ce travail avant la lecture, car le code généré sait convaincre. Il présente noms, branches, contrôles et commentaires sous des formes familières. Face à une implémentation propre, le relecteur commence à expliquer pourquoi elle paraît logique au lieu de demander si elle applique la règle attendue. Le contrat maintient la charge de la preuve en dehors du texte généré.

Les tests de propriétés couvrent un espace d'entrées

Les tests de propriétés conviennent lorsqu'une règle vaut pour beaucoup d'entrées impossibles à énumérer une par une. Ils ne prouvent pas qu'un programme est correct, et une propriété faible peut approuver une absurdité. Leur force consiste à obliger le relecteur à nommer les relations que des exemples isolés masquent.

Choisissez des propriétés issues du métier, pas de l'implémentation. Les propriétés d'aller-retour conviennent aux encodeurs lorsque décoder une valeur valide encodée doit restituer l'original. Les propriétés de conservation s'appliquent à l'argent, aux stocks et aux comptes d'enregistrements. L'idempotence concerne les nouvelles tentatives, la normalisation et les mises à jour qui se comportent comme des ensembles. La monotonie s'applique lorsque l'ajout d'un élément éligible ne peut pas réduire un total. Les propriétés métamorphiques comparent des entrées liées, par exemple en réordonnant des enregistrements que le contrat déclare sans ordre.

Un test de fuzzing Go concis pour une limite de normalisation peut ressembler à ceci:

func FuzzNormalizeAccount(f *testing.F) {
    f.Add(" ab-123 ")
    f.Add("AB123")

    f.Fuzz(func(t *testing.T, raw string) {
        got, err := NormalizeAccount(raw)
        if err != nil {
            return
        }
        again, err := NormalizeAccount(got)
        if err != nil {
            t.Fatalf("normalized value rejected: %q", got)
        }
        if again != got {
            t.Fatalf("not idempotent: first=%q second=%q", got, again)
        }
        if strings.ContainsAny(got, " -\t\n") {
            t.Fatalf("separator survived: %q", got)
        }
    })
}

Ce test vérifie deux règles réelles: une normalisation réussie est idempotente et sa sortie ne contient aucun séparateur interdit. Il n'affirme volontairement pas que toute chaîne doit réussir. Cela transformerait une politique d'entrée inconnue en exigence inventée. Ajoutez un générateur distinct pour les formes de compte valides si la grammaire acceptée est connue, puis exigez le succès uniquement pour ce générateur.

La réduction des cas compte. Quand un générateur découvre un échec dans une charge de 4 000 caractères, l'artefact utile est la plus petite entrée qui échoue encore. Conservez ce cas réduit comme fixture de régression ordinaire. La recherche aléatoire trouve le trou; le cas fixe empêche son retour et rend la revue répétable. Gardez la graine si le framework en fournit une, mais ne dépendez jamais d'elle seule, car une modification du générateur ou du moteur peut changer la séquence.

Méfiez-vous des propriétés qui ne font que répéter le code. Vérifier que SortRecords renvoie le même résultat qu'un autre appel à SortRecords apprend peu de choses. Vérifier que la sortie est ordonnée, contient le même multiensemble d'enregistrements et ne change pas après un second tri examine des faits indépendants. Les tests de mutation révèlent ici les suites faibles: si la modification d'une comparaison ou la suppression d'une branche de validation laisse toutes les propriétés au vert, la suite n'a pas gagné notre confiance.

Les tests différentiels trouvent les dérives oubliées

Un test différentiel exécute les anciennes et nouvelles implémentations avec les mêmes entrées, puis compare les résultats observables selon une politique d'équivalence explicite. Pour réécrire un système ancien, c'est souvent le moyen le plus rapide de découvrir un comportement caché, car la production a déjà exploré des combinaisons qu'un nouveau plan de test omettra.

Construisez le banc d'essai autour d'une frontière, pas de fonctions privées. Capturez une requête ou une entrée de traitement, l'état initial pertinent, le résultat renvoyé, les changements d'état durables et les effets externes. Exécutez ensuite les deux systèmes depuis des états initiaux équivalents. Remplacez horloges, sources aléatoires, identifiants et services distants par des adaptateurs contrôlés afin que le non-déterminisme ne submerge pas la comparaison.

Un enregistrement de comparaison doit être inspectable plutôt que réduit à un compteur vert ou rouge:

{
  "case_id": "replay-01842",
  "input_hash": "sha256:...",
  "old": {"status": "accepted", "total_minor": 1250, "events": ["invoice_posted"]},
  "new": {"status": "accepted", "total_minor": 1250, "events": ["invoice_posted"]},
  "normalizations": ["generated_id", "timestamp_within_1s"],
  "result": "equal"
}

Enregistrez chaque normalisation. Si le banc retire les horodatages, trie les collections, masque les identifiants ou ramène les textes d'erreur à des catégories, cette politique doit être relue. Une normalisation trop large peut supprimer précisément la différence recherchée. Trier tous les tableaux peut cacher un ordre de comptabilisation modifié qui affecte un traitement en aval, alors que comparer des identifiants générés bruts produit des échecs sans intérêt.

La capture du trafic de production exige de la prudence. Retirez ou tokenisez les champs sensibles avant leur arrivée dans un environnement de test général. Préservez les relations dont dépend le comportement, par exemple un même client présent dans plusieurs requêtes. Un sac d'exemples déconnectés et trop nettoyés peut sembler sûr tout en perdant les règles de session, d'ordre et de nouvelle tentative. Dans les environnements réglementés, gardez capture, exécution et artefacts dans le périmètre approuvé.

La couverture doit décrire les comportements représentés, pas seulement le nombre de rejeux. Répartissez les cas par opération, résultat, indicateurs importants, catégorie d'erreur, forme des données et condition limite. Dix mille lectures réussies ne compensent pas l'absence d'écriture échouée, de soumission en double, de bascule de fin de mois ou de reprise après une écriture partielle. Suivez les partitions vides comme une dette de revue explicite.

Exécutez le banc en continu pendant la génération et après les modifications humaines. Un dernier rejeu attrape les nettoyages bien intentionnés qui changent le comportement après le travail du modèle. Gardez les écarts comme des enregistrements durables assortis d'une décision: nouveau défaut, ancien défaut conservé volontairement, ancien défaut corrigé volontairement, changement de politique attendu ou faute du banc. Un écart inexpliqué n'est pas un échec à dispenser, c'est une décision inachevée.

L'ancien système témoigne, il ne tranche pas

Livrer en moins de 30 jours
CodeHero livre le système modernisé avec parité comportementale en moins de 30 jours.

Reproduire exactement l'ancienne implémentation peut conserver des défauts, des valeurs par défaut dangereuses et des contournements dont la raison a disparu. L'égalité différentielle prouve la compatibilité, pas la justesse. Tout comportement aux conséquences sérieuses demande une règle indépendante.

La distinction devient concrète quand l'ancien système accepte un état impossible. Supposons qu'un traitement par lots puisse marquer une facture comme payée après avoir écrit l'entrée comptable, mais avant de confirmer la référence de paiement. Le rejeu de production montre cette séquence, donc la réécriture la reproduit. Une barrière limitée à la parité annonce un succès. Une propriété de conservation peut aussi réussir puisque les montants s'équilibrent. Seul un invariant exigeant une référence confirmée pour l'état payé révèle la transition invalide.

Ne corrigez pas non plus chaque bizarrerie en silence. Un défaut peut être devenu une interface. Des rapports en aval peuvent attendre un résultat d'arrondi inhabituel, les opérateurs peuvent utiliser un code d'erreur précis pour répartir le travail, ou les clients peuvent retenter uniquement après un certain état. Corriger ce comportement sans décision de migration peut provoquer une panne plus large que sa conservation temporaire.

Utilisez un registre des écarts avec cinq champs: comportement observé, règle attendue indépendante, consommateurs touchés, décision choisie et responsable. Si la nouvelle version diffère volontairement, ajoutez un test pour la nouvelle règle ainsi qu'une note de version ou un changement opérationnel lorsque nécessaire. Si le défaut doit rester pour compatibilité, isolez-le derrière une règle nommée afin qu'un futur mainteneur ne le «nettoie» pas par accident.

Le conseil répandu selon lequel la nouvelle suite doit réussir tous les anciens tests est donc incomplet. Les anciens tests sont d'excellents témoins du comportement connu, mais ils portent les mêmes angles morts et hypothèses erronées que le système. Traitez-les comme un ensemble de preuves. Ajoutez des propriétés tirées des règles métier, des tests négatifs tirés de l'analyse des menaces et des contrôles de transition tirés des contraintes des données.

Un relecteur doit se méfier quand la parité atteint trop facilement 100 pour cent. La frontière est peut-être trop étroite, les fixtures omettent les cas difficiles ou le comparateur ignore trop de choses. Examinez un échantillon de traces brutes anciennes et nouvelles, échecs compris, avant de croire l'agrégat. Une bonne preuve reste lisible quand on l'ouvre.

Les invariants doivent survivre à chaque entrée et sortie

Un invariant est une condition qui doit tenir dans tous les états valides, pas une simple assertion posée sur le chemin heureux. Placez les contrôles aux frontières où l'état entre, change et sort: gestionnaires d'API, consommateurs de messages, validations de transactions, imports de fichiers, points de reprise des traitements et sérialiseurs.

Classez les invariants par portée. Les invariants locaux contraignent une valeur, comme une quantité qui ne peut pas être négative. Les invariants agrégés relient une collection, comme l'égalité entre débits et crédits. Les invariants temporels imposent un ordre, comme l'approbation avant le décaissement. Les invariants d'autorité contraignent les acteurs, par exemple un utilisateur ne peut jamais approuver sa propre demande. Les invariants de reprise gouvernent les nouvelles tentatives et redémarrages, avec un seul effet durable par jeton d'idempotence.

Les contraintes de base de données apportent une application forte et indépendante de certaines règles. Une contrainte d'unicité bloque les identifiants dupliqués même si tous les appelants commettent la même faute. Une référence étrangère empêche un enregistrement orphelin. Une contrainte de vérification refuse une combinaison invalide d'état et de champ. Les tests applicatifs doivent tout de même exercer le chemin d'erreur obtenu, car un refus techniquement sûr devient une panne si le worker recommence sans fin.

Les machines à états méritent des tests de transition explicites. Générez des séquences valides et vérifiez que chaque transition conserve tous les invariants. Générez ensuite une transition invalide dans chaque état et exigez son refus sans changement partiel. Une assertion limitée à l'état final rate les dégâts temporaires, les messages en double et les écritures qui survivent à une réponse d'erreur. Capturez l'état avant et après la tentative.

Placez les assertions d'exécution selon les conséquences. Des contrôles peu coûteux sur les entrées non fiables peuvent fonctionner à chaque requête. Un rapprochement coûteux entre tables peut tourner à la validation d'une transaction, dans un processus fantôme ou comme barrière de déploiement. Ne supprimez pas un invariant utile parce qu'il coûte trop cher dans le chemin le plus fréquent; déplacez-le au point le plus proche où il attrape encore la faute avant sa propagation.

Surveillez les violations par identité, pas comme des exceptions génériques. L'alerte doit nommer la règle, l'entité concernée, l'opération et la version. Évitez de journaliser la charge sensible qui a servi à la détection. Un nombre sans identité ne guide ni le retour arrière ni le diagnostic, tandis qu'une charge complète peut créer une autre fuite de données.

Les relecteurs doivent demander qui possède chaque invariant. Si tout le monde convient que les soldes doivent correspondre mais qu'aucun test, contrainte, contrôle d'exécution ou rapprochement planifié ne l'impose, l'invariant n'existe que dans les conversations. Attribuez au moins un contrôle exécutable et une réponse claire à chaque règle dont la violation compte.

La revue humaine vise les points de concentration sémantique

Rendre les écarts inspectables
Chaque réécriture conserve le comportement d'origine tout en remplaçant l'ancienne architecture.

Les humains doivent lire le code lorsque l'intention ne se déduit pas seulement des entrées et sorties, ou lorsqu'une petite décision entraîne une grande conséquence. Ces points comprennent l'autorisation, la cryptographie, les limites transactionnelles, la migration de schéma, la concurrence, la suppression de données, les effets externes, la reprise sur erreur et tout adaptateur qui normalise les preuves de test.

Lisez tous les chemins qui accordent une autorisation. Une grande suite de refus aide, mais le sens d'une politique dépend souvent de l'héritage des rôles, des limites entre locataires, des délégations et du comportement par défaut quand le contexte manque. Comparez la source de la règle et le code. Vérifiez que la valeur par défaut refuse, que les décisions en cache ont la bonne portée et que les journaux ne révèlent pas de données protégées.

Lisez les limites de transaction et de nouvelle tentative comme un tout. Trouvez le point où l'opération devient durable, puis suivez chaque erreur possible avant et après. Vérifiez si une nouvelle tentative répète une écriture, envoie un deuxième message ou voit un état partiellement validé. Le code généré traite souvent chaque erreur localement de manière plausible tout en manquant la séquence entre fonctions qui crée un doublon.

Lisez le comparateur et le banc avec plus de méfiance qu'un auxiliaire de test ordinaire. Les preuves ne sont honnêtes que si la mécanique qui déclare deux exécutions égales l'est aussi. Le modèle auteur du code de production ne doit pas être le seul auteur et juge de sa politique d'équivalence. Une personne doit approuver les champs ignorés, tolérances, ordres canoniques et associations entre catégories d'erreur.

Lisez les changements de dépendances et de configuration générée. Les tests peuvent ne jamais exercer une option d'analyse dangereuse, une permission réseau trop large, une vérification de certificat désactivée ou un groupe de workers sans limite. Examinez les fichiers de verrouillage, scripts de construction, droits des conteneurs, permissions de base, paramètres de désérialisation, délais et limites de ressources. Ces choix changent la surface d'attaque sans modifier les sorties fonctionnelles habituelles.

Échantillonnez le code ordinaire seulement après les points de concentration. Pondérez l'échantillon par le risque: inspectez un chemin vertical complet pour quelques opérations représentatives, ainsi que le code très complexe, marqué par une incertitude inhabituelle du modèle, des réparations manuelles répétées ou une faible portée des tests. Un échantillon de lignes au hasard donne une apparence de sérieux, mais suit rarement une décision assez loin pour la juger.

La revue humaine se termine toujours par une décision écrite. Le relecteur doit nommer ce qu'il a inspecté, les preuves auxquelles il s'est fié, ce qu'il a exclu et le risque résiduel. «Ça a l'air bon» n'est pas une approbation valable pour une modification générée que personne ne pouvait lire entièrement.

Les preuves ont besoin de leur propre chaîne de traçabilité

Garder les modèles chez vous
CodeHero peut exécuter ses modèles hors réseau sur du matériel client ou loué approuvé.

Les grandes modifications générées exigent un registre qui relie exigences, tests, partitions de rejeu, écarts, observations humaines et build exact examiné. Sans ce lien, une équipe accumule des milliers de résultats positifs qui peuvent appartenir à d'autres commits, fixtures, normaliseurs ou versions de dépendances.

Donnez une identité stable à chaque artefact. Notez la révision source, la révision générée, les entrées de construction, la version du banc, l'instantané des fixtures, les graines aléatoires utiles et la configuration d'environnement qui influence le comportement. Calculez l'empreinte des entrées capturées après la suppression approuvée des données afin que les relecteurs sachent si deux rapports utilisent le même corpus sans conserver les données brutes interdites.

Associez chaque règle du contrat à ses preuves. Une règle peut avoir un test de propriété, une contrainte de base, une partition de rejeu et une note d'inspection manuelle. Une autre n'aura qu'une validation humaine parce que l'automatisation ne peut pas observer le jugement métier. Les associations vides sont utiles: elles montrent exactement où une approbation dépend d'une hypothèse. Un tableau rempli de compteurs verts masque ce manque.

Mettez les preuves instables en quarantaine au lieu de relancer jusqu'au vert. Conservez le cas en échec, cherchez si le non-déterminisme vient du produit ou du banc et corrigez la cause. Les relances répétées transforment le sens de la barrière de «le build a réussi» en «une tentative a réussi», affirmation bien plus faible. Si un test ne peut pas encore bloquer, marquez-le comme non bloquant et gardez ses échecs visibles.

Conservez les contre-exemples et décisions sur les écarts avec la modification. Ils expliquent mieux le comportement qu'un commentaire généré parce qu'ils contiennent une entrée, une observation et un résultat approuvé. Quand une réécriture ultérieure touche la même surface, ces artefacts forment une mémoire institutionnelle compacte qui ne dépend pas de la présence du relecteur initial.

CodeHero applique ce principe aux réécritures de systèmes anciens en comparant le comportement au trafic de production enregistré avec un banc de parité, tout en modernisant l'architecture au lieu de recopier l'ancienne ligne par ligne. Cette affirmation ne vaut que si le corpus de rejeu, la politique de comparaison et les décisions sur les écarts restent ouverts à l'examen du client.

Le registre doit être reproductible par une personne qui n'a pas généré le code. Si un deuxième ingénieur ne peut pas lancer les contrôles indiqués et obtenir le rapport, l'équipe possède une présentation, pas une preuve. La reproductibilité réduit aussi la dépendance aux explications du modèle, qui peuvent sembler cohérentes sans correspondre au build compilé.

Les preuves expirent quand le système environnant change. Un rapport de rejeu produit avant une migration de schéma, une mise à jour de dépendance ou une modification du comparateur n'approuve pas le build suivant. Définissez des règles d'invalidation dans le registre: un changement du contrat relance les propriétés touchées, un changement de normalisation impose la revue des égalités précédentes et un changement de persistance relance les séquences de reprise. Un rapport autrefois vert ne devient pas une permission permanente.

Gardez les preuves près de leur surface. Un énorme rapport de livraison rend difficile de savoir quel contrôle protège quel comportement et pousse les relecteurs à approuver le lot entier. Les dossiers par surface permettent de remplacer un composant, de refaire sa démonstration et de laisser les autres preuves intactes. Ils révèlent aussi les contrôles partagés. Si cinq surfaces dépendent du même adaptateur d'horloge ou de la même règle de comparaison, ce composant mérite une lecture directe, car une erreur peut fausser cinq conclusions.

Réexaminez le processus de preuve après un défaut échappé. Demandez quelle clause manquait, quel générateur ne pouvait pas produire le cas, quelle partition était vide, quel invariant n'existait pas ou quelle lecture humaine a sauté la branche décisive. Ajoutez le plus petit contrôle durable qui aurait attrapé cette classe d'erreur. Exiger davantage de lignes arbitraires à lire augmente le coût sans réparer l'angle mort.

Une politique de conservation doit correspondre au besoin de reproduire l'approbation et à la sensibilité des données capturées. Gardez si possible des contre-exemples réduits et des métadonnées. Limitez ou supprimez les charges de production brutes selon les règles du client. Pouvoir expliquer une décision n'autorise jamais à conserver chaque octet utilisé pour la prendre.

L'approbation doit nommer le risque résiduel

Une réécriture générée est prête quand le comportement requis dispose de preuves indépendantes, que les décisions dangereuses ont reçu une inspection humaine et que l'incertitude restante tient dans le budget de défaillance du système. La fin du travail n'est pas un pourcentage de lignes lues. C'est une déclaration défendable sur ce qui peut encore mal tourner et la façon dont l'équipe le détectera ou le contiendra.

Fixez les barrières selon les conséquences. Pour un convertisseur interne peu risqué, des exemples représentatifs, des propriétés d'analyse et un retour arrière peuvent suffire. Pour les mouvements d'argent, le contrôle d'accès, les dossiers réglementés ou une suppression irréversible, exigez des sources contractuelles indépendantes, des tests négatifs, des invariants appliqués, une couverture différentielle des partitions importantes, une inspection directe des points sensibles et une réponse opérationnelle aux violations.

Ne réduisez pas toutes les preuves à un score. Un taux élevé de correspondance ne compense pas un défaut d'autorisation non examiné. Une bonne couverture de propriétés ne compense pas un comparateur qui masque l'ordre. Une lecture attentive ne compense pas l'absence de tests de nouvelle tentative. Gardez les conditions de veto visibles afin qu'un agrégat flatteur n'enterre pas une lacune grave.

Utilisez une courte fiche d'approbation:

  1. Nommez le build, la version du contrat et l'instantané des preuves.
  2. Listez les barrières obligatoires et leurs résultats.
  3. Listez chaque écart accepté et chaque test non bloquant.
  4. Nommez les points relus par des humains et les relecteurs.
  5. Indiquez les risques résiduels, moyens de détection, limites du retour arrière et responsables.

Arrêtez la livraison lorsqu'un comportement à fortes conséquences ne possède ni référence indépendante, ni invariant, ni revue directe. La décision honnête consiste parfois à réduire la portée: migrer les lectures avant les écritures, exécuter les décisions en mode fantôme sans agir, ou garder une opération dangereuse sur l'ancien système jusqu'à comprendre son contrat. C'est une mesure d'ingénierie, pas un manque d'ambition.

La production des modèles change l'économie de l'écriture du code, mais pas l'identité de ceux qui subiront une mauvaise livraison. Demandez aux relecteurs d'approuver des preuves qu'ils peuvent reproduire et des risques qu'ils peuvent nommer. Ne leur demandez pas de bénir un volume de texte qu'aucune personne ne peut absorber sérieusement.

FAQ

Peut-on automatiser la revue du code généré par IA?

Une grande partie de la collecte peut l'être, notamment les propriétés, comparaisons de rejeu, contrôles d'invariants et partitions de couverture. L'approbation ne peut pas être entièrement automatisée quand l'intention d'une politique, l'autorité, les effets irréversibles ou le risque acceptable exigent un jugement humain.

Les relecteurs doivent-ils lire chaque ligne écrite par un modèle?

Non. Ils doivent lire chaque point de concentration sémantique et assez de chemins complets pour juger la structure, tandis que les preuves automatisées couvrent largement le comportement. Lire des lignes au hasard dans une immense modification donne peu d'assurance et gaspille l'attention.

Quelle différence entre test de propriétés et test différentiel?

Un test de propriétés vérifie une règle sur beaucoup d'entrées générées. Un test différentiel compare deux implémentations avec la même entrée; il repère une dérive de comportement, mais peut aussi conserver un ancien défaut.

Combien de trafic de production faut-il rejouer?

Il n'existe aucun nombre universel honnête. Répartissez le trafic par opération, résultat, limite, erreur et transition d'état, puis rendez visibles les partitions importantes non couvertes au lieu de célébrer un grand total brut.

Suffit-il de reproduire l'ancienne implémentation lors d'une réécriture?

Non. La correspondance prouve la compatibilité avec le comportement observé, défauts anciens compris. Ajoutez des invariants indépendants et des tests tirés des politiques partout où un mauvais résultat entraîne des conséquences sérieuses.

Qu'est-ce qu'un bon invariant pour du code généré?

Un bon invariant décrit une condition valable dans tout état valide et vérifiable indépendamment de l'implémentation. Exemples: écritures équilibrées, isolation des locataires, transitions valides et un seul effet durable par identifiant de requête.

Où concentrer la revue humaine du code écrit par un modèle?

Visez autorisation, transactions, concurrence, suppression, cryptographie, schémas, nouvelles tentatives, effets externes et banc de comparaison. Ces emplacements concentrent beaucoup de sens système dans relativement peu de code.

Comment traiter un écart découvert pendant un rejeu?

Enregistrez ancien résultat, nouveau résultat, règle attendue, consommateurs concernés, responsable et décision. Ajoutez ensuite un test du résultat approuvé; ne cachez jamais l'écart dans une normalisation large ou une dérogation inexpliquée.

Peut-on faire confiance aux tests écrits par le même modèle?

Considérez-les comme des brouillons utiles, pas comme une preuve indépendante. Tirez les propriétés de règles externes, inspectez comparateurs et générateurs, employez des tests de mutation si possible et faites approuver les hypothèses qui peuvent masquer une faute.

Quand faut-il bloquer la livraison d'une réécriture générée?

Bloquez-la lorsqu'un comportement à fortes conséquences manque de preuve indépendante, qu'un chemin dangereux n'a pas été relu directement ou qu'un écart sérieux reste sans décision. Réduire la portée de migration vaut mieux qu'approuver une incertitude sans responsable.