fangdididi/trigger-rehearsal

Répète les règles de déclenchement d'un agent événementiel ou en arrière-plan avant de les activer.

Qu'est-ce que trigger-rehearsal ?

Trigger Rehearsal est un outil de simulation qui permet de tester en toute sécurité les règles de déclenchement d'agents IA (comme les règles d'un hub d'agents, les routines, les blocs CI `on:`, les lignes cron ou les automatisations sans code) avant de les activer sur des systèmes réels. Il transforme toutes ces règles en un format neutre (rules.json), les soumet à une analyse lint pour détecter les boucles d'auto-déclenchement, les chaînes non protégées, les limites manquantes et les doubles traitements, puis rejoue des événements réels ou enregistrés pour montrer chaque exécution qui aurait été lancée, ce qui a été fusionné, ignoré, mis en file d'attente ou abandonné, et le coût associé. L'outil supporte les événements GitHub, les sources externes, et peut être intégré en CI pour bloquer les changements dangereux. Il est utilisé par les développeurs qui configurent des agents background, des workflows CI ou des automatisations complexes, et permet de valider avec des chiffres avant de basculer sur un système en production.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/fangdididi/trigger-rehearsal/tree/HEAD

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Répétition des Déclencheurs

Ce que c'est

Un agent qui se réveille sur des événements est aussi sûr que ses règles de déclenchement. L'agent lui-même peut être prudent et brûler le budget d'une journée, car le problème se situe généralement un niveau au-dessus :

  • une règle réagit à un événement que son propre travail produit, donc elle se déclenche encore et encore ;
  • deux règles s'alimentent mutuellement via un second système (l'agent commente, le commentaire se synchronise, la synchronisation déclenche un webhook) ;
  • une source bruyante envoie dix modifications en deux minutes et chacune lance une nouvelle exécution ;
  • une ligne cron prévue pour "vérifier de temps en temps" se déclenche 288 fois par jour ;
  • deux règles traitent le même événement et effectuent le travail deux fois ;
  • une règle qui rembourse, supprime ou envoie des messages s'exécute sans demander à personne.

Aucun de ces problèmes n'apparaît lorsque vous testez l'agent sur un exemple. Ils apparaissent lorsque le trafic réel arrive. Trigger Rehearsal fait arriver le trafic réel tôt, sur le papier : vous écrivez les règles dans un format neutre, rejouez un jour ou une semaine d'événements à travers elles, et lisez la chronologie avant que quoi que ce soit ne soit armé.

Quand l'utiliser

  • Avant d'activer une règle qui permet à un agent de commencer un travail sans qu'une personne ne tape une invite.
  • Lors de l'ajout d'une règle à un ensemble existant (une nouvelle règle peut fermer une boucle qui était ouverte auparavant).
  • Lorsqu'un agent en arrière-plan s'exécute beaucoup plus souvent, ou beaucoup moins souvent, que prévu.
  • Lors du choix des fenêtres de debounce, des limites de parallélisme et des plafonds quotidiens, et que vous voulez des chiffres plutôt que des suppositions.
  • Lorsqu'un réviseur demande "que se passe-t-il si ce dépôt reçoit 50 problèmes en une heure ?"

Pas pour : vérifier ce que l'agent fait à l'intérieur d'une exécution (c'est une question d'invite ou de compétence), ou tester la charge de la source d'événements elle-même.

La feuille de règles

Tout est traduit en rules.json. Gardez la traduction honnête : une règle de feuille par règle réelle, et notez les gardes qui existent vraiment, pas celles que vous avez l'intention d'ajouter.

