# 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 ``. 3. Remplacement des nombres longs/identifiants numériques par ``. 4. Remplacement des timestamps ISO par ``. 5. Remplacement des adresses IP par ``. 6. Remplacement des hash hexadécimaux longs par ``. 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` 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 = ` - `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] - `). - `artifact_data`: JSON détaillant métriques et exemples de logs. 2. mettre `graylog_subjects.status = 'queued'` et `active_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.