86923542fa
Source : la page d'aide générée https://<host>/ApplicationService/Help, qui documente des champs et des endpoints que le MCP n'utilise pas. Toutes les affirmations ci-dessous ont été testées contre LIMAGRAI2512. D3 corrigé — QueryContextType a quatre valeurs, pas deux : Reading 0 (ApplicationReadingContext), Writing 1 (ApplicationWritingRepository), DataWarehouse 2 (non configuré sur ce tenant : IDataWarehouse non résolu), Metrics 3 (ApplicationMetricDataContext, présent, modèle non exploré). Le message d'erreur nomme le contexte, ce qui donne un moyen rapide de savoir quel QueryType a servi. L4.1 étendu aux quatre contextes. L4.2 tranché sur son point dur : le champ Application ne partitionne pas le contexte de lecture. Context.AgvTasks répond aussi bien avec Application AGV qu'avec EasyWMS — le contexte est commun au tenant. La table de résolution du lot 2 devra donc agréger le Metadata de toutes les applications, mais un paramètre application sur QueryExecute serait inutile. Les entités CustomApp restent inatteignables sous les quatre QueryType, au singulier comme au pluriel, et Metadata renvoie 0 entité pour cette application : ce sont des définitions EasyBuilder sans projection requêtable. L'API AD est le seul accès au spécifique client. Trois chantiers ajoutés : - L4.3 ClientModule, non renseigné, d'où des requêtes du MCP journalisées sous « Client: GNA » et indistinguables du vrai client GNA. - L4.4 API WorkflowLog (GetInstances, GetLogs, Validate), joignable et fonctionnelle, susceptible de remettre en cause D16. - L4.5 champs inexploités de QueryExecute : Parameters (requêtes paramétrées, piste pour D13), CommandTimeout, QueryId + QueryCancel, QueryExecuteStream (piste pour L3.1), plus les endpoints event sourcing et les sondes healthcheck/ready. CLAUDE.md pointe désormais vers la page d'aide comme source de vérité. MONITORING.md documente healthcheck/ready comme sonde légère. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
302 lines
13 KiB
Markdown
302 lines
13 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`). Or `QueryContextType` a **quatre**
|
||
valeurs. Testées une à une :
|
||
|
||
| Valeur | Contexte | Résultat sur `LIMAGRAI2512` |
|
||
|---|---|---|
|
||
| `0` | Reading | opérationnel (seul utilisé aujourd'hui) |
|
||
| `1` | Writing | **opérationnel** — `Context.Products` répond |
|
||
| `2` | DataWarehouse | **non configuré** : `Could not resolve serviceType 'IDataWarehouse…'` |
|
||
| `3` | Metrics | contexte présent (`ApplicationMetricDataContext`), modèle non exploré |
|
||
|
||
Exposer `query_type` sur les outils de requête, défaut `0`. Attention : D3 reste
|
||
vrai — en Writing les champs de statut sont des **énumérations**, donc
|
||
`== "Release"` échoue. La bascule doit être un choix explicite et documenté.
|
||
|
||
Le contexte `Metrics` mérite une exploration à part : c'est probablement là que
|
||
vivent les données agrégées produites par les jobs `MetricGatherer`.
|
||
|
||
### 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 — tranché : le champ `Application` ne partitionne rien.**
|
||
`Context.AgvTasks` (entité de l'application AGV) répond aussi bien avec
|
||
`Application: "AGV"` qu'avec `Application: "EasyWMS"`. Le contexte de lecture est
|
||
**commun au tenant** : toutes les applications y déversent leurs entités.
|
||
|
||
Conséquence pour L2.1 : la table de résolution doit **agréger le Metadata de
|
||
toutes les applications** (`GET /Metadata/Entities?applicationName=…` par
|
||
application, 232 + 20 + 6 + …), et non se limiter à `EasyWMS`. Inutile en
|
||
revanche d'ajouter un paramètre `application` à `QueryExecute` : il ne changerait
|
||
rien.
|
||
|
||
**Les entités `CustomApp` ne sont interrogeables dans aucun contexte.** Les 11
|
||
entités `CST_` ont été testées sous les quatre `QueryType`, au singulier et au
|
||
pluriel : échec partout, et `Metadata/Entities` comme `Metadata/EntitiesAll`
|
||
renvoient **0 entité** pour `CustomApp`. Aucune n'est marquée
|
||
`isDataWarehouse`. Ce sont des définitions EasyBuilder (`FromMetadata: false`)
|
||
sans projection dans un contexte requêtable.
|
||
|
||
**L'API AD reste donc le seul accès au spécifique client** — ce qui rend le
|
||
paramètre `application` sur les outils AD et workflow d'autant plus utile.
|
||
|
||
### L4.3 — Identifier le MCP dans les logs du WMS
|
||
|
||
`QueryExecute` accepte un champ **`ClientModule`** que le MCP n'envoie pas.
|
||
Résultat : ses requêtes apparaissent dans les logs du WMS sous
|
||
`Execute error. Client: GNA` — le client OAuth partagé — donc indistinguables de
|
||
celles du vrai client GNA.
|
||
|
||
Renseigner `ClientModule` (`"MCP-WMS"` ou le nom du profil actif) rend chaque
|
||
requête du MCP traçable côté serveur. Vérifié : le champ est accepté.
|
||
|
||
### L4.4 — Historique d'exécution des workflows par API
|
||
|
||
`ApplicationService` expose une API `WorkflowLog` que le MCP n'utilise pas :
|
||
|
||
| Endpoint | Usage |
|
||
|---|---|
|
||
| `GET /WorkflowLog/GetInstances?processDefinitionId=&skip=&take=&startDateFrom=&startDateTo=` | instances d'un workflow sur une plage de dates, filtrables par attribut |
|
||
| `GET /WorkflowLog/GetInstance?processId=` | une instance |
|
||
| `GET /WorkflowLog/GetLogs?processId=&skip=&take=&logDateFrom=&logDateTo=` | journal d'exécution d'une instance |
|
||
| `GET /WorkflowLog/Validate?applicationName=&processDefinitionId=` | validation d'une définition |
|
||
|
||
Endpoints joignables et fonctionnels — `Validate` renvoie
|
||
`{"Success":true,"ErrorMessage":null,"Warnings":[]}`. `GetInstances` répond `[]`
|
||
sur le workflow testé : à confirmer sur un workflow ayant réellement tourné, la
|
||
journalisation n'étant pas forcément active partout.
|
||
|
||
**Peut remettre en cause D16** (historique des shipment templates jugé hors de
|
||
portée faute de logs fichier) : si l'historique d'exécution est disponible par
|
||
API, la conclusion change. À vérifier avant d'écrire quoi que ce soit.
|
||
|
||
### L4.5 — Champs de `QueryExecute` inexploités
|
||
|
||
La référence de l'API documente des champs que le MCP n'envoie jamais :
|
||
|
||
| Champ | Intérêt |
|
||
|---|---|
|
||
| `Parameters` | requêtes **paramétrées** (dictionnaire `nom -> {TypeName, Value}`) — supprimerait toute concaténation de chaîne dans les filtres, et pourrait débloquer D13 (`Select`) |
|
||
| `CommandTimeout` | timeout par requête, au lieu du timeout HTTP global de 30 s |
|
||
| `QueryId` + `POST /QueryCancel` | annulation d'une requête longue |
|
||
| `POST /QueryExecuteStream` | résultats en flux — piste sérieuse pour L3.1 (sorties volumineuses) |
|
||
|
||
Autres endpoints jamais utilisés, à évaluer : `QueryEvents`, `QueryCommands`,
|
||
`QueryCorrelationEvents`, `QuerySnapshots` (event sourcing — utile en debug),
|
||
`GET /Metadata/Commands|Events|Aggregates` et leurs variantes `…All`,
|
||
`GET /configuration/applications` (liste les applications **avec leur version**,
|
||
plus riche que `/AD/api/Application/GetAll`), `GET /healthcheck?tenantCode=` et
|
||
`GET /ready?tenantCode=` (sondes de disponibilité, répondent 200).
|
||
|
||
---
|
||
|
||
---
|
||
|
||
## É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).
|