koffih/preuve-de-fait

Empêche les fausses complétions (succès hallucinés). Avant toute affirmation que le travail est terminé, corrigé, fonctionnel, passé, déployé ou prêt, la revendication est transformée en un contrat d'acceptation écrit avant le code, chaque critère est prouvé par une commande ou un fichier dont le reçu (code de sortie, sortie, empreinte de l'arbre de travail) est écrit par un script, un vérificateur indépendant rejoue les preuves, et seul le verdict calculé (FAIT, PAS FAIT, BLOQUÉ) peut être rapporté.

Qu'est-ce que preuve-de-fait ?

Ce skill pour agents IA (Claude Code, Cursor, Codex) empêche les affirmations non prouvées de complétion de tâche en imposant un processus formel : avant toute déclaration de fin, de correction, de déploiement ou de succès, un contrat d'acceptation est rédigé sous forme de critères observables. Chaque critère est prouvé via une commande ou un fichier dont la preuve (code de sortie, sortie, empreinte de l'arbre) est enregistrée par le script `proof.py`. Un vérificateur indépendant peut rejouer les preuves pour confirmer le verdict : FAIT, PAS FAIT, BLOQUÉ. Le skill propose aussi un crochet d'arrêt optionnel qui refuse de terminer une session sur un résultat non prouvé. Idéal pour démarrer une fonctionnalité, un correctif ou une migration qui doit vraiment fonctionner, avant de valider, commit, PR, déployer, ou quand un sous-agent rapporte un succès ou que l'utilisateur doute d'un résultat.

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/koffih/claude-skill-proof-of-done/tree/HEAD

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Preuve de fait

Tu ne décides pas que le travail est terminé. Un script le fait, à partir de reçus. Ton travail est d'écrire le contrat, de produire les preuves et de rapporter le verdict que le script calcule, mot pour mot.

Requête : $ARGUMENTS

La règle

PAS DE REÇU, PAS DE DÉCLARATION.
Un reçu ne compte que sur le code où il a été pris.
Le verdict est calculé, jamais écrit à la main.

« Terminé », « corrigé », « ça marche », « passe », « prêt », « déployé », « tout bon », une coche, ou toute phrase qui laisse croire à l'une de ces affirmations est une déclaration. « Devrait marcher » aussi, qui est une déclaration avec une excuse attachée. Chaque déclaration nécessite une ligne PROUVÉE dans le registre pour l'arbre actuel, sinon elle n'est pas faite.

Le moteur

scripts/proof.py dans le dossier de ce skill (généralement ~/.claude/skills/proof-of-done/scripts/proof.py, ou .claude/skills/proof-of-done/... dans un projet). Bibliothèque standard, Python 3.8+. Configure-le une fois par session :

P="python3 $(ls -d ~/.claude/skills/proof-of-done .claude/skills/proof-of-done 2>/dev/null | head -1)/scripts/proof.py"

Tout se trouve dans .proof/ à la racine du projet : acceptance.md (le contrat, à commiter), contract.lock et contract-log.md (à commiter), receipts.jsonl et artifacts/ (preuves locales, ignorées par git).

Les cinq mouvements

1. Contrat, avant le code

$P init, puis écris .proof/acceptance.md. Une ligne par critère, quatre champs :

- AC1 :: un utilisateur connecté peut lier Gmail et voit « Connecté » :: e2e :: run: npx playwright test tests/gmail-connect.spec.ts
- AC2 :: un email devient une tâche avec son sujet comme titre :: integration :: run: pytest tests/test_email_to_task.py -q
- AC3 :: la page inbox affiche la nouvelle tâche sans rechargement :: visual :: see: capture d'écran après conversion d'un email
  • Un critère indique ce que quelqu'un peut observer (un utilisateur, un appelant, un fichier, une ligne), pas quel code existe. « Ajouter un gestionnaire » n'est pas un critère.
  • Le niveau de preuve est la force de preuve dont la déclaration a besoin. Lis references/proof-ladder.md pour le choisir : une affirmation d'UI nécessite au moins e2e ou visual, un correctif nécessite un test qui échouait avant le correctif, un déploiement nécessite runtime sur la cible déployée.
  • run: est la commande exacte qui sort avec 0 uniquement si le critère est satisfait. Écris-la comme tu l'exécuteras. Étroite est acceptable (un fichier de test), vide ne l'est pas (true, echo ok, un test sans assertion).
  • Si l'utilisateur a donné des critères, utilise ses mots. Sinon, dérive-les de la demande, affiche-les en un court bloc, et continue (n'attends pas sauf si un critère est vraiment ambigu). Ajoute une liste ## Hors périmètre pour que personne ne t'évalue sur ce qui n'était pas demandé.
  • $P freeze. Désormais, supprimer un critère, abaisser un niveau ou remplacer une commande par une plus facile apparaît dans contract-log.md et nécessite --reason avec l'accord de l'utilisateur. Ajouter des critères est toujours permis.

Pour un changement d'une ligne, le contrat peut être un seul critère. Il existe quand même.

2. Construire, prouver en chemin

Implémente normalement. Après chaque étape cohérente, $P run AC2 (ou $P run --all) et lis ce qu'il affiche. Une ligne ÉCHEC est une information, pas un obstacle à contourner : lis la sortie, corrige la cause, relance. Pour un correctif, exécute le nouveau test avant le correctif et garde ce reçu d'échec en mémoire : un test de régression qui n'a jamais échoué ne prouve rien (rouge, puis vert).

