Phase 5 : Synchronisation de Progress avec l'UUID
Objectif : Conservez le statut d'achèvement de chaque apprenant et repeignez la barre latérale lors du rechargement, le tout sans compte d'utilisateur.ACU burn : 2,7 (prévu 2-3).Résultat : Un minuscule crochet React stocke désormais un UUID généré par le navigateur, appelle l'API GraphQL à chaque passage de test et précharge la progression à chaque fois que le terrain de jeu se monte.
Ce que Devin a réellement fait
Pour la cinquième phase, Devin :
- Client Apollo intégré pour la communication GraphQL entre le frontend et le backend
- Mise en œuvre de la gestion des sessions anonymes avec les UUIDs stockés dans localStorage
- Synchronisation en temps réel des données de progression et des indicateurs visuels au niveau de la catégorie et de l'exercice
- Détection de l'achèvement de l'exercice en se connectant au programme de test Vitest intégré au navigateur.
- Ajout du support hors ligne, des mises à jour optimistes et d'une gestion robuste des erreurs avec une logique de réessai (que je n'ai jamais demandée).
Devin a notamment ajouté la mise à jour optimistic-UI pour que les badges passent instantanément à ✅. Cette caractéristique est importante car elle permet à l'interface d'être rapide, même en cas de connexion à forte latence.
Enseignements tirés
Voici ce que j'en retiens :
- Un champ d'application restreint signifie un minimum d'erreurs : Il s'agissait d'une tâche relativement modeste et d'un champ d'application restreint, et Devin s'en est bien acquitté dans les délais impartis.
- Dites ce que vous voulez, mais aussi ce que vous ne voulez pas : J'ai remarqué que Devin a tendance à essayer d'étendre le champ d'application, et une fois de plus, il m'a donné plus que ce que je demandais. Dans ce cas, cela ne m'a pas dérangé, mais s'il y a quelque chose que vous ne voulez vraiment pas qu'il fasse, dites-le explicitement. Par exemple, dans chaque invite, j'ai spécifié "pas de fonctionnalité de connexion" parce que je me suis dit qu'il allait essayer d'y aller.
Nous avons maintenant la preuve que notre pipeline de sessions anonymes fonctionne de bout en bout. Il est temps de le mettre en valeur lors de la phase finale de polissage.
Phase 6 : Polissage de l'interface utilisateur et tableau de bord de l'état d'avancement
Objectif : Transformez l'interface utilitaire en une expérience pastel et "aérée" et ajoutez un tableau de bord qui visualise la progression de chaque apprenant, l'échelle de difficulté et l'activité hebdomadaire.ACU burn : 11 (prévu ≈ 3).Résultat : Thèmes pastel clair / foncé, cartes d'exercice redessinées et tableau de bord en direct affichant les anneaux, les barres et les compteurs de foulées. Devin a réalisé les grandes lignes, mais je suis intervenu pour sauver les incohérences de noms et les échanges de dépendances malhonnêtes.
Au cours de cette phase, j'ai délibérément élargi le champ d'application pour voir comment Devin gérerait un plus grand nombre de demandes. Je pensais en fait qu'il serait beaucoup plus facile pour Devin de s'attaquer à cette phase que la phase 3, avec toute l'implémentation du backend. Alerte au spoiler : Je me suis trompé.
Ce à quoi Devin s'est attaqué dès le début
Voici la répartition de mes besoins et de la production de Devin :
|
Exigence |
La production de Devin |
|
Système de conception pastel |
Ajout de variables CSS Tailwind pour le bleu doux primaire, le succès menthe, les accents lavande. Définissez des coins |
|
Typographie et espacement |
Introduction d'une classe |
|
Tableau de bord des progrès |
Nouvel itinéraire
|
|
Cartes améliorées |
Remplacement de |
|
Extension du catalogue |
Génération de 10 exercices supplémentaires avec des noms narratifs et des modèles d'espaces réservés. Les métadonnées comprennent la difficulté, le temps estimé et la catégorie. |
Où Devin s'est trompé
Les choses n'ont pas été parfaites - Devin :
- Modification des noms de fichiers des paquets d'exercices sans mettre à jour le wrapper ou le resolver → runtime 500s ; patching +1 ACU.
- A tranquillement remplacé Postgres par SQLite "pour faciliter le développement local" sans me demander mon accord. Je ne l'aurais pas su si je n'avais pas regardé.
- J'ai laissé des douzaines de déclarations
console.logdans les composants React, et les contrôles lint n'arrêtaient pas de réessayer.
Enseignements tirés
Ce que j'en retiens :
- La logique du tableau de bord doit encore être améliorée: Devin a câblé des compteurs de stries et de temps passé, mais les a laissés non fonctionnels. Les métriques back-end doivent faire l'objet d'au moins un test d'intégration afin que l'interface utilisateur "happy-path" ne soit pas fusionnée prématurément.
- L'utilisation de l'ACU s'accélère lors de longues sessions: Après ~8 UCA, la session s'est sensiblement ralentie. Des sessions courtes et limitées (< 5 UCA) permettent de maintenir le contexte et la réactivité de l'agent.
- Devin va "utilement" échanger les dépendances: Il a remplacé Postgres par SQLite sans le demander. Épinglez les services essentiels dans votre prompteur : "Ne changez pas de moteur de base de données ; restez sur Postgres.
- Les tâches de conception déclenchent des changements de charge à chaud: Chaque rafraîchissement de Tailwind/Vite compte comme du temps d'agent. Une meilleure façon de procéder est peut-être de mettre la session en pause avant d'éditer les styles en masse, puis de réveiller Devin lorsque le projet se compile proprement.
Cette tâche a été longue et coûteuse par rapport au reste du travail effectué. Au moins, Devin sait où les choses ont mal tourné :

