sh0 v1.6.0 est sorti avec toutes les fonctionnalités prévues. 230+ endpoints API, 103 outils MCP, 170 templates de déploiement, serveurs mail, auth, realtime, functions -- la plateforme complète. Puis le CEO s'est assis pour l'utiliser réellement. Ce qui a suivi est la session de QA la plus productive de l'histoire de sh0.
La mise en place
Le CEO a testé sh0 comme le ferait un développeur : déployer des stacks, créer des domaines mail, configurer des tâches cron, provisionner des serveurs d'authentification. Chaque bug était signalé en temps réel via capture d'écran + journal d'erreurs, et corrigé immédiatement dans la même conversation.
Pas d'environnement de staging. Pas de tickets Jira. Pas de planification de sprint. Juste : "c'est cassé" -> investiguer -> corriger -> "prochain problème."
Les bugs (et ce qu'ils révèlent)
La comparaison de chaînes (bug à 0,05 $, impact à 500 $)
Le badge SSL sur la page de paramètres affichait "SSL pending" alors que le HTTPS fonctionnait parfaitement. Cause racine : l'API de Caddy renvoyait "managed" mais le tableau de bord vérifiait "active". Une comparaison de chaînes. Un seul mot de différence dans le comportement.
C'est le genre de bug qui fait perdre confiance aux utilisateurs. Si l'indicateur SSL est faux, quoi d'autre est faux ? Une correction d'une ligne qui préserve la crédibilité.
La boucle infinie (piège de réactivité Svelte 5)
L'onglet Queue du mail provoquait un rafraîchissement infini du navigateur. Le coupable : une variable $state contenant un handle setInterval, lue et écrite dans un $effect. La réactivité fine de Svelte 5 signifie que chaque lecture crée une dépendance, chaque écriture déclenche une réévaluation. Le handle du timer n'a pas besoin de réactivité -- c'est un détail d'implémentation, pas un état d'interface.
Leçon : En Svelte 5, tout ne doit pas être $state. Les handles de timer, les références WebSocket et la gestion interne doivent rester en let simple.
L'image fantôme (archéologie du registre Docker)
Le serveur Auth (Logto) ne parvenait pas à se créer parce que l'image Docker logto/logto:1.22.0 n'existe pas. N'a jamais existé. L'image correcte est svhd/logto -- publiée par Silverhand, l'entreprise derrière Logto, utilisant leur ancien acronyme comme namespace Docker Hub.
Mais même après avoir corrigé le nom de l'image, le conteneur crashait en boucle avec npm error Missing script: "node". L'image svhd/logto utilise ENTRYPOINT ["npm", "run"] avec CMD ["start"]. Notre surcharge CMD ["node", ".", "--env", "production"] était ajoutée à l'entrypoint, donnant npm run node . --env production -- et il n'existe pas de script npm appelé "node."
La correction : surcharger entièrement l'entrypoint avec le pattern docker-compose officiel : sh -c "npm run cli db seed -- --swe && npm start".
Leçon : Lors de l'intégration d'images Docker tierces, vérifiez toujours le Dockerfile réel, pas la documentation qui peut référencer une version différente.
La mémoire musculaire cPanel
Un développeur a tenté de créer une tâche cron avec : curl -s "https://api.example.com/cron" > /dev/null 2>&1
C'est la syntaxe crontab standard que chaque administrateur Linux a écrite des centaines de fois. Mais sh0 exécute les commandes curl nativement (sans shell), donc les caractères > et & étaient rejetés par le validateur de commandes.
Plutôt que de demander aux utilisateurs de changer leurs habitudes, nous avons ajouté sanitize_command() qui supprime les redirections shell avant la validation. Collez votre ligne crontab telle quelle ; sh0 s'occupe du reste.
Le mot de passe admin silencieux
Le serveur mail Stalwart génère automatiquement un mot de passe admin au premier démarrage et l'affiche dans les logs du conteneur. Personne ne lit les logs de conteneur. Les utilisateurs créaient des boîtes mail, puis ne pouvaient pas se connecter au webmail parce qu'ils ignoraient l'existence du mot de passe admin.
La correction : déchiffrer le mot de passe admin stocké et l'afficher dans l'onglet Overview du mail avec un bouton afficher/masquer. Le mot de passe était toujours là dans la base de données -- il n'était simplement pas exposé.
La méthode
Chaque correction suivait le même schéma :
- Le CEO signale -- capture d'écran + journal d'erreurs, pas d'interprétation
- L'IA investigue -- lit le code source, remonte jusqu'à la cause racine
- L'IA corrige -- changement minimal, pas de dérive de périmètre
- Le CEO continue les tests -- signale le problème suivant
Pas de changement de contexte. Pas de tri de tickets. Pas de "on s'en occupe au prochain sprint." La boucle de retour se mesurait en minutes, pas en jours.
Après toutes les corrections, un agent d'audit a revu chaque changement pour vérifier la justesse, la cohérence et les régressions. Il a trouvé 3 problèmes supplémentaires (un champ de struct manquant qui aurait cassé la compilation, une fuite de timer et un bug d'ordonnancement de patterns). Tous corrigés avant la publication.
Les chiffres
| Métrique | Valeur |
|---|---|
| Bugs trouvés | 20+ |
| Services affectés | Mail, Auth, Cron, Realtime, Functions, Settings |
| Fichiers modifiés | 72 |
| Lignes modifiées | +4 856 / -3 508 |
| Tests réussis | 155/155 |
| Temps de correction total | ~4 heures |
| Version | v1.6.0 -> v1.6.1 |
Ce que cela signifie
Le QA traditionnel pour une plateforme de cette taille nécessiterait une équipe de testeurs pendant une semaine pour trouver ces bugs, et une équipe de développeurs une semaine de plus pour les corriger. Nous l'avons fait en une seule session parce que l'IA détient l'ensemble du codebase en contexte -- chaque handler Rust, chaque composant Svelte, chaque clé i18n dans 5 langues.
L'IA ne se fatigue pas de lire des journaux d'erreurs. Elle n'oublie pas ce que fait le handler mail quand elle passe à la correction du planificateur cron. Elle n'a pas besoin de réapprendre la structure du projet pour chaque bug.
C'est ce que signifie "l'IA comme CTO" en pratique : non pas remplacer le jugement humain sur quoi tester, mais amplifier la vitesse à laquelle les problèmes sont trouvés, diagnostiqués et corrigés. Le temps du CEO est le goulot d'étranglement. Chaque minute passée à attendre un build ou à chercher un bug est une minute non consacrée à décider ce que le produit doit devenir.
v1.6.1 est plus propre que v1.6.0. Non pas parce que nous l'avions planifié ainsi, mais parce que nous l'avons testé comme le feraient les utilisateurs.