docs: add Graylog auto-resolve design spec

This commit is contained in:
thibaud-lclr 2026-04-17 12:19:11 +02:00
parent 5dbaa3c717
commit e4377f08c9

View file

@ -0,0 +1,402 @@
# Orchai - Design Graylog Auto-Resolve (V1)
Date: 2026-04-17
Statut: Validé en session de brainstorming
## 1. Objectif
Ajouter un module projet `Graylog` qui:
1. Interroge Graylog à intervalle régulier.
2. Détecte des sujets d'erreur récurrents à partir des logs récents.
3. Attribue un score déterministe à chaque sujet (`sévérité + fréquence + récence`).
4. Déclenche automatiquement le pipeline agent existant `analyst -> developer` pour les sujets au-dessus d'un seuil.
5. Crée une branche/worktree locale de correction via le flux actuel Orchai.
Le module doit rester isolé par projet avec des credentials Graylog propres à chaque projet.
## 2. Décisions validées
1. Exécution automatique au-dessus du seuil: oui.
2. Pipeline de traitement: réutilisation stricte du pipeline existant `analyst -> developer`.
3. Scoring: formule déterministe uniquement.
4. Définition d'un sujet: `source/service + message normalisé`.
5. Déduplication: stricte, une seule branche active par sujet.
6. Portée de la configuration Graylog: par projet.
7. Approche d'architecture: extension ciblée sans refonte complète du modèle Tuleap.
## 3. Architecture cible
## 3.1 Module projet
Nouveau module dans `project_modules`:
- `module_key`: `graylog_polling_auto_resolve`
- `name`: `Polling Graylog + auto-resolve`
- `description`: surveillance Graylog, scoring, déclenchement automatique du pipeline agent.
## 3.2 Composants backend
1. `graylog_client`
- Appelle l'API Graylog (requêtes de recherche, filtres, stream éventuel).
- Transforme les réponses en événements de logs exploitables.
2. `graylog_scoring`
- Normalise les messages.
- Regroupe par sujet.
- Calcule le score déterministe.
3. `graylog_poller`
- Boucle périodique (comme les services de fond existants).
- Charge la configuration de chaque projet.
- Applique dédup et seuil.
4. `graylog_to_queue_bridge`
- Insère un item de traitement dans la file existante pour réutiliser l'orchestrateur.
## 3.3 Réutilisation du pipeline actuel
Le traitement des sujets Graylog utilise:
1. `processed_tickets` comme file de traitement commune.
2. `services/orchestrator.rs` pour exécuter `analyst -> developer`.
3. `services/worktree_manager.rs` pour créer la branche/worktree locale.
Le poller Graylog détecte et pousse en file; il ne lance pas directement de correction.
## 4. Modèle de données
## 4.1 Nouvelles tables
1. `graylog_credentials` (unique par projet)
- `id TEXT PRIMARY KEY`
- `project_id TEXT NOT NULL UNIQUE REFERENCES projects(id) ON DELETE CASCADE`
- `base_url TEXT NOT NULL`
- `api_token_encrypted TEXT NOT NULL`
- `analyst_agent_id TEXT NOT NULL REFERENCES agents(id)`
- `developer_agent_id TEXT NOT NULL REFERENCES agents(id)`
- `stream_id TEXT` (optionnel)
- `query_filter TEXT NOT NULL DEFAULT ''`
- `polling_interval_minutes INTEGER NOT NULL DEFAULT 10`
- `lookback_minutes INTEGER NOT NULL DEFAULT 30`
- `score_threshold INTEGER NOT NULL DEFAULT 70`
- `created_at TEXT NOT NULL`
- `updated_at TEXT NOT NULL`
2. `graylog_subjects` (état courant d'un sujet)
- `id TEXT PRIMARY KEY`
- `project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE`
- `subject_key TEXT NOT NULL`
- `source TEXT NOT NULL`
- `normalized_message TEXT NOT NULL`
- `first_seen_at TEXT NOT NULL`
- `last_seen_at TEXT NOT NULL`
- `last_score INTEGER NOT NULL DEFAULT 0`
- `active_ticket_id TEXT REFERENCES processed_tickets(id)`
- `status TEXT NOT NULL DEFAULT 'idle'` (`idle|queued|processing|done|error|cancelled`)
- `created_at TEXT NOT NULL`
- `updated_at TEXT NOT NULL`
3. `graylog_detections` (historique des cycles)
- `id TEXT PRIMARY KEY`
- `subject_id TEXT NOT NULL REFERENCES graylog_subjects(id) ON DELETE CASCADE`
- `window_start TEXT NOT NULL`
- `window_end TEXT NOT NULL`
- `critical_count INTEGER NOT NULL DEFAULT 0`
- `error_count INTEGER NOT NULL DEFAULT 0`
- `warning_count INTEGER NOT NULL DEFAULT 0`
- `total_count INTEGER NOT NULL DEFAULT 0`
- `last_seen_at TEXT NOT NULL`
- `score INTEGER NOT NULL`
- `triggered INTEGER NOT NULL DEFAULT 0`
- `triggered_ticket_id TEXT REFERENCES processed_tickets(id)`
- `created_at TEXT NOT NULL`
## 4.2 Évolution de `processed_tickets`
Ajouts:
1. `project_id TEXT REFERENCES projects(id)` (renseigné pour tous les tickets)
2. `source TEXT NOT NULL DEFAULT 'tuleap'`
3. `source_ref TEXT` (référence externe, ici `graylog_subjects.id`)
Évolutions:
1. `tracker_id` devient nullable pour supporter les sources non-Tuleap.
2. Le code de lecture par projet ne dépend plus d'un `JOIN` obligatoire vers `watched_trackers`.
3. Les tickets Tuleap continuent de renseigner `tracker_id`.
4. Les tickets Graylog renseignent `project_id` et laissent `tracker_id` nul.
Rôle:
- Distinguer les items Tuleap et Graylog.
- Réutiliser l'orchestrateur sans dupliquer la mécanique de queue/worktree.
## 4.3 Index recommandés
1. `UNIQUE(project_id, subject_key)` sur `graylog_subjects`.
2. `INDEX(subject_id, created_at DESC)` sur `graylog_detections`.
3. `INDEX(source, source_ref)` sur `processed_tickets`.
4. `INDEX(project_id, detected_at DESC)` sur `processed_tickets`.
5. Index unique Tuleap conservé en version partielle:
`UNIQUE(tracker_id, artifact_id) WHERE tracker_id IS NOT NULL`.
## 4.4 Migration des données existantes
Ordre de migration recommandé:
1. Ajouter `project_id`, `source`, `source_ref` sur `processed_tickets`.
2. Backfill `project_id` pour les lignes existantes via `JOIN watched_trackers`.
3. Rendre `tracker_id` nullable.
4. Remplacer l'index unique historique `(tracker_id, artifact_id)` par l'index partiel Tuleap.
5. Ajouter les nouvelles tables Graylog.
## 5. Définition d'un sujet et normalisation
## 5.1 Clé de regroupement
`subject_key = source + '|' + normalized_message`
`source` correspond au champ service applicatif si présent, sinon au champ `source` Graylog.
## 5.2 Normalisation V1
Transformation déterministe:
1. Passage en minuscules.
2. Remplacement des UUID par `<uuid>`.
3. Remplacement des nombres longs/identifiants numériques par `<num>`.
4. Remplacement des timestamps ISO par `<ts>`.
5. Remplacement des adresses IP par `<ip>`.
6. Remplacement des hash hexadécimaux longs par `<hash>`.
7. Réduction des espaces multiples.
Objectif: regrouper des occurrences logiquement identiques malgré des valeurs dynamiques.
## 6. Scoring déterministe
Score total entre 0 et 100:
`score_total = severity_score + frequency_score + recency_score`
## 6.1 Sévérité (0..50)
1. Si au moins un `critical`: `50`
2. Sinon si au moins un `error`: `35`
3. Sinon si au moins un `warning`: `20`
4. Sinon: `0`
## 6.2 Fréquence (0..35)
Barème sur `total_count` dans la fenêtre du cycle:
1. `1` -> `5`
2. `2-3` -> `12`
3. `4-7` -> `22`
4. `8-15` -> `30`
5. `>=16` -> `35`
## 6.3 Récence (0..15)
Barème sur l'âge du dernier événement du sujet:
1. `<=2 min` -> `15`
2. `<=10 min` -> `12`
3. `<=30 min` -> `8`
4. `<=120 min` -> `4`
5. `>120 min` -> `0`
## 6.4 Seuil
`score_threshold` est porté par projet dans `graylog_credentials`.
Valeur par défaut V1: `70`.
## 7. Flux d'exécution
## 7.1 Cycle planifié
1. Le scheduler Graylog se déclenche toutes les 60 secondes.
2. Pour chaque projet:
- vérifier module `graylog_polling_auto_resolve` activé;
- charger credentials + config;
- vérifier si `polling_interval_minutes` est atteint;
- interroger Graylog sur la fenêtre `lookback_minutes`.
3. Regrouper les logs en sujets.
4. Calculer score par sujet.
5. Persister détections et état des sujets.
6. Décider du déclenchement.
## 7.2 Règle de déclenchement
1. Si `score < threshold`:
- `triggered = 0` dans `graylog_detections`.
- aucun item queue créé.
2. Si `score >= threshold`:
- si sujet sans traitement actif: créer un item `processed_tickets` de source `graylog`.
- sinon: ne rien créer (dédup stricte), garder la trace en détection.
## 7.3 Dédup stricte
Un sujet est considéré actif si:
1. `graylog_subjects.active_ticket_id` non nul, et
2. le ticket lié est dans `Pending|Analyzing|Developing`.
Conséquence:
- une seule branche active par sujet.
- pas de duplication de branche tant que le ticket actif n'est pas terminé.
## 7.4 Nommage de branche
Format recommandé:
`orchai/graylog/<subject_hash>`
`subject_hash` est dérivé de `subject_key` pour conserver un nom stable et compact.
## 8. Intégration orchestrateur/worktree
## 8.1 Représentation queue Graylog
Lors du trigger:
1. créer un `processed_tickets` avec:
- `project_id = <project_id>`
- `tracker_id = NULL`
- `source = 'graylog'`
- `source_ref = graylog_subjects.id`
- `artifact_id`: identifiant synthétique négatif (dérivé de hash de sujet, avec fallback anti-collision) pour compatibilité UI.
- `artifact_title`: résumé court (`[Graylog] <source> - <message normalisé>`).
- `artifact_data`: JSON détaillant métriques et exemples de logs.
2. mettre `graylog_subjects.status = 'queued'` et `active_ticket_id = <ticket_id>`.
## 8.2 Transition de statut sujet
Synchroniser `graylog_subjects.status` avec le ticket lié:
1. `Pending` -> `queued`
2. `Analyzing` -> `processing`
3. `Developing` -> `processing`
4. `Done` -> `done` puis `idle` au cycle suivant si pas de nouveau dépassement
5. `Error` -> `error`
6. `Cancelled` -> `cancelled`
## 8.3 Sélection des agents Graylog
Pour un ticket `source='graylog'`, l'orchestrateur charge les agents depuis `graylog_credentials` du projet:
1. `analyst_agent_id` pour l'étape d'analyse.
2. `developer_agent_id` pour l'étape de correction.
Comportement en cas de configuration invalide:
1. le ticket passe en erreur explicite;
2. l'événement d'erreur est émis;
3. aucun worktree n'est créé.
## 9. Contrats Tauri (backend)
## 9.1 Credentials/config
1. `set_graylog_credentials(project_id, base_url, api_token, analyst_agent_id, developer_agent_id, stream_id, query_filter, polling_interval_minutes, lookback_minutes, score_threshold)`
2. `get_graylog_credentials(project_id)`
3. `test_graylog_connection(project_id)`
4. `delete_graylog_credentials(project_id)`
5. Les commandes de configuration incluent `analyst_agent_id` et `developer_agent_id`.
## 9.2 Pilotage et visibilité
1. `manual_graylog_poll(project_id)`
2. `list_graylog_subjects(project_id)`
3. `list_graylog_detections(project_id, subject_id?)`
## 10. Événements frontend
Événements Tauri ajoutés:
1. `graylog-polling-started`
2. `graylog-subject-triggered`
3. `graylog-polling-finished`
4. `graylog-polling-error`
Ces événements sont complémentaires des événements existants du pipeline ticket.
## 11. UI
## 11.1 Modules projet
Dans `ProjectModules`, afficher le module Graylog avec activation/désactivation.
## 11.2 Vue Graylog projet
Nouvelle page projet dédiée:
1. Formulaire de configuration (`URL`, `token`, `stream`, `query`, intervalle, lookback, seuil).
2. Bouton `Tester la connexion`.
3. Liste des sujets:
- source
- message normalisé
- score actuel
- dernière occurrence
- statut
- ticket/branche liés s'ils existent
4. Historique des détections par sujet.
## 11.3 Dashboard
Le dashboard projet affiche les événements Graylog récents au même titre que les événements de polling et d'orchestration actuels.
## 12. Gestion d'erreurs et robustesse
1. Erreur API Graylog:
- journaliser côté backend,
- émettre `graylog-polling-error`,
- reprendre au cycle suivant sans bloquer le reste.
2. Credentials absents/invalides:
- projet ignoré pour le cycle,
- statut explicite côté UI.
3. Aucune erreur Graylog ne doit arrêter:
- le poller Tuleap,
- l'orchestrateur,
- le task runner.
## 13. Tests
## 13.1 Unit tests
1. Normalisation de message.
2. Calcul de score (cas limites inclus).
3. Dédup stricte (pas de second ticket si sujet actif).
## 13.2 Intégration DB
1. Migration vers le nouveau schéma.
2. Création d'un ticket `source='graylog'`.
3. Cohérence de `active_ticket_id` et des transitions de statut sujet.
## 13.3 Services
1. Poll sous seuil -> pas de trigger.
2. Poll au-dessus seuil -> trigger unique.
3. Poll répété au-dessus seuil avec sujet actif -> pas de nouveau trigger.
## 13.4 UI
1. Toggle module Graylog.
2. Sauvegarde config + test connexion.
3. Affichage des sujets et statut lié au ticket.
## 14. Critères d'acceptation
1. Un sujet Graylog au-dessus du seuil crée automatiquement un traitement complet `analyst -> developer`.
2. Les sujets sont regroupés par `source + message normalisé`.
3. Tant qu'un sujet est actif, aucune branche supplémentaire n'est créée pour ce sujet.
4. Les décisions (trigger/dédup) sont auditables via l'historique des détections.
5. Désactiver le module Graylog coupe les nouveaux déclenchements sans perdre l'historique.
## 15. Plan de rollout
1. Livrer backend (migrations, services, commandes).
2. Livrer UI (module + écran Graylog + événements).
3. Activer sur un projet pilote.
4. Ajuster seuil et barèmes de scoring si nécessaire.
5. Généraliser projet par projet.