Skip to content

Vaynerov Technologies

Nous ne nous contentons pas de développer — nous façonnons chaque ligne de code et chaque pixel comme par enchantement.

L'artisanat à l'ère du code généré

On pose la même question à tous les studios cette année : si un modèle sait écrire le code, que facturez-vous au juste ? Notre réponse, sous la forme des choses que notre propre build refuse d'accepter.

Edward AmirainFondateur, Vaynerov Technologies
Publié 9 min de lecture
Sur cette page
  1. Des vérifications qui tournent sans moi
  2. Le modèle propose ; le moteur décide
  3. Savoir ce contre quoi vous ne vous êtes pas défendu

Écrire du code a cessé d'être la partie coûteuse. Le lire n'est jamais devenu moins cher, et cette seule asymétrie résume toute l'année.

Un modèle produira quatre cents lignes de TypeScript plausible le temps que vous finissiez une phrase. Votre capacité à tenir quatre cents lignes dans votre tête et à demander qu'est-ce qui devrait être vrai pour que ce soit faux est exactement celle de 2019. Le goulot d'étranglement s'est déplacé vers la seule partie du processus qui n'accélère pas. Tous les débats sur l'ingénierie assistée par l'IA qui m'intéressent partent de là ; ceux qui m'ennuient parlent secrètement de savoir si la frappe au clavier a jamais été le sujet.

Le code généré échoue aussi d'une façon particulière et désagréable : il échoue de manière plausible. Les erreurs écrites à la main ressemblent en général à des erreurs — une variable mal nommée, une branche qui de toute évidence ne s'exécute jamais, un commentaire qui contredit la ligne d'en dessous. Les erreurs d'un modèle arrivent correctement habillées. Le nommage est bon, la structure est conventionnelle, les commentaires sont d'accord avec le code, et la deuxième réponse DNS n'est jamais vérifiée.

Nous avons donc cessé de demander qui avait écrit une ligne pour demander ce qui, dans le build, protesterait si cette ligne était fausse.

Des vérifications qui tournent sans moi

L'Orrery propage des orbites de satellites dans le navigateur à partir des jeux d'éléments publiés par CelesTrak. En développement, avant qu'un seul pixel de tout cela ne s'affiche, un autotest tourne. Donnez-lui un jeu d'éléments de classe ISS — moyen mouvement de 15,495 révolutions par jour — et il doit renvoyer une période orbitale de 92,933 minutes et une vitesse de 7,660 km/s. Donnez-lui un jeu géostationnaire et la longitude doit dériver de 0,010° en six heures. Ces chiffres ne sont pas les nôtres. Ils viennent de la physique, et ils étaient vrais bien avant que le fichier n'existe.

La valeur de ce test tient entièrement à ce qu'il empêche : une carte satellite fausse partout et manifestement fausse nulle part. L'erreur orbitale ne s'annonce pas. Chaque point continue de se déplacer sans à-coup, la planète continue de tourner, et rien à l'écran ne vous dit que le solveur de Kepler a perdu une itération dans le rangement de quelqu'un. Les assertions, si.

Le même instinct, à l'échelle du jeu. Slipstream est un runner à couloirs dont les rangées d'obstacles proviennent de motifs générés, et un motif qui ne laisse aucune voie atteignable à pleine vitesse n'est pas un niveau difficile — c'est un niveau cassé. Ce défaut survit merveilleusement bien aux tests de jeu, parce qu'un testeur qui meurt suppose qu'il a mal joué. Les motifs sont donc validés au chargement du module : on propage vers l'avant les voies que l'appareil peut physiquement atteindre à la vitesse la plus défavorable, 32 unités par seconde, et on vérifie que chaque rangée en garde au moins une survivable. Le commentaire de ce fichier tient toute la philosophie en neuf mots — juste pour le validateur égale juste pour le joueur.

