Commit Graph

17 Commits

Author SHA1 Message Date
Arthur Ria b941f367ae Révision lot 4 : validé ; ligne Writing énorme et champ tool absent consignés
Les vérifications attendues des trois blocs rejouées via le protocole
passent : api://catalog assaini (plus de QueryType 1, d'Aliases ni de
suffixe d'assembly), query_type opérationnel (Writing 1 ligne, Metrics en
erreur parlante, 7 rejeté localement sans aucun trafic réseau, warning de
résolution conservé jusque dans l'échec WMS), caches par application
étanches (4012/153, retour en cache hit, invalidation complète à la
bascule). Baseline 23/6, npm test 4/4 exit 0, diffs propres.

Deux découvertes consignées en points ouverts : une ligne Products en
Writing pèse 95 288 caractères (famille D24), et les catch locaux
d'api-tools omettent le champ tool du contrat (antérieur au lot).

Leçon de révision : mon appel search_workflows(search_term=...) des lots
précédents était silencieusement ignoré pré-D23 — le paramètre s'appelle
query. La validation D23 a transformé mon erreur en signal.

handoff-lot4.md supprimé (livré et révisé).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 11:46:50 +02:00
Arthur Ria 92de85cf53 L4.2 : paramètre application sur les outils AD et workflow (D26)
L'application venait de WMS_APPLICATION (partagée par tous les profils) : le
MCP n'interrogeait que EasyWMS, alors que CustomApp porte le spécifique
client (153 workflows CST_ sur ce tenant) et que 9 applications sont
déclarées par Application/GetAll.

Paramètre application (défaut : l'application du profil, comportement
inchangé sans lui) sur get_ad_elements, search_ad_elements,
get_ad_element_details, search_workflows, get_workflow_details,
list_workflow_categories. Clés de cache : ad-service passe par
(application, type), workflow-service par application — sans quoi un appel
CustomApp polluerait le cache EasyWMS. L'invalidation reste l'abonnement
onSwitch (D8), le chargement reste paresseux (aucun préchargement des 9
applications, D10). list_workflow_categories s'adosse à Application/GetAll
(liste allégée en cache : le blob data de chaque application pèse ~100 Ko) ;
get_application_summary regroupe par application et ne détaille que les
entrées en cache (D24), workflows compris. Acté en D26 ; CLAUDE.md mis à
jour (Caches, AD), L4.2 retiré de la ROADMAP.

Vérifications rejouées via le protocole (LIMAGRAIN / LIMAGRAI2512),
requêtes séquentielles :
- search_workflows(CST_, application:CustomApp) -> 5 objets peuplés dont
  CST_SendRejectContainersToPK ([Workflow] Successfully cached 153 workflows
  for "CustomApp").
- get_ad_elements(Workflow, application:CustomApp) -> count 153, éléments
  CST_* ([AD] Successfully cached 153 CustomApp::Workflow).
- Séquence EasyWMS -> CustomApp -> EasyWMS sur search_workflows : 4012 vs
  153, retour en cache hit ([Workflow] Using cached data for "EasyWMS"),
  aucune pollution ; get_application_summary montre les deux caches
  (workflowCachesByApplication EasyWMS 4012 / CustomApp 153).
- Sans paramètre application -> comportement inchangé (W1 = W3).
- switch_wms_profile EUROTRAFIC puis retour -> [Workflow] Cache cleared,
  [AD] All caches invalidated, [EntityResolver] Cache cleared ; summary vide.
- list_workflow_categories -> 9 applications, comptes réels des applications
  chargées.
Baseline : tools/list 23 (les 23 noms répondent), resources 6, rejet D23
d'un paramètre inconnu OK (search_workflows/applikation), npm test 4/4
exit 0.

Anomalie hors périmètre consignée dans ROADMAP.md : get_workflow_details
peut dépasser le seuil de rejet client (~101 800 caractères mesurés sur
CST_SendRejectContainersToPK), comportement antérieur au lot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 11:24:12 +02:00
Arthur Ria 706e628715 L4.1 : expose query_type sur les outils de requête (D25)
QueryType était figé à 0 en dur dans executeQuery/executeScalarQuery : le
modèle Writing, opérationnel et mesuré, était inatteignable. Paramètre
query_type (défaut 0) sur call_query_api, query_wms_entities,
count_wms_entities — get_entity_schema et search_wms_data restent des
raccourcis Reading.

D3 reste la règle par défaut : la bascule est un opt-in, avertie dans les
descriptions d'outils (statuts en énumérations en Writing). Garde de valeur
assertValidQueryType dans le code (le wrapper D23 ne valide pas les valeurs),
avant tout réseau. En query_type != 0, un nom inconnu du Metadata Reading
passe tel quel avec warning (allowUnknown du resolver) — conservé aussi dans
la réponse d'erreur si le WMS échoue ensuite. Acté en D25 ; CLAUDE.md nuancé,
L4.1 retiré de la ROADMAP (reliquat : exploration Metrics, rapport à part).

