@mostajs/kind-catalog 0.3.0 → 0.4.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/CHANGELOG.md CHANGED
@@ -2,6 +2,78 @@
2
2
 
3
3
  **Auteur** : Dr Hamid MADANI <drmdh@msn.com>
4
4
 
5
+ ## 0.4.0 — 2026-09-06
6
+
7
+ ### Corrigé — le faux positif des épreuves rétrospectives, en trois temps
8
+
9
+ L'épreuve n° 1 (RestoTrax) a signalé `KIND-SUPPRESSION-DATEE-01` **5 fois sur 5** alors que le plan
10
+ portait la règle explicitement, sous un autre vocabulaire. Trois causes distinctes, toutes dans mon
11
+ propre test de couverture, découvertes en les levant l'une après l'autre :
12
+
13
+ 1. **La couverture se juge sur le `titre` d'une erreur, plus sur sa `consequence`.** La conséquence
14
+ est **notre** prose : elle explique le coût à qui lit la fiche, et un plan n'a aucune raison de
15
+ la contenir. L'inclure rendait une erreur d'autant plus « non couverte » qu'elle était **bien
16
+ expliquée**, et une exigence courte mais explicite ne pouvait **jamais** couvrir une erreur
17
+ verbeuse. Seuil de reconnaissance : `Math.min(2, nombre de mots du titre)`.
18
+ 2. **Les `synonymes` d'une fiche sont des RADICAUX, rapprochés par préfixe.** Écrits en mots
19
+ entiers, ils demandaient d'énumérer toutes les flexions du français — `supprimer`, `supprime`,
20
+ `supprimée`, `supprimées`… — liste qu'on croit finie et qui ne l'est jamais : la première version
21
+ tenait neuf mots pour un seul groupe et laissait passer `supprimée`. Un radical de **quatre
22
+ lettres au moins** ; plus court, il cesse de désigner (`dat` attraperait `dattes`).
23
+ 3. **Les mots-clés sont retenus à partir de QUATRE lettres**, et non cinq. `date`, `note`, `vote`,
24
+ `lieu`, `taux` étaient écartés — c'est-à-dire, très souvent, **le mot qui distingue** : « le
25
+ retrait est un simple drapeau, sans **date** » ne retenait que `retrait`, `simple`, `drapeau`, et
26
+ l'exigence qui disait « horodatés » ne pouvait pas la couvrir. Les mots vides de quatre lettres
27
+ sont écartés **nommément**, par la liste `VIDES`, pas par leur longueur.
28
+
29
+ Effet cumulé sur le plan initial de RestoTrax : **35 → 23 erreurs signalées**, la règle en cause
30
+ passant de **5/5 à 1/5**. La seule erreur qui subsiste — « la restauration recrée un objet neuf » —
31
+ n'est **pas** un faux positif : ce plan ne dit rien d'une restauration.
32
+
33
+ Contrôle de non-régression sur le plan initial de LabTrax : total **inchangé à 11**. Le seuil à
34
+ quatre lettres n'a ajouté aucun bruit.
35
+
36
+ ### Ajouté
37
+
38
+ - **`synonymes`** — champ déclaré d'une fiche : des groupes de radicaux qui désignent la même chose
39
+ dans le vocabulaire du domaine. Aucun rapprochement lexical ne peut **deviner** que
40
+ « désactivation » vaut « retrait » : cela se déclare, comme le reste de la fiche. Un groupe d'un
41
+ seul mot est écarté au montage — il ne relie rien. Six groupes posés sur `KIND-SUPPRESSION-DATEE-01`.
42
+ - **`motsCles` et `normaliser`** sont exportés : les décisions de découpage sont désormais
43
+ vérifiables du dehors (`T-KC-26`).
44
+
45
+ ### Éprouvé
46
+
47
+ - `SPEC-KC-10` et cinq essais — `T-KC-22` à `T-KC-26` — gardent chacune des trois décisions ci-dessus,
48
+ **y compris celles qui refusent** : un radical trop court, un groupe d'un seul mot. 37 essais verts.
49
+ - **`docs/EPREUVE-02-LABTRAX-06092026.md`** — deuxième épreuve rétrospective, sur un objet qui en
50
+ valait un : le plan initial de LabTrax comptait **16 exigences**, le plan atteint en compte **49**.
51
+ Résultat : **3 anticipés · 3 divergents · 5 sans objet · 0 contredit**, pour un rappel utile de
52
+ **3 sur 33** et un coût de lecture d'une minute. La double borne écarte **11 fiches sur 21** — et
53
+ six des fiches écartées retombent mot pour mot sur des exigences que LabTrax a dû écrire, ce qui
54
+ démontre que la borne est indispensable : sans elle j'aurais publié 18 % au lieu de 9 %.
55
+ - `docs/EPREUVE-01-RESTOTRAX-06092026.md` reçoit un **addendum** ; ses chiffres d'origine ne sont pas
56
+ réécrits — un rapport d'épreuve qu'on réécrit ne mesure plus rien.
57
+
58
+ ### Contrôle d'avant-publication — deux défauts trouvés, tous deux dans la surface publiée
59
+
60
+ Six contrôles passés avant de publier, dont deux ont mordu :
61
+
62
+ | contrôle | relevé |
63
+ |---|---|
64
+ | **verdicts des 21 fiches** | ✓ **0 injustifié.** Les 14 `eprouve` portent chacune au moins une origine `incident` ou `terrain` ; les 6 `propose` n'ont que des `reference`. `auditCatalogue()` rend une liste vide |
65
+ | **surface publiée éprouvée** | ❌ **6 des 24 exports n'étaient touchés par aucun essai** : `AFFINABLES`, `PLAN_VERSION`, `PROVENANCES`, `blocDeFiche`, `marqueur`, `normaliser`. Une constante exportée est un **contrat** : celui qui construit une fiche la lit pour savoir ce qui est admis, et si elle diverge de ce que le code applique, elle envoie droit dans le mur — c'est exactement le défaut qu'avait `validateKind`, qui déclarait « verdict inconnu » sur un verdict qu'il posait lui-même. Fermé par `SPEC-KC-11` et `T-KC-27`..`T-KC-31` |
66
+ | **`llms.txt` (#6)** | ❌ **`synonymes` n'y était pas déclaré** — un champ neuf que le lecteur-machine ne connaissait pas, alors que c'est précisément le document qui existe pour qu'il le connaisse. `diagnostiquer`, `motsCles` et `normaliser` y manquaient aussi, ainsi que les deux pièges de la couverture. Corrigé |
67
+ | README, poids, binaires exclus | ✓ 103,9 kB, 43 fichiers, aucun PDF ni PNG |
68
+ | correspondance plan ↔ code | ✓ 42 essais, 42 entrées au plan, aucun orphelin |
69
+ | chiffres périmés dans les livrables | ✓ aucun |
70
+
71
+ Les deux essais qui ont échoué en s'écrivant l'ont fait **par ma faute, non par celle du code** : le
72
+ refus de provenance existait bien (mon motif de recherche ne collait pas), et `instantiate` exige un
73
+ `motif` par champ affiné — garde délibérée que j'avais contournée au lieu de l'éprouver. Elle est
74
+ désormais éprouvée, ainsi que le refus d'un affinage qui **casse** la fiche : on n'affine pas jusqu'à
75
+ détruire l'exigence.
76
+
5
77
  ## 0.3.0 — 2026-09-04
6
78
 
7
79
  ### Ajouté — `diagnostiquer()` : le tranchant « AMÉLIORER »
@@ -53,6 +53,18 @@
53
53
  "title": "DIAGNOSTIQUER un plan existant : proposer les occurrences, NOMMER les erreurs qu'il ne mentionne pas",
54
54
  "priority": "critical",
55
55
  "status": "verified"
56
+ },
57
+ {
58
+ "ref": "SPEC-KC-10",
59
+ "title": "Le test de couverture porte sur le TITRE d'une erreur, et le vocabulaire du domaine se DÉCLARE",
60
+ "priority": "critical",
61
+ "status": "verified"
62
+ },
63
+ {
64
+ "ref": "SPEC-KC-11",
65
+ "title": "La surface publiée ne promet rien que rien ne vérifie : chaque constante exportée est éprouvée CONTRE le code qui l'applique",
66
+ "priority": "critical",
67
+ "status": "verified"
56
68
  }
57
69
  ],
58
70
  "realisations": [
@@ -127,6 +139,24 @@
127
139
  "artifact": "src/diagnostic.js",
128
140
  "progress": 100,
129
141
  "status": "done"
142
+ },
143
+ {
144
+ "ref": "REL-KC-10",
145
+ "specRef": "SPEC-KC-10",
146
+ "kind": "fix",
147
+ "title": "couverture sur le titre seul · champ `synonymes` · canonisation par fiche",
148
+ "artifact": "src/diagnostic.js + src/kind.js",
149
+ "progress": 100,
150
+ "status": "done"
151
+ },
152
+ {
153
+ "ref": "REL-KC-11",
154
+ "specRef": "SPEC-KC-11",
155
+ "kind": "test",
156
+ "title": "cinq essais de contrat sur les six exports que la suite ne touchait pas",
157
+ "artifact": "test-scripts/unit/catalogue.test.mjs",
158
+ "progress": 100,
159
+ "status": "done"
130
160
  }