Ce qui tourneCe qu'elle affirmePourquoi un humain ne peut pas la couvrir
Autotest de propagation de l'OrreryOrbite de classe ISS → période de 92,933 min, 7,660 km/s ; dérive géostationnaire de 0,010° sur 6 hL'erreur orbitale est invisible au premier coup d'œil : la carte a l'air juste tout en étant fausse
Validateur de motifs de SlipstreamChaque rangée d'obstacles garde une voie atteignable à la vitesse la plus défavorableLes tests de jeu peuvent rater la rangée injuste ; ils ne peuvent pas prouver qu'il n'en existe aucune
Schéma, bornes et assainisseur de Blueprint3 à 14 nœuds, exactement 3 phases, aucune arête orpheline, aucun identifiant d'option inconnuLa sortie du modèle se lit couramment même quand elle est structurellement impossible

Trois vérifications câblées dans des chemins de code qu'un développeur emprunte déjà. Aucune ne se soucie de savoir qui a écrit le code qu'elle vérifie.

Cette dernière propriété compte davantage que les vérifications elles-mêmes. Une vérification qu'il faut penser à lancer est une vérification que vous finirez par sauter, généralement le jour où vous avancez le plus vite — c'est-à-dire, désormais, presque tous les jours.

Le modèle propose ; le moteur décide

Blueprint est l'endroit où il a fallu répondre à cette question commercialement plutôt que philosophiquement. Un visiteur décrit un produit, Claude rédige une architecture, la page la dessine et y attache un prix. La catastrophe évidente, c'est un modèle de langage qui invente un chiffre qu'un inconnu prendra ensuite, à juste titre, pour un devis venant de nous.

Il y a donc dans ce code une règle, écrite sous forme de phrase plutôt que de drapeau de configuration : le LLM ne fixe jamais aucun prix — il ne fait que proposer des sélections, et même celles-ci sont assainies d'abord.

En pratique, le modèle choisit dans un catalogue fermé : plateformes, fonctionnalités, capacités IA, niveau de design, nombre d'intégrations. Les identifiants inconnus sont écartés à l'arrivée. Les champs obligatoires à choix unique revenus vides sont remplis par des valeurs par défaut. Puis l'arithmétique se produit à un endroit que le modèle ne peut pas atteindre — unités de base sommées sur les sélections, multipliées par la complexité du produit, le niveau de QA et le périmètre de lancement, converties via une fourchette de taux unitaire ; le délai avec les plateformes en parallèle, le reste à quinze unités par semaine, plus deux semaines de marge. C'est le même moteur déterministe que celui derrière notre page de tarifs, lisant les mêmes règles. La liste d'énumérations du schéma de sortie, le catalogue d'options imprimé dans le prompt et la liste blanche de l'assainisseur dérivent tous du même objet de règles : ils ne peuvent pas diverger en silence.

Le modèle a le droit d'avoir de l'imagination sur l'architecture. Il n'a pas le droit d'approcher un chiffre sur lequel un client pourrait agir.

Deux décisions plus petites dans le même esprit. L'idée du visiteur est encadrée par des balises et traitée comme une donnée, pas comme une instruction, parce qu'un champ de texte sur une page publique est une entrée non fiable, aussi conversationnelle qu'elle paraisse. Et quand un blueprint devient une demande de devis, l'estimation est recalculée sur le serveur à partir des sélections assainies ; les chiffres arrivés du navigateur sont ignorés purement et simplement. Le prix d'un client ne devrait jamais être une valeur passée par un endroit qu'un inconnu peut modifier.

Savoir ce contre quoi vous ne vous êtes pas défendu

Un serveur qui va chercher des URL tapées par des inconnus est une arme chargée pointée sur votre propre réseau, et c'est précisément ce qu'est le Reliquary : vous collez un lien, notre serveur récupère la page, l'analyse et renvoie une œuvre. Les adresses qui valent la peine d'être attaquées ne sont pas sur l'internet public. 169.254.169.254, c'est là que les fournisseurs cloud garent les métadonnées d'instance ; les plages privées, c'est là où vit le reste de votre infrastructure. Nous avons raconté cette construction en juin ; la garde en est la partie la moins glamour et celle que je défendrais en premier.