Pour les critères see: : produis la preuve (capture d'écran Playwright, sortie curl -i sauvegardée dans un fichier, CSV exporté, extrait de log), ouvre-la et regarde-la (Lis l'image, lis le fichier), puis $P attach AC3 chemin/vers/capture.png --note "inbox après conversion, tâche visible". Le fichier est copié dans .proof/artifacts/, donc il ne perturbe pas les autres reçus. Attacher une capture d'écran que tu n'as pas regardée est le même mensonge que citer un test que tu n'as pas exécuté.

3. Verdict

$P run --all      # nouveaux reçus pour chaque critère run:, sur l'arbre final
$P verdict        # le registre et le verdict ; sort avec 0 uniquement si FAIT

États : PROUVÉ (reçu passe sur l'arbre actuel), ÉCHEC, EN ATTENTE (pas de reçu), OBSOLÈTE (code modifié après la preuve), INADAPTÉ (le reçu a exécuté une autre commande que le contrat), SUSPECT (sortie 0 mais zéro tests exécutés, seulement des sauts, un outil manquant, ou la preuve a modifié l'arbre), BLOQUÉ, EXEMPTÉ. Verdicts : FAIT, FAIT AVEC EXEMPTIONS, BLOQUÉ, PAS FAIT.

Toute modification après la dernière exécution, même un commentaire, rend les reçus OBSOLÈTES. C'est le but : relancer en dernier, rapporter juste après.

4. Vérification indépendante

Le créateur n'évalue jamais son propre travail. Quand la tâche est plus qu'un petit changement, a touché une UI, un déploiement ou des données, ou a été faite par des sous-agents, lance un sous-agent vérificateur avec l'invite dans references/checker.md. Il relit le contrat, réexécute les preuves lui-même, regarde les fichiers joints, lit le diff pour les dérives de périmètre et les falsifications de barrière, et retourne ACCEPTÉ ou REJETÉ avec des raisons. Un REJETé renvoie à l'étape 2. Quand un sous-agent te dit qu'il a réussi, traite-le de la même manière : git diff --stat, exécute sa preuve toi-même.

5. Rapport

Commence par la ligne de verdict exactement comme calculée, puis les reçus :

VERDICT : FAIT   (ou PAS FAIT / BLOQUÉ / FAIT AVEC EXEMPTIONS)

| Critère | Preuve | Résultat |
|---|---|---|
| AC1 utilisateur connecte Gmail, voit « Connecté » | npx playwright test tests/gmail-connect.spec.ts | sortie 0, 3 réussis |
| AC2 email devient tâche | pytest tests/test_email_to_task.py -q | sortie 0, 5 réussis |
| AC3 inbox affiche tâche sans rechargement | .proof/artifacts/AC3-...png (regardé) | tâche visible en haut |

Vérificateur : ACCEPTÉ (ou REJETÉ : ...)
Non prouvé : aucun   (ou chaque critère ouvert, pourquoi, et la prochaine action)
Hors périmètre : ...

En cas de PAS FAIT, dis-le d'abord et clairement, puis ce qui est prouvé, ce qui ne l'est pas, et la plus petite étape suivante. Un PAS FAIT clair est un bon rapport. Un FAIT qui s'avère faux coûte à l'utilisateur une session de débogage et sa confiance.

Garde de langue

Avant d'envoyer tout message, scanne-le. Ceux-ci nécessitent un reçu PROUVÉ sur l'arbre actuel, ou ils disparaissent :

  • fait, fini, complet, corrigé, résolu, marche, fonctionne, passe, vert, prêt, expédié, déployé, en direct, tout bon, devrait marcher, devrait être corrigé, probablement, a l'air bien, ✅, « Parfait ! », « Super, ça a marché »
  • « les tests passent » quand tu as exécuté un sous-ensemble ; « la construction passe » quand tu as exécuté le linter ; « déployé » quand tu as poussé ; « corrigé » quand tu as changé du code et n'as pas reproduit le symptôme.

Dis ce que tu as exécuté et ce qu'il a retourné : « pytest tests/test_email_to_task.py : 5 réussis, sortie 0 » se suffit à lui-même. Quand tu ne l'as pas exécuté : « pas encore vérifié ».

La table complète des excuses et les façons dont une preuve est détournée se trouve dans references/anti-gaming.md. Lis-la une fois par projet ; la version courte : n'affaiblis jamais, ne saute pas, ne moque pas, ne supprime pas ce qui prouve la déclaration, et ne modifie jamais un test pour correspondre à une sortie erronée.

Crochet d'arrêt (optionnel, par projet)

$P hook --install ajoute un crochet Stop à ./.claude/settings.local.json (--shared pour le settings.json commité). Dans un projet qui a .proof/acceptance.md, quand la session essaie de se terminer alors que le verdict n'est pas FAIT, le crochet la renvoie une fois avec les critères ouverts, sauf si le dernier message contient déjà VERDICT : PAS FAIT ou VERDICT : BLOQUÉ. Il ne boucle jamais (il laisse passer le second arrêt) et ne fait rien dans les projets sans contrat. Installe-le pour un travail long ou non supervisé ; informe l'utilisateur qu'il est là.

Quand la preuve ne peut pas être exécutée

Pas de navigateur, pas d'accès à l'environnement de staging, un secret manquant, une API payante : ne remplace pas une preuve plus faible en silence. $P block AC4 --reason "pas d'identifiants staging" et rapporte BLOQUÉ avec exactement ce qui manque et la commande qui prouverait une fois qu'il est présent. $P waive existe seulement pour un critère que l'utilisateur abandonne explicitement, dans ses propres mots, cités dans la raison.

Petites tâches

Une faute de frappe ou une configuration d'une ligne : un critère, une commande, un reçu, une ligne dans le rapport (VERDICT : FAIT + la commande et son résultat). La cérémonie se réduit ; la règle, non.

Skills associés