- hermes-tt/nyora-notes-tt-message-id-elem-id-volatile-08-08-2026.md : cycle complet --
hypothese elem_id stable, test insuffisant (1 msg position 0, appels rapproches) qui l'a
faussement valide, test rigoureux (19 msg, ensembles disjoints, 0/20 meme index) qui
l'infirme, cause (id de rendu DOM volatile), decision (message_id reste hash SHA256 stable,
conservation conversation_id data-convid niveau thread + fix retry /search count:0), garde-fou
dedup (399 notes en dossiers 'done' jamais re-scannes -> pas de doublon).
- PROTOCOL-INFRA.md : regle "id DOM d'un SPA jamais presume stable" (tester >=2 rendus reels +
plusieurs echantillons) + fix /search count:0 transitoire + piege split('|') sur attrs.
- _INDEX.md : entree ajoutee.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
243 lines
21 KiB
Markdown
243 lines
21 KiB
Markdown
# PROTOCOL-INFRA — Regles operationnelles infra
|
|
|
|
## Protocole post-deployement (OBLIGATOIRE)
|
|
|
|
Apres tout deployement reussi ou probleme resolu, avant de cloturer la mission :
|
|
|
|
1. Creer un runbook dans le repo Gitea bolbol/nas-runbooks
|
|
- Ecrire UNIQUEMENT dans le dossier hermes-[identite]/
|
|
- Utiliser le template /opt/data/RUNBOOK-TEMPLATE.md
|
|
- La section "Ce qui NE fonctionne PAS" est OBLIGATOIRE
|
|
|
|
2. Poster une note NyoraNotes
|
|
- Tags : [infra, runbook]
|
|
- Contenu : resume du probleme, solution, lien runbook Gitea
|
|
|
|
3. Mettre a jour _INDEX.md dans nas-runbooks
|
|
- Ajouter l entree dans le tableau de l instance
|
|
|
|
4. git add . && git commit && git push vers Gitea
|
|
|
|
## Regle de contribution
|
|
- Ecriture : chaque instance ecrit UNIQUEMENT dans son dossier hermes-[nom]/
|
|
- Lecture : tous les dossiers sont accessibles en lecture
|
|
- Le runbook sans les echecs n a pas de valeur — toujours documenter les tentatives infructueuses
|
|
|
|
## Acces Gitea nas-runbooks
|
|
URL clone : http://192.168.100.33:3232/bolbol/nas-runbooks.git
|
|
Dossier local suggere : /opt/data/workspace/nas-runbooks/
|
|
|
|
---
|
|
|
|
## Protocole de suivi de projet — checklist des operations validees
|
|
|
|
Pour tout projet a plusieurs etapes validees en discussion (surtout sur plusieurs sessions ou
|
|
avec un budget forfait limite) : la liste ordonnee des operations validees devient une
|
|
checklist markdown dans une NyoraNote dediee, plutot que d'etre reconstituee de memoire ou
|
|
re-diagnostiquee a chaque session.
|
|
|
|
- Creer la note des qu'un plan a plusieurs etapes est valide, taguee `checklist-projet`
|
|
(+ tags du projet)
|
|
- Cocher au fur et a mesure de l'execution reelle (pas de la simple discussion)
|
|
- Ajouter une ligne des qu'une nouvelle etape est validee par Nabil en conversation -- jamais
|
|
de reformulation retroactive de ce qui a ete decide
|
|
- En debut de session sur un projet deja entame : chercher la note existante (tag
|
|
`checklist-projet`) avant de re-diagnostiquer un etat deja connu
|
|
|
|
Reference complete de la tactique (pourquoi, comment) : NyoraNote "TACTIQUE -- Checklist des
|
|
operations validees (suivi de projet)", id 75fd1181-3061-480d-ae60-c069ba942ebc.
|
|
|
|
---
|
|
|
|
## REGISTRE DES SERVICES — Mise a jour obligatoire
|
|
|
|
Le fichier /volume1/docker/ports-registry.md est la source de verite de l'etat du NAS.
|
|
Il contient deux sections distinctes a maintenir en permanence :
|
|
|
|
### 1. SERVICES ACTIFS (en tete du fichier)
|
|
Mise a jour OBLIGATOIRE a chaque installation OU desinstallation :
|
|
- Installation : ajouter la ligne avec statut ACTIF, port, domaine, notes
|
|
- Desinstallation : changer le statut en "DESINSTALLE JJ/MM/AAAA", liberer le port
|
|
- Ne JAMAIS supprimer une ligne — les services desinstalles restent visibles avec leur date
|
|
|
|
### 2. Historique des modifications (fin du fichier)
|
|
Ajouter une ligne datee pour CHAQUE action :
|
|
- Format : | AAAA-MM-JJ | ACTION | Port | Service |
|
|
- Actions a documenter : Deploiement, DESINSTALLATION, Migration, Changement de port
|
|
|
|
### Verification avant documentation
|
|
Avant de marquer un service comme DESINSTALLE, TOUJOURS verifier :
|
|
curl --max-time 4 http://172.17.0.1:<PORT> -o /dev/null -w "HTTP %{http_code}"
|
|
Si le port repond → le service est encore actif → NE PAS marquer DESINSTALLE
|
|
|
|
### Chemin du fichier
|
|
- Copie locale NAS : /volume1/docker/ports-registry.md
|
|
- Copie nas-runbooks : /volume1/docker/nas-runbooks/common/ports-registry.md
|
|
- Les deux doivent rester synchronisees (copier l'un vers l'autre apres modification)
|
|
- Push Gitea obligatoire apres toute modification
|
|
|
|
|
|
---
|
|
|
|
## Skills transverses — deploiement automatique sur les 3 instances
|
|
|
|
Quand une lecon apprise doit etre appliquee automatiquement par l agent (pas juste documentee pour lecture humaine), la deployer comme skill actif plutot que de compter sur un rappel manuel a chaque fois :
|
|
|
|
1. Creer data/skills/<nom-skill>/SKILL.md sur les 3 instances (hermes-tt, hermes-nyora, hermes-perso), avec un frontmatter description contenant les mots-cles qui doivent declencher le skill
|
|
2. Supprimer le cache .skills_prompt_snapshot.json (racine data/ et data/.hermes/) sur les 3 instances pour forcer la regeneration de l index
|
|
3. Redemarrer les 3 containers hermes-agent-* (via socket Docker /var/run/docker.sock depuis mcp-nas, ou Portainer)
|
|
4. Documenter quand meme via le protocole standard (runbook common/, _INDEX.md, note NyoraNotes) — le skill rend la regle automatique, le runbook garde la tracabilite
|
|
|
|
Exemples deployes le 02/07/2026 : desactivation des skills concurrents a nyora-doc-api (docx/pdf/pptx/xlsx), et skill generation-contenu-volumineux (chunking obligatoire pour eviter la troncature DeepSeek V4 Flash sur les taches lourdes).
|
|
|
|
---
|
|
|
|
## Verification obligatoire avant toute lecture/ecriture sur nas-runbooks depuis mcp-nas
|
|
|
|
Git est ABSENT du container mcp-nas (confirme le 02/07/2026). Toute ecriture sur
|
|
bolbol/nas-runbooks depuis une session mcp-nas passe par l API Gitea (curl + token,
|
|
PUT/POST /api/v1/repos/bolbol/nas-runbooks/contents/<chemin>, avec le sha courant
|
|
recupere par un GET prealable) — jamais par un dossier local suppose a jour.
|
|
|
|
Piege decouvert le 02/07/2026 : /mnt/docker/nas-runbooks etait un clone git reel
|
|
mais sur branche locale master, alors que le remote n a qu une branche main. 14
|
|
commits locaux (15-23 juin, jamais pousses) contenaient du contenu reel absent du
|
|
remote. Cause probable : le binaire git a disparu de mcp-nas avant l etape push.
|
|
Fix applique : recuperation des 14 fichiers via l API vers main, _INDEX.md corrige,
|
|
clone local renomme en nas-runbooks.STALE-clone-local-jamais-pousse-20260702
|
|
(conserve pour inspection, plus utilise comme source).
|
|
|
|
Regle : avant de lire ou modifier un fichier sous /mnt/docker/nas-runbooks (ou tout
|
|
repo Gitea) depuis mcp-nas, verifier d abord via l API que le contenu local
|
|
correspond au remote reel :
|
|
GET /api/v1/repos/bolbol/<repo>/branches
|
|
GET /api/v1/repos/bolbol/<repo>/contents/<chemin>
|
|
Si un vrai clone git fonctionnel est necessaire (multi-fichiers, historique),
|
|
le faire depuis le Mac ou git est present, chemin partage /Volumes/docker ==
|
|
/volume1/docker.
|
|
|
|
## gstack (garrytan/gstack) — decision actee le 02/07/2026
|
|
|
|
Installation prevue sur le futur MacBook M5 Pro via Claude Code natif, PAS sur
|
|
hermes-perso (mem_limit container 600m incompatible Chromium/Playwright, routing
|
|
Sonnet/Opus incompatible regle DeepSeek exclusif Hermes, bug upstream #2015
|
|
AskUserQuestion/clarify non resolu sur --host hermes). Detail complet :
|
|
common/GSTACK-EVALUATION-MACBOOK-VS-HERMES.md.
|
|
|
|
## Piege .env vs docker-compose.yml — decouvert le 03/07/2026
|
|
|
|
Ajouter une variable au .env d un service NE SUFFIT PAS si le
|
|
docker-compose.yml declare un bloc environment: qui whiteliste
|
|
explicitement chaque variable transmise au container (cas
|
|
d hermes-platform/docker-compose.yml). Une variable absente de ce bloc
|
|
n atteint jamais le container meme si elle est correcte dans le .env.
|
|
|
|
Regle : pour toute nouvelle variable d integration (cle API, URL de
|
|
service), toujours verifier ET modifier les deux fichiers :
|
|
1. .env (definition de la valeur)
|
|
2. docker-compose.yml, bloc environment: du/des service(s) concerne(s)
|
|
(transmission de la valeur au container)
|
|
|
|
Verification post-fix : docker exec <container> env | grep <VAR> sur
|
|
le container recree.
|
|
|
|
Cas reel : NYORA_DOC_API_KEY manquante des deux fichiers pour les 3
|
|
instances Hermes -> 401 sur nyora-doc-api. Detail complet :
|
|
common/nyora-doc-api-hermes-guide.md, section "Panne corrigee le
|
|
03/07/2026".
|
|
|
|
|
|
## RÈGLE CRITIQUE — Cron Hermes et publish n8n : une modif écrite sur disque n'est pas une modif live
|
|
|
|
### Cron Hermes (jobs.json)
|
|
Le service cron de chaque agent Hermes (hermes-agent-tt / hermes-agent-nyora / hermes-agent-perso) charge jobs.json UNIQUEMENT au démarrage du container. Il ne relit jamais le fichier en cours de route. Modifier jobs.json (horaire, prompt, modèle) laisse le service tourner avec l'ancienne config en mémoire tant que le container n'est pas redémarré.
|
|
- Après toute modification de jobs.json : redémarrer le container agent correspondant (nom réel : hermes-agent-tt / hermes-agent-nyora / hermes-agent-perso — PAS hermes-tt/hermes-nyora/hermes-perso, ce sont les containers hermes-workspace-*).
|
|
- Restart via API Portainer : POST /api/endpoints/2/docker/containers/{id}/restart timeout systématiquement sur cette instance. Utiliser stop puis start explicites (2 appels), pas restart.
|
|
- Après redémarrage, TOUJOURS vérifier next_run_at dans jobs.json correspond bien au nouveau schedule — sinon le corriger manuellement (le daemon ne recalcule pas toujours correctement au premier boot).
|
|
- Portainer : endpoint local = id 2. Auth via 172.17.0.1:9000/api/auth (pas 192.168.100.33 depuis un container), credentials dans hermes-platform/.env.
|
|
|
|
### Publish n8n (workflow actif modifié via l'outil update_workflow)
|
|
update_workflow sauvegarde un brouillon (nouveau versionId) mais n'active PAS automatiquement ce brouillon sur un workflow déjà publié — le workflow continue de servir l'ancienne activeVersion. publish_workflow peut échouer silencieusement avec "Version not found" sur un workflow dont la chaîne de versions est corrompue, y compris en réessayant depuis l'UI n8n elle-même (pas un bug de l'outil MCP).
|
|
- Après toute modification d'un workflow n8n déjà actif : vérifier avec get_workflow_details que `versionId` == `activeVersionId`. Si différent, le changement n'est PAS en production.
|
|
- Si publish_workflow échoue de façon persistante (même après unpublish_workflow puis republish) : ne pas insister, dupliquer le workflow (bouton Duplicate dans l'UI n8n) — la copie repart avec une chaîne de versions saine et se publie normalement. Archiver l'original cassé (archive_workflow) une fois la copie confirmée active.
|
|
|
|
### Fuseau horaire
|
|
Le NAS et n8n tournent en UTC. Tunis = UTC+1 toute l'année (pas de changement d'heure). Pour un cron en heure de Tunis, toujours retirer 1h à l'expression cron (ex: 7h/12h/20h Tunis = "0 6,11,19 * * *" en UTC).
|
|
|
|
### Leçon générale
|
|
Une réponse "success" d'un outil de modification (update_workflow, edit de jobs.json) ne garantit jamais que le changement est en production. Toujours vérifier l'état réel après coup : next_run_at recalculé pour un cron Hermes, activeVersion == draft pour un workflow n8n.
|
|
|
|
|
|
## Git depuis mcp-nas — canal actuel (2026-07-10)
|
|
|
|
`git` n'est plus présent dans le container mcp-nas **ni sur le NAS**. Le canal standard pour toute écriture Gitea est l'**API HTTP change-files** :
|
|
|
|
- Auth : `GITEA_DEPLOY_TOKEN` (scope write:repository, `.env` hermes-platform), header `Authorization: token <TOK>`. **L'ancien password `bolbol` est périmé (401)** — le runbook `git-push-depuis-mcp-nas.md` est obsolète sur ce point.
|
|
- Endpoint : `POST /api/v1/repos/bolbol/<repo>/contents` avec `files:[{operation:create|update, path, content(base64), [sha]}]` → 1 commit multi-fichiers (Gitea 1.21.11).
|
|
- Réseau : toujours `172.17.0.1:3232` depuis le container. Fichiers NAS lisibles/éditables via le mount `/mnt/docker` = `/volume1/docker`.
|
|
- SSH `Best0f` par mot de passe : non fonctionnel depuis mcp-nas (pas de clé, `SSHPASS` ≠ mdp Best0f) — ne pas compter dessus.
|
|
- Restart de containers sans docker CLI : **API Portainer** (creds `bestof` dans `.env`), `POST /endpoints/{id}/docker/containers/{id}/restart`.
|
|
|
|
|
|
## 2026-07-20 — Partition système `/dev/md0` pleine (95%, 113 Mo restants) — résolu
|
|
|
|
**Symptôme** : `df -h /` sur l'hôte NAS à 95%. Piège : depuis le container mcp-nas, `df -h /` pointe sur `/dev/mapper/cachedev_0` (volume data, 11 To) — toujours `ssh nas-host` pour voir la vraie partition système `/dev/md0` (~2,3 Go, taille fixe DSM).
|
|
|
|
**Méthode** : `du -sx /` sans sudo (Best0f) sous-estime toujours l'usage réel — les dossiers `root` en permissions restrictives (souvent `0700`) sont exclus silencieusement du total, pas juste illisibles en contenu. Comparer `du -sx / 2>/dev/null` au "Used" de `df -h /` ; un écart de plusieurs centaines de Mo pointe vers un dossier root oublié. Lister les coupables : `du -sx / 2>&1 1>/dev/null | grep denied`.
|
|
|
|
**Cause ici** : `/usr/lib/python3.8/site-packages` (`0700 root:root`) contenait une stack data-science/Streamlit complète (pandas, numpy, pyarrow, pillow, altair, jupyter) installée à la main début 2026 dans le Python système de base — pas un paquet Package Center, aucun process actif, aucun lien avec le stack actuel. Prototype abandonné.
|
|
|
|
**Fix** : `sudo rm -rf /usr/lib/python3.8/site-packages/* /usr/etc/jupyter /usr/share/jupyter` → 2,1 Go → 1,7 Go utilisés, 113 Mo → 529 Mo disponibles (95% → 77%). Diagnostic fait en lecture seule par Best0f (sans sudo), suppression exécutée par Nabil (le mot de passe sudo Best0f n'est jamais transmis à un agent). Runbook détaillé : common/partition-systeme-nas-du-vs-df-permissions.md.
|
|
|
|
## REGLE CRITIQUE -- Anti-invention sur chiffres de recherche/benchmarks (2026-07-27)
|
|
|
|
Avant de presenter un chiffre (benchmark, prix, score) dans un rapport : le chiffre doit venir d'une page reellement lue en entier, pas d'un snippet de recherche. Si un fetch demande ne renvoie qu'une coquille vide (page JS, < 500 caracteres utiles) -> le dire explicitement, ne jamais compenser en silence par une recherche generique. Verifier le nom EXACT de la variante (Pro/Max/Flash/base) avant d'attribuer un chiffre -- deux benchmarks avec un score identique = signal d'hallucination a corriger avant envoi, jamais a ignorer. Detail complet : common/anti-hallucination-benchmarks-recherche-chiffree.md.
|
|
|
|
## FIX -- auxiliary.vision mal route sur modeles text-only (2026-07-27)
|
|
|
|
`auxiliary.vision.provider: auto` resout vers le modele principal -- casse systematiquement sur deepseek-v4-flash (text-only). Toute instance avec un modele principal text-only DOIT router `auxiliary.vision` explicitement vers `google/gemini-2.5-flash` via bifrost-proxy (meme base_url/api_key que le modele principal). Applique sur hermes-perso et hermes-tt le 27/07/2026. Detail : common/vision-auxiliaire-routing-text-only-modeles.md.
|
|
|
|
## FIX -- approvals.mode: smart + deny rules sur les 4 instances Hermes (2026-07-27)
|
|
|
|
Passage de manual/auto (valeur invalide sur tt) a `smart` sur hermes-perso, hermes-tt, hermes-nyora, hermes-nabil. `cron_mode: deny` inchange (un job planifie qui tombe sur une commande signalee reste bloque, jamais auto-approuve). Ajout de `approvals.deny` (patterns absolus, bloques avant meme le jugement du modele auxiliaire ou un /yolo) -- rm -rf /*, dd vers /dev/*, redirection vers .env/credentials/secrets, git push --force, docker volume rm/system prune, DROP TABLE/DATABASE ; + TRUNCATE et DELETE Baserow en plus sur hermes-tt. `auxiliary.approval` route explicitement vers deepseek-v4-flash (jamais mimo-v2.5, meme quand c'est le modele principal de l'instance) -- le juge de securite doit etre le modele le plus fiable des deux, pas le defaut. Exception : hermes-nabil (VPS) n'a aucune route deepseek disponible, laisse en auto (mimo-v2.5), ecart documente. Detail : common/smart-approvals-deny-rules-4-instances.md.
|
|
|
|
## FIX -- root cause des tool_calls casses sur hermes-nyora : prompt du job veille, pas mimo-v2.5 (2026-07-27)
|
|
|
|
Les 24 incidents "Unrepairable tool_call arguments" venaient du prompt du cron veille-ia-nexum-4ee61494 qui ordonnait d'ecrire jusqu'a 20 analyses (champs sans limite de longueur) en UN SEUL heredoc -- exact anti-pattern du skill generation-contenu-volumineux, qui perd face a une instruction de prompt precise et contraire. Ce n'etait pas un probleme de fiabilite du modele. Fix : prompt reecrit pour une construction chunkee (1 fichier /tmp/veille_item_NN.json par opportunite, assemblage par script Python, jamais un nouvel appel LLM pour la fusion). Reflexe a generaliser : avant de blamer un modele sur des echecs de tool_call recurrents sur une tache precise, verifier D'ABORD si le prompt de cette tache contredit la regle de generation chunkee. Detail : common/veille-chunking-nyora-root-cause.md.
|
|
|
|
## FIX -- watchdog telegram gateway autonome, sans acces DSM Task Scheduler (2026-07-27)
|
|
|
|
Incident hermes-perso (gateway Telegram bloque 2h17 en silence). Best0f n'a pas de sudo general (scope docker/rsync/journalctl), pas d'acces DSM Task Scheduler, pas de crontab utilisateur disponible -- ne jamais chercher a contourner ca en devinant un mot de passe ou en modifiant sudoers sans geste explicite de Nabil lui-meme. Solution retenue : container autonome `hermes-watchdog-telegram` (image docker:cli + python3, socket Docker monte, --restart unless-stopped) qui verifie toutes les 10 min les 3 instances NAS pour le motif exact de l'incident, redemarre automatiquement si detecte, et n'alerte (webhook veille-infra) que si un redemarrage automatique n'a pas suffi. Pattern reutilisable : toute tache planifiee cote NAS realisable via des commandes docker peut passer par un petit container autonome plutot que par le Planificateur DSM. Detail : common/watchdog-telegram-gateway-container-autonome.md.
|
|
|
|
## FIX -- nyora-notes-tt : disk I/O error post-backup, moteur SQLite mixte sur WAL live (2026-08-02)
|
|
|
|
Tous les tools MCP RAG mail cassaient juste apres chaque backup n8n (toutes les 2h) : sqlean.dbapi2.OperationalError: disk I/O error des l'ouverture de connexion. Pas de piste materielle (dmesg propre, volume a 70%). Cause : la route /backup ouvrait une connexion avec le module sqlite3 stdlib, un moteur different de sqlean (utilise partout ailleurs dans l'app sur la meme DB WAL). Le checkpoint automatique au close() de cette connexion stdlib recree le -wal/-shm pendant que les connexions sqlean deja ouvertes tiennent encore les anciens fd -> index WAL desynchronise entre les deux moteurs -> disk I/O error. Absence de PRAGMA busy_timeout aggravait (echec dur au lieu d'attente). Reflexe a generaliser pour tout futur service Hermes/nyora-notes-* sur sqlean+WAL : jamais un deuxieme moteur/binding SQLite (stdlib, autre) sur une DB WAL live partagee avec un process long-vivant, meme pour une simple sauvegarde -- un seul moteur par DB, et PRAGMA busy_timeout systematique a l'ouverture de toute connexion. Detail : hermes-tt/nyora-notes-tt-backup-wal-moteur-mixte.md.
|
|
|
|
## FIX -- cron n8n orphelin, boucle infinie sur statuts finaux (error_409/404), cause reelle instabilite hermes-mail-browser (2026-08-02)
|
|
|
|
Workflow n8n 'nyora-notes-tt -- Ingestion continue' actif depuis le 31/07, toutes les 10 min (292 executions), en boucle sur les memes dossiers error_409/error_404 -- statuts FINAUX (jamais retraitables avec succes), donc sa condition d'arret 'automatique quand tout est done' ne se declenchait jamais. `neverError:true` sur le noeud HTTP masquait le probleme (292/292 executions n8n 'success' malgre des 409 systematiques). Consequence : contention reguliere sur la page Playwright partagee de hermes-mail-browser, prise a tort pour de l'instabilite structurelle OWA. Desactive (unpublish_workflow). Verifie ensuite : hermes-mail-browser sain (RAM/CPU), timings /search et /message/attachments conformes aux baselines deja documentees une fois le bruit de fond supprime. Reflexe a generaliser : toute boucle n8n a condition d'arret basee sur un etat DB doit distinguer statut final vs statut retry-able, sinon elle ne se videra jamais ; et `neverError:true` cache ce genre de boucle inutile au monitoring standard n8n -- verifier le contenu des reponses, pas juste le statut d'execution. Avant de blamer un service externe pour de la lenteur persistante, chercher d'abord un consommateur interne recurrent via `docker logs` filtre par IP source. Detail : hermes-tt/n8n-cron-orphelin-hermes-mail-browser-instabilite.md.
|
|
|
|
## REGLE -- id DOM d'un SPA (OWA/React) : jamais presume stable, tester sur plusieurs rendus + plusieurs echantillons (2026-08-08)
|
|
|
|
Un attribut `id=`/`data-*` scrape sur une ligne d'un SPA n'est PAS presume stable dans le temps.
|
|
Cas nyora-notes-tt : `elem_id` (attribut `id` de ligne OWA), exploite comme `message_id` natif,
|
|
s'est revele VOLATILE -- OWA/React regenere un GUID frais a chaque rendu (test rigoureux : 0/19
|
|
messages stables entre deux appels /search identiques, ensembles d'id disjoints, meme index -> id
|
|
different ; l'ordre de liste est stable mais pas l'id, `aria-posinset` non peuple). Un premier test
|
|
a 1 seul message toujours en position 0 sur appels rapproches l'avait faussement valide (le DOM
|
|
n'etait pas re-rendu entre les appels -> meme id volatile reutilise). Reflexe : pour juger la
|
|
stabilite d'un id DOM, faire >= 2 rendus REELS distincts (appels espaces OU requetes forcant un
|
|
re-render), sur PLUSIEURS elements, apparier par une identite externe stable (ex. texte de la ligne)
|
|
et verifier le RECOUVREMENT D'ENSEMBLES -- jamais un seul echantillon en position fixe. Seul
|
|
`data-convid` (ConversationId Exchange, niveau THREAD) est stable cote ligne OWA ; aucun id natif
|
|
par-message n'est expose par le scraping DOM. Detail : hermes-tt/nyora-notes-tt-message-id-elem-id-volatile-08-08-2026.md.
|
|
|
|
## FIX -- /search hermes-mail-browser : count:0 transitoire sur appels rapproches (2026-08-08)
|
|
|
|
Deux appels `/search` a < ~10 s d'ecart : le 2e renvoie parfois `count:0` (liste virtualisee OWA pas
|
|
encore stabilisee cote Playwright). Fix cote client (`hermes_mail_client.search_folder`) : si `items`
|
|
est vide de facon inattendue, retry UNIQUE apres `time.sleep(4)` avant d'abandonner (simple, pas de
|
|
backoff). Piege de parsing associe : `attrs` (string pipe-delimitee) reinjecte `aria-label` en fin de
|
|
chaine (texte libre non echappe, `|` et sauts de ligne possibles) -> NE JAMAIS `split('|')` global ;
|
|
extraire par regex ciblee (`data-convid=([^|]+)`, base64 sans `|`). Detail : meme runbook ci-dessus.
|