Roadmap : lots de correction issus du diagnostic du 24/08
Ajoute ROADMAP.md et le relie depuis README.md et CLAUDE.md.
Origine : un rapport d'usage d'une session Cowork sur le profil LIMAGRAIN a
signalé 8 anomalies. Vérification faite contre le WMS réel, 4 bugs sont
confirmés et reproduits, dont un non signalé par le rapport.
Cause racine commune : entity_type est interpolé dans Context.{entity_type}
sans aucune validation, alors que le nom attendu est le TableName de l'API
Metadata et non le nom d'entité de l'AD. Container -> Containers, mais
Alias -> Alias : c'est un mapping, pas une règle de pluralisation. L'API
Metadata connaît 232 entités là où le MCP en expose 12 en dur, et la liste
documentée était fausse (Aliases n'existe pas).
Lot 1 (déblocage) : corps des erreurs HTTP remonté, routage des outils par
table explicite, projections de champs des workflows.
Lot 2 (fond) : résolution des entités via l'API Metadata, rejet des
paramètres inconnus.
Lot 3 : bornage des sorties volumineuses, documentation.
Trois propositions du rapport sont explicitement écartées, avec leur raison :
uniformisation des noms de paramètres, indexStatus sur generic_search, outil
dédié d'aide à la syntaxe.
CLAUDE.md : la section « Points ouverts » renvoie désormais vers la roadmap et
avertit des deux pièges non encore corrigés.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@ volontaires ; les références `D1`, `D2`… de ce fichier y renvoient.
|
|||||||
| Installer, lancer, brancher Claude Desktop | [README.md](README.md) |
|
| Installer, lancer, brancher Claude Desktop | [README.md](README.md) |
|
||||||
| Pourquoi le code est ainsi, pièges terrain | [DECISIONS.md](DECISIONS.md) |
|
| Pourquoi le code est ainsi, pièges terrain | [DECISIONS.md](DECISIONS.md) |
|
||||||
| Le serveur ne répond pas, lire ses logs | [MONITORING.md](MONITORING.md) |
|
| Le serveur ne répond pas, lire ses logs | [MONITORING.md](MONITORING.md) |
|
||||||
|
| Ce qui reste à faire | [ROADMAP.md](ROADMAP.md) |
|
||||||
| Accéder aux logs du WMS | [docs/logs.md](docs/logs.md) |
|
| Accéder aux logs du WMS | [docs/logs.md](docs/logs.md) |
|
||||||
| Références EasyWMS (API, entités) | [docs/](docs/) |
|
| Références EasyWMS (API, entités) | [docs/](docs/) |
|
||||||
|
|
||||||
@@ -273,11 +274,16 @@ printf '%s\n%s\n%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"
|
|||||||
|
|
||||||
## Points ouverts
|
## Points ouverts
|
||||||
|
|
||||||
- **`select_expression`** : projections en erreur de compilation côté serveur
|
Voir [ROADMAP.md](ROADMAP.md) : lots de correction planifiés, cause racine
|
||||||
(D13). Principal irritant restant.
|
commune (résolution `Name` -> `TableName` des entités), et propositions
|
||||||
- **Historique des shipment templates** : hors de portée, les logs concernés
|
explicitement écartées.
|
||||||
n'existent pas sur l'hôte joignable (D16).
|
|
||||||
- **Logs chargés intégralement en mémoire** : coûteux sur les gros fichiers
|
⚠️ Deux pièges connus et non encore corrigés, à garder en tête en attendant le
|
||||||
([docs/logs.md](docs/logs.md) §6).
|
lot 1 :
|
||||||
- **Déploiement sur VM par SSH** : non finalisé. L'exécutable est validé, la
|
|
||||||
configuration SSH reste à faire.
|
- `entity_type` est interpolé sans validation dans `Context.{entity_type}`. Le
|
||||||
|
nom attendu est le `TableName` de l'API Metadata, pas le nom d'entité de l'AD
|
||||||
|
(`Container` -> `Containers`, mais `Alias` -> `Alias`). Un mauvais nom donne un
|
||||||
|
HTTP 500 dont le détail est aujourd'hui perdu.
|
||||||
|
- `get_entity_metadata` et `list_log_files` sont listés dans `tools/list` mais
|
||||||
|
non routés dans `src/index.js` : ils renvoient `Unknown tool`.
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ C:\WMS\mcp\.env
|
|||||||
| [CLAUDE.md](CLAUDE.md) | Architecture, inventaire des outils, conventions de code |
|
| [CLAUDE.md](CLAUDE.md) | Architecture, inventaire des outils, conventions de code |
|
||||||
| [DECISIONS.md](DECISIONS.md) | **Pourquoi** le code est ainsi + pièges vérifiés en production |
|
| [DECISIONS.md](DECISIONS.md) | **Pourquoi** le code est ainsi + pièges vérifiés en production |
|
||||||
| [MONITORING.md](MONITORING.md) | Superviser le serveur MCP : logs, token, caches, symptômes |
|
| [MONITORING.md](MONITORING.md) | Superviser le serveur MCP : logs, token, caches, symptômes |
|
||||||
|
| [ROADMAP.md](ROADMAP.md) | Travaux planifiés par lot, et ce qui a été écarté |
|
||||||
| [docs/logs.md](docs/logs.md) | Accès aux logs du WMS |
|
| [docs/logs.md](docs/logs.md) | Accès aux logs du WMS |
|
||||||
| [docs/](docs/) | Références EasyWMS (API, entités) |
|
| [docs/](docs/) | Références EasyWMS (API, entités) |
|
||||||
|
|
||||||
|
|||||||
+171
@@ -0,0 +1,171 @@
|
|||||||
|
# Roadmap
|
||||||
|
|
||||||
|
Travaux planifiés, par lot. Chaque lot est livrable indépendamment.
|
||||||
|
|
||||||
|
Constats issus de la session de diagnostic du **24/08/2026** (profil `LIMAGRAIN`,
|
||||||
|
host `10.255.255.2`, tenant `LIMAGRAI2512`), déclenchée par un rapport d'usage
|
||||||
|
d'une session Cowork. Toutes les anomalies ci-dessous ont été **reproduites**
|
||||||
|
contre le WMS réel — ce ne sont pas des hypothèses.
|
||||||
|
|
||||||
|
Les décisions actées vivent dans [DECISIONS.md](DECISIONS.md) ; ce fichier ne
|
||||||
|
contient que ce qui reste à faire.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cause racine commune
|
||||||
|
|
||||||
|
Le MCP interpole `entity_type` dans `Context.{entity_type}` **sans aucune
|
||||||
|
validation** (vérifié : aucune liste blanche dans le code). Or le nom attendu
|
||||||
|
par le contexte de lecture n'est pas le nom d'entité de l'Application
|
||||||
|
Dictionary.
|
||||||
|
|
||||||
|
L'API Metadata (`GET /Metadata/Entities`, **232 entités**) donne la
|
||||||
|
correspondance exacte :
|
||||||
|
|
||||||
|
| `Name` (renvoyé par `search_ad_elements`) | `TableName` (attendu par `Context.`) |
|
||||||
|
|---|---|
|
||||||
|
| `Container` | `Containers` |
|
||||||
|
| `Product` | `Products` |
|
||||||
|
| `ContainerType` | `ContainerTypes` |
|
||||||
|
| `Alias` | `Alias` — **invariant, pas de pluriel** |
|
||||||
|
| `Item` | *n'existe pas dans le modèle Reading* |
|
||||||
|
|
||||||
|
Ce n'est donc pas une règle de pluralisation : c'est un mapping, et seul
|
||||||
|
`TableName` fait foi. `TableName` est unique sur les 232 entités.
|
||||||
|
|
||||||
|
Conséquences déjà constatées :
|
||||||
|
- une session utilisant les noms de l'AD (singuliers) déclenche un **HTTP 500**
|
||||||
|
sur chaque requête ;
|
||||||
|
- la liste d'entités documentée était fausse (`Aliases` n'existe pas, c'est
|
||||||
|
`Alias`) ;
|
||||||
|
- le MCP n'expose que 12 entités figées là où l'API en connaît 232.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lot 1 — Déblocage
|
||||||
|
|
||||||
|
Objectif : rendre le MCP auto-diagnosticable et réparer ce qui est cassé. Ce lot
|
||||||
|
seul aurait suffi à ce qu'une session se débrouille sans intervention.
|
||||||
|
|
||||||
|
### L1.1 — Remonter le détail des erreurs HTTP
|
||||||
|
|
||||||
|
Aujourd'hui toute erreur d'API se résume à `Request failed with status code 500`.
|
||||||
|
Or le WMS renvoie déjà le diagnostic complet dans le corps de la réponse :
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"ClassName":"System.AggregateException","Message":"Compile Error: ...
|
||||||
|
'ApplicationReadingContext' ne contient pas de définition pour 'Container' ..."}
|
||||||
|
```
|
||||||
|
|
||||||
|
Enrichir l'erreur au point de passage unique (`api-service.post` / `.get`) avec :
|
||||||
|
statut, URL, verbe, payload envoyé, corps de réponse tronqué à ~2000 caractères.
|
||||||
|
|
||||||
|
**Fichier :** `src/services/api-service.js` (catch de `post` et `get`).
|
||||||
|
|
||||||
|
### L1.2 — Fiabiliser le routage des outils
|
||||||
|
|
||||||
|
Deux outils sont listés dans `tools/list` mais ne sont routés vers aucun module,
|
||||||
|
à cause du routage par préfixe :
|
||||||
|
|
||||||
|
| Outil | Cause | Erreur observée |
|
||||||
|
|---|---|---|
|
||||||
|
| `get_entity_metadata` | capté par `startsWith('get_entity_')` avant sa propre branche | `Unknown WMS query tool` |
|
||||||
|
| `list_log_files` | ne contient pas `_logs` mais `_log_files` | `Unknown tool` |
|
||||||
|
|
||||||
|
Remplacer le routage par préfixe par une **table explicite nom → module**,
|
||||||
|
construite depuis les `listTools()` de chaque module. Un outil listé mais non
|
||||||
|
routé devient alors impossible par construction, au lieu d'être rattrapé au cas
|
||||||
|
par cas.
|
||||||
|
|
||||||
|
**Fichier :** `src/index.js` (handler `tools/call`).
|
||||||
|
|
||||||
|
### L1.3 — Corriger les projections de champs des workflows
|
||||||
|
|
||||||
|
L'API AD renvoie les champs en minuscules (`id`, `name`, `version`,
|
||||||
|
`applicationName`). Deux endroits supposent une autre forme :
|
||||||
|
|
||||||
|
- `search_workflows` projette `w.Id`, `w.Code`, `w.Name`, `w.Category` → tous
|
||||||
|
`undefined`, supprimés par `JSON.stringify` → **50 objets vides** pour un
|
||||||
|
`count` pourtant correct ;
|
||||||
|
- `workflow-service` lit `w.category || w.Category`, deux clés inexistantes →
|
||||||
|
`list_workflow_categories` renvoie **0 catégorie** et classe les 4012
|
||||||
|
workflows en `Uncategorized`.
|
||||||
|
|
||||||
|
Le champ le plus proche d'une catégorie est `applicationName`, mais il vaut
|
||||||
|
`EasyWMS` pour tous les workflows : la notion de catégorie n'a **aucun support**
|
||||||
|
dans les données. Décider en connaissance de cause plutôt que d'inventer une
|
||||||
|
taxonomie.
|
||||||
|
|
||||||
|
**Fichiers :** `src/tools/workflow-tools.js`, `src/services/workflow-service.js`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lot 2 — Correctif de fond
|
||||||
|
|
||||||
|
### L2.1 — Résolution des entités via l'API Metadata
|
||||||
|
|
||||||
|
Accepter `entity_type` au nom d'entité (`Container`) ou au nom de jeu
|
||||||
|
(`Containers`), insensible à la casse, et émettre `Context.{TableName}`. Cache
|
||||||
|
identique aux autres (TTL partagé, invalidation au changement de profil).
|
||||||
|
|
||||||
|
Sur nom inconnu, échouer **avant tout appel réseau**, avec un message
|
||||||
|
actionnable :
|
||||||
|
|
||||||
|
> « Item » n'existe pas dans le modèle Reading. Proches : ItemGroup, StockItem.
|
||||||
|
> 232 entités disponibles — utilisez `get_entity_metadata` pour la liste.
|
||||||
|
|
||||||
|
Supprime la cause des 500 et débloque 232 entités au lieu de 12.
|
||||||
|
|
||||||
|
### L2.2 — Rejeter les paramètres inconnus
|
||||||
|
|
||||||
|
Le SDK MCP ignore silencieusement les paramètres non déclarés : un appel
|
||||||
|
`read_recent_logs(lines: 60)` retombe sur le défaut `count = 100` sans le
|
||||||
|
moindre signal, et l'appelant conclut à un paramètre ignoré.
|
||||||
|
|
||||||
|
Ajouter `additionalProperties: false` aux 23 schémas d'outils.
|
||||||
|
|
||||||
|
C'est le correctif retenu **à la place** d'une uniformisation des noms de
|
||||||
|
paramètres : renommer casse les usages existants pour un gain cosmétique, alors
|
||||||
|
que la cause réelle est l'absence de signal.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lot 3 — Ergonomie et documentation
|
||||||
|
|
||||||
|
### L3.1 — Bornage des sorties volumineuses
|
||||||
|
|
||||||
|
- `get_system_parameters` : ajouter `limit` / `offset`, aujourd'hui absents
|
||||||
|
(sortie constatée : 70 000 caractères, rejetée par le client).
|
||||||
|
- `search_logs` : garde-fou de taille. `max_results` existe déjà, mais les
|
||||||
|
`context_lines` multiplient le volume (88 000 caractères pour 50 résultats).
|
||||||
|
- Renvoyer `truncated: true` explicitement plutôt que de laisser le client se
|
||||||
|
faire rejeter.
|
||||||
|
|
||||||
|
### L3.2 — Documentation
|
||||||
|
|
||||||
|
- DECISIONS.md : **D21** la règle `TableName`, **D22** le routage par table
|
||||||
|
explicite.
|
||||||
|
- CLAUDE.md : corriger la liste d'entités (`Aliases` → `Alias`) et renvoyer vers
|
||||||
|
`get_entity_metadata` comme source de vérité.
|
||||||
|
- `wms://query-examples` : un exemple singulier/pluriel commenté.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Écarté
|
||||||
|
|
||||||
|
| Proposition | Raison |
|
||||||
|
|---|---|
|
||||||
|
| Uniformiser les noms de paramètres (`entity_type` / `query` partout) | Casse les usages existants ; les alias de transition doublent la surface à maintenir. La cause réelle est traitée par L2.2. |
|
||||||
|
| Exposer un `indexStatus` sur `generic_search` | `TotalDocuments: 0` est déjà le signal. Le MCP n'a aucun moyen d'interroger l'état de l'index de recherche. |
|
||||||
|
| Outil dédié `get_query_syntax_help` | L'information doit se trouver dans le message d'erreur, là où elle est lue (L2.1), pas dans un outil qu'il faut penser à appeler. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Points ouverts (hors lots)
|
||||||
|
|
||||||
|
- **`select_expression`** : les projections via le paramètre `Select` provoquent
|
||||||
|
des erreurs de compilation côté serveur (D13). Irritant principal restant.
|
||||||
|
- **Déploiement SSH sur la VM** : l'exécutable est validé, la configuration SSH
|
||||||
|
reste à faire.
|
||||||
|
- **Historique des shipment templates** : hors de portée, les logs concernés
|
||||||
|
n'existent pas sur l'hôte joignable (D16).
|
||||||
Reference in New Issue
Block a user