Vérifications rejouées via le protocole (LIMAGRAIN / LIMAGRAI2512) :
- call_query_api(Products, query_type:1, limit:1) -> success, 1 ligne,
  queryType:1 dans la réponse.
- call_query_api(Products, query_type:3) -> erreur structurée contenant
  'ApplicationMetricDataContext' ne contient pas de définition pour 'Products'.
- call_query_api(Products, query_type:7) -> erreur locale nommant les 4
  contextes, aucun [API] POST/GET dans stderr.
- query_wms_entities(Container, limit:1) sans query_type -> comportement
  inchangé (resolvedTableName Containers, Reading, pas de champ queryType).
- call_query_api(FooBar123, query_type:1) -> transmis tel quel (payload
  QueryType:1 Expression Context.FooBar123...), erreur WMS
  ApplicationWritingRepository + warning de résolution dans la réponse.
- count_wms_entities(Product, query_type:1) -> count 51145 (~51160).
Baseline : tools/list 23, resources 6, rejet D23 d'un paramètre inconnu OK.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 11:17:10 +02:00
Arthur Ria 88dab289cc L4.0 (suite) : retire L4.0 de la ROADMAP, oublié au commit précédent
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 11:16:17 +02:00
Arthur Ria 35b53dbef5 Passation lot 4 : query_type, application AD/workflow, catalog D3 (L4.0-L4.2)
Mesures rafraîchies du 25/08/2026 : Writing (QueryType 1) répond 1 ligne
sur Context.Products, Metrics (3) existe sans Products, CustomApp
renvoie ses workflows CST_ sous la clé entities de GetByApplication.
Découverte consignée en L4.0 : la resource api://catalog documente un
exemple QueryType: 1 (le piège D3), un Select dans l'expression et
l'entité fantôme Aliases.

D25 (rapport D3/query_type) et D26 (clés de cache par application)
réservées. L4.3-L4.5 et l'exploration Metrics explicitement hors
périmètre. Le point délicat resolver/Writing est cadré : nom inconnu du
Reading transmis tel quel avec warning quand query_type != 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 10:58:50 +02:00
Arthur Ria b37c2ac251 L3.1c : acte le contrat de troncature en D24, retire le lot 3 de la ROADMAP
Les deux bornages (L3.1a pagination, L3.1b plafond de volume) partagent
le même vocabulaire de signal — truncated présent uniquement quand la
réponse est coupée, hint actionnable, returned vs total avant coupe —
mais gardent des implémentations locales : paginer et plafonner un
volume sont deux mécanismes distincts, un helper commun forcerait une
abstraction qu'ils n'ont pas. D24 consigne ce contrat, les garde-fous
de cadrage (défauts inchangés, mesure protocolaire qui fait foi) et le
changement de sens de totalParameters.

ROADMAP : L3.1 livré, le lot 3 devenait vide — section retirée ; la
référence à L3.1 dans L4.5 (QueryExecuteStream) renvoie désormais à
D24. read_recent_logs est laissé tel quel : sans helper partagé, rien
de gratuit à lui apporter (L3.1c).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 10:36:37 +02:00
Arthur Ria 37c68a4d9a Révision lot 2 : validé ; log du resolver corrigé, concurrence des appels consignée
Les vérifications attendues des quatre correctifs ont été rejouées via le
protocole et passent toutes : résolution Container/Alias/Item (échec avant
tout POST, 6 GET seulement), rejet des paramètres inconnus et requis
manquants, garde-fous get_workflow_details/search_logs, corps STS dans
les erreurs d'auth sans fuite de credential. Contrôle latéral séquentiel :
la bascule EUROTRAFIC reconstruit bien la table par tenant (280 entités,
7 applications, contre 288/5 sur LIMAGRAIN).

Trivialité corrigée : tableNames.size (undefined sur un tableau) ->
.length dans le log de chargement du resolver.

Découverte de révision consignée en point ouvert : le serveur traite les
tools/call en concurrence, une bascule de profil pendant des appels en
vol les fait partir sur le nouveau profil.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 09:35:37 +02:00
Arthur Ria 808586e615 L3.2 : fait remonter statut et corps de la réponse STS dans les erreurs d'auth
authenticate() ré-enveloppait l'erreur axios en "Authentication failed:
Request failed with status code 400" et jetait le corps de la réponse du
STS, qui contenait le diagnostic exact ({"error":"invalid_request",
"error_description":"Tenant not found"} sur le profil AD).

