Pick Your Side : j'ai construit une machine qui vous fabrique une équipe de Coupe du monde, ancrée dans la vraie histoire
Toutes les apps Coupe du monde sont pour les gens qui suivent déjà. Celle-ci est pour tous les autres : on donne deux nations, elle lit leur vraie histoire, choisit le camp qu'on était censé aimer, et un annonceur de stade nous fait prêter serment. Toute l'architecture plie sur une règle : rien de l'histoire n'est inventé. Gemini fait la recherche avec le grounding Google Search actif, puis réécrit dans un responseSchema strict, puis ElevenLabs joue le tout sur une foule de stade qu'ElevenLabs a aussi générée.
Annoncé par l'équipe DEV ici :
Le thème du challenge était la passion, alors j'ai pris le chemin le plus littéral. Toutes les apps Coupe du monde jamais construites sont pour ceux qui suivent déjà : calendrier, tableau, fantasy. Toutes supposent qu'on est arrivé avec un camp. Quelques milliards de personnes vont regarder ce tournoi, et l'écrasante majorité n'a pas d'équipe. Pick Your Side est pour elles.
On donne deux nations. Elle lit leur histoire réelle, choisit celle qu'on était censé aimer, explique pourquoi, et un annonceur de stade nous fait prêter serment. Deux nations en entrée. Un camp en sortie, et une raison de le porter.

La contrainte de design : la passion fabriquée ne fonctionne que si la source est vraie
Le vrai problème, c'est qu'on ne peut pas simuler ça avec un joli adjectif. Si l'app raconte que Ghana et Uruguay ont une histoire amère et que l'histoire est inventée, la passion qu'elle vous tend est contrefaite, et dès qu'on vérifie on se sent bête et on ne rouvre jamais. Alors toute l'architecture plie sur une règle : rien de l'histoire n'est inventé.
Deux appels Gemini (parce qu'un seul ne marche pas)
- L'appel 1 a le grounding Google Search actif. Gemini va chercher le vrai bilan face-à-face, la vraie rencontre légendaire, et où en sont les deux sélections dans le tournoi en cours. Il revient avec les pages lues et les recherches effectuées, et l'app affiche les deux. Sur Maroc-France, il vous parle du quart de finale 2026, un résultat qui date d'il y a quelques jours et qu'aucun LLM ne pouvait savoir depuis son entraînement.
- L'appel 2 reçoit ces faits recherchés et rien d'autre, tenu à un responseSchema pour que la sortie ait toujours la même forme : camp, verdict, histoire, enjeux, un moment légendaire, votre raison, une phrase à partager, un script d'annonceur. Consigne : choisir le camp avec la blessure la plus profonde, pas le nom le plus célèbre.
Les deux ne peuvent pas être combinés en un seul appel. Demander à gemini-2.5-flash le grounding Search et un responseSchema en même temps ne lève pas d'erreur : ça ignore silencieusement le schéma et renvoie de la prose, ce qui est amusant à découvrir dans une UI qui attend du JSON. Donc : recherche d'abord, forme ensuite.
Pendant que l'appel Search ancré tourne, un écran de scouting s'affiche : les deux drapeaux sur fond sombre, un murmure de stade inquiet, et la lumière d'un tableau d'affichage qui clignote au fur et à mesure que les sources reviennent. Ce n'est pas décoratif. C'est la fenêtre pendant laquelle le modèle est en train de faire la lecture, et c'est là que l'ambiance de stade commence à tirer le regard vers l'avant, pour que quand le nom tombe, l'audio qui tombe sur le temps ait déjà été mérité.

ElevenLabs joue le tout (et génère aussi le stade)
Gemini écrit le serment et ElevenLabs est la voix qui le prononce, par-dessus un stade qu'ElevenLabs a aussi généré : une foule agitée sous l'écran de scouting pendant qu'il réfléchit, et une éruption à l'instant où le nom du pays tombe. La foule est mixée sous l'annonceur et ne rivalise jamais avec lui. Le son est actif par défaut, parce qu'une révélation muette n'est qu'une affiche, et la commande pour le couper est visible en permanence.
- Annonceur en direct : eleven_flash_v2_5 (retour sous la seconde pour que la voix tombe sur le temps).
- Révélations vedettes pré-rendues : eleven_v3 (plus lent mais expressif, comprend les balises audio, et la latence n'existe pas quand on génère hors ligne).
- Ambiance de stade : générée aussi par ElevenLabs. Agitée pendant le scouting, en éruption à la révélation.

À propos du cache
Le free-tier de Gemini autorise environ dix appels par minute, et chaque révélation en coûte deux. Alors les matchs vedettes sont pré-générés par scripts/seed-reveals.mjs et commités dans data/reveals.json. Ils répondent instantanément et ne coûtent rien, ce qui empêche un lien qui voyage de servir une erreur de rate-limit à la moitié des visiteurs au lieu d'une équipe. Les révélations pré-générées sortent du même pipeline ancré que les live (vraies recherches, vraies sources) : elles sont mises en cache, pas inventées. Tout match non pré-généré est traité en live puis gardé six heures en mémoire. Le tournoi est encore en cours, donc un « ce qui est en jeu » périmé est pire qu'un lent.
Les détails qui comptent plus qu'ils ne le devraient
- Les nations, leurs couleurs et leurs surnoms sont curés dans lib/teams.ts. Le modèle ne voit jamais qu'un identifiant validé, jamais de texte utilisateur brut.
- Les deux routes sont limitées par IP avec un plafond quotidien global au-dessus, pour qu'une clé free-tier ne puisse pas être vidée par un lien qui voyage.
- Les drapeaux sont des images, pas des emoji. Windows ne rend pas les emoji drapeau (il retombe sur des paires de lettres), et un drapeau cassé est pire que pas de drapeau.
- Les animations respectent prefers-reduced-motion. L'éruption du stade devient un fondu pour les visiteurs qui le demandent.

Pick Your Side: I Built a Machine That Manufactures a World Cup Team for You, Grounded in Real Football History
Voir le projet
Loose Ends : l'agent Slack qui refuse de fermer une boucle tant qu'il n'a pas vu la preuve
Dans un Slack d'ONG ou d'entraide, un « quelqu'un peut faire un suivi avec la famille Diaz ? » lâché n'est pas un deck en retard, c'est une personne non servie. Chaque commitment bot du marché marque une boucle terminée quand une minuterie se déclenche ou quand quelqu'un clique « fait ». Loose Ends surveille le même canal pour un message ultérieur qui prouve que le travail a réellement eu lieu, et traite une échéance dépassée sans preuve comme BROKEN. Ancré dans un vrai chiffre : 93 % des dossiers de services sociaux ont été marqués fermés, seulement 38 % ont livré le service (JAMA Network Open, 2024). Fermé n'est pas fait.

FlakeWarden : 90,7 % de précision et 0 % de faux positifs côté sécurité sur le triage des tests instables, sur UiPath Maestro
Les tests instables sont le mode d'échec le plus corrosif en CI : un build rouge peut être une vraie régression ou juste du bruit, et les ingénieurs finissent par ignorer les builds rouges jusqu'à ce qu'un vrai bug parte en prod. FlakeWarden répond à la seule question qui compte (vrai défaut, instable, ou environnement) avec un scoreur d'instabilité déterministe pour les cas clairs et un classifieur UiPath Agent Builder ancré pour les cas ambigus, orchestré par Maestro avec un humain qui valide chaque changement. 90,7 % de précision sur un corpus de 150 cas, avec un taux de faux positifs côté sécurité de 0 % tenu par mécanisme.