Audit de Conception → Maquettes → Registre des Décisions
Objectif
Transformer un clone local d'un site web en : (1) preuve hachée ancrée à un commit git, (2) constats qui citent chacun une règle et pointent vers les fichiers source probables, (3) maquettes « tel quel » et « cible » dans Figma, (4) enregistrements de décisions expliquant chaque modification, (5) enregistrements d'approbation humaine, et (6) briefs d'implémentation pour les décisions approuvées que Claude Code ou Codex exécute dans une session séparée. Le registre git est la source de vérité. Figma en est une projection. Ce skill conçoit et enregistre ; il ne modifie jamais le code source du site.
Flux de travail prévu
- L'étudiant clone le dépôt de son site (depuis GitHub, ou le dépôt à partir duquel un projet Vercel est déployé) et l'exécute localement. Les étudiants doivent avoir un accès éducatif au Figma MCP.
- Ce skill capture depuis le serveur de développement local, audite et construit des maquettes dans Figma.
- Un humain trie les constats, examine les décisions et approuve.
- Ce skill rédige un brief de remise par décision approuvée. Claude Code ou Codex implémente chaque décision sur sa propre branche. Ce skill recapture pour vérifier.
Commandes
Le dossier du skill contient une commande, fwd, et un fichier CLAUDE.md qui explique comment y répondre. Lorsque l'utilisateur tape help, check, init ou tutorial, suivez CLAUDE.md :
helpexécutefwd help(vérifications de configuration plus une prochaine étape) et, si les outils Figma sont présents,whoamipour le siège. D'abord les éléments manquants ; une seule prochaine étape ; aucune modification effectuée pour le compte de l'étudiant.tutorialexécute le premier tutoriel en sept étapes (refonte de votre page d'accueil). Il s'agit des propres phases de ce skill, pilotées étape par étape.fwd approve|reject|defer <D-id>est la commande de l'étudiant, exécutée dans son propre terminal. Elle écrit le fichier d'approbation et l'événement du registre. L'élément non négociable 1 s'applique : ne jamais l'exécuter, ne jamais écrire dansaudit/approvals/.fwd ledger verifyvérifie la chaîne de hachage et que chaque fichier d'approbation correspond au registre.
Éléments non négociables
- Seul un humain peut définir une décision comme approuvée, rejetée ou différée, ou en rouvrir une. N'écrivez jamais ces états. N'écrivez jamais de fichiers dans
audit/approvals/. - Chaque constat cite un
rule_iddepuisaudit/rulebook/rules.yaml. Pas de règle, pas de constat : enregistrez-le comme uneobservationpour l'humain. - Les étiquettes des constats suivent le niveau de la règle : normatif →
failure, heuristique →concern, maison →deviation. N'appelez jamais un constat heuristique un échec. N'utilisez jamais d'icônes ou de mots de type réussi/échoué (✅ ❌ « violé ») pour les constats heuristiques. - Chaque différence entre une image « tel quel » et son image « cible » porte au moins un identifiant de décision. Signalez les différences non étiquetées ; ne les absorbez pas.
- Ne modifiez jamais la page
00 As-Is. Ne modifiez ni ne supprimez les nœuds que le skill n'a pas créés. Touchez uniquement les annotations dans les propres catégories du skill, et faites toujours lecture-fusion-écriture. - Ne définissez jamais le statut Dev Mode (Prêt pour le développement / Terminé). Ne résolvez ni ne supprimez jamais les commentaires humains.
- Aucune écriture Figma dans un fichier existant tant que l'humain n'a pas enregistré une version de base nommée et que son ID n'est pas enregistré. Exception : un fichier Figma créé par cette exécution elle-même. Il commence vide, donc le fichier vide est sa propre version de base ; enregistrez-la dans
capabilities.json. - Capturez uniquement à partir d'un clone local d'un dépôt que l'utilisateur possède ou pour lequel il a les droits de travail, servi depuis localhost, ou à partir du site déployé ou d'un aperçu Vercel de ce même dépôt lorsque l'utilisateur fournit son URL. Ne capturez jamais, n'injectez jamais de scripts et ne retirez jamais les en-têtes de sécurité sur des sites tiers en production.
intent.yamldoit enregistrer le dépôt et le commit épinglé. - Ne remplacez jamais une image de constats précédente ou la sortie d'une exécution antérieure. Les ré-exécutions créent une nouvelle image versionnée (voir Phase 7). Ne localisez jamais vos propres nœuds par nom de calque, couleur de remplissage ou heuristiques de texte ; utilisez les ID de nœuds enregistrés dans le registre.
- Ne modifiez jamais le code source du site. L'implémentation se produit uniquement dans une session Claude Code ou Codex séparée, à partir d'un brief de remise pour une décision approuvée.
Structure des répertoires
audit/
intent.yaml # renseigné par l'humain (Phase 0)
rulebook/rules.yaml # confirmé par l'humain (Phase 1)
schema/ # schémas de constat, décision, approbation, événement
runs/R-YYYYMMDD-NN/
capabilities.json # ce que cette exécution pouvait réellement faire
manifest.json # hachages et état de la capture
captures/{width}/ # screenshot.png, dom.html, axe.json, checks.json, skeleton.json
findings.json
decisions/D-NNNN.json
approvals/A-NNNN.json # humains uniquement
handoff/ # briefs d'implémentation, décisions approuvées uniquement
README.md # règles partagées pour l'agent implémenteur
D-NNNN.md # un brief par décision approuvée
ledger.jsonl # ajout uniquement, événements chaînés par hachage
Le clone du site se trouve en dehors de audit/ (à local_path). Ce skill le lit et n'y écrit jamais. audit/ peut se trouver dans un dossier frère ou sur sa propre branche, afin que les enregistrements d'audit ne se mélangent jamais avec les commits du site.
Phase 0 — Intention (Porte G0)
Si audit/intent.yaml est manquant ou a des champs obligatoires vides, demandez les champs manquants de manière conversationnelle, un ou deux à la fois. Ne capturez, n'évaluez et n'écrivez rien tant que l'utilisateur n'a pas rempli tous les champs obligatoires. Si l'utilisateur n'a pas encore cloné le dépôt, donnez-lui la commande git clone exacte (pour un projet Vercel, le dépôt GitHub à partir duquel il est déployé) dans son propre bloc de code et attendez.
repo: "" # obligatoire : URL GitHub (ou projet Vercel) du site
local_path: "" # obligatoire : chemin du clone local
commit: "" # obligatoire : SHA du commit sur lequel l'audit est épinglé
dev_command: "" # obligatoire : par ex. "npm run dev"
dev_url: "http://localhost:3000"
routes: [] # obligatoire : chemins à auditer, par ex. ["/", "/apply"]
ownership: "" # obligatoire : "propre dépôt", ou qui a accordé la permission, et quand
implementer: "" # obligatoire : "claude-code" ou "codex"
conformance_target: "WCAG 2.2 AA"
breakpoints: "derive" # "derive" à partir du CSS du site, ou une liste de largeurs
house_rules: "" # chemin vers les tokens du système de conception, ou "none"
figma_file: "" # obligatoire pour les phases Figma ; vide = mode JSON uniquement
approvers: [] # obligatoire : noms et rôles
out_of_scope: []
Phase 1 — Schéma (Porte G1)
Résumez le recueil de règles (nombre de règles par niveau et mode) et les schémas d'enregistrement. Demandez à l'utilisateur de confirmer ou de modifier. Enregistrez un événement de registre schema.confirmed avec le nom de l'utilisateur et la date. Ne continuez pas sans cela.
Sondage des capacités d'exécution
Avant la Phase 2, écrivez capabilities.json :
- Quels outils Figma MCP sont présents (
use_figma,generate_figma_design,html_to_figma,get_metadata,get_screenshot,generate_diagram,upload_assets). - Résultat de
whoami: type de siège sur le plan qui possèdefigma_file. Si les écritures ne sont pas possibles, définissezmode: json-onlyet ignorez les écritures Figma pour l'exécution. Les étudiants doivent avoir un accès au plan éducatif ; enregistrez toujours le siège et le plan réels plutôt que de supposer, et notez toute erreur de limite de débit. - Environnement local : versions de Node et du gestionnaire de packages, si
dev_commanddémarre, et si l'arbre de travail àlocal_pathest propre et aucommit. - Chargez le skill
figma-usede Figma avant tout appel àuse_figma. - Lisez le schéma de l'outil
use_figmaen direct et enregistrez s'il accepte un paramètreskillNames. Un skill Figma comparable (Throughline) passeskillNames: "throughline"sur chaque appel. Si le paramètre existe, passezskillNames: "figma-webdesigner"sur chaque appel àuse_figma; sinon, enregistrezskillNames: unsupported. - Connu depuis la première exécution (2026-11-07, siège étudiant complet), revérifiez plutôt que de supposer :
setSharedPluginDatafonctionne ;addAnnotationCategoryAsyncetnode.annotations(aveclabelMarkdownetcategoryId) fonctionnent ;figma.saveVersionHistoryAsyncn'est PAS pris en charge, donc l'agent ne peut jamais créer la version de base ;figma.root.namen'est PAS définissable, donc le fichier ne peut pas être renommé via l'API. Si l'un d'entre eux échoue maintenant, portez les ID de décision dans les noms d'image sous forme de⟦D-0007⟧plus annotations, et enregistrez le résultat. - Nommez le fichier Figma pour le site (par exemple
jobs.humanitarians.ai) lors de l'appel àcreate_new_file; il ne peut pas être renommé par la suite. Les pages sont des étapes (00 Kit & Legend,01 As-Is Wireframes,02 To-Be Wireframes) ; les images sontpage / width / as-is|to-be / state.
Conventions de script use_figma
Chaque script que ce skill envoie via use_figma doit suivre ces règles :
- Les frères de hauteur égale ont besoin de
layoutSizingVertical = 'FILL'sur chaque enfant (etlayoutAlign = 'STRETCH'seul ne suffit pas lorsque le parent ajuste sa hauteur au contenu). Le texte dans une cellule de hub ou de tableau qui doit être renvoyé à la ligne a besoin detextAutoResize = 'HEIGHT'et d'une largeur. - Polices d'abord. Appelez
figma.loadFontAsyncpour chaque style de police que le script utilise (y compris Italique et Gras si utilisé) dans un seulPromise.allen haut, avant de créer ou de modifier tout texte. - Définissez le dimensionnement après le parent. Ajoutez chaque nœud à son parent, puis définissez
layoutSizingHorizontaletlayoutSizingVertical. Utilisez uniquement les noms de propriétés documentés (cornerRadius, pascorner) ; une propriété inconnue est ignorée silencieusement. - Retournez un reçu d'écriture. Le script doit retourner un objet avec
createdNodeIdsetmutatedNodeIds(toujours renseignés honnêtement ; des tableaux vides uniquement lorsque rien de ce genre ne s'est produit), plusframeId,stamped(si des données de plugin ont été écrites), etpageId. - Enregistrez le reçu. Après chaque appel, ajoutez un événement
figma.writecontenant le reçu, l'ID d'exécution, les ID de décision impliqués etversion_before. Les phases ultérieures trouvent les nœuds appartenant au skill à partir de ces ID, jamais à partir de noms ou de couleurs. - État avant pour les mutations. Si le script modifie un nœud existant (annotations sur un nœud créé par le skill, texte, remplissages), retournez les valeurs précédentes dans le reçu afin que le registre puisse les enregistrer. L'écrasement sans un état avant enregistré n'est pas autorisé.
- Échouez bruyamment. Pas de succès silencieux. Si une recherche ne trouve rien, retournez une erreur qui liste ce qui a été trouvé ; ne signalez jamais un succès pour une opération nulle.
Phase 2 — Capture
- Préparez le clone. Confirmez que
local_pathest aucommitavec un arbre de travail propre (sinon, enregistrezdirty: trueet arrêtez-vous pour demander), installez les dépendances, démarrezdev_command, et confirmez quedev_urlrépond. Enregistrez le SHA du commit, le drapeau dirty et la version de Node dansmanifest.json. Ne modifiez aucun fichier source. Si le projet a besoin de variables d'environnement ou de secrets qui ne sont pas présents, demandez à l'utilisateur ; ne les inventez jamais. - Dérivez les points de rupture à partir de la propre configuration du dépôt (config Tailwind, requêtes de médias CSS personnalisées, thème du framework) et à partir des requêtes de médias CSS calculées du site (sauf si l'intention liste les largeurs). Capturez à 320, à chaque point de rupture moins un et au point de rupture, et à une grande largeur de bureau.
- Par largeur : capture d'écran pleine page, DOM, résultats axe-core (balises wcag2a, wcag2aa, wcag21aa, wcag22aa), vérification de débordement, vérification de géométrie de cible, squelette structurel (points de repère, titres, grappes interactives avec boîtes englobantes).
- Enregistrez l'état de capture (bannière de consentement, authentification, variante) et le SHA-256 de chaque fichier dans
manifest.json. - Ajoutez un événement
capture.completed.
Phase 3 — Mesure
Exécutez des vérifications automatisées et assistées. Les résultats automatisés deviennent directement des constats. Les résultats assistés deviennent des constats avec mode: assisted et triage: null ; notez quelle exception (espacement, en ligne, équivalent, essentiel, tableau de données) pourrait s'appliquer.
Correspondance source. Pour chaque constat, recherchez dans le clone la source de l'élément (son texte, noms de classe, nom de composant ou attributs de données) et enregistrez source: {file, line, confidence}. C'est au mieux : utilisez confidence: low pour une supposition et omettez source plutôt que de prétendre à un emplacement que vous n'avez pas trouvé. Ce sont des indices pour l'implémenteur, pas des instructions.
Phase 4 — Évaluation
Exécutez le passage heuristique. Pour chaque constat, enregistrez :
rule_id, localisateur, chemin de preuve et hachage- sévérité 0–4 (Nielsen : fréquence, impact, persistance)
- confiance (élevée/moyenne/faible)
scope: un desingle-section,cross-section,component,interaction- une phrase sur ce que la preuve montre
Indications de portée :
single-section: le problème se trouve à l'intérieur d'un bloc d'une seule page.cross-section: le problème n'apparaît que sur plusieurs blocs, pages ou largeurs (ordre de priorité par rapport à l'ordre visuel, motifs incohérents, navigation qui change entre les pages). Recherchez-les délibérément ; ils sont souvent les plus importants et les plus faciles à manquer lors de l'examen d'une seule section à la fois.component: un élément réutilisable se comporte ou a l'air incohérent partout où il apparaît.interaction: le problème se trouve dans un état, un flux ou un comportement plutôt que dans une mise en page statique.
Pour les longues pages, évaluez chaque section à partir de sa propre capture d'écran et notez les positions y ; effectuez ensuite un passage séparé pour les constats inter-sections. Incluez uniquement les règles avec suffisamment de preuves visibles ; ignorez les règles qui ne peuvent pas être évaluées à partir de la capture plutôt que de deviner. Considérez-vous comme un seul évaluateur ; dites-le dans le résumé des constats.
Porte G2 — Triage
Présentez les constats groupés par sévérité, puis par page, sous forme de tableau : ID, règle, étiquette, portée, page/largeur, sévérité, confiance, preuve en une ligne. Demandez à l'utilisateur d'accepter, de rejeter ou de réévaluer. Enregistrez chaque appel de triage comme un événement du registre attribué à l'utilisateur. Seuls les constats acceptés avancent.
Phase 5 — Référence Figma (Porte G3)
- Capturez les écrans « tel quel » dans la page
00 As-Isviagenerate_figma_design(ouhtml_to_figma), une image par largeur capturée qui montre un changement structurel. - Construisez des maquettes structurelles « tel quel » sur la page
01 As-Is Wireframesà partir deskeleton.json, en utilisant le kit de maquettes du fichier sisearch_design_systemen trouve un. - Passez le relais : demandez à l'utilisateur de verrouiller
00 As-Iset d'enregistrer une version nommée intituléebaseline R-…, puis de vous donner son ID de version. Vous ne pouvez pas enregistrer les versions vous-même. - Enregistrez l'ID comme
version_before. Aucune autre écriture tant que vous ne l'avez pas.
Phase 6 — Proposer
- Regroupez les constats acceptés en décisions. Chaque
D-NNNN.json: titre, ID de constats, contexte, proposition, alternatives (le cas échéant), état (draft), catégorie (normative,heuristic,house), priorité (P0–P4), pages/largeurs concernées,source(copié du constat principal),target_deadline(facultatif). Le titre doit être une phrase impérative en français : « Ajouter un texte alternatif à l'icône de profil ». Adressez-vous à l'implémenteur ; pas de jargon commercial. - Assignez une catégorie de mise en œuvre :
component(modifier un élément réutilisable utilisé à plusieurs endroits),layout(repositionner ou redimensionner des éléments dans un bloc),content(texte ou actifs),interaction(changement d'état ou de comportement),meta(modifications dans<head>, attributs ARIA qui ne changent pas le rendu, correctifs de séquence de tabulation). - Écrivez un résumé pour l'humain. Demandez à l'utilisateur d'approuver, de rejeter, de différer ou de modifier la proposition. N'acceptez pas un « Continue » comme approbation ; l'utilisateur doit taper
fwd approve D-0001explicitement. Lisez le fichier résultant, ne le validez pas seulement. - Enregistrez l'événement
decision.proposedavec les champs de la décision, l'ID de version de la proposition (si une maquette Figma « cible » a été écrite), les hachages des alternatives, etoutcome: proposed.
Phase 7 — Maquette « cible »
- Pour chaque décision approuvée, construisez une image « cible » sur la page
02 To-Be Wireframes. Utilisez les précédentes si la décision ne modifie pas une section ; ne les reclonez pas. Ajoutez l'annotation⟦D-0007⟧au nom du nœud parent de la section et une annotation de catégorie du skill sur le nœud lui-même. - Liez chaque nœud de décision à son ID dans le registre en écrivant des
pluginDatade décision viasetSharedPluginData. - Ajoutez un événement
wireframe.candidatecontenant les ID des nœuds créés, le hachage du répertoire des maquettes, etstage: proposed.
Phase 8 — Validation humaine (Porte G4)
- Présentez la page de validation : un tableau des décisions approuvées (ID, titre, décision, date). Chaque ligne montre l'humain qui a approuvé.
- Demandez à l'utilisateur d'enregistrer manuellement une version Figma nommée
approved R-…(vous ne pouvez pas le faire) et de vous donner l'ID de version. Enregistrez-le commeversion_after. L'IDversion_beforedoit être défini et doit différer. - Déplacez l'image du carrousel de la phase 7 de
stage: proposedàstage: approveddans le registre. Figma n'a pas de notion d'approbation ; le registre seul l'a. - Enregistrez un événement
human.approvedavec l'ID de la version Figma après approbation, l'ID de la version Figma de la baseline,version_beforeetversion_after.
Phase 9 — Remise
- Pour chaque décision approuvée, écrivez
handoff/D-NNNN.md. Modèle :
Objet : D-0001 : Ajouter un texte alternatif à l'icône de profil
Catégorie : content Constat : IC-0003 (manque de texte alternatif sur l'icône de profil dans l'en-tête) Règle : wcag-4.1.2 (name, role, value)
Situation actuelle
L'icône de profil dans l'en-tête .header-nav (ligne 42 de components/Nav.tsx) est un <img> sans attribut alt. L'image est présentée comme un lien de navigation principal ; son nom accessible est donc nul.
État cible
Ajoutez alt="Profil" (ou alt="Mon profil" s'il mène à une page de profil personnelle) à l'icône de profil. Utilisez alt="" si l'icône est décorative et qu'un texte de lien adjacent la décrit déjà, mais vérifiez d'abord qu'il n'y a pas de nom accessible en double.
Preuve
audit/runs/R-20261201-01/captures/1280/axe.json chemin : nœud #25 axe/findings/deficient-item-0
Critères de vérification
- L'attribut
altest défini et non vide (ou intentionnellement vide) dans le rendu HTML. - Axe-core ne signale pas d'élément
<img>manquant de texte alternatif dans ce composant. - L'outil de vérification du texte alternatif de l'extension Wave ne trouve pas de problèmes.
Zone du dépôt
components/Nav.tsx ligne 42
-
Mettez à jour
handoff/README.mdavec les conventions de codage partagées : règles de guidage du plan, prompt système pour l'agent implémenteur, validation des modifications (l'implémenteur doit écrire un test de régression pour chaque modification). -
Résumez :
X décisions sur Y approuvées, Z différées, W rejetées.
Phase 10 — Vérification (Porte G5)
- Exécutez à nouveau la capture et la mesure (Phase 2, Phase 3) sur une nouvelle branche sur laquelle l'implémenteur a fusionné ses modifications. Utilisez la même
intent.yamlmais pointez vers le nouveau commit contenant les modifications fusionnées. - Comparez les résultats : seuls les constats marqués comme résolus par les décisions approuvées doivent être absents. Toute régression (nouvel échec dans une zone que vous avez modifiée) doit être signalée comme un constat de suivi. Enregistrez les deux états dans le registre.
- Si prévu dans l'intention, relisez les modifications de code de l'implémenteur pour détecter les régressions de conception (espacement, couleur, taille, comportement) en comparant les captures « tel quel » et « cible » rendues.
- Enregistrez un événement
verification.completedavec les ID des constats de suivi.
Journalisation et vérification du registre
Chaque événement dans ledger.jsonl a ces champs obligatoires :
{
"event_id": "E-001",
"type": "human.approved",
"timestamp": "2026-12-01T15:30:00Z",
"actor": "student",
"data": {
"decision_id": "D-0001",
"version_after": "V42"
},
"hash": "sha256",
"parent_hash": "sha256"
}
Le hash est sha256(type + timestamp + actor + JSON.stringify(data) + parent_hash). parent_hash du premier événement est "0000". Chaque événement pointe vers son parent. fwd ledger verify recalcule et échoue si la chaîne est rompue. Le registre est la source de vérité ; Figma est une projection.