Réutilise _enrichHttpError (L1.1) dans authenticate() et
refreshOAuthToken(), avec payload volontairement omis : il contient les
credentials (password grant) ou le refresh_token ; l'helper n'inclut
jamais les headers. Le chemin "token trop vieux -> password grant" de
refreshOAuthToken() sort du try : un échec d'authenticate() y était
rattrapé pour... rappeler authenticate() à l'identique ; il propage
désormais son erreur enrichie directement.

Mesure (via le protocole) : switch_wms_profile("AD") puis
count_wms_entities("Products") ->
  Count failed for Products: Authentication failed: POST
  https://10.255.255.2/EasySTS/OAuth/Token failed (HTTP 400): Request
  failed with status code 400
  Response body: {"error":"invalid_request","error_description":"Tenant
  not found"}
Aucun credential ni header dans la réponse (vérifié : pas de
password/Basic/Bearer/payload).

ROADMAP : L3.2 retirée, point ouvert "profil AD" mis à jour.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 17:36:26 +02:00
Arthur Ria 97ab56f928 L2.3 : garde-fous get_workflow_details et search_logs
Deux anomalies préexistantes au lot 1, mesurées le 24/08/2026 :

- get_workflow_details({}) renvoyait success: true avec le premier
  workflow du cache : getWorkflowDetails() comparait w.Id/w.Code/w.Name,
  clés qui n'existent pas sur les objets AD réels (minuscules, D5) —
  undefined === undefined matchait. Clés mortes supprimées (id et name
  seuls existent, les parseInt sur des GUID étaient morts aussi), garde
  d'entrée rejetant workflow_id absent avec renvoi vers search_workflows.
- search_logs({}) plantait en "Cannot read properties of undefined
  (reading 'toLowerCase')" : garde d'entrée nommant "keyword" avec un
  exemple d'appel.

Le wrapper D23 rejette déjà ces appels via required — les gardes côté
code restent, la validation SDK n'étant pas garantie pour les appelants
directs des services.

Mesures :
- via le protocole, les deux appels {} -> "Paramètre(s) requis
  manquant(s) pour ... " (wrapper D23)
- gardes appelées en direct (sans wrapper) :
  getWorkflowDetails(undefined) jette "workflow_id est requis (id ou nom
  exact du workflow)..." ; search_logs({}) répond success: false avec le
  message nommant keyword
- get_workflow_details avec un id réel (2e workflow du cache, pas le
  premier) -> objet brut complet ($id, validFrom, ..., data), id/name
  conformes à la recherche

ROADMAP : L2.3 retirée, lot 2 soldé.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 17:34:38 +02:00
Arthur Ria 5386f54922 L2.2 : rejette les paramètres inconnus et les requis manquants (D23)
Mesure V1 (24/08/2026) : le SDK MCP ignore additionalProperties: false —
read_recent_logs({lines: 5}) avec la clause sur le schéma répondait
success: true, returnedLines: 100 (retombée silencieuse sur le défaut).
La validation vit donc dans le wrapper tools/call de src/index.js,
pilotée par les schémas de la table de routage (D22) : paramètre inconnu
ou requis manquant -> erreur structurée nommant le fautif et les
paramètres valides, avant tout dispatch.

Les 23 schémas portent additionalProperties: false — inerte côté SDK,
mais c'est le contrat que lisent les clients. Pas de renommage de
paramètres (écarté, cf. ROADMAP).

Mesures (via le protocole) :
- read_recent_logs({"lines": 5}) -> "Paramètre(s) inconnu(s) pour
  read_recent_logs : lines. Paramètres valides : count, log_file."
- read_recent_logs({"count": 5}) -> succès, returnedLines: 5
- boucle sur 22 outils avec {} (execute_command vérifié statiquement) :
  22/22 répondent, aucun Unknown tool, les 11 outils à paramètres requis
  échouent avec le message actionnable
- handshake : 23 outils, 6 resources

Docs : D23 dans DECISIONS.md, L2.2 retirée de la ROADMAP.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 17:32:15 +02:00
Arthur Ria cb625a7918 L2.1 : résout entity_type via l'API Metadata (D21)
Context.{entity_type} attend le TableName du Metadata, pas le nom
d'entité de l'AD (Container -> Containers, mais Alias -> Alias) : un nom
faux partait en HTTP 500 de compilation LINQ. Nouveau service
entity-resolver.js : table Name|TableName (insensible à la casse) ->
TableName, agrégée sur les applications déployées (via
GET /configuration/applications — les applications sans contexte
requêtable n'y figurent pas et n'apportent 0 entité Metadata), cache TTL
partagé, invalidation par onSwitch (D8). Branché dans wms-query-service
(query/count/schema/search) et call_query_api.

