L5.4 : rendre les autres applications visibles depuis les recherches
Cas reel du 25/08/2026 : une session Cowork cherchant des workflows CST_ sans
passer application="CustomApp" a conclu que l'AD n'en contenait aucun -- alors
que CustomApp en porte 153. Le parametre application existait bien (D26) et
etait documente ; ce qui manquait, c'est que RIEN dans la reponse ne disait
qu'on n'avait regarde qu'une application sur neuf. Un defaut silencieux se lit
comme une exhaustivite.
search_workflows et search_ad_elements rappellent desormais TOUJOURS
l'application effectivement interrogee (plus seulement quand le parametre a ete
passe), et ajoutent un hint quand la recherche revient vide.
Seuil a 0 resultat, pas "peu" : toute valeur non nulle produirait un hint
parasite sur une recherche legitimement etroite, et le mode d'echec observe est
bien le zero pris pour une absence.
Le hint nomme les autres applications depuis la liste allegee DEJA en cache ;
sans elle il reste generique et renvoie vers list_workflow_categories. Aucun
appel reseau n'est fait pour construire un hint -- ce serait exactement le
prechargement que D26 interdit.
Verifie en execution (protocole, LIMAGRAIN) :
search_workflows {"query":"CST_"} 404 chars
application: "EasyWMS", count: 0, hint nommant CustomApp et renvoyant
vers list_workflow_categories
search_workflows {"query":"CST_"} apres
list_workflow_categories 461 chars
meme hint, enrichi de la liste en cache : Common, Notifications, SmartUI,
WarehouseWebDesigner, GalileoFaults, CustomApp, User, AGV
search_workflows {"query":"CST_","application":"CustomApp"}
count: 44, application: "CustomApp" -- dont CST_SendRejectContainersToPK
search_workflows {"query":"stacker"} 14 192 -> 14 220 chars
count: 50 inchange, application: "EasyWMS" presente, aucun hint parasite
search_ad_elements Command "CST_" 457 chars
application: "EasyWMS", count: 0, meme hint
stderr : aucun fetch d'une application non demandee. Seules EasyWMS et
CustomApp sont chargees, chacune sur demande explicite.
Rebouclage complet apres modification des schemas : 23 outils, 6 resources,
les 23 noms de tools/list atteignent leur module (aucun "Unknown tool" ;
execute_command verifie statiquement, non appele car il ecrit dans le WMS),
D23 rejette toujours un parametre inconnu sur les quatre schemas modifies,
npm test 4/4 en code 0.
Lot 5 retire de la ROADMAP.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -191,7 +191,10 @@ cache incluent l'application pour éviter toute pollution croisée (D26).
|
|||||||
| `ad-service` | **un par (application, type)** (20 types) | `AD_ELEMENT_TYPES` : `View` 200, `Workflow` 5000, `Resource` 15000, autres 100000 |
|
| `ad-service` | **un par (application, type)** (20 types) | `AD_ELEMENT_TYPES` : `View` 200, `Workflow` 5000, `Resource` 15000, autres 100000 |
|
||||||
|
|
||||||
**Ne préchargez jamais les 9 applications** : seule l'application demandée est
|
**Ne préchargez jamais les 9 applications** : seule l'application demandée est
|
||||||
chargée (D26).
|
chargée (D26). `search_workflows` et `search_ad_elements` rappellent toujours
|
||||||
|
l'application interrogée et, sur résultat **vide**, ajoutent un `hint` nommant
|
||||||
|
les autres — construit depuis la liste d'applications **déjà en cache**, jamais
|
||||||
|
par un appel réseau (D26).
|
||||||
|
|
||||||
Les tailles de page par type viennent de l'observation des timeouts serveur —
|
Les tailles de page par type viennent de l'observation des timeouts serveur —
|
||||||
ne les augmentez pas à l'aveugle.
|
ne les augmentez pas à l'aveugle.
|
||||||
|
|||||||
@@ -622,3 +622,26 @@ Règles associées :
|
|||||||
ne détaille que les entrées **effectivement en cache** : la sortie reste
|
ne détaille que les entrées **effectivement en cache** : la sortie reste
|
||||||
bornée quel que soit le nombre d'applications interrogées (D24). Il expose
|
bornée quel que soit le nombre d'applications interrogées (D24). Il expose
|
||||||
aussi les caches de workflows par application.
|
aussi les caches de workflows par application.
|
||||||
|
|
||||||
|
**Le paramètre ne suffisait pas : il faut que la réponse le dise** (lot 5,
|
||||||
|
25/08/2026). Cas réel : une session Cowork cherchant des workflows `CST_*` sans
|
||||||
|
passer `application: "CustomApp"` a conclu que l'AD n'en contenait aucun — alors
|
||||||
|
que `CST_PickingTasksSequencing_PR` et `CST_ChooseDestinationFromPS` existent.
|
||||||
|
Le paramètre était disponible et documenté ; ce qui manquait, c'est que **rien
|
||||||
|
dans la réponse ne disait qu'on n'avait regardé qu'une application sur neuf**.
|
||||||
|
Un défaut silencieux se lit comme une exhaustivité.
|
||||||
|
|
||||||
|
`search_workflows` et `search_ad_elements` rappellent donc **toujours**
|
||||||
|
l'application effectivement interrogée (plus seulement quand le paramètre a été
|
||||||
|
passé), et ajoutent un `hint` quand la recherche revient **vide** :
|
||||||
|
|
||||||
|
- Seuil à **0 résultat**, pas « peu ». Toute valeur non nulle produirait un hint
|
||||||
|
parasite sur une recherche légitimement étroite, et le mode d'échec observé
|
||||||
|
est bien le zéro pris pour une absence.
|
||||||
|
- Le hint nomme les autres applications depuis la liste allégée **déjà en
|
||||||
|
cache** ; sans elle, il reste générique et renvoie vers
|
||||||
|
`list_workflow_categories`. **Jamais de fetch pour construire un hint** —
|
||||||
|
ce serait précisément le préchargement que cette décision interdit.
|
||||||
|
- Il nomme `CustomApp` en clair, sauf quand c'est déjà l'application
|
||||||
|
interrogée : c'est une connaissance statique, déjà portée par les
|
||||||
|
descriptions d'outils, pas une donnée à aller chercher.
|
||||||
|
|||||||
-31
@@ -82,37 +82,6 @@ plus riche que `/AD/api/Application/GetAll`), `GET /healthcheck?tenantCode=` et
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Lot 5 — Clore la famille D24 (rejets client sur sorties volumineuses)
|
|
||||||
|
|
||||||
Mesures du 25/08/2026 (protocole, LIMAGRAIN), toutes au-dessus du seuil de
|
|
||||||
rejet client (~70 000 caractères, D24) :
|
|
||||||
|
|
||||||
| Appel | Taille |
|
|
||||||
|---|---:|
|
|
||||||
| `query_wms_entities("Products", limit: 200)` — Reading ordinaire | **957 234** |
|
|
||||||
| `search_wms_data("PAL")` | **847 543** |
|
|
||||||
| `get_workflow_details(CST_SendRejectContainersToPK)` | ~101 800 |
|
|
||||||
| `call_query_api("Products", query_type: 1, limit: 1)` — **une seule ligne** Writing | **95 288** |
|
|
||||||
|
|
||||||
### L5.4 — Rendre les autres applications découvrables depuis `search_workflows`
|
|
||||||
|
|
||||||
Cas réel (25/08/2026, session Cowork sur LIMAGRAIN) : une session cherchant
|
|
||||||
des workflows `CST_*` sans passer `application: "CustomApp"` a conclu à tort
|
|
||||||
« l'AD contient 4 012 workflows, aucun CST_ » — alors que
|
|
||||||
`CST_PickingTasksSequencing_PR` et `CST_ChooseDestinationFromPS` existent bien
|
|
||||||
dans CustomApp (vérifié en révision). Le paramètre `application` (D26) existe,
|
|
||||||
mais rien dans la **réponse** ne signale qu'on n'a regardé qu'une application.
|
|
||||||
|
|
||||||
Ajouter aux réponses de `search_workflows` (et `search_ad_elements`) un rappel
|
|
||||||
peu coûteux : l'application interrogée, et — quand la recherche renvoie peu ou
|
|
||||||
pas de résultats — un hint listant les autres applications (la liste allégée
|
|
||||||
d'`Application/GetAll` est déjà en cache, D26) avec renvoi vers le paramètre
|
|
||||||
`application`. Aucun préchargement des autres applications (D26).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Écarté
|
## Écarté
|
||||||
|
|
||||||
| Proposition | Raison |
|
| Proposition | Raison |
|
||||||
|
|||||||
@@ -275,6 +275,7 @@ function getAvailableTypes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
resolveApplication,
|
||||||
getElements,
|
getElements,
|
||||||
searchElements,
|
searchElements,
|
||||||
getElementDetails,
|
getElementDetails,
|
||||||
|
|||||||
@@ -133,6 +133,49 @@ async function fetchApplications() {
|
|||||||
return applicationsCache;
|
return applicationsCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liste des applications déjà en cache, ou null si le cache est vide/expiré.
|
||||||
|
* Ne déclenche AUCUN appel réseau — c'est ce qui permet d'enrichir une réponse
|
||||||
|
* de recherche sans jamais précharger une application non demandée (D26).
|
||||||
|
* @returns {Array<{name: string, id: string, version: number}>|null}
|
||||||
|
*/
|
||||||
|
function getCachedApplications() {
|
||||||
|
if (applicationsCache && applicationsTimestamp &&
|
||||||
|
Date.now() - applicationsTimestamp < CACHE_TTL) {
|
||||||
|
return applicationsCache;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hint de découvrabilité (L5.4). Une recherche n'interroge qu'UNE application
|
||||||
|
* sur les neuf déclarées, et rien dans la réponse ne le disait : une session
|
||||||
|
* cherchant des workflows `CST_*` sans `application: "CustomApp"` a conclu à
|
||||||
|
* tort qu'il n'y en avait aucun (25/08/2026).
|
||||||
|
*
|
||||||
|
* Les autres applications sont nommées depuis la liste allégée **déjà en
|
||||||
|
* cache** ; sans elle, le hint reste générique et renvoie vers
|
||||||
|
* `list_workflow_categories` — jamais de fetch pour construire un hint.
|
||||||
|
*
|
||||||
|
* @param {string} application - application effectivement interrogée
|
||||||
|
* @param {string} sujet - ce qui a été cherché ('workflow', 'élément Command'…)
|
||||||
|
*/
|
||||||
|
function buildOtherApplicationsHint(application, sujet) {
|
||||||
|
const cached = getCachedApplications();
|
||||||
|
const others = (cached || []).map(a => a.name).filter(n => n !== application);
|
||||||
|
|
||||||
|
const liste = others.length
|
||||||
|
? `Autres applications déclarées sur ce tenant : ${others.join(', ')}.`
|
||||||
|
: `Appelez list_workflow_categories pour lister les autres applications déclarées.`;
|
||||||
|
|
||||||
|
const custom = application.toLowerCase() === 'customapp'
|
||||||
|
? ''
|
||||||
|
: ` Le spécifique client (préfixe CST_) vit dans "CustomApp" : relancez avec application: "CustomApp".`;
|
||||||
|
|
||||||
|
return `Aucun ${sujet} trouvé dans l'application "${application}" — c'est la SEULE interrogée, ` +
|
||||||
|
`les autres ne le sont jamais implicitement.${custom} ${liste}`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search workflows by query string.
|
* Search workflows by query string.
|
||||||
* Real AD keys (lowercase, cf. D5): id, name, version, applicationName,
|
* Real AD keys (lowercase, cf. D5): id, name, version, applicationName,
|
||||||
@@ -251,6 +294,9 @@ function getCacheStatus() {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
fetchAllWorkflows,
|
fetchAllWorkflows,
|
||||||
fetchApplications,
|
fetchApplications,
|
||||||
|
getCachedApplications,
|
||||||
|
buildOtherApplicationsHint,
|
||||||
|
resolveApplication,
|
||||||
searchWorkflows,
|
searchWorkflows,
|
||||||
getWorkflowDetails,
|
getWorkflowDetails,
|
||||||
getWorkflowStats,
|
getWorkflowStats,
|
||||||
|
|||||||
+11
-1
@@ -247,15 +247,25 @@ async function searchADElementsTool(args) {
|
|||||||
code: e.code || e.Code
|
code: e.code || e.Code
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// L5.4 : même correctif que search_workflows — l'application interrogée est
|
||||||
|
// toujours rappelée, et un résultat vide signale que les huit autres n'ont
|
||||||
|
// pas été regardées. Le hint se construit depuis la liste d'applications
|
||||||
|
// DÉJÀ en cache : aucun appel réseau, aucun préchargement (D26).
|
||||||
|
const effectiveApplication = adService.resolveApplication(application);
|
||||||
|
const hint = mappedResults.length === 0
|
||||||
|
? workflowService.buildOtherApplicationsHint(effectiveApplication, `élément ${element_type}`)
|
||||||
|
: null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [{
|
||||||
type: 'text',
|
type: 'text',
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
elementType: element_type,
|
elementType: element_type,
|
||||||
...(application ? { application } : {}),
|
application: effectiveApplication,
|
||||||
query,
|
query,
|
||||||
count: mappedResults.length,
|
count: mappedResults.length,
|
||||||
|
...(hint ? { hint } : {}),
|
||||||
elements: mappedResults
|
elements: mappedResults
|
||||||
}, null, 2)
|
}, null, 2)
|
||||||
}]
|
}]
|
||||||
|
|||||||
@@ -134,13 +134,23 @@ async function searchWorkflows(args) {
|
|||||||
|
|
||||||
const results = await workflowService.searchWorkflows(query, category, limit, application);
|
const results = await workflowService.searchWorkflows(query, category, limit, application);
|
||||||
|
|
||||||
|
// L5.4 : l'application interrogée est TOUJOURS rappelée (pas seulement quand
|
||||||
|
// elle a été passée), et un résultat vide dit qu'une seule application sur
|
||||||
|
// neuf a été regardée — c'est ce silence qui avait fait conclure à tort à
|
||||||
|
// l'absence de workflows CST_.
|
||||||
|
const effectiveApplication = workflowService.resolveApplication(application);
|
||||||
|
const hint = results.length === 0
|
||||||
|
? workflowService.buildOtherApplicationsHint(effectiveApplication, 'workflow')
|
||||||
|
: null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [{
|
||||||
type: 'text',
|
type: 'text',
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
...(application ? { application } : {}),
|
application: effectiveApplication,
|
||||||
count: results.length,
|
count: results.length,
|
||||||
|
...(hint ? { hint } : {}),
|
||||||
// Clés réelles de l'API AD (minuscules, cf. D5) : id, name, version,
|
// Clés réelles de l'API AD (minuscules, cf. D5) : id, name, version,
|
||||||
// applicationName, commonInfo. Pas de code/category/description.
|
// applicationName, commonInfo. Pas de code/category/description.
|
||||||
workflows: results.map(w => {
|
workflows: results.map(w => {
|
||||||
|
|||||||
Reference in New Issue
Block a user