On nous a remis les écrans, puis une copie de ce qui tourne réellement sur le serveur, puis le lendemain le texte de travail du développeur — celui qu'il modifie, et dont il tire ce qu'il met en ligne. Les deux ne coïncident pas, et le prestataire l'écrit lui-même. Sept analyses spécialisées ont lu le code, une huitième a été chargée de les attaquer ; sept affirmations n'y ont pas survécu et sont retirées à la fin de ce document.
Première version, 7 septembre 2026 à 18 h 03 (heure de Barcelone) — dépôt jeremy-flexylead/flexylead-crm, branche main, référence 888cf02, signature de contrôle de l'ensemble f68816ff, récupérée 46 secondes après publication. 872 fichiers, dont 363 pour les écrans, 73 programmes de serveur, 38 scripts et 356 paquets prêts à l'emploi. Le manifeste — la liste officielle de ce qui doit être mis en ligne — en déclare soixante-huit ; le dossier de production en contient quatre-vingt-trois, parce qu'un même programme y est installé sous plusieurs noms.
Seconde version, 8 septembre 2026 à 13 h 51 — référence 730a5e7, signature 11bf212e, récupérée trente-sept minutes après publication. 200 fichiers, 101 612 lignes ajoutées : le texte de travail du serveur, les programmes qui manquaient, 86 fichiers de test — 83 en JavaScript, 3 en Go — et cinq fichiers décrivant six grilles de notation. Le numéro de version de l'application, lui, n'a pas bougé : 1.1.20 — cette livraison a ajouté du texte de travail, pas une nouvelle mise en ligne.
Le dépôt a été créé le 7 septembre : il ne garde que sept étapes de sauvegarde, toutes des 7 et 8 septembre, sur vingt et une heures. L'histoire du logiciel — qui a changé quoi, et quand — n'y est pas. C'est ce qui empêche de dater le moindre défaut, donc de savoir depuis combien de temps il coûte de l'argent.
Cinq points. Le reste du document les démontre.
Rien n'écrit, fonction par fonction, quelle version est en service.
Le serveur du CRM n'est pas un seul programme : c'est une collection de petits programmes, un par question que les écrans posent — « donne-moi les appels de ce commercial », « calcule ce qui est dû à ce centre ». Il y en a quatre-vingt-trois en service. Le manifeste n'en déclare que soixante-huit, parce qu'un même programme est publié plusieurs fois sous des noms différents : celui de l'espace commercial est déployé vingt-trois fois à lui seul.
Nous avons comparé chacun d'eux à la source censée l'avoir produit. Vingt-huit sont identiques au caractère près, trente-huit diffèrent, deux ne sont pas comparables. Et deux copies du même programme, déployées sous deux noms, ne portent pas la même version : l'une est à jour, l'autre a cent soixante-neuf lignes de retard. Ce n'est pas une déduction : les deux fichiers ont été comparés caractère par caractère.
Vingt-trois corrections sont déjà écrites dans le texte de travail et ne tournent pas. Elles portent sur dix-huit programmes.
Le sens est établi : le texte de travail est plus récent que ce qui tourne, pas l'inverse. Trois de ces corrections réparent notre premier constat, celui des chiffres d'appels ; une autre est la réponse du prestataire aux neuf appels mal attribués qu'il a lui-même trouvés le 7 septembre. Il écrit d'ailleurs lui-même que son texte de travail contient des corrections non installées. Plusieurs portent sur les mécanismes exacts de nos constats : le diagnostic est fait, le remède est écrit, il n'a jamais été mis en service.
Le logiciel calcule bien plus qu'il n'enregistre.
Chaque décision d'aiguillage est motivée et conservée. Mais pour chaque montant dû à un centre, le système établit quelle règle s'est appliquée et pourquoi — puis jette ce raisonnement sans l'écrire ni l'afficher. Le jour où un centre conteste sa facture, ni lui ni vous n'avez le détail du calcul à mettre sur la table.
Aucun montant dû à un centre n'est jamais figé.
Tout est recalculé à chaque ouverture d'écran, à partir des barèmes du jour. Il n'existe aucune facture de centre. Le logiciel sait pourtant très bien figer un montant : il le fait déjà, complètement, sur l'argent qui rentre. Quand un fournisseur d'énergie ou de télécom envoie son relevé de commissions, chaque ligne est rapprochée d'une vente, une facture est émise avec son numéro, et le montant ne bouge plus. Rien de tel n'existe sur l'argent qui sort.
Le système ne sait pas dire quand il se trompe.
Aucun seuil, aucune alerte, aucun déclenchement automatique. Un contrôle de cohérence existe, il est correct, et rien ne le lance. Les 283 signalements relevés dans le fil de discussion viennent tous d'un être humain qui a vu quelque chose d'anormal à l'écran. Jamais du système.
Cinq étages. Ce qui entre, ce qui décide, qui travaille, ce que ça produit, ce qui repart — et en dessous, ce sur quoi tout repose. Les encadrés rouges signalent un défaut établi plus bas, les verts un point solide.
Le CRM ne va rien chercher : il reçoit. Quatre choses lui arrivent, par quatre portes différentes — et c'est là que se décide déjà une partie des erreurs.
Un vendeur de listes envoie une fiche : quelqu'un a rempli un formulaire sur internet.
DéfautLe système devine « énergie » ou « télécom » en cherchant des mots. Il teste l'énergie en premier : l'erreur va toujours dans le même sens.Le client compose le numéro. L'opérateur téléphonique demande aussitôt au CRM à qui le donner.
SolideLe CRM se donne une seconde pour répondre, deux et demie au grand maximum ; au-delà il renonce sans bloquer la ligne, et il note pourquoi il a choisi ce commercial.Un robot téléphonique a pris rendez-vous avec un client. Le CRM le range avec le reste à rappeler.
Ce qui a été dépensé en publicité pour obtenir ces contacts, récupéré automatiquement.
DéfautToutes les dix minutes, un automate réécrit les chiffres de la semaine écoulée, plus une seule autre semaine tirée au hasard dans les trois derniers mois. Les dépenses plus anciennes ne sont donc jamais toutes à jour, et le coût par contact du passé bouge sans prévenir.Deux mécanismes séparés, qui n'ont rien à voir. Le premier répond en deux secondes pendant que le téléphone sonne. Le second distribue à tête reposée tout ce qu'il faudra rappeler plus tard.
Cherche l'historique du numéro à sept endroits, vérifie les quotas et qui est disponible, puis fait sonner un ou plusieurs commerciaux.
DéfautIl ouvre une ligne par commercial chez qui ça sonne, et refuse volontairement de les regrouper : un appel qui sonne chez trois personnes en laisse trois. Tout compteur d'appels bâti là-dessus est gonflé.Leads achetés, appels manqués, rendez-vous et rappels attendent au même endroit. Chacun est confié à une personne, ou proposé à un groupe entier.
DéfautUn lead, un rappel ou un rendez-vous qui n'est pas confié à quelqu'un dans la journée ne le sera jamais : il est payé, et personne ne l'appellera.Quatre rôles, quatre écrans. Chacun ne voit que ce que son rôle autorise, et sur ce point le logiciel est bien fait. Ce qu'ils voient, en revanche, ne concorde pas toujours.
Prend un lead ou un rappel dans la file, appelle, puis qualifie : vente, rappel, ou refus. Quatre tentatives pour un numéro qui ne répond pas.
Voit son centre seulement : ses appels, ses ventes, ses notes de qualité, et ce qui lui sera versé.
Voit plusieurs centres à la fois, compare, et arbitre les litiges.
Voit tout : volumes d'appels, coût d'acquisition d'un contact, rentabilité centre par centre.
DéfautLe mot « manqué » a trois définitions différentes selon l'écran, et les compteurs ne se recoupent jamais entre eux.Une fois l'appel passé, le CRM fabrique quatre choses : le texte de l'appel, sa note de qualité, la prime du commercial, et ce qui sera versé au centre. Les deux dernières sont de l'argent.
L'enregistrement est envoyé à un prestataire extérieur, qui le transforme en texte.
DéfautLe texte ne dit pas qui parle. Le client et le commercial sont mélangés dans un même bloc.Une intelligence artificielle relit ce texte et note l'appel critère par critère, selon la grille de qualité négociée avec le centre.
DéfautOnze contrôles cherchent des phrases dans ce texte. Un client qui dit « je n'ai pas d'impayé » fait créditer le commercial à sa place.Calculée au moment de la vente, à partir de l'offre, du type de vente, du centre et de la date. Écrite sur la vente.
SolideLa note de qualité n'entre pas dans ce calcul. Une mauvaise note ne retire rien au commercial.Refait à neuf à chaque ouverture de l'écran, à partir des ventes du mois, de leurs notes de qualité et du barème négocié avec ce centre.
DéfautAucun montant n'est jamais enregistré. Il n'existe aucune facture de centre dans le système.Le CRM ne fait pas que recevoir : il répond au vendeur de leads, et il alimente les chiffres sur lesquels la direction décide où mettre son argent.
À la seconde où la fiche arrive, le CRM répond au vendeur : accepté, ou refusé.
DéfautSi le vendeur renvoie deux fois la même fiche, le CRM répond « accepté » sans rien créer. Et si le CRM est en panne, il répond « refusé » : la fiche est perdue, alors qu'elle peut rester facturable selon le contrat.Ce que la direction regarde pour décider où mettre l'argent : combien coûte un contact, ce que rapporte chaque centre.
DéfautLe coût par contact est divisé par un quatrième compteur d'appels, qui n'existe que pour lui. Il est donc impossible de le retrouver à partir des chiffres que voient les centres et les superviseurs.La plateforme d'Apteva — écrite par Marco, et utilisée aussi pour ses autres projets. C'est elle qui porte la base de données, les fichiers audio, les identités, et qui exécute les fonctions du serveur. Elle pèse plusieurs fois le volume du code écrit pour FLEXYLEAD — un rapport que nous n'avons pas recompté dans cette version du document. Les clés de la transcription, de l'intelligence artificielle et de l'accès aux enregistrements lui appartiennent : ce ne sont pas des accès que FLEXYLEAD emporte en changeant d'hébergeur.
Un jugement d'ensemble serait commode, et faux. Plusieurs de nos alertes de départ ont été retirées après lecture du code : nous les avions écrites en ne regardant que les écrans.
Il n'est pas dans la qualité du code. Il est dans le fait que personne ne peut dire ce qui tourne.
Le 8 septembre, les sources de travail du serveur ont été livrées. Le document qui les accompagne prévient, en toutes lettres, qu'elles « contiennent des correctifs locaux non déployés », que les copies de production « n'ont été ni rafraîchies ni écrasées », et que « la publication n'est pas un certificat de mise en production ».
Vérification faite : sur les soixante-huit fonctions déclarées, vingt-huit se reconstituent à l'identique et trente-huit divergent — une n'est pas comparable parce qu'elle est empaquetée avant d'être envoyée, une dernière n'a pas de copie de production du tout. Et la même source est déployée sous deux noms, flexylead-app-quality-query et quality-partner-gateway : la seconde a 169 lignes de retard. Ailleurs, deux générations d'un même programme commercial cohabitent, soixante-trois lignes les séparent, et le code de la plus récente porte le commentaire de son auteur : « compatibilité de déploiement progressif uniquement ». Il savait qu'il déployait par vagues.
Ce qui manque, ce n'est pas le talent ni le diagnostic. C'est ce qui garantit qu'une vague se termine.
C'est l'objection qu'on nous fera, et elle est légitime : si personne ne peut dire quelle version tourne, que valent vos constats ? La réponse tient en deux registres, et le document les distingue.
Une partie des constats est établie par différence. Les deux copies ne sont pas identiques : quelle que soit celle qui tourne, l'une des deux est fausse, et personne ne peut dire laquelle. Ces constats-là ne dépendent d'aucune hypothèse sur la production.
L'autre partie décrit un comportement de production, et repose sur la déclaration du prestataire lui-même : c'est son document d'accompagnement qui présente ce dossier comme l'archive de ce qui est déployé. Nous le prenons au mot dans les deux sens — son archive nous sert de référence, et son propre avertissement nous interdit d'en dater le contenu. La contradiction n'est pas dans l'audit : elle est dans la livraison.
Et elle se referme d'une seule façon. Le numéro de version en service de chaque fonction, avec sa date de mise en ligne, existe côté plateforme et coûte une commande. Le seul relevé fourni couvre dix fonctions, choisies par le prestataire, sans l'aiguillage, sans le pilotage, sans le tableau de bord. C'est la première demande de ce document, et cette objection en est la meilleure justification.
Vingt-trois correctifs, six fonctionnalités neuves, et aucune régression. C'est le classement des quarante-quatre divergences relevées, ramenées aux dix-huit programmes distincts qui les portent. Le sens est établi sur cinq indices convergents — la source est postérieure au déployé — dont un qui ne dépend d'aucune déclaration : la source a cessé d'appeler une fonction que la production appelle encore, et l'a laissée derrière elle. On ne fait pas ça en sens inverse.
Et la production ne déploie pas un programme : elle déploie certaines de ses instances. Un même fichier est déployé vingt-trois fois. Le script n'en connaît que vingt-deux : la vingt-troisième, flexylead-app-commercial-call-audio-query, est sortie de la liste sans être arrêtée. Elle ne sera plus jamais mise à jour. Trois chantiers y sont déployés sur deux exemplaires, et sur aucun des vingt et un autres. Deux comportements différents du même programme tournent donc en même temps.
Une conséquence qu'il faut mesurer. Tant qu'on ignore quelle version est en service, on peut écrire les correctifs, on ne peut en vérifier aucun. Un relevé partiel livré le 8 septembre donne le numéro de version de dix fonctions : elles s'échelonnent de la 1742 à la 1915 — cent soixante-treize mises en ligne d'écart à l'intérieur d'un même lot de dix fonctions.
Le même jour, d'après les échanges de la matinée du 8 septembre, un composant extérieur s'est mis à jour de lui-même et a cassé l'authentification : les commerciaux n'ont plus pu se connecter, donc plus recevoir d'appel. Réparé en une demi-heure, retombé vingt minutes plus tard. Cette dépendance est datée et racontée par ceux qui l'ont subie ; elle n'est pas reconstituée depuis le code.
Et le désordre se voit jusque dans les paquets livrés. Le dossier contient onze constructions différentes de l'interface, de la version 1.1.12 à la 1.1.20, jamais nettoyées. Un même numéro de version en désigne trois. Deux versions consécutives sont fichier pour fichier identiques. Le dossier de sortie habituel contient la 1.1.12, compilée contre un projet de développement — dont l'identifiant est écrit en clair dans cinq de ces paquets.
Vingt-trois, en quatre familles. Pour chacun : ce qui se passe, sa gravité, le temps et la difficulté de la correction. Quand un correctif existe déjà dans les sources, c'est dit.
Le mot « manqué » a trois définitions selon l'écran. Un seul appel qui sonne chez trois personnes laisse trois lignes, que le code refuse volontairement de regrouper. Et la colonne « uniques » du total ne compte que les appels venus de la publicité : elle ne peut pas, structurellement, égaler la somme des lignes en dessous.
Trois correctifs existent déjà dans les sources. Ils réparent la définition de « manqué », la colonne du total, et le rattachement au bon commercial. Aucun n'est en service. Il reste à trancher, une fois pour toutes, ce que « reçu » et « manqué » veulent dire.
Le pilotage suit la règle en vigueur à la date. La vente, elle, garde le montant figé au moment où elle a été conclue. Ce ne sont pas deux compteurs faux, ce sont deux compteurs justes — un test du prestataire exige même qu'ils diffèrent. Mais rien, à l'écran, ne dit lequel on regarde.
Renommer, et afficher la règle appliquée à côté du chiffre. C'est un problème d'intitulé, pas de calcul.
Une seule fonction, loadFullState, déclare onze tables « facultatives » : si l'une d'elles ne répond pas, l'écran la remplace par une liste vide et n'affiche aucune erreur. Deux de ces onze tables sont les barèmes et les périodes de paie. Le serveur fait la même chose. Le cas le plus lourd est la fonction unique dont sont tirées les vingt-trois fonctions de l'espace commercial : elle contient seize conversions d'erreur en résultat vide. Les fonctions de pilotage, elles, refusent de le faire.
Un correctif existe déjà dans les sources, et la production fait toujours l'ancien geste.
Le pilotage découpe ses grosses requêtes en quatre morceaux et réessaie deux fois en cas d'échec. Or la production compte le dépassement de délai parmi les échecs qui méritent une reprise. Une seule demande d'écran peut donc déclencher douze exécutions de la même requête coûteuse. La source a retiré ce comportement, avec le commentaire de son auteur : « rejouer la même requête coûteuse multiplie la charge sans rien changer ».
Le dépassement de délai n'est donc pas seulement un symptôme de la surcharge : il en est aussi une cause.
Le correctif est déjà écrit dans les sources. Il n'est pas en service.
Le logiciel contient un vérificateur qui cherche les incohérences : une opportunité attribuée deux fois, un rappel dont l'appel a disparu. Il est écrit avec soin, mais il ne compte que les cent premières anomalies de chaque type, et il rend zéro quand il échoue. Aucun écran ne le lance. Deux programmes de vérification l'appellent, à la main, dont un qui vise la base de production.
Lui donner un bouton et une exécution quotidienne. C'est l'instrument avec lequel on jugera toutes les autres corrections — il doit passer en premier.
Tout est recalculé à chaque ouverture d'écran, avec les seules règles encore actives aujourd'hui, dans leur version datée du jour de la vente. Une formule désactivée disparaît donc aussi de toutes les périodes passées : c'est monthlyFormulaRuleFor qui écarte l'inactif avant de lire les dates. Il n'existe aucune facture de centre. Le logiciel sait pourtant le faire, et il le fait déjà dans l'autre sens — sur ce que les fournisseurs d'énergie et de télécom doivent à FLEXYLEAD. flexylead-manage-facturation importe leur relevé, rapproche chaque ligne d'une vente du CRM, puis émet une facture : totaux enregistrés par createInvoice, transitions d'état contrôlées par transitionInvoice — irréversibles une fois la facture approuvée — et copie de la règle appliquée gelée dans chaque ligne. Ce dispositif ne connaît que l'argent qui rentre. Aucune de ses tables ne porte de colonne « centre ».
Appliquer aux centres le modèle qui existe déjà pour l'argent qui rentre. Le code de référence est écrit et éprouvé : il n'a jamais été appliqué au sujet qui fâche.
Le montant déjà écrit sur la vente survit ; c'est la règle qui l'explique, et qui permettrait de le recalculer, qui disparaît. Au premier réenregistrement de la vente, le montant part avec elle.
Retirer une règle du catalogue devrait l'empêcher de s'appliquer aux ventes futures. Elle disparaît aussi de tout l'historique, parce que la recherche écarte les règles inactives avant de regarder les dates. Rouvrir une vente ancienne et y changer l'offre ou la nature de la vente efface sa prime — ou bloque la modification. existingRemunerationSnapshot protège le cas où rien de tout cela ne bouge ; remunerationFor gouverne tous les autres.
Deux lignes de logique, et il faut vérifier ce qui a déjà été effacé.
Côté centre, impossible d'entrer une date passée, et changer le barème referme l'ancien la veille au lieu de l'écraser. Côté prime du commercial : date facultative, rétroactivité libre, écriture par-dessus l'ancienne valeur. Et l'écran ne rattrape rien.
Appliquer au second barème la règle déjà écrite pour le premier. Le modèle est dans le fichier voisin, flexylead-manage-production-economics : validatedEffectiveFrom pour la date, versionRule pour la nouvelle version. Rien à inventer, tout à recopier.
Pour chaque contrat d'énergie, le système établit quelle règle s'est appliquée et pourquoi. Il ne l'écrit nulle part et ne l'affiche nulle part, sauf pour le montant mensuel. Un centre qui conteste un montant n'a donc rien à opposer, et FLEXYLEAD non plus.
Écrire ce que le code produit déjà. Le calcul existe ; il lui manque une destination.
La transcription est demandée sans séparer les interlocuteurs : client et commercial sont mélangés dans un même bloc. Onze contrôles automatiques y cherchent des tournures. Un client qui dit « je n'ai pas d'impayé » fait créditer le commercial à sa place — cette phrase est littéralement dans la règle de recherche. Sur une grille, trente-trois points sur cent se décident ainsi ; sur une autre, vingt-cinq.
Demander la séparation des interlocuteurs, et vérifier qu'elle arrive jusqu'au bout : la plateforme écarte aujourd'hui le détail mot à mot où vivent ces étiquettes. Activer l'option ne suffira pas. En attendant, ces onze contrôles devraient être coupés — mais il faut l'annoncer aux centres, car deux d'entre eux retirent des points : les couper relèvera certaines notes.
Deux des grilles livrées fonctionnent par retrait de points sur une note de départ. Deux versions du moteur cohabitent dans la livraison : celle qui est archivée comme déployée applique bien le retrait ; une seconde copie, nommée « avant correction des instructions », l'ignore et additionne. Rien, dans la livraison, ne dit laquelle tourne.
Si c'est l'ancienne : sur hop_selectra_universelle_v1, un appel qui devrait valoir 90 sur 100 est rapporté 59,5 sur 69,5 — 85,6 % au lieu de 90 %. Sur selectra_compensation_carbone_v1, 96 sur 100 devient 10 sur 14, soit 71,4 %. C'est la question à faire trancher, et elle commande le sort de toutes les notes déjà rendues sur ces deux grilles.
Demander laquelle des deux copies est en service. Si c'est l'ancienne, déployer celle qui connaît les deux modes — elle est dans le dossier — et recalculer les notes déjà rendues sur ces grilles.
Le dispositif de correction existe : il garde le verdict et le score d'origine de chaque ligne — mais pas la note globale d'origine, qui est écrasée, il note qui a corrigé et quand, il affiche un bandeau. Mais il n'additionne pas la note globale comme le moteur, dès que la grille fonctionne par malus. L'écran possède pourtant la fonction qui sait le faire, grilleScoringSummary ; l'écran de correction ne l'appelle pas. Sur une grille, un appel parfait passe de 100 à 69,5 après une simple correction ; sur une autre, de 100 à 14. Sous le seuil configuré pour le centre, la vente cesse d'être rémunérée. Ce seuil n'est pas dans le code : il est enregistré dans la formule de rémunération du centre. Le geste de contrôle qualité fabrique le défaut de qualité.
Et la correction ne survit pas : si l'appel repasse dans la chaîne, le rapport est réécrit de bout en bout ; si l'IA conclut que l'appel ne correspond pas à l'offre, il est supprimé. Rien, dans le moteur, ne sait qu'un humain était passé.
Faire calculer la correction comme le moteur, et marquer les rapports corrigés pour qu'une réévaluation ne les écrase pas. Avant tout : compter combien de notes ont déjà été corrigées à la main.
La notation est confiée à un modèle qui ne rend pas deux fois exactement la même réponse. Rien n'enregistre la version du modèle ni les instructions qui lui ont été données. Le calcul retient d'office la plus récente. Faute d'avoir gardé le modèle et les instructions, personne ne peut dire si c'est la bonne.
Enregistrer, avec chaque note, le modèle et les instructions employés. Les cases existent déjà sur la fiche d'appel ; seuls les programmes de démonstration les remplissent. C'est le seul dont l'estimation soit ferme.
Un rendez-vous pris par l'agent vocal et non distribué dans la journée n'est pas seulement perdu : le système lui écrit « absent au rendez-vous » et « injoignable ». Il sort donc des statistiques comme un échec de contact, et non comme une opportunité que le logiciel n'a pas su distribuer. Personne, en lisant les chiffres, ne peut faire la différence.
Distinguer les deux états, et compter combien de clients ont déjà été classés ainsi.
Quand un rappel se termine, le système est censé libérer la fiche pour qu'un nouvel essai soit possible. La production ne la libère pas — et la fonction qui déclenche le rappel suivant refuse alors, avec le message « un rappel existe déjà pour cet appel ». Trois fonctions, un seul défaut : buildTransition ne libère pas la fiche, assertActiveMissedCallClaim refuse alors le rappel suivant, et le rattrapage recoverFailedCallbackPointer n'existe que dans les sources. Le piège se referme sur lui-même : le cycle des quatre tentatives ne peut pas se dérouler.
Les trois pièces du correctif sont écrites dans les sources, et aucune n'est en service. À vérifier en premier, car cela touche directement le nombre de leads réellement travaillés.
La marque existe en production — isUnattributedIVRAnswer écrit « serveur vocal » sur l'appel. Aucun compteur ne la lit : confirmedBusinessAnswerSql, la règle qui décide de ce qu'est « un appel pris », ignore ce champ. Le prestataire a écrit la correction dans huit fichiers — dont le tableau de bord, l'acquisition, la répartition du travail, la reprise des manqués et la porte d'entrée des appels — plus un module neuf. Aucun n'est déployé.
Un dispositif cohérent en huit fichiers, plus un module neuf, déjà écrit. Il suffit de le mettre en service, et de vérifier qu'il atteint tous les exemplaires.
Trois fonctions reçoivent les événements des opérateurs téléphoniques. Deux sont publiquement joignables de façon établie ; pour la troisième, le dépôt ne dit pas si son adresse est ouverte. Une seule vérifie qui l'appelle — et elle le fait très bien. Les deux autres ne vérifient rien : le champ prévu pour ça est déclaré une seule fois sur 4 565 lignes, à sa déclaration. Qui connaît l'adresse peut créer un appel, créer ou modifier un prospect, en supprimer un, ou écrire une décision d'aiguillage. En revanche, rien de ce qu'elles écrivent ne détourne un appel : l'aiguillage décide sur un autre champ, bien gardé.
Appliquer le contrôle déjà en place sur la première porte. Pour la troisième, écrite dans le même langage, c'est une recopie. Pour la deuxième, écrite dans un autre, il faut le réécrire et lui donner accès au secret partagé — elle ne lit aujourd'hui aucun réglage d'environnement.
Quand le vendeur de leads n'indique pas la campagne, le système cherche des mots dans le formulaire. Il teste l'énergie en premier : l'erreur va donc toujours du télécom vers l'énergie. Un lead mal classé part dans la mauvaise file d'attribution. Et en production, une vente d'une offre télécom précise n'est classée ni en télécom ni en énergie — le correctif est dans les sources, pas en service.
Marquer « à classer » plutôt que de deviner — d'autant qu'aujourd'hui le seul reclassement possible porte sur la campagne, par l'éditeur d'administration, et jamais sur le lead lui-même. Un second classeur, mieux écrit, existe déjà dans le même fichier.
Le client donne trois accords quand il remplit le formulaire : courriel, téléphone, SMS. Les trois traversent le système sans jamais entrer dans une case qu'on puisse relire — au mieux ils finissent noyés dans un champ de notes en texte libre, tronqué. On ne peut donc pas prouver, dossier par dossier, qu'on avait le droit d'appeler.
Trois colonnes, et les remplir à l'arrivée. Compter d'abord combien de fiches existantes n'ont aucun accord enregistré — cela se fait en lecture seule.
Deux filets rattrapent les enregistrements que le chemin principal a manqués. Le second est bien réglé ; le premier n'est déclenché par rien, nulle part. Et quand un rattrapage échoue, il marque lui-même l'enregistrement « indisponible » — ce qui l'exclut définitivement des deux filets.
Déclencher le premier filet, et lui faire choisir les appels en attente du plus ancien au plus récent, comme le second le fait déjà. Et cesser de marquer « indisponible » de façon définitive.
Dans une base ordinaire, on déclare qu'une vente appartient à un commercial : la base refuse alors une vente orpheline. Ici aucun lien de ce genre n'est déclaré, et le format employé ne permet pas d'en déclarer un. Dans le même esprit, treize fonctions modifient la structure de la base en pleine requête, faute de procédure prévue — l'une d'elles crée elle-même une colonne dont l'absence avait provoqué un incident du mois d'août.
Ce n'est pas corrigible à court terme : c'est une contrainte de la plateforme. À porter au cahier des charges de toute cible future, avec l'interdiction d'écrire dans plusieurs tables d'un seul geste, qui oblige aujourd'hui le code à tenir un journal de rattrapage à la main.
Consulter le portefeuille d'un commercial par la fonction prévue laisse une trace complète : jeton signé, quinze minutes maximum, lecture seule, ligne d'audit. Une seconde porte donne exactement le même accès sur simple présence d'un droit — sans jeton, sans durée, sans écrire une ligne. Une réponse à « qui a consulté le portefeuille de X ? » sera donc incomplète, et rien ne l'indiquera.
Autre asymétrie : prendre une opportunité n'est journalisé nulle part ; la rendre, si. Et un rendez-vous pris par l'agent vocal est détenu sans limite de temps, alors qu'un appel manqué repart au bout de dix minutes.
Faire passer les deux portes par le même chemin, et poser une expiration sur les rendez-vous.
Une vente conclue réserve le client à ce centre pour trois mois. Si elle est annulée, le verrou reste. Le programme qui libère les verrous ne connaît que deux origines, et pas celle-là. Aucune fonction du logiciel ne peut rendre ce client aux autres centres.
Libérer le verrou à l'annulation, et recenser les verrous déjà posés par des ventes annulées.
C'est la seule question qui compte pour décider. Voici la réponse que nos constats autorisent — ni plus, ni moins.
Oui. Et rien de ce que nous avons trouvé n'oblige à réécrire ce logiciel. Aucun des vingt-trois constats ne dit « c'est mal conçu, il faut recommencer ». Ils disent tous « ce mécanisme est écrit à moitié », « ce chiffre n'a pas la définition qu'on croit », « ce montant n'est enregistré nulle part ». Ce sont des réparations, pas une reconstruction.
Trois conditions, dans cet ordre, et elles ne coûtent presque rien comparées au reste.
Ces trois conditions posées, les vingt-trois constats redeviennent du travail ordinaire — de l'ordre de quatre-vingts jours, étalés, avec un ordre de priorité qui est donné plus bas. Sans elles, le même travail se fait à l'aveugle et rien ne garantit qu'il tienne.
Ce que nous ne pouvons pas promettre. Nous n'avons jamais ouvert la base de données ni lu un journal d'exécution. Nous savons donc que ces mécanismes sont faux ; nous ne savons pas combien de ventes, de leads ou de notes ils ont déjà abîmés. Les trois mesures en lecture seule demandées plus bas répondent à cette question en quelques heures, et elles changeront l'ordre des priorités.
Et une réserve de méthode. Un logiciel devient fiable quand on peut le prouver, pas quand on le déclare. Tout ce document consiste à dire ce qui manque pour pouvoir le prouver — c'est pour cela que le vérificateur de cohérence passe en premier, avant toute correction.
L'ordre compte plus que le total. Trois mesures servent à vérifier les autres, et le plus grave doit passer en dernier.
Elles se font en lecture seule et donnent la taille réelle du problème : combien de ventes ont une note affichée différente de celle qui a servi à payer, combien d'appels n'ont aucun enregistrement rangé, combien de leads n'ont aucun accord du client. Ces trois chiffres changeront les arbitrages.
Compter environ quatre-vingts jours de développement — de l'ordre de quatre mois d'une personne — plus la mise en service de ce qui est déjà écrit, qui ne demande presque pas de développement mais beaucoup de vérification.
Le détail, pour qui veut refaire le calcul : additionner les vingt-deux estimations à leurs extrêmes donne soixante-sept à cent vingt-neuf jours. Ce total-là ne veut rien dire : il suppose que les vingt-deux chantiers aillent tous au mieux, ou tous au pire. En retirant les cinq dont le correctif existe déjà, il reste dix-sept chantiers, soit cinquante-cinq à cent quatre jours — quatre-vingts au milieu.
Et trois chantiers pèsent à eux seuls le tiers du reste : figer ce qui est dû aux centres, brancher le contrôle de cohérence, et séparer les interlocuteurs dans la transcription. C'est là que se joue l'arbitrage, pas sur les quatorze autres. L'estimation vaut pour ce que nous avons pu lire, et sera à revoir dès qu'on saura quelle version est en service.
Une première version de ce document a été établie le 7 septembre. La livraison du lendemain en a démenti sept affirmations. Nous les listons plutôt que de les effacer.
Deux chiffres ont aussi été corrigés à la baisse : la part de copie du serveur est de six lignes sur dix et non de deux sur trois, et l'écart entre deux exemplaires d'une même fonction est de soixante-trois lignes et non de soixante-sept. Deux écarts que nous jugions spectaculaires se sont révélés être des artefacts de mesure : ils ont été retirés.
Ce document ne suppose pas. Voici, explicitement, ce qui reste ouvert.
Un mot sur le contexte, et il compte pour lire ce document. L'infrastructure a changé deux fois en trois jours, et une troisième était annoncée entre les deux. Changement d'hébergeur le 6 septembre ; une nouvelle machine annoncée pour le 8 au soir ; puis, le 8 en fin de journée, changement de fournisseur : une machine a été créée chez un troisième hébergeur à 19 h 11, et la migration a été annoncée terminée le 9 au matin.
Nos mesures portent sur la machine du 8 septembre : deux cœurs, quatre gigaoctets. Le processeur y tenait un plateau de soixante pour cent du milieu de matinée à la fin de journée, avec un pic à soixante-dix-huit. La mémoire n'a jamais dépassé deux gigaoctets et demi — elle n'a donc jamais été le facteur limitant. Le seul indicateur réellement tendu était le disque : soixante-quatorze mégaoctets écrits par minute en moyenne, cent quatre-vingts en pointe. La machine qui la remplace a quatre cœurs et seize gigaoctets, à Paris.
Deux réserves sur cette migration, au 9 septembre au matin. Les adresses publiques n'ont pas été basculées : le trafic arrive toujours sur une machine du prestataire, qui le renvoie ensuite. Le point d'entrée du système reste donc en dehors des comptes de FLEXYLEAD, et ce n'est pas la première fois dans ce dossier. Et les enregistrements audio n'ont pas suivi : ils sont restés chez l'hébergeur précédent.
Enfin, un fait relevé le 9 septembre sur le dépôt public de la plateforme : la prise en charge de cette gamme de machines dans la plateforme d'Apteva a été corrigée à 18 h 11, une heure avant que la machine de FLEXYLEAD ne soit créée dessus. La production repose donc sur un chemin de déploiement qui avait quelques heures. Et depuis notre référence du 8 septembre à 13 h 51, onze publications ont eu lieu sur la plateforme, et aucune sur le logiciel de FLEXYLEAD — alors même que la migration, le déploiement et le renvoi ont été faits entre-temps.