triage-flaky-test

Par datadog-labs · agent-skills

Charger lors de l'investigation d'un test instable spécifique. Récupère l'historique, le pattern d'échec et la catégorie, puis recommande un correctif, une mise en quarantaine ou une escalade.

npx skills add https://github.com/datadog-labs/agent-skills --skill triage-flaky-test

Triage de Test Instable

Résumé en une ligne : Investiguer un test instable spécifique — obtenir l'historique, le pattern de défaillance et la catégorie, puis recommander un correctif, une quarantaine ou une escalade.

Nécessite : skill dd-pup (CLI pup installé et authentifié).


Backend

Détection — Au début de chaque invocation, avant toute action, déterminez quel backend utiliser :

  1. Si l'utilisateur a passé --backend pup n'importe où → utilisez le mode pup immédiatement. Ignorez les étapes 2–4.
  2. Vérifiez si get_datadog_flaky_tests figure parmi vos outils disponibles.
  3. Si présent → utilisez le mode MCP partout. Appelez les outils exactement comme nommés dans les sections workflow de ce skill.
  4. Si absent → vérifiez si pup est exécutable : lancez pup --version via Bash. Une réponse JSON contenant "version" confirme que pup est disponible.
  5. Si pup répond → utilisez le mode pup partout. Traduisez chaque appel d'outil en utilisant l'appendice Tool Reference en bas de ce fichier.
  6. Si aucun n'est disponible → arrêtez et dites à l'utilisateur :

    « Ni le serveur MCP Datadog ni la CLI pup n'est disponible. Connectez le serveur MCP ou installez pup (brew install datadog-labs/pack/pup). »

Règles d'invocation pup :

  • Invoquez via Bash. pup retourne toujours du JSON — parsez directement.
  • Les ID de repository passés à pup doivent être entièrement en minuscules (l'API rejette la casse mixte).
  • Les valeurs de tri commençant par - nécessitent la syntaxe = : --sort="-last_flaked" (pas --sort "-last_flaked").
  • Si pup retourne 401/403, dites à l'utilisateur d'exécuter pup auth refresh ou pup auth login.

Entrée

Paramètre Description
Nom du test Nom du test complètement qualifié (ex. TestMyFunc ou com.example.MyTest)
Repository Minuscules, URL sans schéma (ex. github.com/org/repo). Dérivez de git remote get-url origin si non fourni.

Workflow

ÉTAPE 0 — Analyser l'entrée

Dérivez l'ID du repository de git s'il n'est pas fourni :

git remote get-url origin
# Supprimez le protocole et le .git de fin, puis mettez en minuscules le résultat
# ex. https://github.com/DataDog/my-repo.git → github.com/datadog/my-repo

Repli de validation : Si l'ÉTAPE 1 ne retourne aucun résultat, confirmez le repository correct en recherchant sans filtre de repo :

Outil : search_datadog_test_events
query: @test.name:"<test-name>"
from: now-30d
test_level: test

Extrayez @git.repository.id_v2 des résultats et relancez l'ÉTAPE 1 avec la valeur confirmée.

ÉTAPE 1 — Obtenir les détails du test instable

Préféré — utiliser fingerprint_fqn si connue (fingerprint_fqn est une facette de recherche CI Visibility valide) :

Outil : get_datadog_flaky_tests
query: fingerprint_fqn:<fqn>
sort_field: last_flaked
sort_order: desc

Repli — utiliser nom + suite + repo :

Outil : get_datadog_flaky_tests
query: @test.name:"<test-name>" @test.suite:"<suite>" @git.repository.id_v2:"<repo>"
sort_field: last_flaked
sort_order: desc

Omettez @test.suite si inconnue. Ne filtrez pas par flaky_test_state — retournez le test quel que soit l'état.

Remarque : la facette de filtre de requête est flaky_test_state ; l'attribut retourné est flaky_state — n'utilisez pas flaky_state:active comme filtre de requête.

Extrayez des résultats :

  • fingerprint_fqn — identifiant unique du test ; utilisé comme id dans l'appel d'écriture de l'ÉTAPE 5. S'il est absent, ne procédez pas à la quarantaine — voir ÉTAPE 5.
  • flaky_state — état actuel (active / quarantined / disabled / fixed)
  • test_stats.failure_rate_pct — pourcentage de runs qui échouent
  • flaky_category — catégorie de cause racine
  • codeowners — équipe responsable
  • pipeline_stats.total_lost_time_ms — total du temps CI perdu

ÉTAPE 2 — Obtenir l'historique des défaillances récentes

Outil : search_datadog_test_events
query: @test.name:"<test-name>" @test.suite:"<suite>" @test.status:fail @git.repository.id_v2:"<repo>"
from: now-7d
test_level: test

Extrayez :

  • Messages d'erreur et stack traces (@error.message, @error.stack)
  • Branches défaillantes (@git.branch) — spécifique à une branche vs. généralisée
  • Pattern de fréquence — timing aléatoire ou conditions spécifiques
  • Valeurs uniques de @ci.pipeline.id pour le rayon d'impact (ÉTAPE 3)

ÉTAPE 3 — Vérifier le rayon d'impact

Comptez les pipelines distincts impactés en utilisant les ID de pipeline de l'ÉTAPE 2 :

Outil : aggregate_datadog_ci_pipeline_events
query: @ci.status:error @ci.pipeline.id:(<id1> OR <id2> OR ...) @git.repository.id_v2:"<repo>"
ci_level: pipeline
aggregation: count
group_by: ["@ci.pipeline.name"]
from: now-7d

Utilisez les 10 premiers ID de pipeline de l'ÉTAPE 2 (limité à 10 ; s'il y en a plus, lancez un second batch et fusionnez les résultats en additionnant les comptages par @ci.pipeline.name entre les batches). Signalez le rayon d'impact comme : nombre total de pipelines uniques impactés et si les défaillances sont spécifiques à une branche ou généralisées.

