7621b87c49
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>
234 lines
9.6 KiB
Markdown
234 lines
9.6 KiB
Markdown
# 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 | 0–8 | 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).
|