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

6.6 KiB

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 ; 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).