Nom inconnu -> échec avant tout appel réseau de requête, suggestions
proches + renvoi vers get_entity_metadata. Metadata injoignable -> le
nom passe tel quel avec un warning dans la réponse.

Mesures (LIMAGRAIN, via le protocole) :
- query_wms_entities("Container", limit 1) -> succès, 1 ligne, résolu
  Containers
- query_wms_entities("Alias") -> succès, invariant (pas de pluriel)
- query_wms_entities("Item") -> "Item" n'existe pas dans le modèle
  Reading. Proches : RFMenuItems, Sites. 288 entités disponibles —
  aucune ligne [API] POST dans stderr
- count_wms_entities("Product") -> 51160
- get_entity_schema("Container") et call_query_api("Container") : mêmes
  résolutions
- 288 TableName distincts sur 5 applications, aucun conflit
  Name -> TableName (mesuré le 24/08/2026)

Docs : D21 dans DECISIONS.md ; CLAUDE.md (piège retiré des points
ouverts, liste d'entités corrigée Aliases -> Alias, entity-resolver dans
la structure) ; exemple singulier/pluriel dans wms://query-examples ;
ROADMAP allégée (cause racine + L2.1 + L3.3 livrés).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 17:28:27 +02:00
Arthur Ria 8c5792da52 Révision lot 1 : validé ; passation lot 2 (L2.1-L2.3 + L3.2), L2.3 consigné
Lot 1 révisé selon la grille : vérifications L1.1/L1.2/L1.3 rejouées en
protocole (22 outils routés + execute_command en statique), diffs lus,
baseline 23/6 et npm test 4/4 confirmés. Deux anomalies préexistantes
découvertes en bouclant sur les outils avec arguments vides :
get_workflow_details({}) renvoie le premier workflow du cache (clés
mortes Id/Code/Name dans la comparaison), search_logs({}) échoue en
TypeError non actionnable — consignées en L2.3.

handoff-lot1.md supprimé (livré), handoff-lot2.md rédigé : D21 et D23
réservés, profil AD signalé cassé (ne pas réinvestiguer), vérifications
attendues par correctif.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 17:13:19 +02:00
Arthur Ria 52b5f90521 Roadmap : profil AD en échec (tenant introuvable), erreurs d'auth muettes (L3.2)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 17:04:46 +02:00
Arthur Ria e5614f3b60 Roadmap : retire le lot 1 livré, invalide la piste ClientModule (L4.3)
Le lot 1 (erreurs HTTP détaillées, routage par table, projections des
workflows) est livré et vérifié contre le WMS réel — il sort de la
roadmap. D22 étant écrite, L3.2 est ajusté en conséquence.

L4.3 est corrigé d'après mesure : le champ ClientModule de QueryExecute
est accepté mais sans effet observable dans les logs du WMS — une
requête en échec envoyée avec ClientModule: "MCP-WMS" reste tracée
« Execute error. Client: GNA », et la chaîne n'apparaît dans aucun log.
Le champ n'a donc pas été renseigné.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 16:47:14 +02:00
Arthur Ria 86923542fa Roadmap et décisions : exploitation de la référence API du service
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>
2026-08-24 15:58:28 +02:00
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
Arthur Ria 1a1b9ebe03 Roadmap : lots de correction issus du diagnostic du 24/08
Ajoute ROADMAP.md et le relie depuis README.md et CLAUDE.md.

Origine : un rapport d'usage d'une session Cowork sur le profil LIMAGRAIN a
signalé 8 anomalies. Vérification faite contre le WMS réel, 4 bugs sont
confirmés et reproduits, dont un non signalé par le rapport.

Cause racine commune : entity_type est interpolé dans Context.{entity_type}
sans aucune validation, alors que le nom attendu est le TableName de l'API
Metadata et non le nom d'entité de l'AD. Container -> Containers, mais
Alias -> Alias : c'est un mapping, pas une règle de pluralisation. L'API
Metadata connaît 232 entités là où le MCP en expose 12 en dur, et la liste
documentée était fausse (Aliases n'existe pas).

Lot 1 (déblocage) : corps des erreurs HTTP remonté, routage des outils par
table explicite, projections de champs des workflows.
Lot 2 (fond) : résolution des entités via l'API Metadata, rejet des
paramètres inconnus.
Lot 3 : bornage des sorties volumineuses, documentation.

Trois propositions du rapport sont explicitement écartées, avec leur raison :
uniformisation des noms de paramètres, indexStatus sur generic_search, outil
dédié d'aide à la syntaxe.

CLAUDE.md : la section « Points ouverts » renvoie désormais vers la roadmap et
avertit des deux pièges non encore corrigés.

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