Remarque : une défaillance de pipeline n'est pas nécessairement causée uniquement par ce test instable — traitez le rayon d'impact comme un signal, non un comptage définitif.

ÉTAPE 4 — Recommander un correctif ou une quarantaine

Utilisez flaky_category de l'ÉTAPE 1 et les messages d'erreur de l'ÉTAPE 2.

Cause racine d'abord :

  • Lisez la trace d'erreur complète de bas en haut — les erreurs chaînées masquent la véritable cause ; l'erreur la plus interne est la cause racine, non la première ligne.
  • Identifiez la source exacte du non-déterminisme (race, ordonnancement, état obsolète, timing).
  • Si la cause racine est un problème d'infrastructure CI (runner indisponible, défaillance du démon Docker, panne réseau) → ne proposez PAS de correctif de code ; classifiez comme infra et recommandez une relance à la place.
  • Si la cause racine est incertaine et ne peut pas être confirmée par la stack trace → ignorez le correctif, allez à la quarantaine.

Correctif à la bonne couche :

  • Problème de test → corriger dans le test ou le helper de test uniquement.
  • Bug de production exposé par le test → corriger dans le code de production.
  • Helper partagé utilisé par plusieurs tests → corriger le helper ET mettre à jour tous les sites d'appel.

Interdits — ne proposez pas ceux-ci :

  • Hacks de timing : augmenter les timeouts, ajouter des sleeps, élargir les fenêtres de temps, ajouter des retries.
  • Masquage : relâcher les assertions (ex. correspondance exacte → au moins 1), supprimer les validations.
  • Correctifs partiels : toucher un site d'appel quand plusieurs partagent la cause racine.

Patterns de correctif par catégorie :

Catégorie Approche
timeout Identifiez l'opération lente et rendez-la synchrone ou déterministe — ne relevez PAS simplement la constante timeout
concurrency Ajoutez une synchronisation déterministe (barrières, canaux, verrous) ; supprimez l'état mutable partagé entre les tests
network Mockez ou stubifiez les appels réseau à la limite ; si le test nécessite une connexion réelle, isolez-le avec un serveur de test
time Injectez une horloge contrôlable ; remplacez les assertions wall-clock par des vérifications relatives ou événementielles
order_dependency Isolez l'état du test avec setup/teardown ; éliminez les dépendances sur l'ordre d'exécution ou l'état global
environment_dependency Mockez les variables d'env et la config externe ; utilisez des fixtures locales au test, pas de répertoires partagés ou singletons
resource_leak Assurez-vous que chaque ressource ouverte dans un test est fermée en teardown ; utilisez des hooks de cleanup qui s'exécutent même en cas d'échec
randomness Fixez la graine aléatoire pour l'exécution du test ; utilisez des entrées déterministes au lieu de génération aléatoire
asynchronous_wait Remplacez les sleeps fixes par du polling conditionnel ou des attentes basées sur événement/signal avec un hard timeout
io Utilisez des fichiers/répertoires temp nettoyés en teardown ; mockez ou stubifiez les interactions système de fichiers
unknown Ignorez la tentative de correctif → allez à la quarantaine

