Maintenir la synchronisation des spécifications, des tests et du code dans le développement de l'IA

Évitez que les agents IA ne s’éloignent des spécifications, des tests et du code.

Sommaire

Les agents de codage IA déploient des fonctionnalités rapidement, mais les spécifications, les tests et le code dérivent silencieusement. Ce guide couvre un modèle de traçabilité, la cartographie spécification-test et spécification-code, ainsi que les vérifications d’intégration continue (CI) qui détectent les écarts avant une fusion.

Une spécification que personne ne vérifie par rapport au système en cours d’exécution est pire que l’absence de spécification, car elle crée une confiance illusoire. Les réviseurs font confiance au document plutôt qu’au diff, et un agent IA invité à « suivre le modèle existant » suivra joyeusement ce que le code fait réellement, même quand cela contredit l’exigence qu’il était censé satisfaire.

La solution n’est pas plus de documentation. C’est un petit lien contraignant entre quatre éléments qui existent déjà dans la plupart des dépôts : l’exigence, la décision de conception derrière elle, les tests qui la prouvent, et les commits ou les demandes d’extraction (pull requests) qui l’ont modifiée.

liens de traçabilité connectant les spécifications, les tests et le code

Une fois que ce lien existe sous forme de données plutôt que comme une compréhension partagée, vous pouvez l’interroger. Vous pouvez demander quelles exigences n’ont pas de couverture de tests, quels tests ne correspondent plus à aucune exigence, et quels fichiers ont changé dans une demande d’extraction sans ID d’exigence correspondant. Cette interrogation est le véritable livrable de cet article, et le reste de l’article explique comment la construire avec des outils que vous utilisez probablement déjà.

Le problème de la dérive : pourquoi les spécifications, les tests et le code sortent de synchro

La dérive apparaît sous quatre formes reconnaissables, et les équipes assistées par l’IA ont tendance à rencontrer les quatre plus rapidement que les équipes qui écrivent chaque ligne à la main.

  • La spécification change, le code non. Une exigence est clarifiée lors d’une conversation de suivi ou d’un fil de commentaires, mais personne ne régénère ou n’édite l’implémentation pour qu’elle corresponde.
  • Le code change, la spécification non. Un agent ou un développeur corrige un bug ou refactorise un module, et la spécification continue de décrire l’ancien comportement comme s’il était toujours actuel.
  • Les tests couvrent l’implémentation, pas l’intention. Les tests unitaires affirment ce que le code fait actuellement, ce qui est circulaire : ils passent par construction même lorsque le code satisfait la mauvaise exigence.
  • Les demandes d’extraction ne référencent pas les exigences. Les réviseurs approuvent un diff sur la base du « ça a l’air raisonnable » car il n’y a aucune affirmation explicite à vérifier.

Les recherches récentes sur les frameworks de développement IA identifient la dérive des spécifications comme un risque récurrent précisément parce que les agents régénèrent le code rapidement et répétément, et chaque régénération est une nouvelle opportunité pour que la spécification et l’implémentation divergent un peu plus. Le débat Développement piloté par les spécifications contre Vibe Coding est en réalité un argument sur ce même mode de défaillance : une spécification que personne n’applique se dégrade en la même dérive qu’avec une, mais avec une cérémonie supplémentaire.

Les workflows modernes de style « spec-kit » encadrent de plus en plus cela comme une dégradation des spécifications : la spécification continue de paraître autoritaire tout en perdant silencieusement sa connexion avec ce que le système fait réellement. La définition centrale du développement piloté par les spécifications traite la spécification comme la source de vérité, mais une source de vérité ne reste vraie que si quelque chose continue de la vérifier par rapport à la réalité.

Un modèle de traçabilité pour le développement assisté par IA

Un modèle de traçabilité fonctionnel nécessite six identifiants qui connectent une exigence métier jusqu’aux lignes de code et à la demande d’extraction qui l’a implémentée. La plupart des équipes en ont déjà trois ou quatre ; ceux qui manquent sont généralement l’ID de décision de conception et le lien explicite retour depuis les tests et les commits.

Identifiant Emplacement Exemple
ID d’exigence requirements.md ou outil de spécification REQ-014
ID de décision de conception ADR / registre de décision ADR-0032
ID de tâche décomposition de tâche ou suivi de problèmes TASK-014-3
ID de test fichier de test ou nom de test test_req_014_password_reset
Lien Commit / PR historique Git PR #482
Fichiers modifiés diff Git auth/reset.go, auth/reset_test.go