{
  "tz": "Europe/Paris",
  "run_s": 180,
  "external_sources": ["github"],
  "budget": {"runs_per_day": 40, "cost_per_run": 0.15, "cost_per_day": 6},
  "rules": [
    {
      "name": "tri-nouveau-probleme",
      "on": {"source": "github", "types": ["issues.opened", "issues.edited"]},
      "where": {"repo": "moi/app"},
      "key": "subject",
      "debounce_s": 300,
      "parallel": 1,
      "max_per_day": 20,
      "unless_actor": ["mon-bot"],
      "unless_label": "trié",
      "emits": [{"source": "github", "types": ["issues.labeled"], "actor": "mon-bot", "labels": ["trié"]}],
      "sensitive": [],
      "asks": false
    },
    {"name": "digest-matin", "on": {"cron": "0 9 * * 1-5"}, "max_per_day": 1}
  ]
}
ChampSignification
on.source + on.typesQuels événements démarrent la règle. Laissez types de côté pour correspondre à tous les types de cette source.
on.cronUne ligne cron à cinq champs dans le fuseau horaire de la feuille. Une règle a soit source soit cron.
whereLes champs d'événement doivent être égaux à une valeur (ou faire partie d'une liste).
keyChamp d'événement nommant le sujet (numéro de problème, identifiant de ticket, URL). Utilisé pour fusionner les répétitions.
debounce_sAttendez cette durée après le dernier événement pour un sujet, puis exécutez une fois.
parallelCombien d'exécutions de cette règle peuvent être actives en même temps. Les exécutions supplémentaires attendent.
max_per_dayPlafond strict par jour local. Les exécutions supplémentaires sont abandonnées.
run_sDurée typique d'une exécution, utilisée pour la mise en file d'attente. Par défaut, la valeur de la feuille, puis 120.
unless_actor, unless_labelGardes : ignorer les événements effectués par ces acteurs, ou portant cette étiquette.
emitsÉvénements que l'exécution elle-même produit (commentaires, étiquettes, changements de statut, événements de suivi). Incluez l'acteur et les étiquettes qu'ils porteront.
sensitive + asksActions qui nécessitent une personne (supprimer, dépenser, redémarrer, envoyer). asks: true signifie que l'exécution s'arrête et demande d'abord.
external_sourcesSources alimentées par le monde extérieur. Tout le reste doit être émis par une règle.
budgetOptionnel : exécutions par jour, coût par exécution et coût par jour utilisés pour le verdict.

Étape par étape

  1. Collectez les vraies règles. Lisez la configuration réelle, pas la description. Fichiers de règles du hub d'agents, routines sauvegardées, blocs on: du workflow CI, lignes crontab, écrans d'automatisation sans code. Notez tout ce qui écrit dans une source qu'une autre règle surveille.
  2. Traduisez en rules.json. Commencez par python3 scripts/rehearse.py new rehearsal/. Pour chaque règle, posez trois questions et remplissez les champs : qu'est-ce qui la réveille, qu'écrit une exécution, et qu'est-ce qui l'empêche de se réveiller sur ses propres écritures. Si la réponse à la troisième est "rien", laissez la garde de côté. La répétition est conçue pour attraper cela.
  3. Analysez. python3 scripts/rehearse.py lint rehearsal/rules.json. Corrigez chaque HOLD avant de rejouer ; les éléments REVIEW peuvent attendre les chiffres.
  4. Rassemblez les événements. Le mieux : exportez une vraie journée chargée de la source (journal de livraison webhook, chronologie de problème, journal d'audit du service d'assistance) dans events.jsonl, un objet JSON par ligne avec au moins t, source, type, plus les champs utilisés par votre key et where. Si aucun historique n'existe, écrivez intentionnellement une courte rafale synthétique : dix modifications en trois minutes, deux sujets à la fois, un événement créé par votre propre bot.
  5. Rejouez sur des journées entières. python3 scripts/rehearse.py replay rehearsal/rules.json rehearsal/events.jsonl --from 2026-11-02T00:00:00Z --to 2026-11-03T00:00:00Z --md rehearsal/report.md. Passez --from/--to pour que les chiffres par jour ne soient pas gonflés par une courte fenêtre.
  6. Lisez la chronologie, pas seulement le verdict. Recherchez des exécutions sur le même sujet à quelques minutes d'intervalle (debounce manquant ou trop court), des chaînes de profondeur croissante (boucles), de longues attentes (parallélisme trop faible), des abandons (plafond trop bas pour le travail réel, ou signe que la règle se déclenche sur du bruit).
  7. Ajustez et répétez. Modifiez un paramètre à la fois et rejouez les mêmes événements, afin que la différence provienne clairement de ce changement.
  8. Décidez. ARMEZ seulement lorsque la dernière répétition est ARM sur une journée réaliste. Conservez le rules.json final, le fichier d'événements et report.md ensemble comme preuve de pourquoi les règles ont été activées.