Avant de proposer des changements de code, vérifiez tous les points suivants — si l'un échoue, ignorez le correctif et recommandez la quarantaine :

  • La cause racine est l'erreur la plus interne de la trace, non un symptôme de surface.
  • La défaillance est un problème de code, non un problème d'infrastructure CI.
  • Le correctif élimine la cause racine (ne réduit pas seulement la probabilité de flake).
  • Le correctif est à la bonne couche (test vs. production vs. helper partagé).
  • Tous les sites d'appel de tout code partagé sont mis à jour.
  • Aucun hack de timing ou assertion relâchée introduit.

Décision :

  • Si la catégorie est unknown OU la vérification ci-dessus échoue → ignorez le correctif, recommandez la quarantaine
  • Si la catégorie est connue ET la cause racine est confirmée ET le correctif est valide → proposez un changement de code spécifique

ÉTAPE 5 — Produire le rapport de triage et agir

Rapport de triage du test instable
===================================
Test :           <nom du test complètement qualifié>
Service :        <@test.service>
Catégorie :      <flaky_category>
Taux d'échec :   <test_stats.failure_rate_pct>%
Temps perdu :    <pipeline_stats.total_lost_time_ms>ms
Codeowners :     <codeowners>
Rayon d'impact : <N> pipelines (<spécifique à une branche | généralisé>) [approximatif — d'autres défaillances dans les mêmes exécutions de pipeline peuvent ne pas être liées]

Preuves :
  <1-2 lignes clés de message d'erreur de l'ÉTAPE 2>

Recommandation : <correctif | quarantaine | escalade>
Confiance :      <haute | moyenne | basse>
Action :         <prochaine étape spécifique>

Seuils de décision :

  • failure_rate_pct > 10 OU rayon d'impact > 5 pipelines → quarantaine
  • failure_rate_pct ≤ 10 ET catégorie connue ET correctif clair → correctif
  • failure_rate_pct ≤ 10 ET catégorie unknownescalade vers les codeowners avec le rapport de triage

Si vous recommandez la quarantaine, présentez et exigez l'approbation explicite de l'utilisateur avant l'écriture :

Action proposée : quarantaine "<test-name>"
  id (fingerprint_fqn): <fingerprint_fqn de l'ÉTAPE 1>
  Effet : le test s'exécute toujours mais les défaillances sont supprimées (CI ne sera pas bloquée)
  Réversible : oui — réglez new_state: active pour restaurer

Approuvez-vous ? (oui/non)

Si fingerprint_fqn n'a pas été retournée à l'ÉTAPE 1 (test pas encore dans FTM ou la requête n'a retourné aucun résultat) : ne tentez pas l'écriture. Surfacez une erreur et demandez à l'utilisateur d'ouvrir l'UI Flaky Test Management directement pour quarantainer manuellement.

Seulement après approbation explicite et un fingerprint_fqn confirmé :

Mode MCP :

Outil : update_datadog_flaky_test_states
test_ids: ["<fingerprint_fqn>"]
new_state: quarantined

Mode pup :

cat > /tmp/flaky-update.json <<'EOF'
{
  "data": {
    "type": "UpdateFlakyTestsRequest",
    "attributes": {
      "tests": [{"id": "<fingerprint_fqn>", "new_state": "quarantined"}]
    }
  }
}
EOF
pup test-optimization flaky-tests update --file /tmp/flaky-update.json

Pour annuler : répétez avec new_state: active / "new_state": "active".


Référence des outils

Cet appendice s'applique uniquement en mode pup. En mode MCP, utilisez les noms d'outils des sections workflow directement.

Outil MCP Commande pup
get_datadog_flaky_tests (par fingerprint_fqn) pup cicd flaky-tests search --query "fingerprint_fqn:<fqn>" --sort="-last_flaked" --limit 5
get_datadog_flaky_tests (par nom + suite + repo) pup cicd flaky-tests search --query "@test.name:\"...\" @test.suite:\"...\" @git.repository.id_v2:\"...\"" --sort="-last_flaked" --limit 10
search_datadog_test_events (repli de validation) pup cicd tests search --query "@test.name:\"<test-name>\"" --from 30d --limit 5
search_datadog_test_events (historique de défaillance) pup cicd tests search --query "@test.name:\"...\" @test.suite:\"...\" @test.status:fail @git.repository.id_v2:\"...\"" --from 7d --limit 20
aggregate_datadog_ci_pipeline_events (rayon d'impact) pup cicd events aggregate --query "@ci.status:error @ci.pipeline.id:(...) @git.repository.id_v2:\"...\"" --compute count --group-by "@ci.pipeline.name" --from 7d
update_datadog_flaky_test_states Écrivez le corps dans /tmp/flaky-update.json, puis pup test-optimization flaky-tests update --file /tmp/flaky-update.json

Skills similaires