Files
mcp-wms-api/ROADMAP.md
T
Arthur Ria 242b0c0f1c L6.3 : une reponse hors enveloppe leve, au lieu de se faire passer pour vide
Les services lisaient `response?.entities || []` sur les reponses de l'API AD
(enveloppe { entities: [...] }, D4). Toute reponse d'une AUTRE forme — corps
vide, objet d'erreur, champ absent — devenait donc un tableau vide,
indistinguable d'une page finale legitime, et etait mise en cache avec un
timestamp valide : un cache vide empoisonne pour tout le TTL, sans le moindre
message. C'est la cause probable du `count: 0` mesure sous rafale, et le mode
d'echec le plus couteux du lot, parce qu'il se lit comme une reponse.

Le contrat est porte par src/services/ad-envelope.js pour les trois sites
(Workflow/GetByApplication, Application/GetAll, <Type>/GetByApplication) :
`{ entities: [...] }`, `[]` reel compris, est rendu tel quel ; toute autre
forme leve. entity-resolver etait deja conforme — il leve deja si
/configuration/applications ou le Metadata ne rendent aucune entite.

Volontairement sans retry ni logique de resilience : le but est de rendre
l'anomalie visible et non persistante. La rattraper la rendrait invisible,
c'est-a-dire exactement le defaut corrige.

--- Verifications (LIMAGRAIN) ---

Vide LEGITIME — search_workflows sur SmartUI (0 workflow, D26) :

  search_workflows(SmartUI) : success=true application=SmartUI count=0
                              isError=false
    error   : (aucune)
    hint    : Aucun workflow trouve dans l'application "SmartUI" — c'est la
              SEULE interrogee, les autres ne le sont jamais implicitement.
              Le specifique client (prefixe CST_) vit dans "CustomApp" : [...]
    cache pose ? workflowCachesByApplication =
      {"SmartUI":{"cached":true,"count":0,"timestamp":1787665868988,
                  "age":0,"valid":true}}
  stderr : No more workflows to fetch / Successfully cached 0 workflows

Forme SANS `entities` — non declenchable a la demande contre le vrai WMS,
couverte par un test direct (apiService.post substitue, renvoie {}) :

  --- workflow-service  fetchAllWorkflows("EasyWMS") avec une reponse {} ---
    erreur levee : Failed to fetch workflows for application "EasyWMS":
      Reponse inattendue de l'API AD sur Workflow/GetByApplication
      (application "EasyWMS", offset 0) : un objet vide, au lieu de
      l'enveloppe attendue { entities: [...] }. Rien n'a ete mis en cache —
      relancez l'appel. Si l'erreur persiste, l'API AD est en defaut [...]
    cache : {}  (attendu {})
  --- workflow-service  fetchApplications() avec une reponse {} ---
    erreur levee : Reponse inattendue de l'API AD sur Application/GetAll : [...]
    cache : {}  (attendu {})
  --- ad-service        getElements("Command") avec une reponse {} ---
    erreur levee : Failed to fetch Command for application "EasyWMS": [...]
    cache : {}  (attendu {})
  --- puis une reponse normale : le refetch repart (rien de coince) ---
    1 workflow(s), cache : {"EasyWMS":{"cached":true,"count":1,...}}

Cas nominaux du helper (unitaire) : { entities: [] } et { entities: [1,2] }
passent ; {}, null, undefined, [], { error }, "texte" levent tous.

--- Non-regression, rafales rejouees 3 fois ---

  L6.1 rafale workflow  RUN 1/2/3 : 6/6 a count=44 | fetch=1 joins=5
  L6.1 rafale resolver  RUN 1/2/3 : 6/6 succes | chargements=1 joins=5 GET=5
  L6.1 rafale mixte     RUN 1/2/3 : CustomApp@44=3 EasyWMS@50=3 |
                                    fetch=2 joins=4
  L6.2 bascule          RUN 1/2/3 : caches peuples : 0 (attendu 0)
  sequentiel nominal    count=50 puis count=50 | fetch=1 cached=1 joins=0

Baseline finale : tools/list 23, resources/list 6 ; npm test 4/4, exit 0.

ROADMAP : lot 6 retire. Le point ouvert « bascule de profil concurrente aux
appels en vol » reste — D27 borne les chargements paresseux, pas le routage
d'une requete deja partie.

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

123 lines
6.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.
---
## Lot 4 — Modèle de données et applications
Deux angles morts constatés le 24/08/2026, plus larges que les lots 2 et 3. Les
chiffres ci-dessous sont mesurés sur le tenant `LIMAGRAI2512`.
### L4.1 (reliquat) — Explorer le contexte Metrics
L'exposition de `query_type` est livrée (D25). Reste l'investigation : le
contexte `Metrics` (`QueryType: 3`, `ApplicationMetricDataContext`) mérite une
exploration à part — c'est probablement là que vivent les données agrégées
produites par les jobs `MetricGatherer`. Livrable : un rapport, pas du code
(même phase d'investigation que L4.4).
### L4.3 — Identifier le MCP dans les logs du WMS
Les requêtes du MCP apparaissent dans les logs du WMS sous
`Execute error. Client: GNA` — le client OAuth partagé — donc indistinguables de
celles du vrai client GNA.
**La piste `ClientModule` est invalidée** (mesuré le 24/08/2026, lot 1) : le
champ est bien accepté par `QueryExecute` (pas d'erreur), mais il est **sans
effet observable**. Une requête en échec envoyée avec
`ClientModule: "MCP-WMS"` est tracée `Execute error. Client: GNA`, et ni
`MCP-WMS` ni `ClientModule` n'apparaissent nulle part dans
`ApplicationService.log` ni `HttpResponseTime.log`. Le `Client:` des logs vient
du client OAuth, pas du payload — le champ n'a donc **pas** été renseigné.
Piste restante (non vérifiée) : un client OAuth dédié au MCP côté EasySTS
changerait le `Client:` des logs, mais suppose une configuration côté WMS.
### 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 long terme pour les sorties volumineuses, au-delà du bornage signalé de D24 |
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)
- **Profil `AD` : tenant introuvable** (mesuré le 24/08/2026). `npm test -- --all`
échoue 0/4 sur ce profil ; le STS de `10.255.255.2` répond
`400 {"error":"invalid_request","error_description":"Tenant not found"}` pour
le tenant `AD`. L'hôte et le STS fonctionnent (LIMAGRAIN, même hôte, passe
4/4) : c'est la valeur `AD_TENANT` du `.env` qui ne correspond plus à un
tenant existant. Correction côté propriétaire du dépôt (mettre à jour ou
retirer le profil) — pas un bug du code. Depuis L3.2, le corps de la réponse
du STS (`Tenant not found`) remonte dans les erreurs d'outils et du smoke
test.
- **Bascule de profil concurrente aux appels en vol** (mesuré le 25/08/2026,
révision du lot 2). Le serveur traite les `tools/call` **en concurrence** :
un `switch_wms_profile` émis pendant que des requêtes sont en vol les fait
partir sur le nouveau profil (observé : une requête destinée à EUROTRAFIC
exécutée sur l'hôte `10.255.255.2` après la bascule suivante). Conséquence du
singleton d'état global (D8). À traiter si un cas réel de mélange de profils
est observé (piste : sérialiser les `tools/call` ou figer le profil résolu au
début de chaque appel). La manifestation « caches » de la même concurrence
est **traitée** (D27 : single-flight par clé, garde de génération) ; celle-ci
ne l'est pas — D27 borne les chargements paresseux, pas le routage d'une
requête déjà partie.
- **`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).