Neuf jours. C'est le temps qu'une équipe de sécurité de cinq personnes a passé à vider quatre cent trente signalements sortis d'un nouveau scanneur de code à intelligence artificielle, et le jeudi après-midi le tableau de bord affichait enfin zéro dans toutes les catégories de gravité, ce qui ressemblait pas mal à une victoire. Quelqu'un a commandé de la pizza. Le travail était réel.
Deux semaines plus tard, la même fonctionnalité sortait de la production. Pas de brèche, pas de plantage; elle calculait l'admissibilité aux remboursements sur la mauvaise frontière de journée pour à peu près onze mille comptes, fidèlement, chaque nuit, exactement comme c'était écrit. Personne n'avait jamais écrit quel fuseau horaire servait de coupure. Fait que le code en a choisi un.
Tous les signalements étaient réglés. Le logiciel était encore fautif, et aucun refactoring, aucun correctif, aucune mise à niveau de modèle et aucun réglage de scanneur n'allait jamais faire remonter ça, parce que le code était une implémentation impeccable d'une exigence qui n'existait pas. Ça, c'est la dette d'exigences. On ne la refactore pas. On ne peut même pas la chercher avec un grep.
C'est quoi, la dette d'exigences?
La dette d'exigences, c'est le coût accumulé d'une intention jamais captée, mal captée, ou jamais validée, puis implémentée correctement. Une seule propriété la sépare de la dette technique, et elle est décisive. La dette technique est visible dans l'artéfact : on ouvre le fichier, un linter la signale, un profileur la mesure, un réviseur peut argumenter avec toi sur la valeur du raccourci, et un refactoring l'enlève sans rien changer à ce que le logiciel fait pour le monde. La dette d'exigences n'est pas dans l'artéfact. Elle vit dans l'écart entre ce que quelqu'un voulait dire et ce que quelqu'un a écrit.
Donc elle n'a pas d'adresse. Un item de dette technique reçoit un billet, une estimation, une place dans un sprint; la dette d'exigences, non, parce que la chose contre laquelle on ouvrirait le billet, c'est l'absence d'une phrase que personne n'a remarqué qu'elle manquait. Les intérêts courent pareil. Ils composent à travers chaque artéfact bâti en aval de l'écart, alors le design en hérite, la suite de tests en hérite, et les critères d'acceptation le confirment, tout le monde d'accord avec tout le monde, et tout le monde fautif dans la même direction. Rien ne contredit. C'est cet accord-là qui coûte cher.
J'appelais ça un problème de documentation. Vingt-cinq ans dans la livraison de logiciels d'entreprise m'ont fait changer d'idée pas mal solidement. La documentation, c'est ce qu'on produit après que la réflexion a eu lieu, et une équipe peut sortir quatre cents pages impeccables en traînant plus de dette d'exigences qu'une équipe qui a produit neuf points en rafale, puis en a débattu deux heures dans un local à Boucherville avec des crayons de tableau blanc à moitié secs. Le volume, ce n'est pas de la validation. La dette vit dans les questions que personne n'a posées.
Pourquoi la dette de sécurité de l'IA est-elle le symptôme et non la maladie?
Parce qu'une vulnérabilité a une forme et qu'une exigence manquante n'en a pas. Demande à un responsable de la sécurité ce qui l'inquiète cette année : la réponse est constante, et elle a maintenant du poids de sondage derrière elle.
Ce budget-là répond à quelque chose de vrai. Les modèles génératifs produisent des patrons non sécuritaires, échappent des identifiants dans les commits, et livrent les deux plus vite que la révision les absorbe; j'ai défendu cette thèse au long dans le texte sur la dette de sécurité de l'IA. Rien de faux là-dedans. C'est juste en aval.
Voici le mécanisme. Une vulnérabilité est un défaut dans la façon dont le code fait une chose, et chaque scanneur sur le marché fonctionne parce que la mauvaise chose a une forme reconnaissable : une requête non paramétrée, un identifiant en dur, une borne non vérifiée, une dépendance avec un avis publié. La dette d'exigences n'a aucune forme à reconnaître. La fonctionnalité de remboursement du début de ce texte a passé toute la chaîne du premier coup avec zéro signalement, et c'était normal, parce qu'aucun jeu de règles au monde ne contient une règle qui dit « cette fonction assume silencieusement l'heure de l'Est ». Du code correct. Du logiciel fautif.
Alors l'argent suit les signalements, et les signalements suivent les formes. Ce n'est pas de la bêtise. C'est la mesurabilité qui fait ce qu'elle fait toujours, soit rendre le problème comptable plus important que l'autre, et c'est la plus vieille erreur d'allocation budgétaire de l'industrie avec un habit neuf.
Peut-on refactorer pour sortir d'une mauvaise exigence?
Non. La raison est structurelle, pas une question d'effort ni de talent. Le refactoring a une définition, et celle que tout le monde utilise vient de Martin Fowler : changer la structure interne d'un logiciel sans changer son comportement observable. Relis ça deux fois en pensant à une mauvaise exigence. Le comportement observable, c'est précisément ce que la mauvaise exigence a raté, alors un refactoring fidèle préserve le défaut par construction et te remet une version plus propre, mieux nommée et mieux testée de la même erreur.
Corrige la vulnérabilité : le comportement reste. Réécris le module dans un langage plus sûr : le comportement reste. Pointe un agent sur le dépôt en lui demandant de moderniser, et le comportement arrive plus vite, avec des docstrings. Il existe maintenant une mesure de ce qui arrive quand l'instruction elle-même est floue.
Deux mots comptent plus que les chiffres : fonctionnellement divergentes. Devant la même exigence floue, le modèle ne bloque pas et ne demande rien. Il tranche. Il choisit une interprétation et écrit du code propre, plausible et bien structuré autour, puis le modèle suivant choisit une autre interprétation et fait exactement la même affaire, et les deux sorties passent la révision parce que les deux sont cohérentes en elles-mêmes. Ambiguïté à l'entrée, assurance à la sortie. C'est ça, l'accélérant.
Où s'accumule vraiment la dette d'exigences?
Quatre endroits, et aucun n'est le dépôt de code.
La question jamais posée. Quelqu'un dans la bâtisse connaît la réponse et personne ne va lui demander, souvent parce que la question a l'air trop de base pour la poser à voix haute devant la salle. Les fuseaux horaires. Les règles d'arrondi. Qui compte comme utilisateur actif, exactement, le jour du renouvellement.
La décision prise dans le corridor. Deux personnes règlent une vraie ambiguïté en quatre-vingt-dix secondes devant la porte d'une salle, correctement, et la résolution n'atteint jamais un texte. Six mois plus tard, ni l'une ni l'autre ne se souvient d'avoir décidé, le code est le seul témoin qui reste du choix, et plus personne ne peut expliquer à un auditeur pourquoi le logiciel se comporte comme ça.
La valeur par défaut assumée. Personne n'a choisi l'heure de l'Est. L'absence de fuseau écrit s'est réglée en silence, par une librairie, dans une couche que personne ne surveillait, et l'hypothèse est devenue une exigence à la seconde où elle a été livrée.
L'exigence qui était vraie en mars. La réglementation bouge, les prix bougent, l'intégration du partenaire bouge. La spec ne bouge pas, parce que rien dans le système ne sait que le monde a changé.
Remarque le point commun. Chacun de ces quatre cas est un fait sur des personnes, un moment ou un contexte, pas un fait sur du code, et c'est exactement pour ça que l'outillage boulonné à ta pile de développement n'en voit rien; j'ai détaillé ce que cette pile couvre et ne couvre pas dans le coût caché que ta pile IA de codage ignore. Le dépôt est le mauvais endroit où chercher. Il n'y manque rien.
Entre le 21 et le 31 décembre 2022, Southwest Airlines a annulé près de 17 000 vols. Le déclencheur était une tempête hivernale, sauf que la tempête a frappé tous les transporteurs et qu'un seul s'est effondré. Ce qui a cédé, c'est le système d'assignation des équipages.
Ce logiciel n'était pas défectueux au sens habituel du mot. Il roulait depuis des années, il était entretenu et corrigé, et il faisait précisément ce pour quoi il avait été bâti. Ce qu'on ne lui avait jamais demandé de faire, c'était de reconstruire les jumelages d'équipages au volume produit par la tempête, d'un coup, sur tout un réseau point à point. Ce scénario-là n'avait jamais été écrit comme exigence.
Le chef de l'exploitation Andrew Watterson a témoigné devant le comité du commerce du Sénat américain le 9 février 2023, et son compte rendu est que la perturbation avait révélé le besoin d'ajouter des fonctionnalités au logiciel d'assignation pour venir à bout d'un large arriéré de jumelages brisés. La mise à niveau est entrée en production le lendemain. Southwest a investi lourdement dans ce système depuis.
Regarde ce qu'était le correctif. Pas un refactoring. Pas un patch sur une logique brisée. Un nouveau comportement, spécifié pour un cas qui n'avait jamais été spécifié, la seule chose qui pouvait marcher. Pas cher à demander en planification. Cher à apprendre dans un aéroport.
Source : Témoignage écrit d'Andrew Watterson, chef de l'exploitation, Southwest Airlines, comité du commerce, de la science et des transports du Sénat des États-Unis, « Strengthening Airline Operations and Consumer Protections », 9 février 2023. Sujet fournisseur : Southwest décrivant son propre incident, ce qui en fait la source primaire correcte pour le mécanisme.
Comment rembourser la dette d'exigences avant le code?
On ne la rembourse pas après, alors toute la réponse se trouve en amont du premier commit. Trois gestes, classés par ce qu'ils rapportent.
Faire de l'absence un livrable à part entière. Chaque révision dans ton organisation demande si ce qui est écrit est correct. Presque aucune ne demande ce qui n'est pas écrit, parce qu'il n'y a pas d'artéfact à réviser et pas de responsable évident à qui l'assigner. Change la question. Une passe de découverte dont le livrable est une liste de questions ouvertes, d'hypothèses nommées et de conflits non résolus produit quelque chose qu'aucune révision technique ne produira jamais, et c'est le seul artéfact de toute la chaîne qui décrit l'écart au lieu du contenu.
Écrire les décisions de corridor la journée même. Deux phrases et une date. J'ai vu plus de reprises coûteuses remonter à une entente de cinq minutes jamais notée entre deux personnes compétentes qu'à n'importe quelle erreur de programmation dont je me souviens, et le remède coûte moins cher que la réunion qui l'a produit.
Interroger la spec sous plus d'un angle. Un réviseur seul confirme sa propre lecture d'un paragraphe, ce qui n'est pas un défaut de caractère, c'est simplement comment la lecture fonctionne. Un angle sécurité, un angle données, un angle conformité et un angle livraison qui regardent le même paragraphe vont se contredire, et la contradiction est le produit. C'est l'argument que je défends depuis la mort du vibe coding et la survie des specs brisées, et l'outillage génératif n'a fait que l'aiguiser.
Une nuance, parce que rien de tout ça n'est gratuit. La découverte a un coût réel et on peut très bien en abuser; une équipe capable de s'interviewer jusqu'à la paralysie et d'appeler ça de la rigueur, ça existe. Mon test est étroit. Demande-toi si la réponse à la question pourrait changer ce qui va être bâti. Si non, arrête.
La dette technique est un défaut dans la façon dont le code fonctionne. La dette d'exigences est un défaut dans ce qu'on lui a demandé de faire.
La dette technique et la dette de sécurité de l'IA sont visibles dans l'artéfact, et c'est pour ça qu'elles obtiennent des billets, des budgets et des tableaux de bord. La dette d'exigences est l'intention jamais captée, mal captée ou jamais validée, et elle est invisible précisément parce que le code l'implémente fidèlement. Le refactoring préserve le comportement observable par définition, donc il ne peut pas retirer un défaut qui vit dans le comportement lui-même.
L'outillage génératif ne crée pas la dette d'exigences. Il l'accélère, parce qu'une exigence ambiguë produit des implémentations propres, assurées et divergentes au lieu d'un blocage et d'une question. Le seul endroit où la rembourser est en amont, avant qu'il y ait du code avec lequel argumenter.