131
161
  ],
132
162
  "tests": [
@@ -577,6 +607,146 @@
577
607
  "expected": "la mention y est, ainsi que l'explicabilité — c'est KIND-ECRITURE-GARDEE-01 appliqué à l'outil lui-même"
578
608
  }
579
609
  ]
610
+ },
611
+ {
612
+ "ref": "T-KC-22",
613
+ "specRef": "SPEC-KC-10",
614
+ "type": "automated",
615
+ "priority": "critical",
616
+ "title": "T-KC-22 — la CONSÉQUENCE n'entre pas dans le test de couverture",
617
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-22",
618
+ "steps": [
619
+ {
620
+ "action": "une erreur au titre reconnu mais à la conséquence verbeuse",
621
+ "expected": "couverte — la conséquence est notre prose ; un plan n'a aucune raison de la contenir, et l'inclure pénalisait les erreurs bien expliquées"
622
+ }
623
+ ]
624
+ },
625
+ {
626
+ "ref": "T-KC-23",
627
+ "specRef": "SPEC-KC-10",
628
+ "type": "automated",
629
+ "priority": "critical",
630
+ "title": "T-KC-23 — les SYNONYMES déclarés relient deux vocabulaires du même domaine",
631
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-23",
632
+ "steps": [
633
+ {
634
+ "action": "un plan disant « désactivation supprimée » contre une fiche disant « retrait effacé », sans puis avec synonymes",
635
+ "expected": "non reconnue sans, reconnue avec — aucun rapprochement lexical ne peut deviner l'équivalence, elle est propre au domaine"
636
+ }
637
+ ]
638
+ },
639
+ {
640
+ "ref": "T-KC-24",
641
+ "specRef": "SPEC-KC-10",
642
+ "type": "automated",
643
+ "priority": "critical",
644
+ "title": "T-KC-24 — un groupe de synonymes d'un seul mot est ignoré, il ne relie rien",
645
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-24",
646
+ "steps": [
647
+ {
648
+ "action": "déclarer un groupe à un mot",
649
+ "expected": "écarté au montage"
650
+ }
651
+ ]
652
+ },
653
+ {
654
+ "ref": "T-KC-25",
655
+ "specRef": "SPEC-KC-10",
656
+ "type": "automated",
657
+ "priority": "critical",
658
+ "title": "T-KC-25 — un radical trop court est écarté : il ne désignerait plus rien",
659
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-25",
660
+ "steps": [
661
+ {
662
+ "action": "déclarer un radical de trois lettres (`dat`) et un plan parlant de « dattes »",
663
+ "expected": "écarté — sous quatre lettres un radical cesse de désigner, et un rapprochement injustifiable est pire que pas de rapprochement"
664
+ }
665
+ ]
666
+ },
667
+ {
668
+ "ref": "T-KC-26",
669
+ "specRef": "SPEC-KC-10",
670
+ "type": "automated",
671
+ "priority": "critical",
672
+ "title": "T-KC-26 — un mot de QUATRE lettres désigne, et il porte souvent tout le sens",
673
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-26",
674
+ "steps": [
675
+ {
676
+ "action": "extraire les mots-clés d'une phrase portant `date`, `note`, `vote`, `lieu` et des mots vides de quatre lettres",
677
+ "expected": "les porteurs de sens sont retenus, les mots vides écartés nommément — le seuil à cinq lettres écartait le mot qui DISTINGUE"
678
+ }
679
+ ]
680
+ },
681
+ {
682
+ "ref": "T-KC-27",
683
+ "specRef": "SPEC-KC-11",
684
+ "type": "automated",
685
+ "priority": "critical",
686
+ "title": "T-KC-27 — PROVENANCES est exactement ce que `defineKind` admet en origine",
687
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-27",
688
+ "steps": [
689
+ {
690
+ "action": "monter une fiche avec chacune des provenances déclarées, puis avec une provenance hors liste",
691
+ "expected": "les trois déclarées passent ; l'inconnue est refusée et le refus ÉNUMÈRE les admises — sinon la constante ne dit rien à qui construit une fiche"
692
+ }
693
+ ]
694
+ },
695
+ {
696
+ "ref": "T-KC-28",
697
+ "specRef": "SPEC-KC-11",
698
+ "type": "automated",
699
+ "priority": "critical",
700
+ "title": "T-KC-28 — PLAN_VERSION est exactement ce que `toDevtest` écrit dans le plan",
701
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-28",
702
+ "steps": [
703
+ {
704
+ "action": "projeter une fiche et relire le champ `plan`",
705
+ "expected": "identique à la constante — qatrax lit ce champ pour accepter le plan"
706
+ }
707
+ ]
708
+ },
709
+ {
710
+ "ref": "T-KC-29",
711
+ "specRef": "SPEC-KC-11",
712
+ "type": "automated",
713
+ "priority": "critical",
714
+ "title": "T-KC-29 — AFFINABLES est exactement ce qu'`instantiate` accepte d'affiner",
715
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-29",
716
+ "steps": [
717
+ {
718
+ "action": "affiner chacun des sept champs déclarés, puis un champ hors liste, puis sans motif, puis avec une valeur qui casse la fiche",
719
+ "expected": "les sept passent ; le champ hors liste, l'affinage sans motif et l'affinage qui invalide la fiche sont tous trois refusés"
720
+ }
721
+ ]
722
+ },
723
+ {
724
+ "ref": "T-KC-30",
725
+ "specRef": "SPEC-KC-11",
726
+ "type": "automated",
727
+ "priority": "critical",
728
+ "title": "T-KC-30 — `marqueur` est ce qui rend `enrichir` idempotent, et il est DANS le bloc rendu",
729
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-30",
730
+ "steps": [
731
+ {
732
+ "action": "chercher le marqueur de la fiche dans le bloc qu'elle engendre",
733
+ "expected": "présent — sans lui un second enrichissement recollerait tout une deuxième fois"
734
+ }
735
+ ]
736
+ },
737
+ {
738
+ "ref": "T-KC-31",
739
+ "specRef": "SPEC-KC-11",
740
+ "type": "automated",
741
+ "priority": "critical",
742
+ "title": "T-KC-31 — `normaliser` retire la casse, les accents et la ponctuation, et rien d'autre",
743
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-31",
744
+ "steps": [
745
+ {
746
+ "action": "normaliser une phrase accentuée et ponctuée, puis `null`",
747
+ "expected": "texte réduit aux mots en minuscules sans accents ; `null` rend la chaîne vide et ne lève pas"
748
+ }
749
+ ]
580
750
  }
581
751
  ]
582
752
  }
