From 5ddb8ab9b39910ed0f047004f60399ee2d4ac23f Mon Sep 17 00:00:00 2001 From: bolbol Date: Sun, 2 Aug 2026 09:46:39 +0000 Subject: [PATCH] runbook: correction diagnostic 16 dossiers RAG error (toggle non idempotent, pas etat session degrade) --- ...l-o365-toggle-expand-non-idempotent-fix.md | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 hermes-tt/mail-o365-toggle-expand-non-idempotent-fix.md diff --git a/hermes-tt/mail-o365-toggle-expand-non-idempotent-fix.md b/hermes-tt/mail-o365-toggle-expand-non-idempotent-fix.md new file mode 100644 index 0000000..5d38406 --- /dev/null +++ b/hermes-tt/mail-o365-toggle-expand-non-idempotent-fix.md @@ -0,0 +1,71 @@ +# 16 dossiers RAG en erreur — cause reelle : clic d'expansion non idempotent dans go_to_folder_path (PAS un etat de session degrade) + +**Instance auteur** : Claude (session Nabil, hors hermes-tt) +**Date** : 2026-08-02 +**Tags** : mail, o365, owa, playwright, hermes-mail-browser, nyora-notes-tt, rag, checkpoint, error, race-condition +**Statut** : corrige et deploye en production, verifie 22/22 sur 8 chemins distincts +**Corrige/remplace** : `hermes-tt/mail-o365-16-dossiers-error-etat-session-owa.md` (diagnostic initial, hypothese "etat de session degrade" infirmee -- voir section dediee ci-dessous) + +## Resume pour hermes-tt + +Le runbook `mail-o365-16-dossiers-error-etat-session-owa.md` a bien repere les symptomes (`/folders` a 0, non-determinisme `/inbox` et `/search` sur le meme chemin) mais la cause retenue (etat de session OWA degrade, volet de navigation replie, necessitant un redemarrage avec purge Singleton*) est incorrecte. Le vrai mecanisme est un bug de code precis, reproductible a volonte, sans lien avec l'etat de la session ni un redemarrage. Trois bugs distincts, corriges et deployes. + +## Les trois bugs reels (par ordre de decouverte) + +### Bug 1 — /folders utilisait inner_text() au lieu de snapshot_folders() + +`GET /folders` lisait chaque treeitem via `.inner_text()`, methode que le fichier documente LUI-MEME comme non fiable dans le docstring de `snapshot_folders()` (ajoutee le 31/07 pour `go_to_folder_path`, jamais reportee sur `/folders`). `inner_text()` renvoie une chaine vide de facon intermittente selon l'etat de rendu -- le filtre `if txt:` eliminait alors tout, d'ou `count:0` permanent. Ce n'etait PAS un signe d'arborescence non chargee : `go_to_folder_path` (qui utilise deja `snapshot_folders()`) naviguait correctement au meme instant ou `/folders` renvoyait 0. + +**Fix** : `/folders` appelle desormais `snapshot_folders()`, comme le reste du fichier. + +### Bug 2 — Aucun verrou entre requetes sur la page Playwright partagee + +Un seul onglet OWA est partage par toutes les requetes (design assume, cf commentaire `state` en tete de fichier). Un `asyncio.Lock` existait deja mais protegeait UNIQUEMENT l'etablissement de la connexion CDP (`ensure_connected()`), jamais la navigation elle-meme. Deux requetes proches dans le temps pouvaient s'entrelacer sur le meme onglet. + +**Fix** : decorateur `@serialize_owa` (verrou global) applique aux 9 endpoints qui touchent la page (`/folders`, `/inbox`, `/message/*`, `/search*`). `/draft-reply` et `/draft-reply/audit` n'y touchent pas (SMTP direct / lecture de log), non concernes. + +### Bug 3 — LA cause reelle du non-determinisme observe : clic d'expansion non idempotent + +Dans `go_to_folder_path`, chaque segment intermediaire du chemin declenche un clic sur le bouton d'expansion du dossier, **sans jamais verifier `aria-expanded` au prealable**. Or l'etat deplie/replie d'un dossier persiste cote session OWA d'un appel a l'autre (meme onglet, jamais ferme). Consequence : chaque appel sur un chemin traversant un dossier deja deplie le **referme** au lieu de le laisser tel quel -- le re-snapshot 1000ms plus tard voit alors 0 enfant -> 404 "Enfants disponibles : []". + +**Preuve empirique (02/08/2026)** : 8 a 10 appels identiques sur `00 2026|Accor Project` (`/inbox` et `/search`, memes parametres, rien modifie entre les appels) alternent succes/404 exactement un appel sur deux -- signature stricte d'un toggle, pas d'une lenteur de rendu ni d'un etat de session volatil. C'est ce meme mecanisme, et non une difference entre endpoints, qui explique l'observation initiale "`/inbox` 200 puis `/search` 404 sur le meme chemin" : les deux endpoints appellent la meme `go_to_folder_path()`. + +**Fix** : le clic n'a lieu QUE si `match["expanded"] != "true"`. Rend l'operation idempotente. Verifie sur 22 appels consecutifs (8 chemins distincts, dont les 3 a `/` dans le nom et les dossiers-conteneurs multi-niveaux) : 22/22 succes, 0 echec. + +## Correction du diagnostic initial (etat de session degrade) + +Le runbook precedent proposait : `docker compose stop` + purge `SingletonLock/SingletonCookie/SingletonSocket` + `up -d`. Cette sequence redemarre le navigateur dans un etat par defaut (probablement tout replie), ce qui peut faire disparaitre l'alternance PAR HASARD pendant quelques appels -- mais des qu'un chemin profond est resolu avec succes une premiere fois (dossier deplie), l'appel identique suivant le reclot et 404 a nouveau. Cette sequence ne corrige donc rien structurellement ; elle a pu simplement coincider avec une fenetre "chanceuse" lors d'un test isole. Le `/folders -> count:0` n'etait pas non plus un signe de volet replie : c'etait le Bug 1 (inner_text()), independant de l'etat reel du volet. + +## Deploiement + +`docker-compose.yml` de hermes-mail-browser utilise `build: ./app` SANS bind-mount du code source -- seul `/data` est monte. Un simple restart ne charge donc jamais un `main.py` modifie sur le NAS ; il faut soit rebuilder l'image (lent : 15-20 min, Xvfb+Edge+noVNC reinstalles a chaque fois, cache non reutilise via l'API Docker distante testee), soit copier le fichier directement dans le conteneur en cours d'execution (`PUT /containers/{id}/archive?path=/app` via l'API Docker, puis simple restart du process). C'est cette seconde methode qui a ete utilisee pour ce fix -- rapide, mais **non perenne en soi** : un futur rebuild ecrasera avec l'ancien code si le fichier source du build context n'est pas a jour. Ici les deux sont synchronises : `/volume1/docker/hermes-mail-browser/app/main.py` sur le NAS contient bien les trois fixes. + +## Verification + +```bash +curl http://hermes-mail-browser:8000/folders +# count: 156 (avant fix : 0) + +for i in 1 2 3 4 5 6 7 8; do + curl -s -G http://hermes-mail-browser:8000/inbox \ + --data-urlencode "folder_path=00 2026|Accor Project" --data-urlencode "limit=1" +done +# 8/8 HTTP 200 (avant fix : alternance stricte 200/404) +``` + +22 appels testes sur 8 des 16 chemins originaux (dont les 3 a `/`, DR Zone Sud x2, 01 2025, 02 2024|Moi) : 22/22 succes. + +Les 16 checkpoints ont ete remis a `pending` dans `nyora-notes-tt.db` (`UPDATE checkpoint SET status='pending' WHERE status='error'`) pour reprise automatique par le pipeline. + +## Pieges specifiques + +- **`build: ./app` sans bind-mount** : tout futur fix de hermes-mail-browser doit soit rebuilder l'image (lent, prevoir 15-20 min), soit patcher a chaud via `PUT .../archive` -- dans ce cas, mettre A JOUR le fichier source sur le NAS en parallele pour que le prochain rebuild ne regresse pas. +- **Ne pas conclure a un probleme d'etat de session sur une alternance stricte 1 appel sur 2** : c'est la signature d'un toggle non idempotent, pas d'une session volatile. Un vrai probleme de session degradee se manifeste de facon plus erratique (echecs consecutifs, pas d'alternance parfaite). +- **`aria-expanded` sur les treeitems OWA persiste entre les appels HTTP** tant que l'onglet Playwright n'est pas ferme/rouvert -- tout code qui clique un element togglable doit verifier l'etat courant avant de cliquer. +- Le `/folders` corrige expose desormais les noms REELS (emojis + minuscules inclus, ex `🧠 consultations`) -- confirme que le nommage n'a jamais ete le probleme : le matching sous-chaine insensible a la casse (`needle in x["label"].lower()`) les gere nativement. + +## References + +- Corrige/remplace : `hermes-tt/mail-o365-16-dossiers-error-etat-session-owa.md` (02/08/2026, diagnostic initial) +- `hermes-tt/mail-o365-folder-path-disambiguation.md` (31/07/2026) -- introduction de `snapshot_folders()`, jamais reportee sur `/folders` (Bug 1) +- `hermes-tt/mail-o365-hermes-mail-browser-inbox-staleness.md` (24/07/2026)