~/projets/quizops45 minutes (dont 5 pour l'exercice optionnel)
Le tag tp2-depart reconstruit l'état de sortie du TP 1 : l'application, ses tests, le CLAUDE.md relu et la permission ajoutée dans .claude/settings.json.
cd ~/projets/quizops
outils/depart.sh 2
.......... [100%]
10 passed in 0.14s
Le cahier des charges, lui, manque volontairement : c'est ce que vous allez produire.
$ wc -l CLAUDE.md
26 CLAUDE.md
$ ls PRD.md
ls: PRD.md: No such file or directory
15 minutes
Obtenir un cahier des charges fidèle au code existant, avec des sections que vous imposez et des critères d'acceptation qu'une commande peut vérifier.
claude --permission-mode plan
Le mode plan est le mode de conception : l'agent lit, cherche, délègue des explorations, rédige un plan et attend votre accord avant la moindre écriture.
Voici la forme d'une session en mode plan sur ce dépôt ; le transcript vient d'une autre demande, mais la mécanique est la même.
⏺ Agent(Explore: Explore backend score-related code)
⎿ Async agent launched successfully.
⏺ Agent(Explore: Explore frontend end-of-game screen)
⎿ Async agent launched successfully.
⏺ Read(~/projets/quizops/app/main.py)
⏺ Read(~/projets/quizops/tests/test_api.py)
⏺ Write(~/.claude/plans/<nom>.md)
⏺ ExitPlanMode({"plan": "…"})
[fin] modèle(s) : claude-sonnet-5 ; entrée 14 + cache 437292 ; sortie 3946 ; durée 36174 ms
Deux explorations partent en parallèle, plusieurs fichiers sont lus, un plan est écrit hors du projet et l'accord est demandé. Rien n'est touché dans ~/projets/quizops.
Demandez le cahier des charges avec ces huit sections, dans cet ordre, et pas d'autres :
Objectif · Utilisateurs · Fonctionnalités existantes · Hors périmètre
Contraintes techniques · Modèle de données · API · Critères d'acceptation
Des sections imposées rendent le document comparable d'un stagiaire à l'autre et empêchent l'agent d'inventer un sommaire à chaque exécution.
L'agent pose des questions avant de rédiger : le public visé, ce qui est hors périmètre, ce qui est déjà livré. Répondez en une ligne par question. Sur ce projet, il n'y a ni compte utilisateur ni authentification, et le fichier JSON reste la seule source des questions.
Approuvez le plan, et laissez l'agent écrire PRD.md à la racine. Trois extraits du cahier des charges de référence, pour comparaison avec le vôtre :
## Modèle de données
- Une question : `id` (entier unique), `categorie` (`docker` ou `kubernetes`), `question`, `propositions` (quatre chaînes), `reponse` (index de 0 à 3).
- Un score : `pseudo` (1 à 30 caractères), `score` (entier de 0 à 100), `date` (horodatage SQLite).
- Une partie envoyée par le navigateur : `pseudo` et la liste des `reponses`, chacune avec `question_id` et `choix` (index, ou `null` si la question a été passée).
## API
| Méthode | Route | Rôle |
|---------|-------|------|
| `GET` | `/api/questions` | Dix questions tirées au hasard, sans le champ `reponse` |
| `POST` | `/api/answers` | Reçoit les réponses d'une partie, enregistre et renvoie le score |
| `GET` | `/` et `/static/...` | L'interface |
## Critères d'acceptation
- [ ] `GET /api/questions` renvoie exactement dix questions, sans doublon et sans le champ `reponse`.
- [ ] Dix bonnes réponses donnent un score de 100 ; dix mauvaises donnent 0.
- [ ] Une partie de dix questions dont cinq seulement ont reçu une réponse, toutes justes, donne 50.
- [ ] Chaque partie terminée ajoute exactement une ligne dans la table `scores`.
- [ ] La suite `uv run pytest -q` est verte avant chaque commit.
🧩 Le troisième critère est le fil rouge du score faux : vrai dans le cahier des charges, faux dans le code à partir du TP 4. C'est à cela que sert un critère écrit.
$ grep -c '^## ' PRD.md
8
Q: Pourquoi imposer les huit sections plutôt que demander « un cahier des charges complet » ?
R: Parce que « complet » n'est pas vérifiable et varie à chaque exécution. Huit titres imposés donnent un document comparable, relisible et un compteur (grep -c '^## ') qui tranche.
15 minutes
Transformer une fonctionnalité en trois lots livrables, chacun relié à un fichier de test déjà écrit et à une commande de contrôle.
Le dossier tests/a-venir/ contient les tests d'acceptation des fonctionnalités non livrées. Trois d'entre eux décrivent le filtrage des questions par catégorie, que vous implémenterez au TP 3.
$ ls tests/a-venir/ | grep categories
test_categories_lot1.py
test_categories_lot2.py
test_categories_lot3.py
$ grep -c 'def test_' tests/a-venir/test_categories_lot*.py
tests/a-venir/test_categories_lot1.py:2
tests/a-venir/test_categories_lot2.py:1
tests/a-venir/test_categories_lot3.py:1
## Lots à venir ajoutée à PRD.md, avec exactement trois sous-sections ### Lot N : titre.curl de contrôle.Contraintes à imposer dans votre prompt
### Lot N : suivi d'un verbe à l'infinitifcurl dont la sortie est prévisible💡 Indice : les tests sont la spécification. Un lot qui ne cite pas son fichier de test n'a pas de critère d'arrêt.
$ grep -c '^### Lot' PRD.md
3
$ grep -c '^## ' PRD.md
9
2. Le prompt rédigé :
Lis les trois fichiers tests/a-venir/test_categories_lot1.py, lot2 et lot3.
Ajoute à PRD.md une section « ## Lots à venir » placée après les critères
d'acceptation, contenant exactement trois sous-sections « ### Lot N : … ».
Chaque lot décrit en deux phrases le comportement attendu, cite le chemin
du fichier de test qui le valide, et donne une commande curl de contrôle
dont la sortie est prévisible.
Ne modifie aucune autre section du fichier.
3. Les trois lots du cahier des charges de référence :
### Lot 1 : filtrer par catégorie
`GET /api/questions?categorie=docker` ne renvoie que des questions Docker. Tests : `tests/a-venir/test_categories_lot1.py`. Contrôle : `curl -s 'http://127.0.0.1:8000/api/questions?categorie=docker' | grep -c kubernetes` renvoie `0`.
### Lot 2 : refuser une catégorie inconnue
`GET /api/questions?categorie=inconnue` renvoie un code 404, pas une liste vide. Tests : `tests/a-venir/test_categories_lot2.py`. Contrôle : `curl -s -o /dev/null -w '%{http_code}' 'http://127.0.0.1:8000/api/questions?categorie=inconnue'` renvoie `404`.
### Lot 3 : lister les catégories
`GET /api/categories` renvoie la liste triée des catégories, et l'interface propose un bouton par catégorie avant de commencer. Tests : `tests/a-venir/test_categories_lot3.py`. Contrôle : `curl -s http://127.0.0.1:8000/api/categories` renvoie `["docker","kubernetes"]`.
✅ Chaque lot a une commande dont la sortie est connue d'avance : 0, 404, ["docker","kubernetes"]. C'est ce qui permettra au TP 3 de savoir quand s'arrêter.
10 minutes
Faire nommer les endroits où une erreur ne provoque aucun message, puis committer le cahier des charges avec un message rédigé depuis le diff.
Une erreur bruyante se voit dans les logs. Une erreur silencieuse produit un score faux ou une partie perdue sans que personne le sache, et c'est cela que le cahier des charges doit nommer.
## Composants critiques en dernière position de PRD.md.PRD.md avec un message que l'agent rédige à partir du diff, pas à partir de votre demande.Contraintes à imposer dans votre prompt
💡 Indice : pour le message de commit, demandez d'abord git diff --staged puis le message. Voici ce que donne un message rédigé depuis un diff.
⏺ Bash(git diff README.md)
⎿ diff --git a/README.md b/README.md (+10 lignes)
⏺ Voici le message de commit proposé :
Précise que le quiz est en français
Le README décrivait le quiz sans mentionner sa langue, ce qui pouvait
prêter à confusion pour de nouveaux contributeurs découvrant le projet
sans avoir lancé l'application au préalable.
$ grep -c '^## ' PRD.md
10
$ grep -o '/api/[a-z]*' PRD.md | sort -u
/api/answers
/api/categories
/api/questions
$ git log --oneline tp2-depart..HEAD | wc -l
1
1. Le prompt rédigé :
Tu connais ce projet et son PRD.md. Trouve les trois endroits du code où une
erreur ne produirait aucun message d'erreur visible : le serveur répond, la
page s'affiche, et pourtant le résultat est faux.
Ajoute à la fin de PRD.md une section « ## Composants critiques » : un
paragraphe par composant, le nom du composant en gras, la question « que se
passe-t-il si… » puis la conséquence pour le joueur.
Ne propose aucun correctif et ne touche pas aux autres sections.
2. Le premier composant du cahier des charges de référence :
- **L'entrée de `POST /api/answers`** : que se passe-t-il si la liste des réponses est vide, si un identifiant de question n'existe pas, si le choix vaut 7 ou si le pseudo fait 200 caractères ? Aujourd'hui la route accepte tout : une erreur silencieuse produit un score faux, une erreur bruyante produit un 500.
Les deux autres portent sur le chargement de data/questions.json, qui empêche le serveur de démarrer si une virgule est en trop, et sur l'écriture dans SQLite, où une partie se perd sans que le joueur le sache.
✅ Ces trois composants deviennent le programme des TP suivants : la validation des entrées au TP 5, la panne du fichier JSON au TP 3, la colonne renommée au TP 5.
5 minutes
Repérer, dans un document que vous venez de faire écrire, la phrase qu'aucune commande ne peut trancher.
Un cahier des charges contient presque toujours un critère du genre « l'interface doit rester agréable ». Il ne coûte rien à écrire et ne prouve rien.
/clear : la session repart sans le souvenir de la rédaction, ce qui évite à l'agent de défendre son propre texte.PRD.md un critère qu'aucune commande ne peut vérifier.Contraintes à imposer dans votre prompt
💡 Indice : si vous ne voyez pas quoi vérifier avec grep, curl ou pytest, le critère est invérifiable.
git diff --stat
La sortie varie selon la reformulation ; la preuve est qu'elle ne cite que PRD.md, et que le critère modifié nomme une commande.
Rendez-vous au TP 3 : les trois lots que vous venez d'écrire deviennent du code, un par un.
➡️ Module associé : Prompt Engineering et Conception · TP suivant : TP 3 : Faire Évoluer du Code Existant