@mostajs/kind-catalog 0.1.0 → 0.2.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,67 @@
2
2
 
3
3
  **Auteur** : Dr Hamid MADANI <drmdh@msn.com>
4
4
 
5
+ ## 0.2.0 — 2026-09-03
6
+
7
+ ### Ajouté — `enrichir()` : projeter pour CRÉER, enrichir pour EXPLOITER
8
+
9
+ Le passage à qatrax a rendu visible une faute de modèle, et le critère qui la tranche :
10
+
11
+ > **Dans le RÉFÉRENTIEL, une même règle deux fois est une duplication. Dans une APPLICATION, la
12
+ > même règle appliquée à un objet précis est une OCCURRENCE d'exploitation — et il en faut autant
13
+ > qu'il y a d'objets.**
14
+
15
+ `toDevtest` projetait la règle **générique** dans le plan de l'application : ni référentiel, ni
16
+ occurrence — **la règle recopiée**. ATC portait déjà **quatre** occurrences du périmètre (le
17
+ portail, le coaching, l'e-learning, le cumul de rôles) et recevait une cinquième exigence qui ne
18
+ parlait de rien. RestoTrax de même, avec `PIL-10` à `PIL-13`.
19
+
20
+ ```js
21
+ enrichir(plan, { kind, specRefs: ['SPEC-POR-01', 'SPEC-COA-01', 'SPEC-ELE-01', 'SPEC-ROL-02'] })
22
+ ```
23
+
24
+ Les erreurs connues de la fiche descendent dans les exigences **que l'application a déjà**.
25
+ **Aucune exigence, aucun essai n'est ajouté** — ce qui referme *par construction* le défaut que
26
+ qatrax avait signalé : des cas de plan que rien ne peut exécuter, parce qu'ils prétendaient qu'un
27
+ essai portant un autre nom les couvrait.
28
+
29
+ `toDevtest` garde son emploi : une application **neuve**, sans aucune exigence, à qui la fiche
30
+ donne les siennes.
31
+
32
+ **Rejouable** (`T-KC-14`) : le bloc est borné par un marqueur et se remplace au lieu de s'empiler —
33
+ le script d'une application se relance à chaque montée du catalogue.
34
+
35
+ **Refuse plutôt que de faire semblant** (`T-KC-15`) : une exigence introuvable — renommée, le plus
36
+ souvent — est une erreur, pas un avertissement ; et enrichir sans rien désigner est refusé, parce
37
+ que c'est ne rien faire tout en croyant l'avoir fait.
38
+
39
+ `retirerProjection()` reprend ce qu'une projection avait posé, pour les applications qui basculent.
40
+
41
+ 27 essais.
42
+
43
+ ## 0.1.1 — 2026-09-03
44
+
45
+ ### Ajouté — `bind` : lier une épreuve à l'essai qui la couvre DÉJÀ
46
+
47
+ Constaté **en instanciant pour la première fois**, dans ATC. Une application qui reprend une fiche
48
+ l'éprouve déjà, la plupart du temps : ATC vérifiait la garde de périmètre par cinq essais avant que
49
+ la fiche n'existe.
50
+
51
+ Sans liaison, la projection ajoutait **cinq essais `automated` sans renvoi** — c'est-à-dire cinq
52
+ trous dans la porte qualité de l'application, et une invitation à réécrire ce qui existe.
53
+
54
+ ```js
55
+ toDevtest(kinds, { project, prefix: 'ATC', bind: {
56
+ 'KIND-PERIMETRE-01': ['test-scripts/unit/portail.test.mjs::T-POR-2', null, …],
57
+ }})
58
+ ```
59
+
60
+ **Une épreuve non liée devient `manual`, et c'est voulu** : elle reste visible dans le suivi comme
61
+ un travail à faire, sans mentir sur son état. La déclarer `automated` sans renvoi prétendrait qu'un
62
+ essai la couvre.
63
+
64
+ `T-KC-6b` tient les deux cas. 23 essais.
65
+
5
66
  ## Non publié — 2026-09-02 (soir) · le corpus double par EXPLORATION du parc
6
67
 
7
68
  Sept applications du parc ont été relues — CRM/TRADING, LabTrax, CollabTrax, LabTraxAdmin, SofTrax,
@@ -41,6 +41,12 @@
41
41
  "title": "Le corpus livré est valide, sourcé et lisible",
42
42
  "priority": "critical",
43
43
  "status": "verified"
44
+ },
45
+ {
46
+ "ref": "SPEC-KC-08",
47
+ "title": "ENRICHIR les occurrences existantes plutôt que RECOPIER la règle dans le plan de l'application",
48
+ "priority": "critical",
49
+ "status": "verified"
44
50
  }