Uniquement http et https, uniquement les ports 80 et 443, aucun identifiant passé en fraude dans le champ userinfo. Une liste noire couvrant les plages privées, réservées, link-local et de NAT opérateur. DNS résolu avec toutes les adresses renvoyées, chacune devant être publique, parce que ne valider que la première réponse est le classique presque-raté. Chaque saut de redirection est ré-analysé et revalidé de zéro — une URL publique qui redirige vers une adresse de bouclage, c'est toute l'attaque. Les préfixes IPv6 sont classés avant la queue en quatre octets, dans cet ordre, puisque l'inverse laisserait passer une adresse mappée sur un quadruplet d'apparence publique.

Et puis la partie dont je suis le plus fier. Un commentaire de ce fichier nomme l'attaque que nous n'avons pas arrêtée : le DNS rebinding. Entre le moment où nous validons un nom d'hôte et celui où la socket se connecte, la réponse peut changer pour quelque chose de privé. Refermer cela correctement suppose d'épingler la connexion à l'adresse déjà validée, donc un dispatcher HTTP maison et une nouvelle surface de dépendance, et nous avons jugé que cela n'en valait pas la peine pour une fonctionnalité qui va chercher des annonces d'enchères. Le jugement est peut-être mauvais. Il est au moins écrit, si bien que la prochaine personne qui lira le fichier hérite du raisonnement au lieu de l'impression que tout est couvert.

C'est la partie qu'aucun générateur ne fait à votre place. Un modèle écrira volontiers un validateur d'URL, et il en écrira peut-être un bon. Ce qu'il ne peut pas faire, c'est décider quel risque résiduel votre entreprise accepte de porter, puis le dire à voix haute quelque part où on puisse le contester. Le jugement, ce n'est pas la capacité à produire la version défendue. C'est connaître la forme de ce qui reste sans défense, le choisir délibérément, et signer ce choix de son nom.

Deux autres choses sont restées obstinément humaines ici. La première, c'est l'invariant — la phrase qu'un système n'a pas le droit de violer — parce que les invariants encodent ce à quoi vous tenez, et rien dans un corpus d'entraînement ne sait à quoi vous tenez. La seconde, c'est de décider ce qu'on ne construira pas. Le Reliquary garde chaque œuvre dans le stockage local de votre navigateur et absolument rien sur nos serveurs. Cela a coûté de vraies fonctionnalités : pas de partage, pas de synchronisation entre un portable et un téléphone, un plafond dur de soixante œuvres, et aucune idée de ce que qui que ce soit en fait. Aucun système entraîné sur la dernière décennie de logiciel n'aurait proposé de refuser les données. C'était une décision de goût, et le goût est précisément ce que le standard de l'enchantement a été écrit pour protéger.

Ce qui m'amène au mot que tout le monde emploie cette année. Le slop n'est pas une propriété de l'IA ; c'est une propriété de la relecture. Du code dont personne ne peut dire qu'est-ce qui devrait être vrai pour que ce soit faux est du slop, qu'il vienne d'un modèle, d'un prestataire ou de moi à une heure du matin. Notre industrie en a livré des océans avant que quoi que ce soit ne sache autocompléter une fonction. Les modèles n'ont pas inventé cette défaillance. Ils en ont abaissé le coût de production, ce qui est un argument pour prendre la relecture plus au sérieux, pas moins.

Ce qu'il y a d'inconfortable dans cette position, c'est qu'elle passe mal à l'échelle, et je crois que ceux qui vendent l'avenir le savent. La génération est presque gratuite et le devient de plus en plus. La vérification est du travail, elle reste obstinément linéaire, et c'est elle que nous facturons réellement. Quand un client demande ce qu'il paie chez un ingénieur en 2026, la réponse honnête est : pas la frappe au clavier. Les refus. Le chiffre qui devait venir du calculateur, la rangée qui devait rester survivable, le risque qui devait être nommé dans un commentaire où quelqu'un pourrait le contester.