Un agent. Un cycle complet : spec lue, code écrit, quality gate, release, QA. Bout en bout.
Méthodologie — spec-first, domain-driven
Je ne prompte pas mes agents.
J'écris un contrat avec eux.
Une spec domaine. Des stories qui tranchent au lieu de décrire. Un agent dev qui suit une archi qu'il ne peut pas contourner. Un agent QA qui rejoue la story sur l'app déployée. Ce qui tourne en prod, c'est ce qui est écrit.
Survole une étape pour l'isoler. Les nœuds ⓘ ouvrent le fichier réel, copiable. Fais glisser le graph. Touche un nœud ⓘ pour ouvrir le fichier réel.
--- title: Story — Distance & durée auto (Google Routes API) status: ready-for-review created: 2026-06-17 fr: FR-16 # l'exigence du PRD que la story couvre epic: E4 — Calculateur author: John (PM) dev_kit: ../layou-dev-kit # l'archi que l'agent dev relit AVANT de coder depends_on: story-address-autocomplete.md --- ## Story As a **chauffeur VTC qui remplit un Transfert**, I want **que la distance et la durée se remplissent toutes seules**, so that **je ne les tape plus à la main et mon tarif colle au réel.** ## Décisions produit (figées avec Youcef — 2026-06-17) | Sujet | Décision | |---|---| | API | Routes API (New) — CORS-compatible depuis Flutter web | | Éditabilité | une AIDE, jamais un verrou : le chauffeur corrige | | Aller-retour | 2 appels (A→B + B→A) puis somme. Pas de ×2 naïf | | Échec API | on ne remplit rien. Champ vide, saisie manuelle | ## Hors scope Proxy Cloud Function · polyline/carte · nouveau champ Firestore. ## Tâches T0 vérifier la clé au curl · T1 domaine (entity + usecase) T2 data (repo Routes API) · T3 calculateur · T4 les 3 forms T5 recalcul du tarif · T6 tests · T7 analyze
// Flutter web rend dans un <canvas> : pas de DOM à cliquer.
// Donc chaque élément interactif porte un Semantics(identifier:)
// stable → dans le DOM : flt-semantics-identifier="nav_fab_create"
// C'est CE détail qui rend l'app pilotable par un agent.
const URL = process.env.UPDRIVE_URL || 'https://updrive-prod.web.app';
function bySemantics(page, identifier) {
return page.locator(`[flt-semantics-identifier="${identifier}"]`).first();
}
async function fillField(page, identifier, value) {
const node = bySemantics(page, identifier);
await node.waitFor({ state: 'visible', timeout: 5000 });
await node.click({ force: true }); // focus le VRAI champ
await page.keyboard.press('End');
for (let i = 0; i < 60; i++) await page.keyboard.press('Backspace');
await page.keyboard.insertText(value); // seul chemin fiable ici
}
// L'agent rejoue la story, écran par écran : inscription →
// dashboard → calculateur → facture → listing. En light ET dark.
// Screenshot à chaque étape. Le contrat
Un prompt s'évapore.
Une story se rejoue.
C'est toute la différence. Une story se relit, se review, se teste, et six mois plus tard elle explique encore pourquoi le code est comme ça. Un agent qui reçoit une story n'a rien à deviner — et un agent qui devine, il invente.
Et je ne la tape pas moi-même. L'agent PM me cuisine : il pose les questions qui piquent, je tranche, il rédige. La story sort de cette séance — c'est exactement pour ça qu'elle contient des décisions et pas des options. Mon boulot dans l'histoire, ce n'est pas l'écriture : c'est d'arbitrer, et de signer.
status:où en est la story dans la bouclefr: FR-16l'exigence du PRD qu'elle couvre — la traçabilité remonte jusqu'à la specepic:le lot auquel elle appartientdev_kit: ../layou-dev-kitl'archi que l'agent dev relit avant d'écrire une lignedepends_on:ce qui doit exister avant — c'est ce qui autorise le parallèle
Ce que la story tranche
- Des décisions, pas des options. « Routes API (New), parce que le SDK JS legacy est inutilisable en Dart. » L'agent n'arbitre pas : il applique.
- Le hors-scope, écrit. C'est la ligne qui empêche un agent zélé de refactorer la moitié de l'app.
- Le comportement en cas d'échec. API muette → on ne remplit rien, le champ reste éditable. Pas de crash, pas de 0,00 € silencieux.
- Des tâches numérotées. T0…T7. Une story qui ne se découpe pas est une story trop grosse.
Plusieurs stories indépendantes → plusieurs agents en parallèle. Agent A sur le sélecteur client, Agent B sur la persistance, en même temps.
depends_on dit qui attend quoi. Deux agents ne se
marchent dessus que si la spec a oublié de le dire.
L'agent dev
Une archi qu'il ne peut pas contourner
Le layou-dev-kit est un repo à part, posé à côté de l'app. La story pointe dessus, l'agent le lit avant de coder. Ce ne sont pas des conseils : ce sont des invariants. Quand l'agent accélère ×10, c'est la seule chose qui empêche le code de partir en vrille ×10.
- 01
presentationn'importe jamaisdata. - 02
domainn'importe nidata, nipresentation, ni Firebase, ni Flutter UI. - 03 La racine
lib/= shell, router, startup, DI. Rien d'autre. - 04 Tout SDK externe est wrappé avant d'atteindre le code de l'app.
- 05 Usecase obligatoire pour les writes, les effets de bord, les décisions métier.
- 06 Ordre d'implémentation : domain → data → app → presentation.
- 07 UI : screen → connector → organism → molecule.
- 08 Clean Architecture dès le jour 1. Même pour un MVP. Zéro code jetable.
L'agent QA
Des tests verts
ne prouvent pas que l'app marche.
Alors le QA ne lit pas le code : il ouvre un vrai navigateur sur l'app
déployée et rejoue la story, écran par écran, comme un
utilisateur. Le piège : une app Flutter rend dans un
<canvas> — il n'y a rien à cliquer. La solution tient
en une ligne d'architecture : chaque élément interactif porte un
Semantics(identifier:) stable. C'est ce qui rend l'app
pilotable par un agent.
- Sur l'app déployée L'E2E tape l'URL de prod. Pas un mock, pas un émulateur : ce que l'utilisateur touche.
- Light ET dark Chaque écran, dans les deux thèmes. C'est là que 80 % des régressions visuelles sortent.
- Une suite par epic epic-1-auth, epic-4-calculator, epic-7-acceptance… + un run-all qui les enchaîne.
- Screenshot à chaque étape La preuve est visuelle. Je relis un parcours complet en 30 secondes.
- Ce qui est stub est écrit Le plan de test dit ce qui n'est pas encore bâti → l'agent ne remonte pas de faux bugs.
- PASS → done. FAIL → story. Un bug ne part pas dans un backlog flou : il redevient une story, avec son contrat.
Honnêtement
Ce que la méthode ne fait pas
Ça ne décide pas à ma place
La spec, les arbitrages produit, le go/no-go : c'est moi. Les agents exécutent un contrat, ils ne le signent pas.
Ça ne remplace pas l'expertise
Si tu ne sais pas pourquoi une liste non lazy va ramer sur un vieux Android, aucun agent ne te le dira spontanément.
Ça ne pardonne pas une story floue
Story vague = code vague, ×10 en vitesse. Le goulot d'étranglement n'est plus le code : c'est l'écrit.
Ce n'est pas du waterfall
Une décision tombe en cours de route ? La story se corrige, le PRD aussi. Ce qui est figé, c'est ce qui est écrit — pas le plan.
Tu veux cette boucle sur ton app ?
Flutter/mobile senior, 7+ ans, delivery accélérée par agents. 20 minutes pour voir si je suis le bon profil.
Réserver un fit-call