45
51
  ],
46
52
  "realisations": [
@@ -97,6 +103,15 @@
97
103
  "artifact": "src/",
98
104
  "progress": 100,
99
105
  "status": "done"
106
+ },
107
+ {
108
+ "ref": "REL-KC-08",
109
+ "specRef": "SPEC-KC-08",
110
+ "kind": "feature",
111
+ "title": "enrichir() · retirerProjection()",
112
+ "artifact": "src/enrichir.js",
113
+ "progress": 100,
114
+ "status": "done"
100
115
  }
101
116
  ],
102
117
  "tests": [
@@ -407,6 +422,76 @@
407
422
  "expected": "au moins trois incidents, issus de projets DISTINCTS — une exigence rencontrée dans trois projets indépendants n'est plus une opinion d'auteur, c'est un fait du métier"
408
423
  }
409
424
  ]
425
+ },
426
+ {
427
+ "ref": "T-KC-6b",
428
+ "specRef": "SPEC-KC-03",
429
+ "type": "automated",
430
+ "priority": "critical",
431
+ "title": "T-KC-6b — une épreuve LIÉE devient automatisée ; non liée, elle reste MANUELLE",
432
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-6b",
433
+ "steps": [
434
+ {
435
+ "action": "projeter une fiche à deux épreuves, dont une seule liée à un essai réel",
436
+ "expected": "la liée est `automated` avec son renvoi ; l'autre est `manual` sans renvoi — la déclarer automatisée prétendrait qu'un essai la couvre, et ouvrirait un trou dans la porte qualité de l'application"
437
+ }
438
+ ]
439
+ },
440
+ {
441
+ "ref": "T-KC-13",
442
+ "specRef": "SPEC-KC-08",
443
+ "type": "automated",
444
+ "priority": "critical",
445
+ "title": "T-KC-13 — enrichir dépose les erreurs dans les exigences EXISTANTES, sans rien ajouter",
446
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-13",
447
+ "steps": [
448
+ {
449
+ "action": "enrichir deux exigences d'un plan",
450
+ "expected": "les descriptions reçoivent les erreurs connues ; aucune exigence ni aucun essai n'est ajouté — c'est ce qui referme le défaut des cas que rien ne peut exécuter"
451
+ }
452
+ ]
453
+ },
454
+ {
455
+ "ref": "T-KC-14",
456
+ "specRef": "SPEC-KC-08",
457
+ "type": "automated",
458
+ "priority": "critical",
459
+ "title": "T-KC-14 — enrichir deux fois ne DOUBLE pas le bloc",
460
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-14",
461
+ "steps": [
462
+ {
463
+ "action": "rejouer l'enrichissement",
464
+ "expected": "description inchangée — le script d'une application se rejoue à chaque montée du catalogue"
465
+ }
466
+ ]
467
+ },
468
+ {
469
+ "ref": "T-KC-15",
470
+ "specRef": "SPEC-KC-08",
471
+ "type": "automated",
472
+ "priority": "critical",
473
+ "title": "T-KC-15 — enrichir REFUSE une exigence introuvable, et refuse de ne rien désigner",
474
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-15",
475
+ "steps": [
476
+ {
477
+ "action": "exigence renommée, puis liste vide",
478
+ "expected": "refus des deux — une exigence renommée ferait partir l'enrichissement dans le vide, en silence"
479
+ }
480
+ ]
481
+ },
482
+ {
483
+ "ref": "T-KC-16",
484
+ "specRef": "SPEC-KC-08",
485
+ "type": "automated",
486
+ "priority": "critical",
487
+ "title": "T-KC-16 — `retirerProjection` reprend ce qu'une projection avait posé",
488
+ "autoRef": "test-scripts/unit/catalogue.test.mjs::T-KC-16",
489
+ "steps": [
490
+ {
491
+ "action": "projeter puis retirer",
492
+ "expected": "les entrées projetées disparaissent, celles de l'application survivent"
493
+ }
494
+ ]
410
495
  }
