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>
This commit is contained in:
Arthur Ria
2026-08-25 15:54:54 +02:00
parent 097b76c7ef
commit 242b0c0f1c
6 changed files with 116 additions and 34 deletions
+26
View File
@@ -707,6 +707,32 @@ d'un bloc, puis `get_application_summary` en séquentiel : **3/3 avant**, le
cache EasyWMS de LIMAGRAIN (3 944 workflows) survit à la bascule avec un
timestamp neuf ; **3/3 après**, aucun cache peuplé.
**Vide anormal ≠ vide réel.** Les services lisaient `response?.entities || []`
sur les réponses de l'API AD (enveloppe `{ entities: [...] }`, D4). Toute
réponse d'une **autre forme** devenait donc un tableau vide, indistinguable
d'une page finale légitime — et mise en cache avec un timestamp valide : un
cache vide empoisonné pour tout le TTL, sans message. C'est la cause probable
du `count: 0` mesuré sous rafale, et le mode d'échec le plus coûteux du lot :
il se lit comme une réponse.
`src/services/ad-envelope.js` porte le contrat pour les trois sites
(`Workflow/GetByApplication`, `Application/GetAll`, `<Type>/GetByApplication`) :
| Réponse | Traitement |
|---|---|
| `{ entities: [...] }`, `[]` réel compris | rendue telle quelle — une application peut être légitimement vide (`SmartUI` : 0 workflow ; 3 types AD valides mais vides, D17) |
| toute autre forme | **lève** — l'appel échoue, rien n'est mis en cache, l'appel suivant refetche |
**Pas de retry, pas de résilience.** L'anomalie doit être **visible et non
persistante** ; la rattraper la rendrait invisible, ce qui est exactement le
défaut corrigé. `entity-resolver` était déjà conforme : il lève déjà si
`/configuration/applications` ou le Metadata ne rendent aucune entité.
Mesures : `search_workflows` sur `SmartUI``count: 0`, `success: true`,
cache posé (`count: 0`, `valid: true`) et hint L5.4 présent. Les trois sites
face à une réponse `{}` → erreur levée, `{}` en cache, et le fetch suivant
repart normalement.
**Mesures après.** Rafale de 6 (CustomApp) → 1 fetch + 5 joins, les 6 réponses
à `count: 44`. Rafale de 6 (resolver) → 1 chargement, 5 GET Metadata au lieu de
30. Rafale mixte EasyWMS + CustomApp → **un fetch par application**, deux au