@@ -0,0 +1,177 @@
1
+ # Épreuve rétrospective n° 1 — RestoTrax
2
+
3
+ **Protocole** : `PROPOSITION-REGLE-RELIRE-LE-PLAN.md` §5.bis
4
+ **Auteur** : Dr Hamid MADANI <drmdh@msn.com> · **Date** : 2026-09-06
5
+ **Objet** : diagnostiquer le plan **initial** du lot assistant-pilote de RestoTrax, et comparer au
6
+ résultat réellement atteint.
7
+
8
+ ---
9
+
10
+ ## 1 · Le dispositif
11
+
12
+ | | |
13
+ |---|---|
14
+ | plan initial | `docs/DEVTEST-PLAN.assistant-pilote.json`, commit `9781b2f` du **31/08/2026** — « état de production, avant restructuration » |
15
+ | contenu | **14 exigences, 18 essais** |
16
+ | corpus complet | **21 fiches** |
17
+ | **corpus retenu** | **13 fiches** — 8 écartées par la double borne |
18
+
19
+ ### La double borne a écarté 8 fiches, et elle a dit pourquoi
20
+
21
+ | écartée | motif |
22
+ |---|---|
23
+ | `KIND-DONNEE-INSUFFISANTE-01` · `KIND-ECRITURE-GARDEE-01` · `KIND-REFUS-LISIBLE-01` | **origine du projet jugé** — nées d'incidents de RestoTrax |
24
+ | `KIND-ACQUIS-01` · `KIND-MAJ-PARTIELLE-01` · `KIND-ECRITURE-HORS-APPLICATION-01` · `KIND-FORMULAIRE-ROUTE-01` · `KIND-CONSIGNER-APRES-SUCCES-01` | **postérieures au plan** |
25
+
26
+ **C'est le bon comportement, et il coûte.** Les trois premières décrivent exactement ce que RestoTrax
27
+ a corrigé après le 31/08 — et l'outil **n'avait pas le droit** de les employer, puisqu'elles ont été
28
+ écrites *depuis* ces corrections. Un score qui les aurait comptées aurait été flatteur et faux.
29
+
30
+ ---
31
+
32
+ ## 2 · Ce que l'outil a dit
33
+
34
+ **35 erreurs signalées, sur 7 règles.** Deux règles rapprochées d'au moins une exigence.
35
+
36
+ | règle | erreurs signalées | occurrences reconnues |
37
+ |---|---|---|
38
+ | `KIND-CHIFFRE-SANS-SOURCE-01` | 7 / 7 | 2 |
39
+ | `KIND-PERIMETRE-01` | 6 / 6 | 0 |
40
+ | `KIND-SUPPRESSION-DATEE-01` | 5 / 5 | 1 |
41
+ | `KIND-ECHEC-FOURNISSEUR-01` | 5 / 5 | 0 |
42
+ | `KIND-DEPENDANCE-DISTANTE-01` | 5 / 5 | 0 |
43
+ | `KIND-SORTIE-GENEREE-01` | 4 / 4 | 0 |
44
+ | `KIND-ECRITURE-HORS-SCHEMA-01` | 3 / 4 | 0 |
45
+
46
+ ---
47
+
48
+ ## 3 · Le classement — et il est mauvais
49
+
50
+ Ce que RestoTrax a **réellement** fait après le 31/08 : la migration vers `@mostajs/assistant-pilote`
51
+ (02/09, trois tables renommées), la normalisation de l'identifiant de connexion et la correction du
52
+ message de refus (02/09).
53
+
54
+ | classe | règles | erreurs | détail |
55
+ |---|---|---|---|
56
+ | **anticipé** | **1 partiellement** | 1 sur 35 | `KIND-ECRITURE-HORS-SCHEMA-01` — *« la migration ne SAIT PAS altérer une table existante »*. RestoTrax a bien renommé trois tables le 02/09, et la bascule n'a été franche **que parce qu'elles étaient vides en production**. Le risque signalé était réel |
57
+ | **FAUX POSITIF** | **1** | **5** | `KIND-SUPPRESSION-DATEE-01` — voir §4 |
58
+ | **sans objet** | 5 | ~29 | tableau de bord, périmètre d'instance, fournisseur externe, sortie générée, dépendance distante : **le lot pilote n'en porte aucun** |
59
+ | **contredit** | 0 | 0 | — |
60
+
61
+ **Ce que RestoTrax a effectivement corrigé après le 31/08 venait de fiches ÉCARTÉES par la borne.**
62
+ L'outil ne pouvait pas le savoir — et c'est correct. **Mais cela signifie que, sur cet essai, le
63
+ rappel utile est proche de zéro pour un coût de lecture de 35 erreurs.**
64
+
65
+ ---
66
+
67
+ ## 4 · ⚠️ Le faux positif — la découverte de cet essai
68
+
69
+ L'outil a signalé **5 erreurs sur 5** pour `KIND-SUPPRESSION-DATEE-01`, comme « non mentionnées
70
+ nulle part ». Or le plan initial porte :
71
+
72
+ > **`PIL-14`** — *« Activation, désactivation et conseils sont tous horodatés et **conservés** par
73
+ > l'ORM, refus compris »*
74
+ >
75
+ > **`TPIL-14`** — *« la désactivation est **DATÉE, pas effacée** »*
76
+
77
+ **La règle est couverte, explicitement, et par une exigence ET un essai.** Le rapprochement a
78
+ échoué parce que **les deux textes disent la même chose avec d'autres mots** : la fiche parle de
79
+ *retrait*, *pierre tombale*, *attribué*, *restauration* ; le plan parle de *désactivation*,
80
+ *horodatés*, *conservés*.
81
+
82
+ **Conséquence directe : le compte des « erreurs non couvertes » est GONFLÉ.** Le rappel du
83
+ mécanisme est meilleur que sa précision ne le laisse croire — mais un lecteur qui vérifie cinq
84
+ signalements pour découvrir qu'ils portent sur une exigence déjà tenue cesse de lire au troisième.
85
+
86
+ ---
87
+
88
+ ## 5 · ⚠️ Le second défaut — la borne porte sur l'ORIGINE, pas sur le CONTENU
89
+
90
+ Une fiche retenue peut avoir été **enrichie après** la date du plan. Mesuré :
91
+
92
+ | règle retenue | origines postérieures au 31/08 |
93
+ |---|---|
94
+ | `KIND-PERIMETRE-01` | **3** |
95
+ | `KIND-CHIFFRE-SANS-SOURCE-01` | **2** |
96
+ | `KIND-SUPPRESSION-DATEE-01` | **2** |
97
+ | `KIND-ECRITURE-HORS-SCHEMA-01` | **2** |
98
+ | `KIND-DEPENDANCE-DISTANTE-01` | **2** |
99
+
100
+ Exemple : deux des sept erreurs de `KIND-CHIFFRE-SANS-SOURCE-01` — celles sur **l'âge d'une valeur
101
+ périmée** — ont été ajoutées le **04/09**, depuis TicketFlow. L'outil « aurait dit » le 31/08 des
102
+ choses qu'il ne pouvait pas savoir.
103
+
104
+ **Le protocole est donc incomplet** : il faudrait borner au niveau de **chaque erreur**, ce qui
105
+ suppose de dater les erreurs individuellement — elles ne le sont pas aujourd'hui.
106
+
107
+ ⚠️ **Et ce défaut est provisoirement infranchissable** : le corpus a **cinq jours**, les plans en ont
108
+ plusieurs mois. Aucune fiche ne précède vraiment les plans qu'on veut juger.
109
+
110
+ ---
111
+
112
+ ## 6 · Conclusion de l'essai n° 1
113
+
114
+ **L'essai ne valide pas la règle. Il ne l'écarte pas non plus — il montre qu'elle n'est pas encore
115
+ éprouvable.**
116
+
117
+ | mesure | valeur | lecture |
118
+ |---|---|---|
119
+ | **rappel utile** | ~1 sur 35 | très faible **sur ce lot** |
120
+ | **coût de lecture** | 35 erreurs, dont 5 sur une exigence déjà tenue | élevé |
121
+ | **faux positifs démontrés** | **1 règle, 5 erreurs** | défaut de mécanisme, corrigeable |
122
+ | **fuite de la borne de contenu** | 5 règles sur 7 | défaut de protocole, non corrigeable aujourd'hui |
123
+
124
+ ### Trois enseignements, et ils valent plus que le score
125
+
126
+ 1. **Le rapprochement lexical produit des faux positifs sur du vocabulaire divergent.** Deux textes
127
+ qui disent la même chose autrement ne se reconnaissent pas. C'est corrigeable — synonymes
128
+ déclarés par fiche, ou rapprochement sur les **épreuves** plutôt que sur les intitulés.
129
+ 2. **Un plan de LOT n'est pas un plan d'APPLICATION.** Cinq des sept règles signalées portent sur
130
+ des sujets que le lot pilote ne traite pas. Diagnostiquer le plan **complet** de RestoTrax — et
131
+ non celui d'un lot — donnerait un résultat tout autre. **L'essai a mal choisi son objet.**
132
+ 3. **La double borne fonctionne, et elle est coûteuse.** Elle a écarté les trois fiches qui
133
+ décrivaient exactement les corrections à venir. C'est la preuve qu'elle mord — et la raison pour
134
+ laquelle un corpus jeune ne peut pas être éprouvé sur des plans anciens.
135
+
136
+ ### Ce que je recommande avant l'essai n° 2
137
+
138
+ | # | action |
139
+ |---|---|
140
+ | 1 | **corriger le faux positif** : rapprocher aussi sur les épreuves, ou déclarer des synonymes par fiche |
141
+ | 2 | **prendre le plan COMPLET** d'une application, pas celui d'un lot |
142
+ | 3 | **dater les erreurs individuellement** dans les fiches — sans quoi la borne de contenu restera une fiction |
143
+ | 4 | **choisir un projet dont le plan est postérieur** à une partie du corpus — CollabTrax (03/08) et LabTrax (31/08) sont de meilleurs candidats que RestoTrax |
144
+
145
+ ⚠️ **Et il reste possible que la règle soit écartée.** Cet essai ne le dit pas encore : il dit que
146
+ l'instrument n'est pas prêt, non que l'idée est fausse. Les deux conclusions sont différentes, et
147
+ les confondre serait la faute que ce document existe pour éviter.
148
+
149
+ ---
150
+
151
+ ## Addendum du 06/09/2026 — le faux positif est corrigé, en trois temps
152
+
153
+ > Les chiffres du corps de ce rapport sont ceux de `@mostajs/kind-catalog` **0.3.0** et restent tels
154
+ > quels : un rapport d'épreuve ne se réécrit pas, sinon on perd la mesure de ce qui a été corrigé.
155
+
156
+ Le faux positif du §4 — `KIND-SUPPRESSION-DATEE-01` signalée **5 fois sur 5** alors que `PIL-14` et
157
+ `TPIL-14` la portaient explicitement — avait **trois** causes, et non une. Elles ne sont apparues
158
+ qu'en les levant l'une après l'autre :
159
+
160
+ | correctif | ce que je m'étais trompé à faire | erreurs signalées | la règle |
161
+ |---|---|---|---|
162
+ | 0.3.0 | — | **35** | 5/5 |
163
+ | couverture sur le **titre** seul | j'exigeais qu'un plan contienne aussi la `consequence` — qui est **notre** prose, écrite pour qui lit la fiche. Une erreur d'autant plus « non couverte » qu'elle était **bien expliquée** | **27** | 3/5 |
164
+ | synonymes au **radical** | je les avais écrits en mots entiers : il fallait énumérer toutes les flexions du français. Neuf mots pour un seul groupe, et `supprimée` passait quand même | **26** | 2/5 |
165
+ | mots-clés à partir de **4 lettres** | `date`, `note`, `vote`, `lieu` étaient écartés — c'est-à-dire **le mot qui distingue**. « le retrait est un simple drapeau, sans **date** » ne retenait que `retrait`, `simple`, `drapeau`, et l'exigence qui disait « horodatés » ne pouvait pas la couvrir | **23** | **1/5** |
166
+
167
+ **La conclusion du §4 est confirmée, sa cause est corrigée, et son remède initial était insuffisant.**
168
+ J'avais proposé « rapprocher aussi sur les épreuves, ou déclarer des synonymes » : les synonymes
169
+ seuls ne retiraient qu'**une** erreur sur cinq. Les deux autres causes étaient dans mon propre test
170
+ de couverture.
171
+
172
+ L'erreur qui subsiste — *« la restauration recrée un objet neuf »* — n'est **pas** un faux positif :
173
+ le plan de RestoTrax ne dit rien d'une restauration. Elle reste signalée à juste titre.
174
+
175
+ Contrôle de non-régression : le même correctif appliqué au plan de LabTrax laisse le total
176
+ **inchangé à 11** — le seuil à quatre lettres n'a ajouté aucun bruit. Voir
177
+ [`EPREUVE-02-LABTRAX-06092026.md`](EPREUVE-02-LABTRAX-06092026.md).
@@ -0,0 +1,152 @@
1
+ # Épreuve rétrospective n° 2 — LabTrax
2
+
3
+ **Auteur** : Dr Hamid MADANI <drmdh@msn.com>
4
+ **Date** : 06/09/2026 · **Objet** : `@mostajs/kind-catalog` 0.4.0 · **Statut** : essai, la règle n'est **pas** adoptée
5
+
6
+ > Deuxième passage de la moulinette prévue au §5.bis de
7
+ > [`PROPOSITION-REGLE-RELIRE-LE-PLAN.md`](PROPOSITION-REGLE-RELIRE-LE-PLAN.md). L'essai n° 1
8
+ > ([RestoTrax](EPREUVE-01-RESTOTRAX-06092026.md)) a buté sur un défaut d'objet : le plan jugé était
9
+ > déjà l'état final, il n'y avait donc **aucun écart** à mesurer. Celui-ci en a un.
10
+
11
+ ---
12
+
13
+ ## 1. L'objet — et pourquoi il vaut mieux que le premier
14
+
15
+ | | |
16
+ |---|---|
17
+ | plan initial | `docs/DEVTEST-PLAN.labtrax.json`, commit `4571c7a` du **27/07/2026** — « parcours réglementaire, arrêté 1275 » |
18
+ | plan atteint | même fichier aujourd'hui, après six semaines de travail |
19
+ | **écart** | **16 exigences → 49** · 24 essais → 85 · 16 réalisations → 59 |
20
+
21
+ **33 exigences ont été ajoutées après le plan initial.** C'est la seule chose qui rende l'épreuve
22
+ possible : ces 33 exigences sont ce que le projet a **découvert en le faisant**, et donc exactement
23
+ ce qu'une relecture du plan initial aurait eu la chance — ou non — de signaler d'avance.
24
+
25
+ ---
26
+
27
+ ## 2. La double borne — 11 fiches sur 21 sont interdites
28
+
29
+ Corpus complet : 21 fiches. **Retenues : 10. Écartées : 11.**
30
+
31
+ | motif d'exclusion | fiches |
32
+ |---|---|
33
+ | **origine dans le projet jugé** (9) | `PERIMETRE`, `CHIFFRE-SANS-SOURCE`, `REFUS-LISIBLE`, `DONNEE-INSUFFISANTE`, `FORMULAIRE-ROUTE`, `CONSIGNER-APRES-SUCCES`, `DEPENDANCE-DISTANTE`, `SUPPRESSION-DATEE` |
34
+ | **postérieure au plan** (3) | `ACQUIS` (01/09), `MAJ-PARTIELLE` (01/09), `ECRITURE-HORS-APPLICATION` (02/09) |
35
+
36
+ Sur les 10 retenues, **6 sont métier** — élevage, apiculture, BTP, alimentaire, agronomie,
37
+ électronique — et n'ont aucun rapport avec une application universitaire. **L'outil disposait donc
38
+ de quatre fiches transverses**, portant 18 erreurs connues, et de rien d'autre.
39
+
40
+ > ### ⚠️ Le fait le plus instructif de cet essai est dans le tableau ci-dessus
41
+ >
42
+ > Les fiches qui auraient **touché** sont précisément celles que la borne interdit. Six des neuf
43
+ > fiches nées de LabTrax retombent, mot pour mot, sur des exigences que LabTrax a dû écrire :
44
+ >
45
+ > | fiche écartée (née de LabTrax) | exigence ajoutée par LabTrax |
46
+ > |---|---|
47
+ > | `PERIMETRE-01` — une permission ouvre une capacité, jamais un périmètre | **SPEC-APP-31** — faire dériver la lecture d'une séance du **mandat**, comme le vote |
48
+ > | `REFUS-LISIBLE-01` — un refus nomme sa cause et offre une issue | **SPEC-APP-35** — dire la **vraie raison** d'un refus, et offrir une issue |
49
+ > | `FORMULAIRE-ROUTE-01` — le formulaire rendu et sa route s'accordent | **SPEC-APP-33** — vérifier l'IHM **telle qu'elle est servie** |
50
+ > | `CONSIGNER-APRES-SUCCES-01` — on ne date qu'après le succès | **SPEC-APP-38** — ne dater qu'**après** l'envoi ; `notifyDecision` n'enregistrait qu'une date |
51
+ > | `SUPPRESSION-DATEE-01` — retirer, c'est dater | **SPEC-APP-26** — pierre tombale **datée, attribuée et motivée** |
52
+ > | `DONNEE-INSUFFISANTE-01` — un calcul insuffisant refuse et chiffre son manque | **SPEC-APP-41** — désigner ce qui bloque **réellement** *(rapprochement plausible, non exact)* |
53
+ >
54
+ > Ce n'est **pas** une mesure de l'outil : ces fiches ont été écrites **depuis** ces exigences,
55
+ > l'ordre causal est inversé. C'est la démonstration que la borne fait son travail — sans elle,
56
+ > j'aurais publié un taux de réussite de 18 % au lieu de 9 %, et il aurait été faux.
57
+
58
+ ---
59
+
60
+ ## 3. Ce que l'outil aurait dit le 27/07/2026
61
+
62
+ **11 erreurs connues sur 4 règles.** Classement selon les quatre classes du protocole — il n'y a
63
+ **pas de classe « faux »** : l'écart entre un avertissement et ce qu'a fait le projet n'est ni bon
64
+ ni mauvais, le besoin du commanditaire est le seul arbitre.
65
+
66
+ | # | avertissement | classe | ce qu'a fait LabTrax |
67
+ |---|---|---|---|
68
+ | 1 | *l'aperçu écrit déjà quelque chose* | **divergent** | **SPEC-APP-25** exige le décompte et le quorum **visibles avant** l'action — même territoire, autre forme : l'**inertie** de l'aperçu n'est écrite nulle part (`aperçu` : 0 occurrence dans le plan final) |
69
+ | 2 | *la garde est posée dans la VUE* | **anticipé** | **SPEC-APP-31** fait dériver la garde du mandat ; **SPEC-APP-32** fait déclarer le catalogue par les modules. Le plan initial ne posait la garde sur la séance que pour le pointage (SPEC-APP-07) |
70
+ | 3 | *seuls les succès sont audités* | **divergent** | 50 occurrences de « refus » dans le plan final, **toutes** du côté de l'écran (SPEC-APP-24, SPEC-APP-35). Aucune ne **compte** les refus. Pour une université, le refus lisible primait le refus dénombrable — et l'avertissement reste ouvert |
71
+ | 4 | *l'action exécutée n'est pas celle prévisualisée* | **sans objet** | LabTrax n'a jamais construit de couple aperçu/appliquer |
72
+ | 5 | *l'essai tourne en mémoire, la production sur schéma* | **anticipé** | **SPEC-APP-33**, écrite après le correctif `da228ce` du 27/07 : « *un test qui fabrique lui-même sa requête ne teste pas l'écran — il teste l'idée qu'on s'en fait* ». L'IHM postait `identifier`, la route lisait `email` |
73
+ | 6 | *le champ est ajouté au code sans l'être au schéma* | **anticipé** | **SPEC-APP-27** — le numéro d'inscription saisi à la candidature **doit être conservé** dans un champ déclaré (`User.externalRef`) |
74
+ | 7 | *la migration n'ALTÈRE pas une table existante* | **sans objet** | aucune migration au plan (`migration` : 0 occurrence) |
75
+ | 8 | *on fait confiance au texte produit* | **sans objet** | aucune sortie générative — le « Service IA » de la commission est un service **humain** |
76
+ | 9 | *clé valide sans crédit confondue avec clé invalide* | **divergent** | **SPEC-APP-38** répond à la même racine — le résultat du fournisseur doit gouverner ce qu'on écrit — par « dater après l'envoi » et « pouvoir renvoyer ». Le **classement** des échecs n'a jamais été écrit |
77
+ | 10 | *un quota temporaire traité comme une panne définitive* | **sans objet** | `quota` : 0 occurrence |
78
+ | 11 | *l'ordre de repli est figé dans la configuration* | **sans objet** | `repli` : 0 occurrence |
79
+
80
+ ### Le couple
81
+
82
+ | mesure | valeur | lecture |
83
+ |---|---|---|
84
+ | **rappel utile** | **3 / 33** = **9 %** | trois des 33 exigences ajoutées étaient signalées d'avance |
85
+ | **coût de lecture** | **11 lignes, dont 5 sans objet** | moins d'une minute de lecture, 45 % de bruit |
86
+ | divergents | 3 | à consigner : ils désignent trois besoins réels que LabTrax a servis autrement |
87
+ | contredits | **0** | aucune fiche n'a été prise en défaut |
88
+
89
+ **9 % est un chiffre faible, et il faut le dire tel quel.** Sa cause est mesurable et n'est pas
90
+ dans le rapprochement : le corpus admissible au 27/07/2026 comptait **quatre** fiches transverses.
91
+ Un rappel de 3 sur 33 avec quatre fiches, c'est **0,75 exigence gagnée par fiche disponible** —
92
+ c'est ce ratio-là, et non le pourcentage, qui se projette.
93
+
94
+ ---
95
+
96
+ ## 4. La mesure du CORPUS — à ne pas confondre avec la précédente
97
+
98
+ Le même plan initial, passé au corpus d'**aujourd'hui** (21 fiches, borne levée) :
99
+ **42 erreurs sur 14 règles** au lieu de 11 sur 4.
100
+
101
+ Ce chiffre ne mesure **pas** l'outil au 27/07 — il est circulaire pour les neuf fiches nées de
102
+ LabTrax. Il mesure deux autres choses, et deux seulement :
103
+
104
+ 1. **la visée** — les fiches nées de LabTrax retombent sur les exigences qui les ont engendrées, et
105
+ nulle part ailleurs. C'est une vérification de justesse du rapprochement, pas de prédiction ;
106
+ 2. **une prédiction, falsifiable** — un projet frère qui démarrerait aujourd'hui recevrait 14 règles
107
+ et 42 erreurs, dont sept correspondent à des exigences que LabTrax a payées de six semaines de
108
+ découverte. **Cette prédiction ne vaut rien tant qu'elle n'a pas été vérifiée sur un projet qui
109
+ n'a pas nourri le catalogue.** C'est l'essai n° 3, et il ne peut pas être fait sur l'existant.
110
+
111
+ ---
112
+
113
+ ## 5. Ce que l'essai a corrigé dans l'outil
114
+
115
+ Le faux positif relevé par l'essai n° 1 — `SUPPRESSION-DATEE-01` signalée 5 fois sur 5 alors que
116
+ `PIL-14`/`TPIL-14` la portaient explicitement — a été poursuivi jusqu'au bout. Trois causes
117
+ distinctes, trouvées dans cet ordre :
118
+
119
+ | correctif | cause | RestoTrax | la règle |
120
+ |---|---|---|---|
121
+ | départ | — | 35 erreurs | 5/5 |
122
+ | **couverture sur le TITRE seul** | la `consequence` est **notre** prose ; un plan n'a aucune raison de la contenir, et l'inclure pénalisait les erreurs **bien expliquées** | **27** | 3/5 |
123
+ | **synonymes au RADICAL** | écrits en mots entiers, ils demandaient d'énumérer toutes les flexions du français — la liste tenait neuf mots pour un groupe et laissait passer `supprimée` | **26** | 2/5 |
124
+ | **seuil des mots-clés à 4 lettres** | `date`, `note`, `vote`, `lieu`, `taux` étaient écartés — et avec eux **le mot qui distingue** : « le retrait est un simple drapeau, sans **date** » ne retenait que `retrait`, `simple`, `drapeau` | **23** | **1/5** |
125
+
126
+ La seule erreur qui subsiste — *« la restauration recrée un objet neuf »* — est un **vrai manque** :
127
+ le plan de RestoTrax ne dit rien d'une restauration. LabTrax reste à 11 erreurs après les trois
128
+ correctifs : **le seuil à 4 lettres n'a ajouté aucun bruit**.
129
+
130
+ Six essais gardent ces décisions : `T-KC-22` (la conséquence hors couverture), `T-KC-23` (les
131
+ radicaux), `T-KC-24` (un groupe d'un mot ne relie rien), `T-KC-25` (un radical de moins de quatre
132
+ lettres est écarté), `T-KC-26` (les mots de quatre lettres portent le sens).
133
+
134
+ ---
135
+
136
+ ## 6. Verdict provisoire — deux essais sur sept
137
+
138
+ **La règle n'est toujours pas adoptable, et l'essai dit maintenant pourquoi.**
139
+
140
+ Ce qui est acquis :
141
+ - la **double borne** fonctionne, et elle est indispensable : elle divise le résultat par deux ;
142
+ - l'outil ne s'est fait **contredire par aucun** des deux projets — 0 contredit sur 37 erreurs signalées ;
143
+ - le **coût de lecture est négligeable** : une minute, pour un plan de 16 à 49 exigences ;
144
+ - la porte **informative** est le bon choix : sur 11 avertissements, 5 étaient sans objet. Une porte
145
+ bloquante aurait arrêté un projet juste pour parler de quotas d'API à une université.
146
+
147
+ Ce qui manque :
148
+ - **cinq projets** — ATC, CollabTrax, qatrax, SofTrax, CRM/TRADING ;
149
+ - surtout, **un projet qui n'a pas nourri le catalogue**. Les deux essais faits mesurent un catalogue
150
+ écrit en grande partie *depuis* les projets qu'il juge. Tant que ce troisième essai n'existe pas,
151
+ le seul chiffre honnête reste **0,75 exigence gagnée par fiche transverse disponible**, et il
152
+ n'autorise aucune promesse.
@@ -0,0 +1,210 @@
1
+ # Proposition de règle — faire relire le plan par l'outil, avant d'écrire le code
2
+
3
+ **Statut : PROPOSITION, en attente de validation.** Ce document n'est pas une règle DEVRULES : il
4
+ en propose une. Rien ne s'y applique tant qu'elle n'est pas validée.
5
+
6
+ **Auteur** : Dr Hamid MADANI <drmdh@msn.com> · **Date** : 2026-09-05
7
+ **À reprendre** : à la fin du développement et des essais d'`@mostajs/auto-pilot` en mode
8
+ « assistant par catalogue éprouvé ».
9
+
10
+ ---
11
+
12
+ ## 1 · L'idée
13
+
14
+ Une fois les trois outils développés — **`auto-pilot`** (la modélisation), **`assistant-pilote`**
15
+ (la garde et le journal), **`kind-catalog`** (les fiches et le diagnostic) —, **leur invocation
16
+ devient une étape de la méthode** :
17
+
18
+ > **Après avoir écrit le plan de développement (#3) et le plan de test (#4), et AVANT d'écrire la
19
+ > première ligne de code, on fait relire ces plans par l'outil** — pour y déceler les manques, les
20
+ > erreurs et les pièges déjà payés ailleurs — **puis on itère** jusqu'à ce qu'il n'ait plus rien à
21
+ > dire.
22
+
23
+ La boucle se referme sur elle-même : les incidents produisent des fiches, les fiches diagnostiquent
24
+ les plans, et les plans corrigés évitent les incidents suivants.
25
+
26
+ ## 2 · Pourquoi maintenant, et pas plus tôt
27
+
28
+ Cette session en a fourni la preuve, deux fois, **contre l'auteur** :
29
+
30
+ - le diagnostic d'ATC a trouvé **5 erreurs sur 5** non mentionnées pour `KIND-ECRITURE-GARDEE-01` —
31
+ sur une application dont le comportement est bon et le plan dense. *Le comportement était juste,
32
+ le raisonnement n'était pas consigné.*
33
+ - l'instanciation dans ATC a révélé, **après** la poussée à qatrax, que la projection créait des
34
+ cas inexécutables. Un diagnostic du plan avant le code l'aurait dit.
35
+
36
+ **Et ce chantier même en aurait profité** : le #3 du port `modeleur` a été écrit sans passer les
37
+ fiches `KIND-ECRITURE-GARDEE-01`, `KIND-REFUS-LISIBLE-01` et `KIND-CHIFFRE-SANS-SOURCE-01` en
38
+ revue. Elles y sont, mais parce que l'auteur les avait en tête — pas parce qu'un outil les a
39
+ rappelées. **Ce qui dépend d'une mémoire attentive finit par échouer une fois** (§5.bis.4).
40
+
41
+ ## 3 · Sur quoi porte la relecture
42
+
43
+ | lu | forme | déjà possible ? |
44
+ |---|---|---|
45
+ | le plan Dev+Test structuré | `mostajs-devtest/1` | **oui** — `diagnostiquer(plan, kinds)` le fait déjà |
46
+ | le plan de développement (#3) | Markdown en prose | **non** — à instruire |
47
+ | le plan de test (#4) | Markdown en prose | **non** — à instruire |
48
+
49
+ ⚠️ **Le lien existe déjà et il est documenté.** `@mostajs/qa-engine` décrit `mostajs-devtest/1`
50
+ comme le *« jumeau structuré des livrables DEVRULES #3 et #4 »*. La relecture porte donc d'abord
51
+ sur le jumeau — c'est le chemin court, et il ne demande rien de neuf. Lire la prose vient ensuite,
52
+ pour ce qu'elle porte et que le jumeau ne porte pas : les **risques**, les **jalons**, les
53
+ **portes de sortie**.
54
+
55
+ ## 4 · Les quatre gardes que cette règle exige
56
+
57
+ Sans elles, la règle produirait exactement ce qu'elle prétend éviter.
58
+
59
+ ### a) L'outil PROPOSE un écart, il ne réécrit pas le plan
60
+
61
+ `T-KC-20` l'impose déjà : *le diagnostic ne modifie pas le plan qu'il lit*. Un outil qui réécrirait
62
+ son objet ferait perdre la distinction entre ce que l'auteur a pensé et ce que l'outil a suggéré —
63
+ et le plan cesserait d'être une décision pour devenir une sortie.
64
+
65
+ ### b) L'itération doit CONVERGER, et se borner
66
+
67
+ Un optimiseur qui propose sans fin ne termine jamais. Règle d'arrêt : **on s'arrête quand un
68
+ passage n'apporte aucun manque nouveau**, avec un plafond de passages, et **chaque passage consigne
69
+ ce qu'il a fait changer**. Sans le journal des passages, on ne saura pas si le plan s'est amélioré
70
+ ou s'il a seulement absorbé les remarques.
71
+
72
+ ### c) L'AUTORITÉ d'un manque dépend de l'ORIGINE de la fiche
73
+
74
+ ⚠️ **C'est le point le moins évident, et le plus important.**
75
+
76
+ Une fiche dont la seule origine est **le projet qu'on diagnostique** ne prouve rien : on se cite
77
+ soi-même. Le rapport doit donc **distinguer** :
78
+
79
+ | force du signal | condition |
80
+ |---|---|
81
+ | **fort** | la fiche porte des incidents de **plusieurs projets, dont pas celui-ci** — un autre a déjà payé |
82
+ | moyen | la fiche est adossée à un corpus établi (`reference`) |
83
+ | **faible** | l'unique origine de la fiche est ce projet même |
84
+
85
+ **Un diagnostic est d'autant plus fort que ses fiches viennent d'ailleurs.** C'est mesurable, et
86
+ cela doit figurer au rapport.
87
+
88
+ ### d) Un outil ne se certifie pas lui-même
89
+
90
+ Diagnostiquer le plan de `kind-catalog` avec le corpus de `kind-catalog` est légitime — mais le
91
+ rapport doit le **dire**. Une auto-certification silencieuse vaut moins que rien : elle donne à un
92
+ lecteur pressé l'impression d'un contrôle indépendant.
93
+
94
+ ## 5 · Où cela s'insérerait dans les DEVRULES
95
+
96
+ **Après #4, avant le code** — dans la §1 (procédure obligatoire), comme un point 5.bis :
97
+
98
+ ```
99
+ 4. Trancher parmi les trois cas (§2)
100
+ 5. Si proposer : produire les livrables §4 AVANT la première ligne de code
101
+ 5.bis ⟵ FAIRE RELIRE #3 et #4 par le catalogue de kinds, et itérer jusqu'à convergence
102
+ 6. Ne jamais sauter cette procédure « pour gagner du temps »
103
+ ```
104
+
105
+ **Porte bloquante ou informative ?** À trancher. L'argument pour la rendre **informative** : un
106
+ manque signalé peut légitimement ne pas concerner le projet, et une porte bloquante pousserait à
107
+ écrire des lignes d'exigence pour faire taire l'outil — ce qui dégraderait les plans au lieu de les
108
+ améliorer. L'argument pour la rendre **bloquante** : ce qui n'est pas bloquant est sauté.
109
+
110
+ **Tranché le 06/09/2026 : INFORMATIVE, mais le rapport est un LIVRABLE** — versionné à côté de #3
111
+ et #4. On n'ignore pas ce qui est écrit dans le dépôt.
112
+
113
+ ### Le livrable est un TRIPTYQUE, et son dernier état porte une signature
114
+
115
+ | état | ce qu'il est | qui l'écrit |
116
+ |---|---|---|
117
+ | **plan initial** | le #3 / #4 tels qu'écrits, avant toute relecture | l'auteur |
118
+ | **plan amélioré** | ce que l'outil propose — manques, erreurs, pièges | **l'outil** |
119
+ | **plan révisé et approuvé** | ce que l'humain retient, écarte, et pourquoi | **l'humain, nommément** |
120
+
121
+ ⚠️ **Les trois états sont CONSERVÉS, pas remplacés.** Un plan amélioré qui écraserait le plan
122
+ initial rendrait la comparaison impossible — et c'est précisément la comparaison qui dira, dans six
123
+ mois, si l'outil a servi. C'est la même raison qui fait conserver `#3.bis` (l'objectif) **et** `#14`
124
+ (le résultat) : **l'écart entre les deux est la mesure honnête de ce qui a dérivé.**
125
+
126
+ ⚠️ **Le troisième état exige un nom.** Un plan « approuvé » sans approbateur n'est pas approuvé :
127
+ c'est un plan que personne n'a refusé. L'état porte donc le nom de l'humain qui l'a arrêté, et la
128
+ liste de ce qu'il a **écarté** — écarter est une décision, pas une omission.
129
+
130
+ ## 5.bis · ⚠️ AVANT toute intégration aux DEVRULES — l'épreuve rétrospective
131
+
132
+ **Décision du 06/09/2026 : la règle ne s'intègre pas avant d'avoir été éprouvée sur les projets
133
+ DÉJÀ RÉALISÉS.** On passe leurs plans à la moulinette, et l'on compare au résultat atteint.
134
+
135
+ C'est la transposition de la paire `#3.bis` / `#14` des DEVRULES — l'objectif et le résultat —
136
+ appliquée non à une image, mais à un plan.
137
+
138
+ ### La condition qui rend l'épreuve honnête, et sans laquelle elle est truquée
139
+
140
+ ⚠️ **Une fiche née d'un incident du projet X ne peut PAS servir à juger le plan initial du projet
141
+ X.** Elle connaît la réponse : elle a été écrite depuis la réponse. L'employer produirait un score
142
+ flatteur et faux — l'outil « prédirait » ce dont il est issu.
143
+
144
+ **Le corpus doit donc être borné dans le TEMPS et par l'ORIGINE** :
145
+
146
+ > Pour diagnostiquer le plan initial du projet X daté du J, on n'emploie que les fiches
147
+ > **dont aucune origine ne vient de X**, et **dont les origines sont antérieures à J**.
148
+
149
+ Sans cette double borne, l'épreuve ne mesure rien. Avec elle, elle mesure quelque chose de réel :
150
+ *ce qu'un autre projet avait déjà payé, et que celui-ci allait payer à son tour.*
151
+
152
+ ### Le protocole, pour chaque projet réalisé
153
+
154
+ | # | geste | source |
155
+ |---|---|---|
156
+ | 1 | retrouver le **plan initial** — première version du #3/#4, ou du plan Dev+Test | historique git |
157
+ | 2 | borner le corpus (temps + origine, ci-dessus) | `kind-catalog` |
158
+ | 3 | **diagnostiquer** ce plan initial | `diagnostiquer()` |
159
+ | 4 | relever ce que le projet a **réellement** ajouté ensuite | exigences, essais et **bugs** sur qatrax |
160
+ | 5 | **classer** chaque manque signalé | ci-dessous |
161
+
162
+ ### Le classement — et il ne comporte AUCUN « faux »
163
+
164
+ ⚠️ **C'est le point le plus important de tout ce document.** Un manque signalé que le projet n'a pas
165
+ suivi **n'est pas une erreur de l'outil**. Le besoin du commanditaire est le seul arbitre, et il
166
+ peut légitimement aller ailleurs.
167
+
168
+ | classe | ce qu'elle dit | lecture |
169
+ |---|---|---|
170
+ | **anticipé** | le projet a ajouté plus tard, de lui-même, ce que l'outil signalait | **l'outil aurait fait gagner du temps** — c'est la mesure utile |
171
+ | **divergent** | le projet est allé ailleurs | **ni faux ni bon** : le commanditaire avait un autre besoin. À consigner, pas à compter comme échec |
172
+ | **sans objet** | jamais devenu pertinent | bruit. À compter honnêtement — c'est le coût de la relecture |
173
+ | **contredit** | le projet a explicitement écarté le point, avec motif | **le plus instructif** : la fiche doit peut-être porter une exception, comme `KIND-REFUS-LISIBLE-01` porte la sienne |
174
+
175
+ **La mesure retenue n'est donc pas un taux de justesse.** C'est un couple :
176
+
177
+ - **combien de ce qui a fini par compter était signalé d'avance** (rappel utile) ;
178
+ - **combien de bruit il a fallu écarter pour l'obtenir** (coût de lecture).
179
+
180
+ Un outil qui signale tout a un rappel parfait et un coût insupportable. C'est ce couple qu'il faut
181
+ publier, jamais un chiffre unique.
182
+
183
+ ### Les projets candidats à l'épreuve
184
+
185
+ Ceux qui ont **un plan initial daté** et **un résultat mesuré sur qatrax** : ATC Smart Campus,
186
+ RestoTrax, LabTrax, CollabTrax, qatrax lui-même, SofTrax, CRM/TRADING.
187
+
188
+ ⚠️ **Et l'épreuve dira peut-être que la règle ne vaut pas.** C'est une issue possible, et elle doit
189
+ rester ouverte : si le rappel utile est faible et le bruit élevé sur sept projets, la règle est
190
+ écartée — **avec son motif**, comme une fiche.
191
+
192
+ ---
193
+
194
+ ## 6 · Ce qu'il reste à faire pour que la règle soit applicable
195
+
196
+ | # | à faire | où |
197
+ |---|---|---|
198
+ | 1 | lire un plan de dev **en prose** (risques, jalons, portes de sortie) | `kind-catalog` — extraction, à instruire |
199
+ | 2 | pondérer un manque par l'**origine** de sa fiche (garde c) | `kind-catalog` — `diagnostiquer` |
200
+ | 3 | consigner les **passages** d'itération et ce qu'ils ont changé | à décider : un journal, ou le dépôt git suffit-il ? |
201
+ | 4 | signaler l'**auto-diagnostic** (garde d) | `kind-catalog` — `rapportDiagnostic` |
202
+ | 5 | **borner un corpus dans le temps et par l'origine** (§5.bis) — sans quoi l'épreuve est truquée | `kind-catalog` — `diagnostiquer` |
203
+ | 6 | conduire l'**épreuve rétrospective** sur les sept projets | une session dédiée |
204
+ | 7 | proposer la règle §1 point 5.bis à la validation — **ou l'écarter avec son motif** | DEVRULES |
205
+
206
+ ## 7 · Le nom
207
+
208
+ « Assistant par catalogue éprouvé » — c'est ainsi que l'idée a été formulée le 05/09/2026, et le
209
+ nom dit l'essentiel : **l'assistant ne conseille pas depuis un modèle de langage, il conseille
210
+ depuis un catalogue dont chaque entrée a été payée.**
@@ -83,6 +83,7 @@ export const kinds = [
83
83
  { type: 'incident', source: 'CRM/TRADING — copilote : transitions et réassignations, aperçu sans --confirm puis exécution (CARNET motif #2)', date: '2026-06-13' },
84
84
  { type: 'incident', source: 'RestoTrax — l’assistant-pilote n’a que deux écritures, et ce sont des DÉCISIONS (TPIL-7)', date: '2026-08-30' },
85
85
  { type: 'incident', source: 'ATC — l’écran de l’assistant ne porte aucune action métier (T-ASS-9)', date: '2026-09-01' },
86
+ { type: 'incident', source: '@mostajs/auto-pilot — `propose()` rend un brouillon INERTE (« modèle + aperçu, rien n’est résolu/agi ») avant que `solve()` n’engage quoi que ce soit', date: '2026-08-10' },
86
87
  ],
87
88
  }),
88
89
  ];
@@ -8,6 +8,19 @@ export default defineKind({
8
8
  enonce: 'Retirer une chose, c’est la DATER — jamais la détruire.',
9
9
  utilisation: 'Toute entité qu’un utilisateur peut « supprimer » : dossier, projet, compte, rôle, activation, solveur.',
10
10
  besoins: [{ nom: 'champs de retrait', forme: '{ retireA, retirePar, motif }' }],
11
+ // ⚠️ DÉCLARÉS après l'épreuve rétrospective n° 1 (06/09/2026) : le plan de RestoTrax couvrait
12
+ // cette règle par « la désactivation est DATÉE, pas effacée » — et le diagnostic signalait
13
+ // 5 erreurs sur 5 comme absentes, faute de reconnaître « désactivation » dans « retrait ».
14
+ // Des RADICAUX, rapprochés par préfixe (voir `canonique` dans src/diagnostic.js) : c'est le
15
+ // vocabulaire du domaine, qu'aucun rapprochement lexical ne peut deviner, et il se déclare.
16
+ synonymes: [
17
+ ['retrait', 'retir', 'supprim', 'desactiv', 'archiv', 'effac'],
18
+ ['datee', 'date', 'horodat'],
19
+ ['conservee', 'conserv', 'survi', 'tombale', 'restaur'],
20
+ ['attribuee', 'attribu', 'nominat', 'auteur'],
21
+ ['ligne', 'entree', 'enregistr'],
22
+ ['motive', 'motif', 'raison', 'justifi'],
23
+ ],
11
24
  succes: [
12
25
  'la ligne SURVIT au retrait et porte sa date, son auteur et son motif',
13
26
  'ce qui est retiré n’apparaît plus dans les listes courantes',
package/llms.txt CHANGED
@@ -9,14 +9,21 @@ EXPORTS
9
9
  toDevtest(kinds, { project, prefix }) -> plan mostajs-devtest/1 ; PLAN_VERSION
10
10
  instantiate(kind, { app, prefix, affine }) -> Instance ; diffInstance(i) ; emplois(instances) ; AFFINABLES
11
11
  loadCatalogue(dir) ; findKinds(kinds, {domaine,verdict,texte}) ; auditCatalogue(kinds) ; statsCatalogue(kinds)
12
+ diagnostiquer(plan, kinds, {minCommuns}) -> candidats ; rapportDiagnostic(...) ; TRANSVERSES
13
+ motsCles(texte) -> Set (mots de 4 lettres et plus, hors mots vides) ; normaliser(texte)
12
14
  CHAMPS DE LA FICHE
13
15
  ref (KIND-…) · enonce · domaine · version · besoins · utilisation · succes* · erreurs* · test
16
+ synonymes groupes de RADICAUX du domaine, rapproches par prefixe (4 lettres mini, groupe de 2 mini)
14
17
  efficacite · evaluation · verdict · motif · origine* · seProsePose (* = requis)
15
18
  VERDICTS propose | eprouve | retenu | ecarte
16
19
  PROVENANCES reference (norme, litterature) | terrain (praticien nomme) | incident (defaut constate)
17
20
  DOMAINES acces donnees apprentissage decision integration · btp alimentaire elevage apiculture agronomie electronique
18
21
  PIÈGES
19
22
  - `succes` ET `erreurs` sont REQUIS : ce sont les champs qu'on omet, et ceux qui servent.
23
+ - La COUVERTURE se juge sur le `titre` d'une erreur, jamais sur sa `consequence` : la
24
+ consequence est NOTRE prose, un plan n'a aucune raison de la contenir.
25
+ - Sans `synonymes`, deux textes qui disent la meme chose avec d'autres mots ne se reconnaissent
26
+ PAS : « retrait » ne vaut pas « desactivation » pour une machine. Cela se declare.
20
27
  - Chaque erreur porte sa CONSEQUENCE : « ne pas oublier X » ne se retient pas (lecon CWE/OWASP).
21
28
  - `eprouve`/`retenu` EXIGENT une origine `incident` ou `terrain` : on ne se decerne pas
22
29
  l'experience. Une `reference` suffit pour ENTRER au catalogue en `propose` — la contrainte
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mostajs/kind-catalog",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Catalogue de KINDS — fiches d'exigence réutilisables, projetables en plan mostajs-devtest/1 lisible par qatrax. N'exécute rien, ne stocke rien.",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-or-later",
package/src/diagnostic.js CHANGED
@@ -30,7 +30,8 @@ dont ou sur sous dans par pour avec sans vers chez entre est sont etre ete a ont
30
30
  tres peu tout tous toute toutes meme aussi ainsi alors quand comme si ne pas non oui son sa ses
31
31
  leur leurs notre nos votre vos ce cet cette ces cela ceci il elle ils elles on nous vous je tu
32
32
  doit doivent peut peuvent faire fait fais rien jamais toujours deja encore apres avant lors
33
- chaque autre autres bien mal seul seule sauf selon`.split(/\s+/).filter(Boolean));
33
+ chaque autre autres bien mal seul seule sauf selon sera seront soit soient afin ceux celui
34
+ celle quel quels quelle telle tels deux puis nul nulle dune dun cest lune lun elles`.split(/\s+/).filter(Boolean));
34
35
 
35
36
  /** Normalise : minuscules, sans accents, sans ponctuation. */
36
37
  export const normaliser = (t) => String(t ?? '')
@@ -39,11 +40,41 @@ export const normaliser = (t) => String(t ?? '')
39
40
 
40
41
  /** Les mots qui DÉSIGNENT quelque chose — au moins cinq lettres, hors mots vides. */
41
42
  export function motsCles(texte) {
42
- return new Set(normaliser(texte).split(' ').filter((m) => m.length >= 5 && !VIDES.has(m)));
43
+ return new Set(normaliser(texte).split(' ').filter((m) => m.length >= 4 && !VIDES.has(m)));
43
44
  }
44
45
 
45
46
  const commun = (a, b) => [...a].filter((m) => b.has(m));
46
47
 
48
+ /**
49
+ * Construit la CANONISATION d'une fiche : chaque groupe de synonymes déclaré ramène ses membres au
50
+ * premier d'entre eux. Deux textes qui emploient deux mots du même groupe se reconnaissent alors —
51
+ * c'est exactement le faux positif relevé par l'épreuve rétrospective n° 1 (06/09/2026), où la
52
+ * fiche disait « retrait / tombale » et le plan « désactivation / horodaté ».
53
+ *
54
+ * ⚠️ LES MEMBRES SONT DES RADICAUX, PAS DES MOTS, et le rapprochement se fait par PRÉFIXE. Écrit
55
+ * en mots entiers, ce champ demandait d'énumérer toutes les flexions du français — `supprimer`,
56
+ * `supprime`, `supprimée`, `supprimées`… — liste qu'on croit finie et qui ne l'est jamais : la
57
+ * première version de ce champ tenait neuf mots pour un seul groupe et laissait passer
58
+ * `supprimée`, ce qu'un essai a montré (T-KC-23). Un radical (`supprim`) les couvre tous.
59
+ *
60
+ * ⚠️ QUATRE LETTRES AU MOINS pour un radical. Plus court, il cesse de désigner : `dat` attraperait
61
+ * `datation` mais aussi `dattes`, et un rapprochement qu'on ne peut plus justifier est pire que
62
+ * pas de rapprochement — c'est la seule défense de cet outil (voir l'en-tête).
63
+ */
64
+ function canonique(kind) {
65
+ const groupes = (kind.synonymes ?? []).map((groupe) => {
66
+ const radicaux = groupe.map((m) => normaliser(m).replace(/ /g, '')).filter(Boolean);
67
+ // La tête reste le PREMIER déclaré, même s'il est trop court pour servir de radical : c'est
68
+ // l'étiquette du groupe, pas un motif de recherche.
69
+ return { tete: radicaux[0], motifs: radicaux.filter((r) => r.length >= 4) };
70
+ }).filter((g) => g.tete && g.motifs.length > 0);
71
+
72
+ return (mots) => new Set([...mots].map((mot) => {
73
+ const g = groupes.find(({ motifs }) => motifs.some((r) => mot.startsWith(r)));
74
+ return g ? g.tete : mot;
75
+ }));
76
+ }
77
+
47
78
  /** Tout le texte d'une exigence, épreuves comprises : c'est là que la règle se dit. */
48
79
  function texteDeSpec(plan, spec) {
49
80
  const essais = (plan.tests ?? []).filter((t) => t.specRef === spec.ref);
@@ -87,24 +118,37 @@ export function diagnostiquer(plan, kinds = [], { minCommuns = 5 } = {}) {
87
118
  ].join(' '));
88
119
 
89
120
  return kinds.map((k) => {
90
- const cles = motsCles(`${k.enonce} ${k.succes.join(' ')} ${k.erreurs.map((e) => e.titre).join(' ')}`);
121
+ const canon = canonique(k);
122
+ const cles = canon(motsCles(`${k.enonce} ${k.succes.join(' ')} ${k.erreurs.map((e) => e.titre).join(' ')}`));
123
+ // Le plan est canonisé AVEC LA TABLE DE CETTE FICHE : chaque fiche apporte son vocabulaire, et
124
+ // celui d'une fiche ne parasite pas la lecture d'une autre.
125
+ const planCanon = canon(toutLePlan);
91
126
 
92
127
  // 1 · LES OCCURRENCES CANDIDATES — proposées, jamais posées.
93
128
  const occurrences = [];
94
129
  for (const s of plan.specs) {
95
- const c = commun(cles, motsCles(texteDeSpec(plan, s)));
130
+ const c = commun(cles, canon(motsCles(texteDeSpec(plan, s))));
96
131
  if (c.length >= minCommuns) occurrences.push({ specRef: s.ref, titre: s.title, communs: c.sort() });
97
132
  }
98
133
  occurrences.sort((a, b) => b.communs.length - a.communs.length);
99
134
 
100
- // 2 · LES ERREURS QUE LE PLAN NE MENTIONNE NULLE PART — c'est le livrable.
101
- // Une erreur est tenue pour COUVERTE si le plan emploie la moitié de ses mots désignants.
102
- // ⚠️ Le seuil est délibérément BAS : mieux vaut proposer une erreur déjà couverte — l'humain
103
- // l'écarte en dix secondes que taire celle qui manque, qu'il ne cherchera jamais.
135
+ /**
136
+ * 2 · LES ERREURS QUE LE PLAN NE MENTIONNE NULLE PART c'est le livrable.
137
+ *
138
+ * ⚠️ ON NE COMPARE QUE LE TITRE, PAS LA CONSÉQUENCE. Corrigé le 06/09/2026, après l'épreuve
139
+ * rétrospective n° 1. La conséquence est NOTRE prose — elle explique le coût de l'erreur à
140
+ * celui qui lit la fiche. **Un plan n'a aucune raison de la contenir.** L'inclure dans la
141
+ * comparaison rendait une erreur d'autant plus « non couverte » qu'elle était bien expliquée,
142
+ * et une exigence courte mais explicite ne pouvait JAMAIS couvrir une erreur verbeuse.
143
+ *
144
+ * ⚠️ Et le seuil porte sur DEUX mots du titre, pas sur une proportion. Une proportion pénalise
145
+ * les titres longs, ce qui est l'inverse du bon sens : un titre long est plus reconnaissable,
146
+ * pas moins.
147
+ */
104
148
  const erreursNonCouvertes = k.erreurs.filter((e) => {
105
- const mots = motsCles(`${e.titre} ${e.consequence}`);
149
+ const mots = canon(motsCles(e.titre));
106
150
  if (mots.size === 0) return false;
107
- return commun(mots, toutLePlan).length < Math.max(2, Math.ceil(mots.size / 2));
151
+ return commun(mots, planCanon).length < Math.min(2, mots.size);
108
152
  });
109
153
 
110
154
  const transverse = TRANSVERSES.has(k.domaine);
package/src/kind.js CHANGED
@@ -84,6 +84,18 @@ export function defineKind(f = {}) {
84
84
  verdict: propre(f.verdict) || 'propose',
85
85
  motif: propre(f.motif) || null,
86
86
  origine: liste(f.origine),
87
+ /**
88
+ * LES SYNONYMES DU DOMAINE — groupes de mots qui désignent la MÊME chose.
89
+ *
90
+ * ⚠️ Ajoutés le 06/09/2026, après l'épreuve rétrospective n° 1. Le diagnostic avait signalé
91
+ * 5 erreurs sur 5 comme « non mentionnées » dans un plan qui les couvrait explicitement : la
92
+ * fiche disait *retrait*, *pierre tombale*, le plan disait *désactivation*, *horodatés*. Deux
93
+ * textes qui disent la même chose avec d'autres mots ne se reconnaissaient pas.
94
+ *
95
+ * Aucun rapprochement lexical ne peut deviner cette équivalence — elle est propre au domaine.
96
+ * Elle se DÉCLARE donc, comme tout le reste de la fiche.
97
+ */
98
+ synonymes: liste(f.synonymes).filter((g) => Array.isArray(g) && g.length > 1),
87
99
  // OÙ la question se pose, quand ce n'est pas là où elle se calcule. Le corpus transverse n'en
88
100
  // avait pas besoin ; le BTP (sur chantier) et l'électronique (sur l'embarqué) l'exigent.
89
101
  seProsePose: propre(f.seProsePose) || null,