411
496
  ]
412
497
  }
package/llms.txt CHANGED
@@ -28,6 +28,10 @@ PIÈGES
28
28
  - Les fiches sont des FICHIERS VERSIONNES (kinds/*.kind.mjs). Ce qui va en base, c'est l'USAGE —
29
29
  et cela appartient a @mostajs/skill-library et au journal d'@mostajs/assistant-pilote.
30
30
  - AUCUN FORMAT NOUVEAU : la projection produit du mostajs-devtest/1, valide par le parseur officiel.
31
+ - PROJETER POUR CREER, ENRICHIR POUR EXPLOITER. Dans le REFERENTIEL, une regle deux fois = duplication ;
32
+ dans une APPLICATION, la regle appliquee a un objet = OCCURRENCE, et il en faut autant qu'il y a d'objets.
33
+ toDevtest = app NEUVE (elle recoit ses exigences) · enrichir = app EXISTANTE (ses occurrences recoivent
34
+ les erreurs connues). enrichir n'AJOUTE ni exigence ni essai — sinon qatrax porte des cas inexecutables.
31
35
  - loadCatalogue() fait un import() : charger un corpus, c'est EXECUTER du code. Une fiche se revoit
32
36
  comme du code, jamais comme un document (docs/15-REVUE-SECURITE).
33
37
  - validateKind() applique les memes defauts que defineKind : on peut lui passer un objet BRUT.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mostajs/kind-catalog",
3
- "version": "0.1.0",
3
+ "version": "0.2.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",
@@ -0,0 +1,91 @@
1
+ /**
2
+ * ENRICHIR — faire descendre les erreurs connues d'une fiche dans les exigences QUE
3
+ * L'APPLICATION A DÉJÀ.
4
+ *
5
+ * ── PROJETER POUR CRÉER, ENRICHIR POUR EXPLOITER ───────────────────────────
6
+ * `toDevtest` sert à une application NEUVE : elle n'a aucune exigence, la fiche lui donne les
7
+ * siennes. `enrichir` sert à une application qui EN A DÉJÀ — et c'est le cas courant, puisqu'une
8
+ * fiche naît précisément de ce que des applications ont éprouvé.
9
+ *
10
+ * ⚠️ LE CRITÈRE QUI SÉPARE LES DEUX (décision du 03/09/2026, après un passage à qatrax qui l'a
11
+ * rendu visible) :
12
+ *
13
+ * · dans le RÉFÉRENTIEL, une même règle deux fois est une DUPLICATION ;
14
+ * · dans une APPLICATION, la même règle appliquée à un objet précis est une OCCURRENCE
15
+ * d'exploitation, et il en faut autant qu'il y a d'objets.
16
+ *
17
+ * D'où la faute que cette fonction répare : projeter la règle GÉNÉRIQUE dans le plan d'une
18
+ * application ajoutait une exigence qui n'était appliquée à rien. Ni référentiel, ni occurrence :
19
+ * la règle recopiée. ATC portait déjà QUATRE occurrences du périmètre — le portail, le coaching,
20
+ * l'e-learning, le cumul de rôles — et recevait une cinquième exigence qui ne parlait de rien.
21
+ *
22
+ * ⚠️ ELLE N'AJOUTE NI EXIGENCE NI ESSAI. C'est ce qui referme, par construction, le défaut que
23
+ * qatrax avait signalé : des cas de plan que rien ne peut exécuter, parce qu'ils prétendaient
24
+ * qu'un essai portant un autre nom les couvrait.
25
+ *
26
+ * Author: Dr Hamid MADANI <drmdh@msn.com> · AGPL-3.0-or-later
27
+ */
28
+ const propre = (v) => String(v ?? '').trim();
29
+
30
+ /** La borne du bloc ajouté — elle rend l'enrichissement REJOUABLE sans empiler. */
31
+ export const marqueur = (ref) => `⟦${ref}⟧`;
32
+
33
+ /** Le bloc que la fiche dépose dans une exigence de l'application. */
34
+ export function blocDeFiche(k) {
35
+ return [
36
+ marqueur(k.ref),
37
+ `Fiche ${k.ref} v${k.version} (${k.verdict}) — ce que d'autres projets ont payé :`,
38
+ ...k.erreurs.map((e) => `⚠ ${e.titre} — ${e.consequence}`),
39
+ ].join('\n');
40
+ }
41
+
42
+ /**
43
+ * Enrichit des exigences EXISTANTES avec les erreurs connues d'une fiche.
44
+ *
45
+ * @param {object} plan plan `mostajs-devtest/1` de l'application — modifié en place
46
+ * @param {object} o
47
+ * @param {object} o.kind la fiche (ou son instance affinée)
48
+ * @param {string[]} o.specRefs les exigences de l'application qui sont des OCCURRENCES de la règle
49
+ * @returns {{ enrichies: string[], bloc: string }}
50
+ */
51
+ export function enrichir(plan, { kind, specRefs = [] } = {}) {
52
+ if (!plan?.specs) throw new Error('enrichir: plan `mostajs-devtest/1` requis');
53
+ if (!kind?.ref) throw new Error('enrichir: fiche requise');
54
+ if (!specRefs.length) {
55
+ // ⚠️ ENRICHIR SANS DIRE QUOI, C'EST NE RIEN FAIRE — et croire l'avoir fait. On refuse plutôt
56
+ // que de rendre un rapport vide qui passerait pour un succès.
57
+ throw new Error(`enrichir(${kind.ref}) : aucune exigence désignée — une fiche s’applique à des OCCURRENCES, nommez-les`);
58
+ }
59
+
60
+ const bloc = blocDeFiche(kind);
61
+ const enrichies = [];
62
+ for (const ref of specRefs) {
63
+ const s = plan.specs.find((x) => x.ref === propre(ref));
64
+ // ⚠️ UNE EXIGENCE INTROUVABLE EST UNE ERREUR, pas un avertissement : le plus probable est
65
+ // qu'elle a été renommée, et l'enrichissement partirait alors dans le vide en silence.
66
+ if (!s) throw new Error(`enrichir(${kind.ref}) : exigence introuvable — ${ref}`);
67
+ const tete = String(s.description ?? '').split(marqueur(kind.ref))[0].trimEnd();
68
+ s.description = tete ? `${tete}\n\n${bloc}` : bloc;
69
+ enrichies.push(s.ref);
70
+ }
71
+ return { enrichies, bloc };
72
+ }
73
+
74
+ /**
75
+ * Retire d'un plan ce qu'une PROJECTION y avait posé — exigences, réalisations et essais.
76
+ * Utile une fois : quand une application passe de `toDevtest` à `enrichir`.
77
+ */
78
+ export function retirerProjection(plan, { kind, prefix } = {}) {
79
+ const corps = propre(kind?.ref ?? kind).replace(/^KIND-/, '');
80
+ const p = propre(prefix).toUpperCase();
81
+ const cible = { specs: `SPEC-${p}-${corps}`, realisations: `REL-${p}-${corps}`, tests: `T-${p}-${corps}-` };
82
+ const retires = [];
83
+ for (const [cle, debut] of Object.entries(cible)) {
84
+ const reste = [];
85
+ for (const l of plan[cle] ?? []) {
86
+ if (l.ref === debut || String(l.ref).startsWith(debut)) retires.push(l.ref); else reste.push(l);
87
+ }
88
+ plan[cle] = reste;
89
+ }
90
+ return retires;
91
+ }
package/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { defineKind, validateKind, VERDICTS, PROVENANCES, DOMAINES } from './kind.js';
2
2
  export { toDevtest, PLAN_VERSION } from './projection.js';
3
+ export { enrichir, retirerProjection, blocDeFiche, marqueur } from './enrichir.js';
3
4
  export { instantiate, diffInstance, emplois, AFFINABLES } from './instance.js';
4
5
  export { loadCatalogue, findKinds, auditCatalogue, statsCatalogue } from './catalogue.js';
package/src/projection.js CHANGED
@@ -27,8 +27,20 @@ const corps = (ref) => propre(ref).replace(/^KIND-/, '');
27
27
  * @param {{key:string,name:string,description?:string}} o.project le projet, au sens qatrax
28
28
  * @param {string} o.prefix préfixe des références — `ATC`, `RESTO`… ISOLE deux applications qui
29
29
  * reprennent la même fiche : sans lui, leurs plans se marcheraient dessus dans le même qatrax.
30
+ * @param {object} [o.bind] ce que l'application COUVRE DÉJÀ : `{ 'KIND-X': [autoRef|null, …] }`,
31
+ * une entrée par épreuve de la fiche, dans l'ordre.
32
+ *
33
+ * ⚠️ POURQUOI `bind` EXISTE — constaté le 03/09/2026, en instanciant pour la première fois.
34
+ * Une application qui reprend une fiche l'éprouve DÉJÀ, la plupart du temps : ATC vérifiait la
35
+ * garde de périmètre par cinq essais avant que la fiche n'existe. Sans `bind`, la projection
36
+ * ajoutait cinq essais `automated` SANS renvoi — c'est-à-dire cinq trous dans la porte qualité,
37
+ * et une invitation à réécrire ce qui existe.
38
+ *
39
+ * ⚠️ UNE ÉPREUVE NON LIÉE DEVIENT `manual`, ET C'EST VOULU. Elle reste visible dans le suivi
40
+ * comme un travail à faire, sans mentir sur son état : la déclarer `automated` sans renvoi
41
+ * prétendrait qu'un essai la couvre.
30
42
  */
31
- export function toDevtest(kinds = [], { project, prefix = 'APP' } = {}) {
43
+ export function toDevtest(kinds = [], { project, prefix = 'APP', bind = {} } = {}) {
32
44
  if (!project?.key || !project?.name) throw new Error('toDevtest: `project` { key, name } requis');
33
45
  const p = propre(prefix).toUpperCase();
34
46
  const plan = { plan: PLAN_VERSION, project: { ...project }, specs: [], realisations: [], tests: [] };
@@ -61,13 +73,18 @@ export function toDevtest(kinds = [], { project, prefix = 'APP' } = {}) {
61
73
  status: 'todo',
62
74
  });
63
75
 
76
+ const lie = Array.isArray(bind?.[k.ref]) ? bind[k.ref] : [];
64
77
  k.test.forEach((t, i) => {
78
+ const renvoi = propre(lie[i]) || null;
65
79
  plan.tests.push({
66
80
  ref: `T-${p}-${corps(k.ref)}-${i + 1}`,
67
81
  specRef,
68
82
  title: `T-${p}-${corps(k.ref)}-${i + 1} — ${t.action}`,
69
- type: 'automated',
83
+ // Lié à un essai réel → automatisé. Non lié → MANUEL : un travail à faire, pas un
84
+ // essai qu'on prétend avoir écrit.
85
+ type: renvoi ? 'automated' : 'manual',
70
86
  priority: 'critical',
87
+ ...(renvoi ? { autoRef: renvoi } : {}),
71
88
  steps: [{ action: t.action, expected: t.attendu }],
72
89
  });
73
90
  });