Nous avons quelque chose de joli, mais cela a pris un peu de temps et ce n'est pas tout à fait fonctionnel. Certains paramètres du tableau de bord sont codés en dur - deux exercices dans notre catégorie d'options ? Nous en avons 10. Les mesures de la distance et du temps passé ne sont pas non plus reliées à quoi que ce soit, et l'interface utilisateur sur les pages des exercices individuels est plutôt mauvaise.
Rétrospective des coûts et des délais
Comment les chiffres se sont révélés
Voici un résumé de ce qui s'est passé :
|
Phase |
UCA prévues |
UCA réelles |
Delta |
Notes |
|
1 - Espace de travail et échafaudage |
1 – 2 |
3.66 |
▲ ≈ 1.7 |
Boucles supplémentaires sur |
|
2 - Paquet d'exercices |
2 |
0.60 |
▼ 1.4 |
Déplacements de fichiers simples ; pas d'installations lourdes |
|
3 - API et Prisma |
4 |
4.20 |
▲ 0.2 |
Config rides (manque |
|
4 - Terrain de jeux et tests |
3 – 4 |
7.20 |
▲ ≈ 3.5 |
Cycles de recharge à chaud, blocage de l'éditeur de fusion |
|
5 - Synchronisation des progrès |
2 – 3 |
2.70 |
▼ ≈ 0.3 |
Crochet simple + requêtes |
|
6 - Polissage de l'interface utilisateur et tableau de bord |
2 – 3 |
11.00 |
▲ ≈ 8 |
Réinstallations, permutation silencieuse de la base de données, rechargements CSS importants |
|
Total |
18 – 24 |
29.36 |
▲ ≈ 6 – 11 |
Environ 35 % de plus que l'estimation initiale |
|
Coût : 29,36 UCA × 2,25 $ ≈ $66 | ||||
Gain de temps par rapport au travail manuel
C'est mon estimation du temps gagné :
|
Tâche |
Estimation humaine |
Devin (+ corrections) |
Net |
|
Bootstrapping NestJS + GraphQL + Prisma |
4 heures |
1 heure (corrections incluses) |
-3 heures |
|
Câblage du navigateur Sandpack + Vitest |
3 heures |
1 h 20 min |
-1 h 40 min |
|
Refonte complète du design et du tableau de bord |
6 heures |
2 heures (mais toujours pas fonctionnel) |
−4 h |
|
Durée totale |
~13 heures |
~4 heures 20 minutes |
-8 heures 40 minutes |
Principaux enseignements
Ce sont des choses que je recommande :
|
Thème |
Ce qu'il faut faire |
Pourquoi c'est important |
|
Des sessions courtes |
- Plafonnez chaque course à ≤ 5 ACU. - Divisez les grands objectifs en petits tickets. |
Les sessions > 8 UCA sont lentes et les taux d'erreur augmentent de ≈35 %. Les courtes périodes de temps restent réactives et moins chères. |
|
Donnez un coup de pouce tôt, faites des pauses souvent |
- Regardez l'onglet Timelapse ; si Devin fait une boucle, tapez "Continue" ou "Sleep". - Faites une pause pendant que vous éditez en masse les CSS ou la documentation, puis réveillez Devin une fois que le code se compile. |
Les boucles d'inactivité continuent de faire tic-tac au compteur ; la surcharge à chaud pendant le travail de conception est une pure brûlure de l'ACU. |
|
Traiter la configuration comme un travail manuel |
- Déplacez/renommez vous-même de grandes arborescences de fichiers (le glisser-déposer bat les scripts 0.8 ACU). - Corrigez manuellement les erreurs de premier paquet, les tentatives sont des puits d'ACU. |
Les E/S de fichiers et les installations répétées représentent ~30 % des crédits gaspillés. |
|
Lint & type-check localement |
- Exécutez toujours vos scripts de test (dans notre cas, lint et typecheck) avant de fusionner. - Ajoutez ces commandes à votre CI (plus d'informations dans le prochain tutoriel !). |
Devin déclarera le succès même si le pipeline échoue. |
|
Pin critical tech |
- Indiquez ce qui ne doit pas changer: "Restez sur Postgres, pas de login, gardez Tailwind". - Liste des variables d'environnement requises dans |
Devin fera "utilement" passer Postgres à SQLite ou ajoutera de nouveaux testeurs à moins qu'on ne lui dise de ne pas le faire. |
|
Gérez vous-même les secrets |
- Supprimez les fichiers - Prévoyez une étape de gestion des secrets pour les tutoriels ultérieurs. |
Devin ne fait pas nécessairement la distinction entre les fausses cartes de crédit et les vraies. |
|
Supprimer les blocages de l'éditeur de fusion |
- Participez à la fusion des commits et à la sortie des processus. |
Les blocages de Vim font perdre des minutes et des UCA. |
|
Supprimez les codes morts dès le début |
- Après les déplacements, |
Les fichiers redondants déroutent l'agent et augmentent les délais de construction. |
|
Ajouter des tests unitaires pour la nouvelle logique |
- Les compteurs de flux, les chronomètres ou les mesures doivent être testés en amont, ne vous fiez pas uniquement à l'interface utilisateur. Encore une fois, attendez un peu, nous aborderons ce sujet dans le prochain tutoriel. |
Devin a câblé le tableau de bord mais a laissé les compteurs non fonctionnels jusqu'à ce que des tests révèlent la faille. |
|
Dites ce que vous voulez et ce que vous ne voulez pas |
- Les négations explicites ("Pas encore d'authentification") permettent d'éviter les dérives. - Examinez le plan proposé par Devin et coupez les extras. |
L'agent aime faire plus que ce qu'on lui demande, ce qui est excellent pour les démonstrations, mais mauvais pour les budgets. |
Quelle est la prochaine étape ?
Nous avons maintenant :
- Un terrain de jeu aux couleurs pastel qui exécute les tests fp-ts dans le navigateur
- Une API NestJS + PostgreSQL qui mémorise le progrès avec rien de plus qu'un UUID
- Un tableau de bord de la progression qui est vraiment amusant
Dans le prochain tutorielnous passerons des fonctionnalités au flux de travail et à la collaboration avec :
- Tests continus: Ajoutez les suites Jest et Playwright, puis laissez Devin garder les deux vertes avec chaque PR.
- Pipeline CI/CD: Générez des actions GitHub qui construisent les applications web et API et exécutent les tests dans Chrome sans tête.
- Intégrations d'équipes: Reliez Devin à Jira pour les mises à jour de tickets, envoyez des résumés de construction à Slack et expérimentez la nouvelle fonctionnalité Wiki de Devin pour une documentation légère.
Si vous êtes prêt à continuer, cliquez sur le troisième élément de la liste ci-dessous pour passer au tutoriel suivant :
- Mise en place et première Pull Request (Partie 1)
- Expédition d'une tranche verticale avec Devin (Partie 2)
- Intégrations, tests et CI/CD (Partie 3)
- Sécurité, déploiement, maintenance (partie 4)

Bienvenue ! Dans le premier tutoriel de cette série, Devin a dépoussiéré mon vieux repo fp-ts-exercices et a ouvert un PR de mise à niveau des dépendances. Dans cette deuxième partie, nous augmentons la difficulté et construisons des fonctionnalités complètes.
Vous pouvez accéder à tous les tutoriels de la série Devin ici :
Lorsque vous aurez atteint le bas de cette deuxième partie, vous aurez.. :
En cours de route, nous laisserons Devin générer sa propre liste de tâches, nous le regarderons jongler avec les tickets frontaux et dorsaux, et nous interviendrons lorsqu'il tombera sur des gremlins de configuration. Je vous montrerai où j'ai dépensé (et économisé) des ACU, ce que j'ai réparé à la main et comment maintenir l'efficacité des sessions.
Récapitulation et conditions préalables
Tout au long de cette série de tutoriels, nous travaillerons sur mon repo d'exercices fp-ts (autrefois) abandonné.
Le projet est une collection de petits défis destinés à enseigner des concepts de programmation fonctionnelle (comme Option, Either, etc.) en TypeScript. Pour l'instant, il s'agit d'un repo cloné et exécuté : les apprenants l'extraient, éditent les fichiers localement et exécutent les tests dans leur propre terminal.
L'objectif est de transformer ces exercices en un terrain de jeu interactif basé sur un navigateur, où les gens peuvent lire une explication, modifier le code dans un éditeur de page et voir les tests réussir (ou échouer) instantanément. Les apprenants auront également la possibilité de se connecter pour enregistrer leurs progrès.
Ce que nous avons accompli dans la première partie
Rappelez-vous que dans le premier tutoriel, nous :
Outils locaux dont vous avez besoin pour la deuxième partie
Pour ce deuxième tutoriel, nous aurons besoin de :
Paramètres recommandés pour Devin
Je recommande les paramètres suivants pour Devin :
Laisser Devin rédiger le plan de match
J'ai pensé qu'il serait intéressant de commencer par tester les capacités de planification de Devin. J'ai créé une invite et j'ai demandé à Devin, à l'aide de la fonction "Ask" (actuellement gratuite en version bêta), de m'aider à planifier le travail que nous ferons aujourd'hui.
Prompt :
Je souhaite transformer mon repo Node + TypeScript existant fp-ts-exercises (actuellement des exercices CLI clonés et exécutés) en une plate-forme d'apprentissage basée sur un navigateur qui suit les progrès.
Expérience cible :
- Les apprenants ouvrent une application web Next.js, choisissent un exercice, éditent le code dans le navigateur et voient les tests Vitest réussir ou échouer instantanément.
- Les progrès (les limaces terminées) sont stockés côté serveur et rechargés lors des visites ultérieures, mais nous n'ajoutons pas encore de comptes d'utilisateurs (utilisez un UUID anonyme stocké dans le navigateur).
Je penche pour les choix technologiques :
- Frontend : Next.js 14 (React 18, App Router)
- Éditeur et gestionnaire de code : Sandpack + @vitest/browser
- API : NestJS 13 avec @nestjs/graphql (Apollo Driver)
- Base de données : Prisma 5 avec PostgreSQL
- Espace de travail : espaces de travail npm ordinaires (apps/web, apps/api, packages/exercices)
Proposez un plan de mise en œuvre étape par étape (liste de tâches) qui donne vie à cette tranche verticale. Estimez le coût relatif de l'ACU pour chaque tâche et signalez toute étape de longue durée (par exemple, les grandes migrations ou les installations de dépendances lourdes).
Devin nous a utilement renvoyé une liste de tâches en six phases avec des estimations d'ACU pour chacune d'entre elles, et a signalé les étapes "d'installation à forte dépendance".
Réponse de Devin :
Phase 1 : Configuration de l'espace de travail (2-3 ACU)
Phase 2 : Migration du paquet d'exercices (3-4 ACU)
Phase 3 : API backend (4-5 ACU)
Phase 4 : Fonctionnalités de base du Frontend (5-6 ACU)
Phase 5 : Curriculum vitae (2-3 ACU)
Phase 6 : Polonais et déploiement (2-3 ACU)
Coût total estimé : 18-24 ACU
Le plan était assez bon dans l'ensemble. J'ai changé certaines choses, notamment dans la phase six, puisque nous aborderons le déploiement dans le quatrième tutoriel.
Phase 1 : Espace de travail et échafaudage frontal
Objectif : Créez des espaces de travail npm, déplacez les fichiers existants et démarrez un shell Next.js 14 vierge.ACU burn : 3,66 (prévu 1-2).Résultat : Le repo contient maintenant
/apps/web, partagépackages/exercises, et une application Next.js prête pour Tailwind fonctionnant surlocalhost:3000.L'invite
J'ai demandé à Devin de construire le plan qu'il a élaboré pour la première phase. Agentic Devin ne connaît pas le contexte de ce que vous avez pu demander précédemment dans la fonction "Ask Devin", vous devez donc créer une invite distincte et fournir le contexte.
Je ne vais pas coller tous les messages dans cet article, mais voici le premier :
Prompt :
Tâche : Initialiser la structure de l'espace de travail npm et le frontend Next.js pour la plate-forme de navigation fp-ts-exercicesContexte :
Je suis en train de convertir mon système d'apprentissage basé sur l'interface de programmation fp-ts-exercices en une plateforme basée sur un navigateur. Le système actuel a des exercices organisés dans 10-from-either.exercise.ts:1-3 avec la configuration TypeScript dans tsconfig.json:88 et la configuration Vitest dans vitest.config.ts:7 .
Exigences :
Produits livrables :
Pile technologique :
Soumission :
Tous les messages que j'ai rédigés par la suite suivaient le même schéma : mise en évidence de la tâche, contexte, exigences, résultats attendus, paquet technologique et détails de la soumission.
Ce que Devin a réellement fait
Il a mis un certain temps à décider de son action (environ quatre minutes), mais il l'a fait :
packages/exercises/src.Pourquoi le coût de l'ACU a-t-il augmenté ?
Le coût de l'ACU a augmenté parce que :
npm installaprès un délai d'attente du miroir.qdans Vim, puisCtrl-C, et les deux ont échoué. Je lui ai laissé un peu de temps pour essayer de résoudre le problème lui-même, mais j'ai fini par intervenir manuellement et quitter les processus les deux fois. Chaque minute supplémentaire signifiait des UCA supplémentaires, et je n'aurais pas détecté ce problème rapidement si je n'avais pas suivi de près les actions de Devin.Interventions humaines et enseignements tirés
Voici un résumé des corrections que j'ai dû apporter:
Fixer
L'heure
Comment j'ai procédé
Tâche de surveillance d'un nœud suspendu
15 s
Processus tué dans le shell de la VM.
Réinstallation de Tailwind
90 s
npm install tailwindcss postcss autoprefixer --workspace=apps/web et reran tailwind init.
Ajout de .next/ à .gitignore
10 s
Commis manuellement pour éviter les PRs gonflés.
Le déplacement de grandes arborescences de fichiers est plus rapide à la main, et beaucoup moins coûteux puisque Devin facture au temps/tâche. J'ai déplacé les dossiers, je les ai validés et j'ai laissé l'agent prendre en compte la nouvelle structure. Il a été capable d'extraire mes modifications sans problème et de faire une fusion tout seul !
Cela dit, j'ai dû lui demander d'exécuter les scripts lint et typecheck, même si je l'avais spécifié dans mon invite initiale. En fin de compte, il les a fait fonctionner tous les deux, mais ils ont échoué. Devin a tout de même considéré qu'il s'agissait d'un succès et s'est rallié à la RP.
J'ai corrigé les deux problèmes localement, j'ai exécuté les scripts moi-même et j'ai lancé le nouveau serveur de développement web pour m'assurer qu'il démarrait comme prévu, et j'ai poussé le commit.
Phase 2 : Emballage des exercices
Objectif : Extraire tous les fichiers d'épreuves dans un paquetage réutilisable
packages/exerciseset générer des métadonnées pour chaque exercice.ACU burn : 0,6 (prévu 2+).Résultat : Le paquet partagé exporte des métadonnées typées que l'application web et la future API peuvent importer à l'adresseimport { exercises } from '@exercises/registry'.Ce que Devin a réellement fait
Devin a créé :
fp-ts.exercise.tset.solution.tsoption-01).getExercises(),getExerciseBySlug(),getExercisesByCategory(),getCategories(),getCategoryBySlug()Pourquoi Devin a terminé en dessous du budget
Devin a réussi à maintenir le coût de l'ACU à un niveau peu élevé - voici comment il y est parvenu :
git mv(bon marché) au lieu de copier-coller plus diffInterventions humaines
Aucune cette fois-ci !
Tirant les leçons de la dernière fois, j'ai consulté la branche de Devin et j'ai exécuté les scripts localement. Tout a été compilé et le registre exporte des définitions de types propres, ce qui en fait un matériau d'entrée parfait pour l'interface utilisateur et l'API que nous construirons ensuite.
Phase 3 : NestJS + GraphQL API
Objectif : Créez un service NestJS 13 qui expose la progression de l'exercice via GraphQL et persiste les données dans PostgreSQL avec Prisma.ACU burn : 4.2 (prévu 4).Résultat :
apps/apibottes surlocalhost:4000/graphql. Vous pouvez interroger et modifier les enregistrements de progression en fonction d'un identifiant de session anonyme.Ce que Devin a réellement fait
Pour la troisième phase, Devin :
apps/apiavec TypeScript et Apollo GraphQLSessionetCompletedExercisepackages/exercises) pour la découverte des donnéesOù Devin a trébuché
Voici les problèmes que j'ai rencontrés au cours de la troisième phase et les corrections que j'ai dû apporter :
Enjeu
Fixer
L'heure
Oubli de l 'importation de
reflect-metadata→ blocage de l'application au démarragea demandé Devin : "Je rencontre cette erreur lorsque j'essaie d'exécuter
"npm run dev":La métapropriété 'import.meta' n'est autorisée que lorsque l' option
--moduleest 'es2020', 'es2022', 'esnext', 'system', 'node16', 'node18' ou 'nodenext'".1 ACU, 5 minutes
Script Lint manquant
a demandé Devin : "Ajoutez le script lint au paquet api et assurez-vous qu'il passe".
1 ACU, 4 minutes
Engagé accidentellement
.envgit rm --cached apps/api/.env && echo '.env' >> apps/api/.gitignore20 s
Enseignements tirés
Voici ce que j'en retiens :
npm run devs'est planté jusqu'à ce quereflect-metadatasoit ajouté..envavec une variableDATABASE_URL, qui contenait un nom d'utilisateur et un mot de passe fictifs. Une fois tiré localement, j'ai changé le nom d'utilisateur et le mot de passe pour mes identifiants de base de données locale et je me suis assuré de supprimer le fichier du système de suivi git et de l'ajouter au site.gitignore. Nous verrons dans les prochains tutoriels comment manipuler les secrets en toute sécurité.Phase 4 : Sandpack Playground & Live Tests
Objectif : Offrez aux apprenants un éditeur de navigateur qui exécute les solutions fp-ts et les contrôles Vitest en temps réel.Brûlure ACU : 7.2 (prévu 3-4).Résultat : La visite de
/exercises/option-01ouvre une vue fractionnée : L'éditeur Sandpack à gauche, le tunnel de test à droite, et un message de réussite s'affiche lorsque toutes les spécifications sont satisfaites.Ce que Devin a réellement fait
Voici ce que Devin a fait pour la quatrième phase :
Où Devin a brûlé des UCA supplémentaires
Devin a brûlé plus d'UCA que prévu pour cette phase - voici pourquoi :
Cause
Comment j'ai corrigé / atténué
J'ai laissé du code d'exécution CLI périmé dans
apps/web- Sandpack a essayé de compiler les deux copies et s'est planté.Suppression de
pages/index.tsxde l'échafaudage original, validation et réorganisation de Devin.Attente d'un retour d'information mais pas de demande explicite → boucle inactive.
Tapez "Ça a l'air bien, continuez" dans le chat après trois minutes de silence.
Enseignements tirés
Voici ce que j'en retiens cette fois-ci :
Devin a pris un peu de temps ici. Il a tourné en boucle, essayant de résoudre les mêmes problèmes, ne connectant pas correctement le backend et le frontend, apportant des modifications, redémarrant les serveurs, vérifiant dans le navigateur si cela fonctionnait, etc. Il s'agissait d'un travail de développement ordinaire, je suppose...
Nous avons maintenant une application fonctionnelle. J'ai pu lancer les serveurs API et Web, naviguer vers localhost, modifier la fonction stub, appuyer sur Save et regarder le volet de test passer du rouge au vert. J'ai ensuite réalisé qu'il ne faisait le travail qu'à moitié et qu'il codait en dur le test et la solution du premier exercice sur chaque page d'exercice. Je l'ai signalé, et après d'autres boucles, il a pu le corriger et pousser ses correctifs.