Les relations entre ces identifiants forment un graphe plutôt qu’une ligne droite, car une exigence peut engendrer plusieurs tâches, et une demande d’extraction peut toucher plusieurs exigences à la fois.

graph TD REQ["Exigence
REQ-014"] --> ADR["Décision de conception
ADR-0032"] ADR --> TASK["Tâche
TASK-014-3"] TASK --> CODE["Modification de code
auth/reset.go"] TASK --> TEST["Test
test_req_014_password_reset"] CODE --> PR["Demande d'extraction
#482"] TEST --> PR PR --> COMMIT["Historique des commits"]

Stocker ce graphe sous forme de données structurées, et non de prose, est ce qui vous permet de l’interroger plus tard. L’écosystème Spec Kit de GitHub s’est exactement déplacé dans cette direction : des extensions comme spec-kit-trace analysent les jetons REQ-XXX intégrés dans les fichiers de spécification et de test et génèrent une matrice déterministe à partir de cette correspondance textuelle littérale, évitant délibérément les devins basés sur des noms flous qui produisent de faux positifs silencieux.

Cartographie Spécification-Test : transformer les critères d’acceptation en cas de test

Chaque critère d’acceptation dans une spécification est, par construction, une assertion comportementale : étant donné cet état, lorsque l’acteur fait ceci, alors le système devrait répondre ainsi. C’est déjà la forme d’un cas de test, c’est pourquoi les workflows SDD les plus robustes génèrent des tests à partir des mêmes critères d’acceptation qui génèrent le code, au lieu de demander à l’agent générant le code d’inventer ses propres tests a posteriori.

Un format largement utilisé pour écrire ces critères est EARS (Easy Approach to Requirements Syntax), qui force chaque exigence dans un pattern non ambigu et testable tel que « Lorsque <déclencheur>, le système doit <réponse>. » Cette structure se mappe proprement sur quatre catégories de tests que chaque exigence devrait porter :

  • Tests positifs — le chemin heureux que l’exigence décrit explicitement.
  • Tests négatifs — les entrées ou états que l’exigence dit doivent être rejetés.
  • Tests aux limites — les bords des plages, limites et seuils mentionnés dans les critères d’acceptation.
  • Tests de migration — le comportement pour les données ou l’état qui précèdent l’exigence, afin qu’un ancien enregistrement ne contournent pas silencieusement une nouvelle règle.
Type d’exigence Catégorie de test à ajouter Erreur courante
« Le système doit rejeter X » Négatif Seul le chemin d’acceptation est testé
« La limite est N éléments » Limite N-1, N et N+1 ne sont pas tous couverts
« Nouveau champ remplace ancien champ » Migration Les anciens enregistrements sans nouveau champ plantent silencieusement
« En moins de 60 secondes » Limite + timing Le test affirme la logique, pas la budget temps réel

Les tests unitaires écrits de cette manière restent importants comme couche rapide et économique de la pyramide ; les patterns pratiques pour les structurer sont couverts dans le guide de test unitaire Go et le guide de test unitaire Python. Ce que la traçabilité ajoute par-dessus est un jeton d’exigence littéral et stable intégré dans le nom du test ou un commentaire de test, afin qu’une interrogation ultérieure puisse prouver — et non supposer — que REQ-014 a une couverture.

Cartographie Spécification-Code : des plans de conception à un tableau de traçabilité

La cartographie spécification-test prouve le comportement ; la cartographie spécification-code prouve la portée. Elle répond à une question différente : quels fichiers étaient censés changer pour cette exigence, et le diff est-il resté dans cette limite ou a-t-il débordé dans des modules non liés ?

Un plan de conception qui liste les fichiers affectés à l’avance — même une liste approximative — vous donne quelque chose à différer avec la demande d’extraction réelle plus tard. Les commentaires dans le code ne devraient référencer un ID d’exigence que lorsque cela ajoute des informations qu’un réviseur ne peut pas obtenir de la spécification elle-même ; un commentaire répétant le texte de l’exigence verbatim est du bruit, mais `// applique la limite REQ-014 : max 5 tentatives de réinitialisation par heure » mérite sa place car le nombre est autrement invisible dans le diff.

Un tableau de traçabilité généré transforme cela en quelque chose de révisable en quelques secondes plutôt que quelque chose qu’un réviseur doit reconstruire en lisant les deux documents côte à côte :

Exigence Décision de conception Fichiers modifiés Tests Statut
REQ-014 ADR-0032 auth/reset.go, auth/reset_test.go test_req_014_* (4) Couvert
REQ-015 ADR-0032 auth/reset.go aucun Lacune
REQ-016 auth/notify.go test_notify_basic Lien de spécification orphelin

Ce seul tableau fait apparaître deux des modèles de défaillance les plus courants en un coup d’œil : REQ-015 a modifié le code avec zéro tests correspondants, et le test attaché à REQ-016 ne référence pas réellement un ID d’exigence, ce qui signifie que soit la spécification est manquante, soit le test a été mal classé.

Le workflow de la demande d’extraction : réviser les diffs de spécification, de code et de test ensemble

Une demande d’extraction construite autour de la traçabilité révise trois diffs côte à côte au lieu d’un : ce qui a changé dans la spécification, ce qui a changé dans le code, et ce qui a changé dans les tests. La question de révision cesse d’être « est-ce que ça a l’air correct ? » et devient beaucoup plus spécifique : « quelle exigence cette modification satisfait-elle, et les preuves le prouvent-elles ? »

sequenceDiagram participant Dev as Développeur ou Agent participant PR as Demande d'extraction participant CI as Pipeline CI participant Rev as Réviseur Dev->>PR: Ouvrir PR avec diff de spécification + diff de code + diff de test PR->>CI: Déclencher les vérifications de traçabilité CI->>CI: Vérifier la présence de l'ID REQ dans la description de la PR CI->>CI: Exécuter la vérification de couverture spécification-test CI->>CI: Exécuter la vérification de portée de fichier spécification-code CI-->>PR: Poster le rapport de traçabilité comme commentaire de PR Rev->>PR: Réviser selon « quelle exigence cela satisfait-il ? » Rev->>PR: Approuver ou demander des modifications

Une liste de contrôle de réviseur courte et concrète fonctionne mieux ici qu’une longue, car les réviseurs sautent les longues listes sous la pression des délais :

  1. La description de la PR nomme-t-elle l’ID (les IDs) d’exigence qu’elle satisfait ?
  2. Chaque fichier modifié apparaît-il dans la liste des fichiers affectés du plan de conception, ou la portée supplémentaire est-elle expliquée ?
  3. Au moins un nouveau test ou un test existant référence-t-il chaque ID d’exigence touché par cette PR ?
  4. Si la spécification a changé, le code et les tests ont-ils changé dans la même PR, ou y a-t-il un suivi tracé ?

Automatiser la traçabilité dans CI

La révision manuelle attrape la dérive seulement aussi souvent que les réviseurs se souviennent de la chercher, c’est pourquoi les vérifications ci-dessus appartiennent à la CI plutôt que dans une page wiki que personne ne relit. Les mêmes mots de passe GitHub Actions patterns que vous utilisez déjà pour les tâches de build et de test s’appliquent directement ici — les vérifications de traçabilité sont juste une autre tâche dans le même pipeline.

Idées d’automatisation pratiques, approximativement par ordre d’effort :

  • Vérifications CI pour les fichiers de spécification — échouer au build si un fichier de spécification a été édité sans modification de code ou de test correspondante dans la même PR, ou vice versa.
  • Exiger des IDs d’exigence dans les titres ou descriptions de PR — une vérification regex légère (REQ-\d+) bloque les fusions qui ne nomment pas ce qu’elles implémentent.
  • Résumés de traçabilité générés par agent — avoir un agent produire un court résumé des exigences qu’une PR touche, pour qu’un humain confirme plutôt que d’écrire à partir de zéro.
  • Couverture de tests par critère d’acceptation, et non pas seulement par ligne — la couverture de ligne vous dit que le code s’est exécuté ; la couverture d’exigence vous dit qu’une affirmation a été vérifiée.
  • Avertissements de spécification périmée — signaler les spécifications qui n’ont pas été touchées depuis N commits touchant leurs fichiers liés, car les spécifications silencieuses depuis longtemps sont celles qui ont le plus de chances d’avoir silencieusement pourri.

Les extensions construites sur le Spec Kit de GitHub implémentent déjà mécaniquement plusieurs de ces éléments : l’un analyse les jetons littéraux REQ-XXX à travers les fichiers de spécification et de test pour construire une matrice et signaler les tests orphelins, et un pack plus strict orienté V-Model va plus loin, générant une spécification de test appariée pour chaque spécification de développement et produisant plusieurs matrices de traçabilité pour les équipes travaillant sous des cadres réglementaires tels que IEC 62304 ou ISO 26262. Vous n’avez pas besoin de ce niveau de cérémonie pour la plupart des projets, mais l’idée sous-jacente — une matrice déterministe, générée par script plutôt qu’un tableau maintenu à la main — se réduit aussi bien qu’elle s’agrandit.

Utiliser les agents IA pour la traçabilité, pas comme un oracle

Les agents IA sont bien adaptés aux parties mécaniques de la traçabilité et mal adaptés à être le juge final de savoir si une exigence a été réellement satisfaite. Trois tâches correspondent directement aux forces d’un agent :

  • Comparer spécification et diff — demander à l’agent de lister chaque exigence mentionnée dans les fichiers de spécification touchés par une PR, et chaque exigence pour laquelle il n’a pas trouvé de code correspondant.
  • Trouver les exigences non couvertes — demander à l’agent de scanner la suite de tests pour les jetons d’exigence et de rapporter quelles exigences dans la spécification n’en ont aucune.
  • Détecter le code non décrit par la spécification — demander à l’agent de signaler les fichiers ou fonctions modifiés qui touchent des modules porteurs d’exigences mais ne correspondent à aucun ID d’exigence dans le diff.

Le mode de défaillance à surveiller est de faire confiance au résumé de l’agent comme vérité terrain au lieu de le considérer comme un point de départ pour le réviseur. Un agent peut mal lire un commentaire, manquer un jeton d’exigence divisé entre deux fichiers, ou déclarer confiant une couverture pour un test qui n’exerce le chemin de code que superficiellement. Traitez chaque rapport de traçabilité généré par agent comme vous traiteriez le passage d’un réviseur junior : utile, rapide, et toujours soumis à un deuxième regard avant qu’il ne bloque une fusion. C’est la même prudence qui s’applique aux registres de décision pour le développement piloté par l’IA — le registre ne reste fiable que si autre chose que l’agent qui l’a écrit finit par le vérifier.

Un modèle de traçabilité minimal que vous pouvez copier

Vous n’avez pas besoin d’un framework lourd pour commencer. Un modèle de cinq fichiers, commité dans le dépôt à côté du code qu’il décrit, couvre l’essentiel :

docs/
  requirements.md     # IDs REQ avec critères d'acceptation style EARS
  design.md           # IDs ADR, fichiers affectés, décisions architecturales
  tasks.md            # IDs TASK mappés à une ou plusieurs IDs REQ
  tests.md            # quels fichiers/fonctions de test référencent quelles IDs REQ
  traceability.md     # tableau généré : REQ -> ADR -> TASK -> fichiers -> tests -> PR

requirements.md, design.md, et tasks.md sont écrits ou édité par des humains et des agents ensemble, de la même manière que le workflow de développement piloté par les spécifications décrit déjà. tests.md et traceability.md devraient être générés, et non maintenus à la main, même si le générateur est un court script qui ne fait que chercher REQ-\d+ à travers le répertoire de test et les fichiers de spécification — les tableaux de traçabilité maintenus à la main sont eux-mêmes une forme de risque de dérive, car personne ne met à jour un tableau sous la pression des délais.

Conclusion

Le développement piloté par les spécifications n’est pas terminé au moment où le code sort d’un agent ; il n’est utile que lorsque le code, les tests et les spécifications se tiennent honnêtement sur le temps, à travers les PRs, les refactorisations et les changements d’exigence qui arrivent à des mois d’intervalle. Un modèle de traçabilité construit à partir de six identifiants simples, appliqué par une poignée de vérifications CI, et révisé avec une courte liste de contrôle de PR vous donne la plupart des avantages sans la surcharge d’un cadre de conformité complet. Commencez par le modèle minimal, câblez la vérification CI la moins chère en premier — les IDs d’exigence dans les descriptions de PR — et ajoutez le tableau de traçabilité et les avertissements de spécification périmée une fois que cette habitude est ancrée.

La traçabilité est une pièce d’une discipline plus large de test et de documentation couverte dans le cluster Architecture d’application en production, et elle s’inscrit aux côtés des questions d’outillage explorées dans le cluster Outils de développement IA pour les équipes choisissant quels workflows d’agents standardiser.

S'abonner

Recevez de nouveaux articles sur les systèmes, l'infrastructure et l'ingénierie IA.