Files
nas-runbooks/common/PROTOCOL-INFRA.md
T

188 lines
15 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/
---
## 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.