Verdicts

  • ARM : aucun résultat HOLD ou REVIEW. Sûr à activer tel quel.
  • TRIM : quelque chose gaspille des exécutions ou peut sauter du travail (pas de clé, pas de plafond, chevauchement, le plafond a abandonné des événements réels, proche du budget). N'activez qu'après avoir réduit, ou avec une raison écrite.
  • HOLD : n'activez pas. Auto-boucle, cycle non protégé, chaîne ayant dépassé la profondeur 5, action sensible sans demander, dépassement du budget, ou ligne cron cassée.

Le code de sortie suit le verdict (0, 1, 2 ; 3 signifie une mauvaise entrée), de sorte qu'une répétition peut bloquer un changement de configuration dans le CI.

Exemple

Une équipe de support souhaite qu'un agent réponde aux tickets du service d'assistance. Leur feuille (dans examples/loopy/) a une règle de réponse qui publie une réponse, ce qui met à jour le ticket, ce qui correspond à la même règle. Une relecture d'une journée ordinaire donne :

HOLD   self-loop            repondre-ticket : la propre sortie de la règle correspond à son propre déclencheur sans garde unless_actor/unless_label
HOLD   runaway              repondre-ticket : la chaîne a continué à se déclencher au-delà de la profondeur 5 (3 coupures)
HOLD   sensitive-unasked    verifier-remboursement : déclare des actions sensibles ['refund'] mais 'asks' n'est pas vrai
HOLD   over-runs-budget     - : 100,0/jour contre un budget de 30/jour
REVIEW cron-tight           boite-reception : jusqu'à 720 déclenchements/jour
VERDICT HOLD

Trois mises à jour de ticket se sont transformées en 18 exécutions de réponse. Le correctif est petit : ajoutez "unless_actor": ["support-bot"] à la règle de réponse, définissez "asks": true sur la règle de remboursement, et remplacez la sonde de deux minutes par un script qui émet inbox.changed uniquement lorsque la boîte de réception a vraiment changé (voir examples/loopy/rules.fixed.json). La prochaine relecture de la même journée passe de 100 exécutions à 4 et le verdict passe à TRIM. Le seul résultat restant est que la réponse et la vérification du remboursement voient toutes deux un ticket de remboursement, ce qui est intentionnel ici, donc il est accepté avec une raison écrite d'une ligne à côté du rapport.

Conseils

  • La meilleure garde anti-boucle est une condition qui devient fausse après l'exécution : une étiquette que l'exécution ajoute et que la règle exclut, ou un statut que la règle ne correspond plus.
  • Les boucles inter-systèmes sont les plus faciles à manquer. Si l'agent écrit dans le système A et que le système A se synchronise avec B, listez l'événement synchronisé sous emits avec l'acteur qu'il affichera.
  • Le debounce ajoute un délai par conception. Choisissez la fenêtre en fonction du temps qu'une personne met pour terminer une rafale de modifications, et gardez-la courte là où quelqu'un attend une réponse.
  • Le debounce n'est pas une déduplication des actions. Pour tout ce qui est irréversible, l'exécution elle-même doit toujours vérifier "déjà fait ?" avant d'agir.
  • Un plafond quotidien est un fusible, pas un plan. Si la relecture d'une journée normale l'atteint, la règle est trop large.
  • Sonder toutes les quelques minutes est généralement moins cher sous la forme d'un petit script qui compare l'état et émet un événement lors du changement ; l'agent ne se réveille que lorsqu'il y a du nouveau.
  • Relancez la répétition à chaque fois qu'une règle est ajoutée. La plupart des boucles sont créées par la deuxième règle, pas par la première.

Skills associés