designwithai-mcp 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -443,6 +443,20 @@ const TOOLS = [
443
443
  },
444
444
  },
445
445
  },
446
+ {
447
+ name: "framing_criteria",
448
+ description: "Charge les CRITÈRES D'ACCEPTATION d'un cadrage écrit avant de construire, pour vérifier " +
449
+ "la feature contre eux — un par un, avec verify_fix. C'est la seule façon de vérifier " +
450
+ "contre des critères posés AVANT : reconstruits de mémoire, ils se moulent sur le " +
451
+ "résultat obtenu.",
452
+ inputSchema: {
453
+ type: "object",
454
+ properties: {
455
+ product_ref: { type: "string", description: "Le produit, pour ne lister que ses cadrages." },
456
+ id: { type: "string", description: "Un cadrage précis, si tu le connais déjà." },
457
+ },
458
+ },
459
+ },
446
460
  {
447
461
  name: "inventory_ds",
448
462
  description: "Inventorie le DESIGN SYSTEM d'un dépôt local — valeurs de style, composants, et lesquels " +
@@ -692,6 +706,8 @@ function toolListReviews(args) {
692
706
  const DEFAULT_INGEST_URL = "https://hbugvurcdmimhvvfdlos.supabase.co/functions/v1/ingest-audit";
693
707
  /** Même compte, même jeton, autre table : les inventaires ont leur point d'entrée. */
694
708
  const DEFAULT_INVENTORY_URL = "https://hbugvurcdmimhvvfdlos.supabase.co/functions/v1/ingest-inventory";
709
+ /** La lecture des cadrages. Le seul point d'entrée en LECTURE de tout le MCP. */
710
+ const DEFAULT_FRAMING_URL = "https://hbugvurcdmimhvvfdlos.supabase.co/functions/v1/read-framing";
695
711
  async function toolPushAudit(args) {
696
712
  const token = process.env.DWAI_TOKEN?.trim();
697
713
  const url = process.env.DWAI_INGEST_URL?.trim() || DEFAULT_INGEST_URL;
@@ -1022,6 +1038,79 @@ function toolNextGate(args) {
1022
1038
  * lecture : la personne a quand même le droit de savoir ce que son dépôt
1023
1039
  * contient, et ce qu'on n'a pas su y lire.
1024
1040
  */
1041
+ /**
1042
+ * `framing_criteria` — la boucle se referme ici.
1043
+ *
1044
+ * Les critères ont été écrits AVANT de construire, et c'est toute leur valeur.
1045
+ * Les relire au moment de vérifier, plutôt que de les reformuler de mémoire,
1046
+ * est la différence entre une vérification et une relecture complaisante : des
1047
+ * critères reconstruits après coup se moulent sur le résultat obtenu.
1048
+ *
1049
+ * L'outil ne juge rien. Il rend les critères, dans leur forme structurée, et
1050
+ * dit explicitement quoi en faire — c'est `verify_fix` qui statue, un critère à
1051
+ * la fois, avec sa preuve.
1052
+ */
1053
+ async function toolFramingCriteria(args) {
1054
+ const token = process.env.DWAI_TOKEN?.trim();
1055
+ if (!token) {
1056
+ return refusal("framing_criteria a besoin de DWAI_TOKEN dans l'environnement du serveur MCP. " +
1057
+ "Génère un jeton dans ton compte (page Compte → « Connecter mon éditeur »).");
1058
+ }
1059
+ const url = process.env.DWAI_FRAMING_URL?.trim() || DEFAULT_FRAMING_URL;
1060
+ let body;
1061
+ try {
1062
+ const res = await fetch(url, {
1063
+ method: "POST",
1064
+ headers: { "content-type": "application/json" },
1065
+ body: JSON.stringify({
1066
+ token,
1067
+ product_ref: args.product_ref ? String(args.product_ref) : undefined,
1068
+ id: args.id ? String(args.id) : undefined,
1069
+ }),
1070
+ });
1071
+ body = (await res.json().catch(() => ({})));
1072
+ if (!res.ok) {
1073
+ return refusal(res.status === 401
1074
+ ? "Le jeton est inconnu ou révoqué : regénères-en un depuis ton compte."
1075
+ : `La lecture a été refusée (${res.status} ${String(body.error ?? "")}).`);
1076
+ }
1077
+ }
1078
+ catch (e) {
1079
+ return refusal(`Impossible de joindre ${url} : ${e instanceof Error ? e.message : String(e)}`);
1080
+ }
1081
+ const cadrages = (Array.isArray(body.framings) ? body.framings : []);
1082
+ if (cadrages.length === 0) {
1083
+ return text("Aucun cadrage enregistré pour ce produit.\n\n" +
1084
+ "Les critères d'acceptation s'écrivent AVANT de construire, sur le site — sans eux, " +
1085
+ "il n'y a rien contre quoi vérifier, et une vérification faite de mémoire se moule " +
1086
+ "sur ce qu'on a construit.");
1087
+ }
1088
+ const lignes = [];
1089
+ for (const c of cadrages) {
1090
+ const criteres = c.criteria ?? [];
1091
+ lignes.push(`CADRAGE « ${c.feature ?? "sans nom"} » — ${c.id ?? "?"}`);
1092
+ if (c.essai)
1093
+ lignes.push(` Ce qui a été tenté : ${c.essai}`);
1094
+ if (c.verdict)
1095
+ lignes.push(` Verdict du cadrage : ${c.verdict}`);
1096
+ if (criteres.length === 0) {
1097
+ lignes.push(" (aucun critère structuré — rien à vérifier contre)");
1098
+ }
1099
+ else {
1100
+ lignes.push(` Critères d'acceptation (${criteres.length}) :`);
1101
+ for (const k of criteres) {
1102
+ lignes.push(` - ${k.quoi ?? "?"} : de ${k.de ?? "?"} à ${k.a ?? "?"}, d'ici ${k.avant ?? "?"}` +
1103
+ (k.mesure ? ` — mesuré par ${k.mesure}` : " — AUCUNE MESURE INDIQUÉE au cadrage"));
1104
+ }
1105
+ }
1106
+ lignes.push("");
1107
+ }
1108
+ lignes.push("CE QUE TU EN FAIS : appelle verify_fix avec ces critères, UN PAR UN, et une preuve " +
1109
+ "par critère prise dans l'état COURANT du produit. Un critère sans mesure indiquée " +
1110
+ "reste vérifiable — mais dis d'où vient ton chiffre, sinon la vérification vaut ce " +
1111
+ "que vaut une impression.");
1112
+ return text(lignes.join("\n"));
1113
+ }
1025
1114
  async function toolInventoryDs(args) {
1026
1115
  const racine = String(args.path ?? "").trim();
1027
1116
  const productRef = String(args.product_ref ?? "").trim();
@@ -1166,6 +1255,8 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
1166
1255
  return toolGenerateDecision(args);
1167
1256
  case "next_gate":
1168
1257
  return toolNextGate(args);
1258
+ case "framing_criteria":
1259
+ return toolFramingCriteria(args);
1169
1260
  case "inventory_ds":
1170
1261
  return toolInventoryDs(args);
1171
1262
  case "connect_repo":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "designwithai-mcp",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "description": "Le serveur designwithai pour ton éditeur : audite ton produit — interface, navigation, performance, sécurité des données, hygiène Figma — trace les corrections, et fait remonter les résultats dans ton tableau de bord.",
@@ -39,6 +39,17 @@ Produit construit rapidement, plusieurs contributeurs, routes hétérogènes, mi
39
39
  | **Données** | Formats de date, nombre, devise, unités, labels et ordre de colonnes. |
40
40
  | **Accessibilité** | Focus, labels, noms accessibles et clavier variables selon les implémentations. |
41
41
 
42
+ ## La frontière avec `better-writing`
43
+
44
+ Les deux juges regardent des mots, et la confusion serait facile.
45
+
46
+ - **Ici, les TERMES et les COMPOSANTS** : le même objet nommé « projet » ici et « espace » là, deux boutons pour la même action, deux formats de date. Une question d'identité — deux choses désignées de deux façons.
47
+ - **Là-bas, le TON et la VOIX** : comment le produit s'adresse aux gens, sur quel registre, avec quelle chaleur dans l'échec. Une question de manière — la même chose dite de deux façons.
48
+
49
+ Un même écran peut relever des deux, et ce n'est pas un chevauchement. Le test qui tranche : qu'est-ce qui changerait en corrigeant ? Un mot remplacé partout, c'est ici. Une phrase réécrite, c'est là-bas.
50
+
51
+ **Ce qui n'est PAS de ce skill** : le tutoiement qui devient vouvoiement, un message d'erreur qui culpabilise, un registre qui glisse d'un écran à l'autre. Ces constats appartiennent à `better-writing`, qui les juge contre la charte de voix déclarée par le produit — une charte que ce skill-ci n'a pas à lire.
52
+
42
53
  ## Séquence d'analyse obligatoire
43
54
 
44
55
  1. **Définir l'échantillon.** Routes, écrans, composants, périodes et plateformes comparés.
@@ -60,6 +60,66 @@ Labels, CTA, onboarding, empty states, erreurs, notifications, formulaires ou te
60
60
  - **Utiliser le même terme pour la même chose.** Créer un mini-glossaire lorsque plusieurs écrans divergent.
61
61
  - **Ne pas cacher les conséquences.** Les actions irréversibles, paiements, permissions et publications doivent être explicites.
62
62
 
63
+ ## La voix du produit — la dimension qui ne s'active pas toute seule
64
+
65
+ Cette grille juge la copie contre des règles générales : clarté, erreurs utiles, terminologie. Elle gagne ici une seconde dimension, qui juge la copie contre **la voix propre du produit** — et celle-ci ne s'exprime qu'à une condition, non négociable.
66
+
67
+ > **Pas de charte confirmée, pas de jugement de voix.**
68
+
69
+ La charte vit sur la fiche du produit. Elle porte six choses : le tutoiement ou le vouvoiement, le registre, les mots maison, les mots bannis, la façon de dire les erreurs, et les emojis.
70
+
71
+ **Quand elle est absente**, la grille générique s'applique seule et le rapport le dit, une fois, sans insister : *« Déclare ta voix sur ta fiche, et je vérifierai que tes écrans la tiennent. »* Aucun constat de voix, aucune insinuation. Une voix qu'on n'a pas déclarée n'est pas une voix qu'on tient mal.
72
+
73
+ **Quand elle est seulement PROPOSÉE** — déduite d'un échantillon d'écrans, pas encore confirmée — elle ne juge rien non plus. Une proposition se montre, elle ne s'applique pas.
74
+
75
+ ### LE GARDE-FOU, et c'est celui qui compte le plus ici
76
+
77
+ > **La charte est celle de l'utilisateur, jamais la tienne.**
78
+
79
+ Un produit qui choisit le vouvoiement, un registre corporate et des emojis partout **a le droit**. Tu vérifies la TENUE, pas le goût. Un constat qui reprocherait le vouvoiement à un produit dont la charte dit « vous » n'est pas un constat sévère : c'est un contresens, et c'est la faute la plus grave possible sur cette dimension.
80
+
81
+ Corollaire : tu ne proposes jamais de changer la charte. Si elle te paraît étrange, elle appartient quand même à quelqu'un qui l'a écrite.
82
+
83
+ ### Ce qu'un constat de voix doit porter
84
+
85
+ Deux choses ensemble, sans quoi il ne s'écrit pas : **la règle de la charte violée**, et **la phrase exacte** qui la viole, avec sa localisation.
86
+
87
+ | Règle violée | Constat |
88
+ |---|---|
89
+ | Adresse | « Ta charte tutoie ; cet écran vouvoie — *"Veuillez réessayer"*, écran de connexion. » |
90
+ | Mots bannis | « *"Utilisateur"* est dans tes mots bannis ; il apparaît 3 fois — page Compte, page Équipe, message d'erreur du formulaire. » |
91
+ | Mots maison | « Tu appelles ça un *dossier* ; cet écran dit *"projet"* — tableau de bord, en-tête. » |
92
+ | Ton des erreurs | « Ta charte dit rassurer ; ce message culpabilise — *"Vous avez fait une erreur"*, formulaire d'inscription. » |
93
+ | Emojis | « Ta charte les exclut ; il y en a deux — bandeau de bienvenue. » |
94
+
95
+ Une occurrence sans localisation n'est pas citable, donc pas un constat. Un compte sans les endroits qui le produisent non plus.
96
+
97
+ ### La cohérence de voix, même sans règle violée
98
+
99
+ Deux registres qui coexistent dans un même produit sont un constat **même si la charte n'interdit ni l'un ni l'autre**. Un accueil chaleureux et des messages d'erreur techniques ne se contredisent pas ligne à ligne : ils se contredisent d'un écran à l'autre, et c'est ce que personne ne voit en relisant un écran à la fois.
100
+
101
+ Ce constat cite au moins **deux endroits**, un de chaque registre. Sans les deux, il n'y a rien à comparer.
102
+
103
+ ### LA FRONTIÈRE AVEC `better-consistency`, à ne pas franchir
104
+
105
+ Les deux juges regardent des mots, et c'est là que la confusion serait facile.
106
+
107
+ - **`better-consistency` juge les TERMES et les COMPOSANTS** : le même objet nommé « projet » ici et « espace » là, deux boutons pour la même action, deux formats de date. C'est une question d'identité — deux choses désignées de deux façons.
108
+ - **`better-writing` juge le TON et la VOIX** : comment on s'adresse, sur quel registre, avec quelle chaleur dans l'échec. C'est une question de manière — la même chose dite de deux façons.
109
+
110
+ Un même écran peut relever des deux, et ce n'est pas un chevauchement : « projet » vs « espace » est un problème de terme ; « Veuillez patienter » vs « Une seconde ! » est un problème de ton. Si tu hésites, demande-toi ce qui changerait en corrigeant : un mot remplacé partout, ou une phrase réécrite.
111
+
112
+ ### Sévérité sur cette dimension
113
+
114
+ | Sévérité | Sur la voix |
115
+ |---|---|
116
+ | **Critique** | La voix se contredit sur le parcours principal — accueil et paiement ne parlent pas au même public. Un mot banni apparaît dans un message que tout le monde voit. |
117
+ | **Majeur** | L'adresse change d'un écran à l'autre. Le ton des erreurs contredit la charte là où l'échec est fréquent. Un mot maison remplacé par un synonyme dans un écran central. |
118
+ | **Mineur** | Une violation isolée sur un écran secondaire — mentions légales, page d'aide rarement ouverte. |
119
+ | **Note** | Une formulation qui tient la charte mais s'en éloigne, sans que rien ne soit faux. |
120
+
121
+ La règle de la dernière hésitation s'applique : entre deux niveaux, prends le plus bas et écris l'hésitation dans la confiance.
122
+
63
123
  ## Patrons de microcopy
64
124
 
65
125
  | Situation | Structure recommandée | À éviter |
@@ -87,5 +87,120 @@
87
87
  "should_refuse": true,
88
88
  "note": "Sans emplacement ni action attendue, réécrire est deviner. Le skill doit demander le contexte d'affichage."
89
89
  }
90
+ },
91
+ {
92
+ "id": "writing-conformant-voix-corporate-tenue",
93
+ "skill": "better-writing",
94
+ "kind": "conformant",
95
+ "delivery_mode": "classique",
96
+ "artifact": "CHARTE DE VOIX DÉCLARÉE PAR LE PRODUIT (confirmée sur la fiche)\n- Adresse : le produit dit « vous ». Toute phrase qui emploie l'autre forme est une violation.\n- Registre : technique — on nomme les choses précisément. Un écran qui bascule dans un autre registre est une violation, même si la phrase est bonne.\n- Messages d'erreur : on dit ce qui s'est passé, puis la suite, sans détour. Un message qui culpabilise est une violation dans les deux cas.\n- Emojis : autorisés.\n- Mots maison — c'est ainsi que CE produit nomme ses objets : dossier, collaborateur, mandat. Employer un synonyme à la place est une violation.\n- Mots bannis, jamais à l'écran : utilisateur, plateforme. Chaque occurrence est une violation, avec sa localisation.\n\nÉCRANS RELEVÉS (lecture complète du HTML servi, 6 pages)\n\n/connexion\n Titre : « Accès à votre espace de travail »\n Champ : « Adresse e-mail professionnelle »\n Bouton : « Se connecter »\n Erreur : « Ce mot de passe ne correspond pas à cette adresse. Réinitialisez-le ou contactez votre administrateur. »\n\n/dossiers\n Titre : « Vos dossiers »\n Vide : « Aucun dossier pour le moment. Créez-en un pour commencer à travailler. »\n Bouton : « Nouveau dossier »\n\n/dossiers/equipe\n Titre : « Collaborateurs du dossier »\n Sous-titre : « Les personnes autorisées à consulter et modifier ce dossier. »\n Bouton : « Inviter un collaborateur »\n\n/mandats\n Titre : « Mandats en cours »\n Colonne : « Échéance » · « Responsable » · « Statut »\n Vide : « Aucun mandat actif. Les mandats clôturés restent consultables dans les archives. »\n\n/facturation\n Titre : « Facturation du dossier »\n Erreur : « Le paiement a été refusé par votre banque. Vérifiez les informations de votre carte, puis réessayez. »\n\n/aide\n Titre : « Centre d'aide »\n Texte : « Consultez la documentation ou écrivez à notre équipe support. » 📄",
97
+ "golden": {
98
+ "expected_findings": [],
99
+ "forbidden_findings": [
100
+ "le vouvoiement met de la distance avec la personne qui lit",
101
+ "conseiller de tutoyer pour un ton plus proche et plus moderne",
102
+ "le registre technique rend les écrans froids et peu accueillants",
103
+ "un emoji dans le centre d'aide détonne avec le reste du produit",
104
+ "les messages d'erreur manquent de chaleur et de réassurance"
105
+ ],
106
+ "expected_verdict": "PASS",
107
+ "should_refuse": false,
108
+ "note": "LE PIÈGE DU GOÛT, et c'est le cas le plus important de cette extension. Le produit a déclaré une voix corporate — vouvoiement, registre technique, erreurs directes, emojis autorisés — et il la tient partout : six écrans, aucune adresse qui glisse, aucun mot banni, les trois mots maison employés exactement là où ils doivent l'être. L'emoji du centre d'aide est AUTORISÉ par la charte. Un juge qui préférerait le tutoiement et le ferait savoir commettrait un contresens, pas une sévérité : il remplacerait le projet de quelqu'un par le sien. Les cinq interdits sont exactement les cinq façons de céder à ce réflexe. La bonne réponse est PASS et le silence."
109
+ }
110
+ },
111
+ {
112
+ "id": "writing-obvious-voix-adresse-qui-glisse",
113
+ "skill": "better-writing",
114
+ "kind": "obvious-defect",
115
+ "delivery_mode": "ai-builder",
116
+ "artifact": "CHARTE DE VOIX DÉCLARÉE PAR LE PRODUIT (confirmée sur la fiche)\n- Adresse : le produit dit « tu ». Toute phrase qui emploie l'autre forme est une violation.\n- Registre : chaleureux — on est à côté de la personne. Un écran qui bascule dans un autre registre est une violation, même si la phrase est bonne.\n- Messages d'erreur : on rassure avant de dire quoi faire. Un message qui culpabilise est une violation dans les deux cas.\n- Emojis : jamais.\n- Mots maison : carnet, note.\n- Mots bannis, jamais à l'écran : utilisateur, contenu.\n\nÉCRANS RELEVÉS (lecture complète du HTML servi, 5 pages)\n\n/accueil\n Titre : « Bienvenue dans ton carnet »\n Texte : « Retrouve ici toutes tes notes, où que tu sois. »\n Bouton : « Ouvrir mon carnet »\n\n/notes/nouvelle\n Titre : « Veuillez saisir le titre de votre note »\n Champ : « Titre »\n Aide : « Vous pourrez le modifier ultérieurement. »\n Bouton : « Enregistrer »\n\n/parametres\n Titre : « Vos préférences »\n Texte : « Veuillez sélectionner la langue d'affichage de votre interface. »\n Bouton : « Valider »\n\n/partage\n Titre : « Partager ta note »\n Texte : « Choisis avec qui tu partages ce contenu. »\n Bouton : « Créer le lien »\n\n/erreur-500\n Titre : « Une erreur est survenue »\n Texte : « Vous avez effectué une action non autorisée. Veuillez réessayer plus tard. »",
117
+ "golden": {
118
+ "expected_findings": [
119
+ "la charte tutoie mais trois écrans vouvoient",
120
+ "l'écran de nouvelle note dit vous alors que l'accueil dit tu",
121
+ "les préférences vouvoient d'un bout à l'autre",
122
+ "le message d'erreur vouvoie et rejette la faute sur la personne",
123
+ "le mot contenu est banni par la charte et apparaît sur l'écran de partage"
124
+ ],
125
+ "forbidden_findings": [
126
+ "conseiller de choisir le vouvoiement pour l'ensemble du produit",
127
+ "le tutoiement n'est pas adapté à un produit professionnel",
128
+ "les titres des écrans ne suivent pas la même hiérarchie visuelle",
129
+ "revoir la mise en page des écrans de paramètres",
130
+ "le terme note est employé de deux façons différentes"
131
+ ],
132
+ "expected_verdict": "FAIL",
133
+ "should_refuse": false,
134
+ "note": "La violation la plus visible, et la plus fréquente en pratique : un produit généré où la moitié des écrans a gardé le vouvoiement par défaut. Trois écrans sur cinq, dont un message d'erreur qui cumule deux violations — le vouvoiement ET la culpabilisation, que la charte refuse dans les deux tons. « contenu » est dans les mots bannis. Les interdits couvrent le contresens du goût (conseiller l'inverse de la charte), l'avis sur le choix lui-même, et deux dérives hors axe — la mise en page, et un constat de TERME qui appartient à better-consistency."
135
+ }
136
+ },
137
+ {
138
+ "id": "writing-subtle-voix-qui-lache-sous-stress",
139
+ "skill": "better-writing",
140
+ "kind": "subtle-defect",
141
+ "delivery_mode": "hybride",
142
+ "artifact": "CHARTE DE VOIX DÉCLARÉE PAR LE PRODUIT (confirmée sur la fiche)\n- Adresse : le produit dit « tu ». Toute phrase qui emploie l'autre forme est une violation.\n- Registre : chaleureux — on est à côté de la personne. Un écran qui bascule dans un autre registre est une violation, même si la phrase est bonne.\n- Messages d'erreur : on rassure avant de dire quoi faire. Un message qui culpabilise est une violation dans les deux cas.\n- Emojis : jamais.\n- Mots maison : carnet, note.\n- Mots bannis, jamais à l'écran : utilisateur, contenu.\n\nÉCRANS RELEVÉS (lecture complète du HTML servi, 7 pages)\n\n/accueil\n Titre : « Ton carnet t'attend »\n Texte : « Reprends là où tu t'es arrêté. »\n\n/notes\n Titre : « Tes notes »\n Vide : « Rien ici pour l'instant. Crée ta première note, ça prend dix secondes. »\n\n/notes/nouvelle\n Titre : « Nouvelle note »\n Aide : « Donne-lui un titre, tu pourras le changer après. »\n\n/partage\n Titre : « Partage ta note »\n Texte : « Choisis qui peut la lire. Tu peux retirer l'accès quand tu veux. »\n\n/parametres\n Titre : « Tes préférences »\n Texte : « Choisis ta langue et le thème qui te va. »\n\nMESSAGES D'ERREUR (relevés dans le même HTML)\n Formulaire de note : « Échec de la validation du formulaire : le champ titre est requis. »\n Import : « Erreur 422 — le fichier fourni ne satisfait pas au format attendu. »\n Partage : « Opération impossible : quota de liens de partage atteint pour la période courante. »\n Connexion : « Authentification échouée. »",
143
+ "golden": {
144
+ "expected_findings": [
145
+ "la voix tient partout sauf dans les messages d'erreur",
146
+ "les messages d'échec basculent dans un registre technique que la charte n'emploie nulle part ailleurs",
147
+ "aucun message d'erreur ne rassure ni ne dit quoi faire ensuite"
148
+ ],
149
+ "forbidden_findings": [
150
+ "le ton chaleureux du produit manque de sérieux",
151
+ "conseiller un registre plus neutre sur l'ensemble des écrans",
152
+ "les écrans principaux emploient un tutoiement inconstant",
153
+ "revoir la hiérarchie des titres sur les écrans de note",
154
+ "le mot note désigne deux objets différents selon les écrans"
155
+ ],
156
+ "expected_verdict": "PASS WITH FIXES",
157
+ "should_refuse": false,
158
+ "note": "LE REGISTRE QUI GLISSE SOUS STRESS. Cinq écrans impeccables — tutoiement, chaleur, phrases courtes, aucun mot banni. Un juge qui relit écran par écran coche tout et s'arrête. La bascule ne se voit qu'en rassemblant les quatre messages d'erreur : « Échec de la validation », « Erreur 422 », « quota atteint pour la période courante », « Authentification échouée » — un autre produit parle. C'est le cas typique où le code d'erreur remonte tel quel du serveur et où personne ne l'a jamais relu à côté du reste. Aucune règle précise de la charte n'est violée mot à mot sur trois de ces messages : c'est la COHÉRENCE de voix qui l'est, et elle se constate en citant les deux registres. Le quatrième viole en plus le ton d'erreur déclaré."
159
+ }
160
+ },
161
+ {
162
+ "id": "writing-out-of-scope-voix-et-mise-en-page",
163
+ "skill": "better-writing",
164
+ "kind": "out-of-scope",
165
+ "delivery_mode": "classique",
166
+ "artifact": "CHARTE DE VOIX DÉCLARÉE PAR LE PRODUIT (confirmée sur la fiche)\n- Adresse : le produit dit « tu ». Toute phrase qui emploie l'autre forme est une violation.\n- Registre : chaleureux — on est à côté de la personne. Un écran qui bascule dans un autre registre est une violation, même si la phrase est bonne.\n- Messages d'erreur : on rassure avant de dire quoi faire. Un message qui culpabilise est une violation dans les deux cas.\n- Emojis : jamais.\n- Mots maison : carnet, note.\n- Mots bannis, jamais à l'écran : utilisateur, contenu.\n\nÉCRANS RELEVÉS (lecture complète du HTML servi, 3 pages)\n\n/accueil\n Titre : « Ton carnet »\n Texte : « Tout ce que tu écris, au même endroit. »\n Bouton : « Ouvrir »\n\n/notes\n Titre : « Tes notes »\n Vide : « Rien pour l'instant. Crée ta première note quand tu veux. »\n\n/note/123\n Titre : « Réunion du 12 mars »\n Texte : « Modifié il y a deux heures. »\n Bouton : « Enregistrer »\n\nCE QUE LA LECTURE A AUSSI RELEVÉ (hors du texte)\n - Les trois écrans emploient quatre tailles de titre différentes : 32, 28, 26 et 24 pixels.\n - Le bouton principal est aligné à gauche sur /accueil et à droite sur /note/123.\n - Les marges entre les blocs varient de 16 à 40 pixels sans logique apparente.\n - Deux composants de bouton coexistent dans le HTML, avec des classes différentes.",
167
+ "golden": {
168
+ "expected_findings": [],
169
+ "forbidden_findings": [
170
+ "quatre tailles de titre coexistent sans échelle typographique",
171
+ "le bouton principal change de côté d'un écran à l'autre",
172
+ "les marges entre les blocs varient sans logique apparente",
173
+ "deux composants de bouton coexistent dans le produit",
174
+ "conseiller de revoir la mise en page avant de travailler les textes"
175
+ ],
176
+ "expected_verdict": "PASS",
177
+ "should_refuse": false,
178
+ "note": "TOUT CE QUI EST VRAI N'EST PAS DE CE JUGE. Les quatre observations hors texte sont exactes et importantes — et pas une seule ne relève de la copie ni de la voix. Les tailles de titre et les marges sont à better-layout ; les deux composants de bouton sont à better-components, ou à better-consistency si c'est leur libellé qui diverge. La voix, elle, tient : trois écrans, tutoiement partout, chaleur constante, aucun mot banni. La bonne réponse est PASS. Le cinquième interdit est le plus tentant de tous — il ne rapporte pas le défaut, il conseille de s'en occuper d'abord, ce qui revient à sortir de son axe par la porte du conseil."
179
+ }
180
+ },
181
+ {
182
+ "id": "writing-obvious-sans-charte-la-voix-se-tait",
183
+ "skill": "better-writing",
184
+ "kind": "obvious-defect",
185
+ "delivery_mode": "ai-builder",
186
+ "artifact": "AUCUNE CHARTE DE VOIX N'EST DÉCLARÉE POUR CE PRODUIT.\n\nLa fiche ne porte pas de voix confirmée. Une voix a été DÉDUITE d'un échantillon d'écrans et proposée, mais elle n'a pas été validée : elle ne fait donc pas foi.\n\nVOIX DÉDUITE, NON CONFIRMÉE (pour information seulement)\n- Adresse dominante observée : « vous » (7 écrans sur 9)\n- Registre dominant : sobre\n\nÉCRANS RELEVÉS (lecture complète du HTML servi, 4 pages)\n\n/connexion\n Titre : « Connexion »\n Champ : « E-mail »\n Bouton : « Envoyer »\n Erreur : « Erreur »\n\n/inscription\n Titre : « Créer un compte »\n Champ : « E-mail » · « Mot de passe »\n Aide : (aucune)\n Bouton : « Soumettre »\n\n/tableau-de-bord\n Titre : « Tableau de bord »\n Vide : (aucun texte)\n\n/parametres\n Titre : « Paramètres »\n Bouton : « Valider »",
187
+ "golden": {
188
+ "expected_findings": [
189
+ "le message d'erreur de la connexion dit seulement erreur, sans ce qui s'est passé ni quoi faire",
190
+ "le bouton soumettre ne dit pas ce qui va se passer",
191
+ "le champ mot de passe n'indique aucune contrainte de format",
192
+ "le tableau de bord vide n'explique pas ce qui apparaîtra"
193
+ ],
194
+ "forbidden_findings": [
195
+ "le produit vouvoie sur sept écrans et tutoie sur les deux autres",
196
+ "la voix déduite montre un registre sobre mal tenu",
197
+ "l'adresse employée manque de constance dans l'ensemble du produit",
198
+ "conseiller de choisir entre le tutoiement et le vouvoiement",
199
+ "le registre du produit ne correspond pas à son public"
200
+ ],
201
+ "expected_verdict": "PASS WITH FIXES",
202
+ "should_refuse": false,
203
+ "note": "LA DIMENSION VOIX SE TAIT, LA GRILLE GÉNÉRIQUE PARLE. Ce cas n'est PAS un `insufficient` — le contrôleur de goldens me l'a fait remarquer, et il avait raison : le skill ne refuse pas, il répond. C'est UNE DIMENSION qui se tait, pendant que l'autre travaille normalement, et le vocabulaire du banc n'a pas de nom pour ça. Le kind teste donc la détection générique ; ce sont les phrases interdites qui testent le silence de la voix.\n\nUne voix a été déduite et proposée — elle n'a pas été confirmée, donc elle ne juge rien. Le piège est double et les deux moitiés sont tentantes : employer la voix déduite comme si elle faisait foi (les cinq interdits le font, sous cinq formes), ou se taire complètement au motif qu'il n'y a pas de charte. Ni l'un ni l'autre. Les quatre constats attendus relèvent tous de la grille générique — un message d'erreur qui dit « Erreur », un bouton « Soumettre », un champ sans contrainte annoncée, un écran vide muet — et aucun ne suppose de savoir comment ce produit veut parler. Le rapport invite à déclarer la voix ; il ne la devine pas."
204
+ }
90
205
  }
91
206
  ]
@@ -40,6 +40,8 @@ Sans cette distinction, le skill condamne tout ce qu'on lui montre, et devient i
40
40
  Deux corollaires, tout aussi fermes :
41
41
 
42
42
  - **Il ne juge jamais la valeur de l'idée.** « Cette feature n'apporte pas grand-chose » n'est pas un constat de cadrage : c'est une opinion, et personne ne l'a demandée. Une feature modeste peut être parfaitement cadrée.
43
+
44
+ La formule qui tient cette ligne, et qu'il faut employer telle quelle : le skill ne dit pas *« cette feature est bonne »* ou *« mauvaise »*. Il dit **« ton dossier est solide »**, ou **« ton dossier repose sur N croyances non vérifiées, les voici »** — et il cite chacune, mot pour mot, en preuve. Une croyance nommée est discutable ; un jugement de valeur ne l'est pas.
43
45
  - **Il ne propose pas la feature à la place de celui qui l'écrit.** Un constat dit ce qui manque pour décider. Il ne réécrit pas l'objectif.
44
46
 
45
47
  ## Déclenchement
@@ -55,6 +57,9 @@ Avant d'engager du travail sur une feature, quand une décision se prend « au f
55
57
  | Invariant | Ce qu'il faut prouver | Ce qui le prouve |
56
58
  |---|---|---|
57
59
  | **Problème testable** | Le problème est formulé de façon **falsifiable** : on peut imaginer une observation qui le contredirait. | Une phrase qui dit qui bute sur quoi, où, et à quelle fréquence. Pas une intention (« améliorer l'onboarding »), pas une solution déguisée en problème (« il manque un tutoriel »). |
60
+ | **Preuve du problème** | Le problème s'appuie sur quelque chose d'**observé**, pas sur une conviction. | Des retours réels, des données, des tickets, des entretiens — avec leur nombre et leur période. « Je pense que », « on sent que », « c'est évident » ne sont pas des preuves, et le skill le dit en citant la phrase. |
61
+ | **Pour qui, précisément** | La population concernée est **nommable et bornée**. | « Les comptes créés depuis moins de sept jours », « les équipes de plus de dix personnes ». « Les utilisateurs » n'est pas une réponse recevable : elle rend le problème invérifiable et le critère de succès incalculable. |
62
+ | **Hypothèse la plus risquée** | Celle qui **tue la feature si elle est fausse** est identifiée. | Une croyance nommée, et ce qui la vérifierait. Un dossier qui n'en a aucune n'est pas sans risque : il n'a pas cherché. |
58
63
  | **Critère de succès observable** | Ce qui compterait comme une réussite est **écrit, chiffré et daté**, avant de commencer. | « X passe de A à B d'ici telle date ». Un critère posé après coup n'en est pas un : il se moule sur le résultat obtenu. |
59
64
  | **Parcours complet** | Le chemin va du **déclencheur** à la **post-condition**, erreurs comprises. | Ce qui déclenche, ce que la personne fait, ce qu'elle voit, ce qui se passe quand ça échoue, et dans quel état on la laisse. |
60
65
  | **On saura après coup** | Les **événements à mesurer** existent, et ils mesurent le critère de succès — pas la présence. | Le nom des événements, ce qu'ils portent, et le lien explicite avec le critère. Compter les ouvertures d'un écran ne dit pas si la tâche a réussi. |
@@ -65,11 +70,12 @@ Avant d'engager du travail sur une feature, quand une décision se prend « au f
65
70
 
66
71
  1. **Lire le dossier en entier** avant de juger quoi que ce soit. Un critère de succès se trouve parfois trois paragraphes plus loin, formulé autrement.
67
72
  2. **Repérer le problème** et le tester : *quelle observation le contredirait ?* Si aucune, c'est une intention.
68
- 3. **Chercher le critère de succès**, puis vérifier qu'il est **antérieur** à la décision et non calqué sur ce qu'on espère.
69
- 4. **Dérouler le parcours** de bout en bout, et s'arrêter à chaque endroit où le dossier ne dit pas ce qui se passe.
70
- 5. **Confronter la mesure au critère** : chaque critère a-t-il de quoi être observé ? Un critère sans mesure est le défaut le plus fréquent, et le plus discret.
71
- 6. **Chercher l'irréversible**, y compris ce qui n'est pas technique : une promesse publique ne se retire pas plus qu'une migration.
72
- 7. **Écrire le périmètre** : ce qui a été lu, et ce qui n'a pas été fourni. Sans cette ligne, aucune conclusion négative n'est recevable.
73
+ 3. **Chercher sur quoi il s'appuie** : combien de retours, sur quelle période, auprès de qui. Une conviction se cite mot pour mot et devient une croyance à vérifier, pas un constat sur l'idée.
74
+ 4. **Chercher le critère de succès**, puis vérifier qu'il est **antérieur** à la décision et non calqué sur ce qu'on espère.
75
+ 5. **Dérouler le parcours** de bout en bout, et s'arrêter à chaque endroit où le dossier ne dit pas ce qui se passe.
76
+ 6. **Confronter la mesure au critère** : chaque critère a-t-il de quoi être observé ? Un critère sans mesure est le défaut le plus fréquent, et le plus discret.
77
+ 7. **Chercher l'irréversible**, y compris ce qui n'est pas technique : une promesse publique ne se retire pas plus qu'une migration.
78
+ 8. **Écrire le périmètre** : ce qui a été lu, et ce qui n'a pas été fourni. Sans cette ligne, aucune conclusion négative n'est recevable.
73
79
 
74
80
  ## La règle de l'absence
75
81
 
@@ -91,7 +97,8 @@ Le verdict se **déduit** des sévérités, il ne se décide pas.
91
97
  |---|---|
92
98
  | **Bloquant** | Un risque irréversible non nommé — migration destructive, promesse publique, changement de prix. On engage quelque chose qu'on ne pourra pas défaire, sans que personne l'ait écrit. |
93
99
  | **Critique** | Aucun critère de succès, ou un critère inobservable. On ne saura jamais si on a eu raison, et la décision suivante se prendra sur la même absence. |
94
- | **Majeur** | Un critère existe mais rien ne le mesure. Le problème est formulé comme une intention. Le parcours s'arrête avant les erreurs. |
100
+ | **Majeur** | Un critère existe mais rien ne le mesure. Le problème est formulé comme une intention. Le parcours s'arrête avant les erreurs. Le problème ne s'appuie sur aucune observation — seulement sur une conviction. La population visée n'est pas bornée : « les utilisateurs ». |
101
+ | **Majeur (bis)** | Aucune hypothèse risquée n'est identifiée. Ce n'est pas l'absence de risque, c'est l'absence de recherche — et elle se corrige en une conversation, d'où majeur et non critique. |
95
102
  | **Mineur** | Le coût d'annulation est évoqué sans être chiffré. Un événement de mesure est nommé sans ce qu'il porte. |
96
103
  | **Note** | Une inconnue assumée, avec sa condition de réévaluation. |
97
104
 
@@ -137,6 +144,10 @@ Dans ce cas, la sortie contient :
137
144
  - Confondre un problème et l'absence d'une solution.
138
145
  - Réécrire l'objectif de la feature à la place de celui qui l'a écrit.
139
146
  - Condamner une feature modeste pour sa modestie.
147
+ - Dire qu'une feature est bonne ou mauvaise, au lieu de compter les croyances sur lesquelles elle repose.
148
+ - Accepter « je pense que » ou « c'est évident » comme preuve d'un problème.
149
+ - Accepter « les utilisateurs » comme réponse à « pour qui ».
150
+ - Nommer une hypothèse risquée à la place de celui qui écrit le dossier.
140
151
  - Cartographier ce que la feature touche dans le code : ce n'est pas cet axe.
141
152
 
142
153
  ## Contrat de sortie exact
@@ -149,9 +160,10 @@ La sortie contient, dans cet ordre :
149
160
 
150
161
  1. **Le périmètre lu** — ce qui a été reçu, ce qui ne l'a pas été.
151
162
  2. **La grille**, invariant par invariant : établi, manquant, ou hors périmètre.
152
- 3. **Les constats**, au schéma commun, triés par sévérité.
153
- 4. **Le verdict**, déduit des sévérités.
154
- 5. **Les questions ouvertes** — ce qui reste à savoir, formulé comme des questions qu'on peut poser à quelqu'un.
163
+ 3. **Les croyances non vérifiées**, s'il y en a — chacune citée mot pour mot depuis le dossier, avec ce qui la vérifierait. C'est la seule forme sous laquelle ce skill parle de la valeur d'une idée : il compte ce sur quoi elle repose sans preuve, et laisse quelqu'un d'autre décider.
164
+ 4. **Les constats**, au schéma commun, triés par sévérité.
165
+ 5. **Le verdict**, déduit des sévérités.
166
+ 6. **Les questions ouvertes** — ce qui reste à savoir, formulé comme des questions qu'on peut poser à quelqu'un.
155
167
 
156
168
  ## Critères de qualité du skill
157
169
 
@@ -87,6 +87,31 @@
87
87
  "note": "LE DÉFAUT NE SE VOIT QU'EN CROISANT DEUX SECTIONS. Le dossier est excellent partout : problème chiffré et instruit, critère antérieur, daté, observable, parcours complet jusqu'aux échecs, rien d'irréversible, retour arrière établi. Et le plan de mesure est riche — cinq événements, ce qui donne l'impression d'un dossier instrumenté. Aucun ne permet de calculer un ABANDON : il faudrait savoir qui quitte l'étape sans la terminer, et rien ne marque la sortie. Un juge qui vérifie « y a-t-il un critère ? » puis « y a-t-il une mesure ? » séparément coche les deux cases et passe à côté. C'est pourquoi la séquence impose de les confronter. Le constat est unique, majeur, et ne remet pas en cause la décision : PASS WITH FIXES."
88
88
  }
89
89
  },
90
+ {
91
+ "id": "cadre-subtle-dossier-de-croyances",
92
+ "skill": "review-feature-framing",
93
+ "kind": "subtle-defect",
94
+ "delivery_mode": "classique",
95
+ "artifact": "DOSSIER REÇU EN ENTIER — docs/features/mode-focus.md\n\nPROBLÈME\nLes utilisateurs sont distraits par l'interface quand ils rédigent un rapport.\nC'est évident dès qu'on regarde l'écran : il y a le rail à gauche, le fil\nd'activité à droite, et les notifications qui arrivent par-dessus. Je pense\nqu'on perd beaucoup de monde à cette étape.\n\nPOUR QUI\nLes utilisateurs qui rédigent des rapports.\n\nCE QU'ON ATTEND\nD'ici le 31 mars 2027 : le taux de rapports terminés une fois commencés passe\nde 54 % à 70 %.\n\nPARCOURS\nDéclencheur : la personne ouvre l'éditeur de rapport et active « Mode focus ».\nLe rail, le fil d'activité et les notifications disparaissent.\nElle rédige. Elle ressort par Échap ou par le bouton en haut à droite.\nSi elle quitte l'onglet, le mode reste actif à son retour.\nÉchec d'enregistrement : bandeau qui le dit, le texte reste à l'écran, elle peut\nréessayer sans rien perdre.\nPost-condition : rapport enregistré, mode désactivé.\n\nMESURE\nÉvénements déjà en place et suffisants :\n rapport_commence { rapport_id }\n rapport_termine { rapport_id }\n mode_focus_active { rapport_id }\nLe taux du critère se calcule sur les deux premiers, qui existent depuis un an.\n\nCE QU'ON NE POURRA PAS DÉFAIRE\nRien. Aucune migration, aucun engagement public, aucun changement de prix.\n\nSI ON REVIENT EN ARRIÈRE\nOn retire le bouton. Les personnes qui l'avaient activé retrouvent l'écran\nnormal. Rien à prévenir, rien à migrer.",
96
+ "golden": {
97
+ "expected_findings": [
98
+ "le problème repose sur une conviction et non sur quelque chose d'observé",
99
+ "la population concernée n'est pas bornée, on ne saura pas sur qui mesurer",
100
+ "aucune hypothèse risquée n'est identifiée dans le dossier"
101
+ ],
102
+ "forbidden_findings": [
103
+ "le mode focus ne réduira pas les abandons de rédaction",
104
+ "cacher le fil d'activité dégradera l'expérience des équipes",
105
+ "cette fonctionnalité n'a pas assez de valeur pour être construite",
106
+ "aucun critère de succès chiffré n'est posé dans ce dossier",
107
+ "les événements de mesure sont absents du plan",
108
+ "conseiller de mener des entretiens avant de continuer"
109
+ ],
110
+ "expected_verdict": "PASS WITH FIXES",
111
+ "should_refuse": false,
112
+ "note": "LE DOSSIER QUI A L'AIR SOLIDE ET REPOSE SUR DES CROYANCES. Quatre invariants sur sept sont impeccables : critère chiffré, daté, antérieur ; parcours complet jusqu'aux échecs ; mesure déjà en place et qui porte le critère ; rien d'irréversible et retour arrière établi. Un juge qui déroule la grille dans l'ordre coche tout et s'arrête. Ce qui manque est en tête du dossier et se lit sans effort une fois qu'on le cherche : « c'est évident », « je pense qu'on perd beaucoup de monde » — deux convictions, zéro observation ; « les utilisateurs qui rédigent des rapports » — une population non bornée, sur laquelle le taux de 54 % ne peut pas se calculer honnêtement ; et aucune hypothèse risquée, alors que la feature entière repose sur celle-ci : que la distraction soit bien la cause des abandons. Le skill NOMME les croyances en les citant, il ne dit pas que l'idée est mauvaise. Trois majeurs, aucun bloquant : PASS WITH FIXES. Les six interdits couvrent les deux dérives symétriques — prédire l'effet, juger la valeur — et les trois faux constats qu'un juge pressé produirait en confondant « problème mal étayé » avec « critère absent »."
113
+ }
114
+ },
90
115
  {
91
116
  "id": "cadre-out-of-scope-dette-et-code",
92
117
  "skill": "review-feature-framing",