Un modèle vidéo prend plus qu'une consigne. Certains prennent une première image et une dernière. Certains prennent une poignée d'images de référence. Certains prennent un clip de référence, et se comportent alors différemment à cause de lui — en coupant leur propre bande son, ou en prenant la durée du clip comme durée du résultat. Certains prennent un clip audio. Chaque modèle dessine cette enveloppe différemment, et la plupart des nôtres n'en envoyaient qu'une partie.
Il existe désormais un seul endroit qui décrit l'enveloppe de chaque modèle : combien d'images, si un clip est autorisé et pour combien de secondes, si l'audio est accepté, si l'audio a besoin d'une image à côté, si un clip coupe le son propre du modèle, si un clip fixe la durée. Cela a été lu dans la documentation propre des fournisseurs, puis exercé le jour même avec de vrais rendus sur de vraies clés — c'est comme ça que les deux points suivants ont été trouvés.
Un fichier sans extension
Donner un clip à un modèle par lien est le chemin évident. Cela échoue sur plusieurs d'entre eux, d'une manière très difficile à deviner : le fichier arrive sans extension, et le modèle valide par extension, donc il refuse un mp4 parfaitement valide au motif qu'il n'est pas un mp4. Les mêmes octets envoyés en ligne étaient acceptés partout. Chaque clip est donc d'abord réencodé dans un format standard puis envoyé en ligne, avec un plafond de taille au-delà duquel le chemin par lien est quand même utilisé, avec un avertissement.
Un palier que personne n'obtenait
Le second coûtait de l'argent aux clients. L'un des modèles vidéo n'a aucun champ de résolution du tout — son palier de qualité se règle via un champ nommé différemment — et la plateforme devant lui rejette silencieusement les champs qu'elle ne reconnaît pas. Donc chaque rendu sur ce modèle depuis son ajout revenait au palier par défaut alors que le client avait payé pour le palier supérieur. Rien n'échouait. La vidéo arrivait. Ce n'était juste pas la vidéo facturée.
Le palier est désormais dérivé de la résolution réellement tarifée, et confirmé par sonde.
Seedance passe sur une voie directe
Dans le même intervalle, toute la famille Seedance est passée de l'agrégateur à l'API propre du fournisseur, l'agrégateur restant en secours. Une ligne de modèle, un nom, deux ensembles de tarifs — et le prix qui t'est annoncé est celui que tu paies même quand la voie principale échoue et que le secours prend le relais, le grand livre enregistrant quelle voie a réellement fait le travail, pour que notre propre comptabilité de marge lise la vérité plutôt que l'offre.
Une chose à savoir en tant qu'utilisateur : quand tu joins un clip de référence sur cette voie, le fournisseur facture les secondes du clip en plus des secondes du résultat. L'estimation du formulaire le dit, et le chiffre annoncé avant l'exécution est le chiffre facturé.
Trouvé en chemin
Trois clients d'API manquaient de l'unique attribut qui rend visible dans notre conteneur une classe nommée d'après un fournisseur. Deux d'entre eux étaient des clients texte-vers-parole, invisibles depuis le jour de leur ajout — c'est pourquoi deux voix semées dans le catalogue n'ont jamais pu être réellement servies. Un test de réflexion fait désormais échouer la compilation à la prochaine omission de ce genre, plutôt que d'attendre que quelqu'un remarque une voix qui ne fait rien.
Et la page de recherche web que nous avions sortie la veille répondait 403 sur chaque palier, sur web et mobile. Elle est verrouillée par une permission parente ; les deux semences de rôles n'accordaient que ses trois permissions enfants, et rien nulle part ne déduit un parent de ses enfants. Quatre autres fonctionnalités avaient chacune corrigé cela à la main à un moment donné. Il existe désormais une vérification qui parcourt l'arbre des permissions et échoue là où un service est verrouillé par une permission qu'aucun rôle ne possède.