# Exploitation : surveiller, réagir, revenir en arrière Page d'entrée de l'exploitation de QualiCheck (staging). Elle dit où regarder, quoi faire quand une alerte arrive et comment revenir en arrière. Elle renvoie aux documents existants au lieu de les recopier. Conception de la vigie : `conception/5_exploitation/vigie.md`. ## 1. Où regarder - **La page « Santé du service »** : `https://vigie.qualicheck.koabana.fr` (en local : `http://localhost:8884`). Mise à jour par la vigie toutes les 15 minutes, lisible sans compte. Elle donne l'état de chaque signal. Si l'heure du dernier passage date de plus de 30 minutes, la vigie ne tourne plus : voir `docker compose logs vigie` sur le serveur. La pastille « i » de chaque ligne dit en une phrase ce que mesure le signal (survol ou touche Tab). - **Les tickets « incident »** du dépôt Gitea : un ticket par signal en alerte, ouvert par la vigie, accompagné d'un e-mail. - **Langfuse** (projet du staging) : les traces en temps réel, pour comprendre une alerte. - **`make traces-agent ARGS="--depuis AAAA-MM-JJ"`** : les mesures de l'agent (tours, statuts, citations) lues dans les traces. Détail de la chaîne : `docs/developpement/surveillance.md`. - **Les journaux du serveur** : `docker compose logs ` sur le serveur de staging. ## 2. Mise en service La vigie est un service du docker-compose : elle démarre avec le premier déploiement qui la contient. À faire **avant ce déploiement** : 1. Créer le compte Gitea dédié `vigie`, **restreint** (il ne voit que les dépôts où on l'ajoute) et collaborateur du seul dépôt `qualicheck` avec le droit **Écriture** (la Lecture ouvre un ticket mais n'y pose pas d'étiquette). Connecté en `vigie`, créer son jeton à la seule portée « tickets » (`write:issue`) : il ne peut pas pousser de code, et la portée d'un jeton Gitea valant pour tous les dépôts de son propriétaire, un jeton du compte principal aurait pu écrire partout. Puis, connecté en administrateur du dépôt, les secrets du dépôt `VIGIE_GITEA_TOKEN` (ce jeton) et `VIGIE_DESTINATAIRE` (les secrets `LANGFUSE_*`, `SMTP_*` et `DEPLOY_*` existent déjà). Les tickets apparaissent signés `vigie`. 2. Vérifier que les étiquettes `incident` et `simulation` existent dans le dépôt. 3. Sur le serveur, deux gestes : l'entrée DNS `vigie.qualicheck.koabana.fr` chez Infomaniak, puis le bloc Caddy du sous-domaine (voir `docs/developpement/deploiement_staging.md`, « Page de la vigie »). Sans eux, la vigie tourne mais sa page n'est pas joignable de l'extérieur. ## 3. Déployer Voir `docs/developpement/deploiement_staging.md` (déploiement, Caddy, page de santé) et `make gate` puis `make staging` pour la mise en service. ## 4. Une fiche par signal Le ticket, l'e-mail et la page renvoient ici, vers l'ancre du signal. Chaque fiche dit ce que le signal veut dire, comment le vérifier, l'action à mener et quand fermer le ticket. Les seuils sont dans `docs/developpement/metriques_seuils.md` (section 6) et dans la section `vigie` de `app/observability/config.yml`. ### Les pannes (alerte dès la première occurrence, sur 30 minutes) #### Citations non vérifiées - **Sens** : une réponse a cité une règle que la vérification n'a pas pu confirmer. Le garde-fou de la réponse a laissé passer ou signalé un doute. - **Vérifier** : dans Langfuse, chercher les traces `questions_libres` dont l'attribut `citations_non_verifiees` est non vide (liste de numéros). - **Action** : lire la réponse et les règles citées ; si la règle existe bien, la vérification est trop stricte, sinon le modèle invente et le prompt ou le garde-fou est à corriger. - **Fermer** : quand la cause est comprise et que la page est revenue à « normal » (30 minutes sans nouvelle occurrence). #### Réponse 503 de `POST /questions` - **Sens** : l'API a répondu « service indisponible » à une question d'un auditeur. - **Vérifier** : dans Langfuse, le span racine `api_business` avec `http.status_code` égal à 503 ; ses spans enfants montrent l'étape en cause. `docker compose logs api-business` donne l'erreur côté serveur. - **Action** : si un fournisseur de modèle est en panne, attendre son rétablissement ; sinon corriger le composant fautif. - **Fermer** : service rétabli et page revenue à « normal ». #### Panne de l'authentification - **Sens** : la vérification du compte a échoué pour une raison technique (et non parce que le jeton est invalide). - **Vérifier** : span `api_business.authentification` au niveau `ERROR` dans Langfuse ; la base de données est le premier suspect (`docker compose ps`, `docker compose logs`). - **Action** : rétablir la base ; si elle est saine, lire l'erreur du span. - **Fermer** : une connexion réussie est visible et la page est « normal ». #### API des règles en erreur ou jeton de l'agent refusé - **Sens** : l'agent n'arrive plus à interroger l'API des règles ; ses réponses perdent leur source. - **Vérifier** : span `tools.appel_api_regles` au niveau `ERROR` ou `api_regles.statut` supérieur ou égal à 500. Un jeton de l'agent refusé apparaît en **502** avec le message « jeton de l'agent refusé ». - **Action** : redémarrer ou corriger l'API des règles ; pour un jeton refusé, vérifier celui configuré pour l'agent (voir `docs/developpement/creation_cle_api_regles.md`). - **Fermer** : un appel réussi est visible et la page est « normal ». #### Contrôle du sujet en panne - **Sens** : le contrôle qui écarte les questions hors sujet n'a pas pu répondre ; la question est traitée sans lui ou refusée. - **Vérifier** : traces dont l'attribut `sujet.categorie` vaut `panne`. - **Action** : vérifier le fournisseur du modèle de ce contrôle et sa configuration. - **Fermer** : plus de trace en panne sur 30 minutes. #### Contrôle de l'intention en panne - **Sens** : même chose pour le contrôle qui détecte les demandes malveillantes. - **Vérifier** : traces dont l'attribut `intention.categorie` vaut `panne`. - **Action** : comme pour le contrôle du sujet. - **Fermer** : plus de trace en panne sur 30 minutes. #### Composant court-circuité - **Sens** : un composant de protection est désactivé par configuration (l'attribut `bypass` du span racine est renseigné). Normal pour une mesure en local, **jamais en staging**. - **Vérifier** : lire l'attribut `bypass` sur la trace, puis les variables d'environnement du staging. - **Action** : retirer le réglage qui court-circuite et redéployer. - **Fermer** : plus de trace avec `bypass` sur 30 minutes. #### Service injoignable - **Sens** : la route `/health` de l'API a échoué deux fois de suite, à 30 secondes d'écart. - **Vérifier** : ouvrir `https://api.qualicheck.koabana.fr/health` ; `docker compose ps` sur le serveur. - **Action** : relancer le conteneur ; si un déploiement vient d'avoir lieu, envisager le retour arrière (section 5). - **Fermer** : `/health` répond et la page est « normal ». #### Purge des comptes arrêtée - **Sens** : la dernière ligne du journal de la purge date de plus de 26 heures ; la purge quotidienne des comptes ne tourne plus. - **Vérifier** : lire la fin de `logs/purge_comptes.log` sur le serveur et la tâche planifiée qui la lance. - **Action** : relancer la purge (`make purge-comptes`) et corriger la tâche planifiée. - **Fermer** : une ligne récente apparaît dans le journal. ### Les dérives (alerte sur une fenêtre, au moins 20 questions) Sous 20 questions dans la fenêtre, la page affiche « pas assez de questions » et rien ne sonne (voir les limites, section 9). #### Questions coupées par la limite de tours - **Sens** : plus de 5 % des questions des dernières 24 heures n'ont pas abouti parce que l'agent a atteint le nombre maximal de tours. - **Vérifier** : `make traces-agent ARGS="--depuis "`, puis dans Langfuse les traces `questions_libres` dont `limite_atteinte` est vrai. - **Action** : regarder si ce sont des questions nouvelles (le jeu de questions a changé) ou une dégradation (outil lent, modèle qui boucle). - **Fermer** : la part repasse sous le seuil ou la cause est traitée. #### 90e centile du nombre de tours - **Sens** : 10 % des questions demandent plus de 4 tours à l'agent ; il cherche plus longtemps qu'avant, souvent avant de dériver vers la limite. - **Vérifier** : comme pour la limite de tours. - **Action** : même analyse ; relire le prompt et les sorties d'outils. - **Fermer** : le centile repasse à 4 ou moins. #### Citations inventées avant correction - **Sens** : plus de 10 % des questions contenaient, avant correction par le garde-fou, une citation de règle inexistante. Le garde-fou rattrape l'erreur, mais le modèle se dégrade. - **Vérifier** : `make traces-agent`, colonne des citations inventées. - **Action** : vérifier si le modèle ou son prompt a changé chez le fournisseur ou dans le dépôt. - **Fermer** : la part repasse sous le seuil. #### Latence de `POST /questions` (sans page et avec page) - **Sens** : le 95e centile du temps de réponse dépasse son seuil (13 s sans page, 24 s avec page, carte #83). Deux signaux, deux tickets possibles : les deux groupes n'ont pas la même durée normale. - **Vérifier** : dans Langfuse, la durée du span racine `api_business` ; `make mesure-latence` rejoue la mesure. - **Action** : chercher l'étape lente (modèle, API des règles, base). - **Fermer** : le centile repasse sous son seuil. #### Fidélité des réponses - **Sens** : la moyenne des 20 dernières notations du juge de fidélité est sous 0,90 : les réponses s'écartent des règles citées. - **Vérifier** : attribut `fidelite` du span `questions_libres.juge`. - **Action** : lire les réponses les moins bien notées ; vérifier si le modèle de réponse a changé. - **Fermer** : la moyenne remonte à 0,90 ou plus. #### Refus d'authentification - **Sens** : plus de 10 refus d'authentification en une heure : jeton expiré distribué par erreur, ou tentative de force brute. - **Vérifier** : spans `api_business.authentification` avec un motif de refus, sur la dernière heure (sans noter d'identité dans le ticket). - **Action** : si c'est un client légitime, corriger son jeton ; sinon vérifier les limites de débit. - **Fermer** : 10 refus ou moins sur l'heure suivante. ### Les mesures sans seuil #### Part refusée par les contrôles, provenance, questions par compte - **Sens** : mesures affichées, sans alerte. Elles restent « à mesurer d'abord » (`docs/developpement/metriques_seuils.md`). - **Vérifier** : la page de santé ; `make traces-agent` pour le détail. - **Action** : aucune pour l'instant ; un seuil sera proposé après plusieurs semaines de traces réelles. - **Fermer** : sans objet, aucun ticket n'existe pour ces mesures. ## 5. Revenir en arrière `make rollback-staging RUN=` rejoue un déploiement réussi précédent (64 secondes mesurées le 14/10). Aucune migration de base n'est défaite. Procédure : `docs/developpement/rollback_staging.md`. ## 6. Le cycle d'un incident 1. **Ouvert** : la vigie ouvre un ticket `[vigie] : ` (étiquette `incident`) et envoie un e-mail, une seule fois par incident. 2. **Rétabli** : quand le signal redevient normal, elle ajoute un seul commentaire « rétabli à HH:MM » et un e-mail. Une panne n'est déclarée rétablie qu'après 30 minutes sans nouvelle occurrence. Si le signal repart avant la fermeture du ticket, un commentaire « revenu à HH:MM » et un e-mail le signalent (rechute). 3. **Fermé** : à la main, après avoir mené l'action de la fiche. La vigie ne ferme jamais un ticket. Si Gitea ou le relais d'e-mails ne répond pas, la page est écrite quand même et l'échec est consigné dans les journaux de la vigie. ## 7. Changer un seuil Les valeurs sont dans la section `vigie` de `app/observability/config.yml` (jamais dans le code). Modifier la valeur, passer les tests, puis fusionner sur `dev` puis déployer : la vigie lit ses seuils dans l'image déployée. Reporter le changement dans `docs/developpement/metriques_seuils.md`. ## 8. Rejouer la démo de la dérive simulée Dans Gitea, onglet Actions, choisir « Vigie — démo » puis « Run workflow ». Un fichier de 25 questions, dont 4 coupées par la limite de tours, remplace Langfuse ; tout le reste est réel. Résultat attendu : deux tickets `[simulation]` (limite de tours et 90e centile du nombre de tours), un e-mail par ticket, la page de santé montrant les deux dérives en alerte. Fermer ensuite les tickets de la démo. La démo a besoin des secrets `VIGIE_*` (jeton Gitea, destinataire) du staging. Sans le jeton, elle tourne à blanc : ni ticket ni e-mail, et le workflow reste vert. En local, sans ticket ni e-mail : `make vigie`. ## 9. Limites connues - **Volume du staging** : environ 8 questions par jour (107 en 14 jours). Avec un minimum de 20 sur 24 heures, les dérives affichent presque toujours « pas assez de questions » : aujourd'hui, seules les pannes et la simulation sonnent réellement. C'est voulu. - **La vigie lance la version `dev` du code**, qui peut avoir un peu d'avance sur le staging. - **La fidélité se lit sur le span du juge** : le Langfuse du staging refuse la lecture des scores par son API publique. - **Pas d'e-mail de secours** : si la vigie s'arrête, rien n'écrit à personne. Une page dont l'heure de passage a plus de 30 minutes signale une vigie arrêtée ; la cause se lit avec `docker compose logs vigie`. - **Langfuse injoignable** : le passage échoue avant d'écrire la page. Elle n'est plus mise à jour (son heure vieillit) et aucune alerte ne part, pas même pour une panne de l'API. Seule trace : `docker compose logs vigie`.