Référence de bmad-plus uat (alias recette) : lint, build, serve, import, read, gate et order pour les recettes d’acceptation humaine, avec options, codes de sortie et exemples.
bmad-plus uat (alias bmad-plus recette) gère les recettes d’acceptation humaine. Une recette est une spécification JSON d’étapes qu’une personne joue à l’écran. La commande valide la spécification, construit une page HTML autonome pour le testeur, enregistre ses réponses dans une exécution JSON, liste les échecs et en tire un verdict de porte. Elle sert quand une livraison doit être vue en fonctionnement par une personne, et pas seulement par des tests. Sentinel la pilote à votre place ; vous en avez besoin pour scripter le processus, brancher une étape de CI ou vérifier ce que l’agent affirme.
Remarque· Ce que la porte prouve, et ce qu’elle ne prouve pas
La porte établit qu’une exécution est terminée, à jour, entièrement répondue et triée. Elle n’établit jamais que le testeur a regardé au bon endroit : tout verdict est donc étiqueté « observé par un humain ». Une porte « passed » peut encore reposer sur des échecs : ils doivent seulement être classés, chacun avec une décision.
action est l’une des sept actions ci-dessous. target est un identifiant de recette (la commande cherche <dir>/specs/<id>.json, puis toute spécification de ce dossier dont l'id correspond) ou le chemin d’un fichier .json. order n’a pas de cible.
Les sept actions
Action
Ce qu’elle fait
Écrit
lint
Valide la spécification : schéma, clés inconnues, balisage, identifiants d’étapes et d’attendus, témoins, budget de 15 étapes / 30 minutes. Avec --src, vérifie que chaque libellé d’écran cité existe dans un fichier source.
rien
build
Lance d’abord le lint et refuse à la moindre erreur, puis écrit la page du testeur.
<dir>/pages/uat-<id>.html
serve
Sert la page construite sur 127.0.0.1 et enregistre chaque réponse envoyée par la page. Tourne jusqu’à Ctrl+C.
<dir>/results/<id>/<runId>.json
import
Enregistre un JSON de résultats exporté depuis la page (fichier ou entrée standard).
<dir>/results/<id>/<runId>.json
read
Liste chaque exécution et chaque attendu en échec ou bloqué avec son texte et la note du testeur.
rien
gate
Calcule le verdict : passed, failed, awaiting ou stale. --emit-check écrit en plus un vérificateur autonome.
<dir>/checks/gate-<id>.cjs (seulement avec --emit-check)
order
Calcule l’ordre de jeu de toutes les recettes de <dir>/specs à partir de leur after et des témoins partagés.
<dir>/ORDER.md
Options
Option
Argument
Défaut
Effet
-d, --directory
<path>
dossier courant
Dossier du projet.
--dir
<path>
_bmad-output/uat
Dossier des recettes dans le projet : specs/, pages/, results/, triage/, checks/.
--src
<path>
aucun
Dossier source scanné pour les libellés d’écran (lint, build). Répétable.
--language
<code>
voir plus bas
Langue de la page : un code (fr), un nom (Français) ou une balise de locale.
--input
<file>
aucun
import seulement : fichier de résultats à enregistrer ; - lit l’entrée standard. Obligatoire pour import.
--port
<number>
4173
serve seulement : port, lié à 127.0.0.1 uniquement.
--emit-check
aucun
désactivé
gate seulement : écrit aussi le vérificateur Nexus checks/gate-<id>.cjs.
--json
aucun
désactivé
Sortie lisible par machine, avec schemaVersion: 1.
Langue de la page, par ordre de priorité : le champ language de la recette, puis --language, puis le communication_language lu dans _bmad/config.yaml, puis l’anglais. La page embarque toujours les dix langues de l’installateur (en, fr, es, de, pt-br, ru, zh, he, ja, it) et le testeur peut en changer sur la page.
Lit : les spécifications de <dir>/specs (refusées au-delà de 4 Mio ou si le fichier est un lien symbolique), _bmad/config.yaml (build seulement, pour communication_language), les résultats de <dir>/results/<id>/ et le fichier de tri <dir>/triage/<id>.json.
Avec --src : ne lit que les fichiers source de ces extensions : ts, tsx, js, jsx, mjs, cjs, vue, svelte, html, htm, php, py, rb, java, kt, cs, go, json, yaml, yml, md. Elle ignore les liens symboliques, les dossiers commençant par un point, node_modules, .git, dist, build, coverage, .next, .nuxt, vendor, __pycache__, .venv, venv, target et out, saute les fichiers de plus de 512 Kio et s’arrête après 20000 fichiers.
Écrit : uniquement les fichiers nommés dans le tableau ci-dessus. Les valeurs ressemblant à des identifiants collées dans une note de testeur sont remplacées par [REDACTED] avant que l’exécution n’atteigne le disque (import et serve) ; l’exécution garde alors le nombre de remplacements dans redactions.
Réseau : aucun, sauf serve, qui n’écoute que sur 127.0.0.1. La page construite ne demande rien à une autre origine. Un testeur sur une autre machine utilise la page comme fichier ou comme artefact et renvoie le JSON pour import.
serve ne répond qu’aux noms d’hôte 127.0.0.1:<port> et localhost:<port> (tout autre en-tête Host reçoit HTTP 403), refuse un corps de requête de plus de 4 Mio et répond HTTP 409 quand une copie plus ancienne d’une exécution remplacerait une plus récente.
La porte prend l’exécution terminée le plus récent de la recette. S’il n’y en a pas, le statut est awaiting. Si cette exécution répond à une autre révision de la spécification (son specSha256 diffère de la spécification actuelle), le statut est stale. Sinon le statut est failed tant qu’au moins une raison ci-dessous s’applique, et passed quand aucune ne s’applique.
Un attendu n’a jamais reçu de réponse (les étapes optionnelles sont ignorées).
Un attendu en échec ou bloqué n’a pas d’entrée dans <dir>/triage/<id>.json, ou sa classe est undecided, ou sa décision n’est pas l’une de fix, amend-spec, remeasure, accept-risk, ask-tester.
Une décision est accept-risk sans decidedBy.
Un attendu est bloqué et sa décision n’est pas accept-risk : rien n’a été observé, il faut le rejouer ou faire accepter le risque par une personne nommée.
Une étape writes: true est passée, mais le tri n’a pas d’entrée writeChecks avec verified: true et un texte evidence : une coche sur une étape qui écrit est une observation, c’est la preuve en lecture seule qui tranche.
Vocabulaire du tri
Classe
Sens
Décision usuelle
product
L’écran diffère de ce que le code devait afficher.
fix
recipe
L’écran est juste, l’attendu le décrivait mal.
amend-spec
data
Le témoin n’est plus dans l’état supposé.
remeasure
undecided
Aucune note, ou non attribuable : interroger le testeur. Garde la porte au rouge.
erreur de lint, gabarit ayant perdu une garantie, ou tout échec
-
-
import
exécution enregistrée
tout échec
-
-
read
exécutions lues, rien en échec
un attendu en échec ou bloqué, ou tout échec
pas encore d’exécution (awaiting)
l’exécution le plus récent répond à une autre révision (stale)
gate
passed
failed (ou tout échec)
awaiting
stale
order
ordre écrit
un cycle, aucune spécification dans le dossier, ou tout échec
-
-
Un échec est toute erreur levée : action inconnue, cible manquante, spécification introuvable, fichier illisible, --input absent. Elle affiche uat: <message> sur la sortie d’erreur, ou {"schemaVersion":1,"status":"error","message":...} avec --json, et sort avec 1. Un script de livraison qui doit distinguer une porte en échec (1) d’une porte qui n’a pas pu s’exécuter utilise la porte de projet uat-release-gate.mjs, qui ajoute le code 4 pour le second cas.
Le premier bloc a été rejoué avec la spécification d’exemple livrée dans la compétence bmad-plus-uat ; les blocs read et gate sont composés à partir des gabarits de messages de la commande, marqués comme simulés, et reprennent le jeu d’essai de tests/unit/uat-cli.test.js. Nombres de fichiers, tailles et empreintes dépendent de votre projet.
Valider puis construire une recette
$ npx bmad-plus uat lint example-1.0.0example-1.0.0: 3 steps, 5 expectations, 8 on-screen labels no error$ npx bmad-plus uat build example-1.0.0/work/app/_bmad-output/uat/pages/uat-example-1.0.0.html — 3 steps, 83 KiB, spec a4a4850b284dopens in English; the tester can switch to any of the 10 languages on the pagecarries the 17 page guarantees: hidden-before-start, no-answer-before-run, verified-local-write, honest-save-status, save-on-every-change, restore-before-capabilities, newer-copy-wins, revision-guard, other-tab-notice, unreadable-draft-kept, progress-accessible, storage-explained, finished-is-not-accepted, unload-guard, utf8-and-escaped-diacritics, export-is-the-run, no-third-party-requests$ npx bmad-plus uat lint example-1.0.0 --src srcexample-1.0.0: 3 steps, 5 expectations, 8 on-screen labels error step 0-setup: do: the label "Folders" is in no source file — copy it from the component, accents included or not error step 1-nominal: where: the label "Technical" is in no source file — copy it from the component, accents included or not# Quatre autres erreurs du même genre suivent et la commande sort avec 1 : ici `src` est un dossier vide, donc aucun libellé de la spécification n’y est trouvé. `--src` doit pointer vers les dossiers qui contiennent réellement les libellés de vos écrans.
Sortie capturée lors d’une exécution réelle. Source: Rejoué avec le paquet 0.23.0 et la spécification d’exemple de la compétence bmad-plus-uat, dans un projet jetable ; le chemin du projet est remplacé par /work/app
Lire une exécution, puis demander la porteSimulé
$ npx bmad-plus uat read demo-1.0.0■ Demo 1.0.0 — Sarah — 2026-09-16 08:00, finished 1 passed · 1 failed · 0 blocked · 0 skipped · 0 to do (_bmad-output/uat/results/demo-1.0.0/20260916-sarah-aaaa.json) ✗ 1-confirm/a (failed) — Confirm expectation: The line reads OPCO confirmed. seen instead: the line still reads OPCO to confirm# Code de sortie 1 : un échec existe.$ npx bmad-plus uat gate demo-1.0.0demo-1.0.0: failed (run 20260916-sarah-aaaa by Sarah) - 1-confirm/a is failed and not triaged# Code de sortie 1. Une fois l’échec classé dans triage/demo-1.0.0.json (classe product, décision fix), la même commande affiche « demo-1.0.0: passed ... » et sort avec 0.
Transcription illustrative, non capturée lors d’une exécution réelle. Source: tools/cli/commands/uat.js (modèles de read et gate) ; tests/unit/uat-cli.test.js (jeu d’essai demo-1.0.0, exécution 20260916-sarah-aaaa)
Faire écrire et construire la recette par Sentinel#
Une version est prête pour l’environnement de test. Vous voulez une page qu’un collègue non technique peut jouer.
Dans votre assistant IA
Sentinel, écris la recette d’acceptation de cette livraison sur notre environnement de test. Valide-la avec lint sur src, construis la page et dis-moi quelles étapes écrivent pour de bon.
Ce que vous devriez obtenir Sentinel écrit la spécification dans _bmad-output/uat/specs/<id>.json, lance bmad-plus uat lint <id> --src src et corrige ce qui est signalé, puis lance bmad-plus uat build <id>, qui écrit _bmad-output/uat/pages/uat-<id>.html et liste les garanties de la page. Il vous remet le lien ou le fichier, la durée et les étapes marquées writes: true, chacune avec son contrôle verify en lecture seule. Si la CLI n’est pas disponible, il le dit au lieu de prétendre que la page est construite.
Sentinel, importe le fichier de résultats results.json pour la recette demo-1.0.0, lis l’exécution, classe chaque échec et dis-moi si la porte passe.
Ce que vous devriez obtenir Sentinel lance uat import demo-1.0.0 --input results.json, puis uat read demo-1.0.0, qui affiche chaque attendu en échec ou bloqué avec son texte et la note du testeur. Il écrit une classe et une décision pour chacun dans _bmad-output/uat/triage/demo-1.0.0.json, vous interroge quand une note n’explique pas l’échec (la classe undecided garde la porte au rouge), puis rapporte uat gate demo-1.0.0 avec le statut et le code de sortie (0 passed, 1 failed, 2 awaiting, 3 stale). Il étiquette la preuve « observé par un humain ».
Brancher la porte dans un script de livraison (porte de projet copiée depuis templates/)
node scripts/uat-release-gate.mjs || exit 1
# deploy only below this line
La compétence livre deux portes de projet dans .agents/skills/bmad-plus-uat/templates/ : uat-spec-present.mjs échoue quand aucune recette ne nomme la version de package.json, et uat-release-gate.mjs lance uat gate avec la CLI installée dans le projet (0 passed, 1 failed, 2 aucune exécution terminée, 3 autre révision, 4 la porte n’a pas pu s’exécuter, ce qui n’est pas un succès).