Files
mcp-wms-api/ROADMAP.md
T
Arthur Ria 7621b87c49 Roadmap : ajoute le lot 4 (modèle de données et applications)
Deux angles morts mesurés sur le tenant LIMAGRAI2512.

L4.1 — QueryType est figé à 0 (Reading) en dur dans api-service.js : le modèle
Writing est inatteignable. Ce n'est pas une limite de l'API, QueryType 1
répond correctement sur Context.Products — il manque le paramètre. D3 reste
vrai en revanche : en Writing les statuts sont des énumérations, donc le
défaut doit rester 0.

L4.2 — Application vient de WMS_APPLICATION, partagé par tous les profils,
sans surcharge possible. Le MCP n'interroge que EasyWMS alors que
/AD/api/Application/GetAll en déclare 9. CustomApp porte le spécifique client
(153 workflows, 54 queries, 11 entités préfixés CST_) et est entièrement
invisible ; avec AGV, Notifications, GalileoFaults et Common, ce sont 260
workflows hors périmètre.

Côté API AD le correctif est simple, l'application n'étant qu'un champ du
payload — vérifié, ["CustomApp", tenant, 5, 0] renvoie bien les workflows CST_.
Il faudra en revanche indexer les caches par application.

Côté QueryExecute c'est non résolu : passer Application "CustomApp" ne change
pas le contexte de lecture, les entités CST_ ne répondent ni au singulier ni au
pluriel et aucune n'apparaît dans les 232 entités du Metadata EasyWMS. Elles
sont définies dans EasyBuilder (FromMetadata: false). Consigné comme question
ouverte, sans solution promise.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 15:45:52 +02:00

234 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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é.
---
## Lot 4 — Modèle de données et applications
Deux angles morts constatés le 24/08/2026, plus larges que les lots 1 à 3. Les
chiffres ci-dessous sont mesurés sur le tenant `LIMAGRAI2512`.
### L4.1 — Le modèle Writing est inatteignable
`QueryType` est figé à `0` (Reading) en dur dans `api-service.js`
(`executeQuery` et `executeScalarQuery`). Aucun outil ne permet d'interroger le
modèle **Writing**.
Ce n'est pas une limite de l'API : `{"Application":"EasyWMS","QueryType":1,
"Expression":"Context.Products.OrderBy(z => z.Id)","Take":1}` répond
correctement. Il manque simplement le paramètre.
Attention en l'exposant : D3 reste vrai — en `QueryType: 1` les champs de statut
sont des **énumérations**, donc les comparaisons par chaîne (`== "Release"`)
échouent. Le défaut doit rester `0`, et la bascule être un choix explicite et
documenté, pas une option qu'on active au hasard.
### L4.2 — Une seule application sur neuf est visible
`Application` vient de `WMS_APPLICATION` dans `.env`, **partagé par tous les
profils**, sans surcharge par appel ni paramètre d'outil. Le MCP n'interroge donc
jamais que `EasyWMS`.
`POST /AD/api/Application/GetAll` en déclare **9** :
| Application | Workflows | Queries | Entities |
|---|---:|---:|---:|
| EasyWMS | 4012 | 2239 | 338 |
| **CustomApp** | **153** | **54** | **11** |
| AGV | 71 | 14 | 5 |
| Notifications | 26 | 35 | 24 |
| GalileoFaults | 9 | 20 | 24 |
| Common | 1 | 7 | 25 |
| SmartUI, User, WarehouseWebDesigner | 0 | 08 | 0 |
**CustomApp porte le spécifique client** — ses workflows sont préfixés `CST_`
(`CST_SendRejectContainersToPK`, `CST_Task`, `CST_Container`…). C'est
précisément ce qu'on cherche en debug, et c'est aujourd'hui invisible. Au total
**260 workflows et ~130 queries** hors périmètre.
Deux chantiers de difficulté très différentes :
**API AD — simple.** L'application est un champ du payload
(`[application, tenant, pageSize, offset]`). Vérifié : `["CustomApp", tenant,
5, 0]` sur `/Workflow/GetByApplication` renvoie bien les workflows `CST_`. Il
suffit d'un paramètre `application` sur les outils AD et workflow, avec une clé
de cache incluant l'application (sinon un cache pollué mélange les
applications).
**QueryExecute — non résolu, à investiguer.** Passer `Application: "CustomApp"`
ne change **pas** le contexte de lecture : l'erreur reste
`ApplicationReadingContext ne contient pas de définition pour …`. Les 11 entités
`CST_` ne sont atteignables ni au singulier ni au pluriel, et **aucune** n'est
présente dans les 232 entités du Metadata `EasyWMS` (vérifié). Elles sont
définies dans EasyBuilder (`FromMetadata: false`) — reste à déterminer si elles
sont interrogeables, et sous quel nom. Ne rien promettre avant d'avoir tranché.
---
## É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).