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 :
- Si l'utilisateur a passé
--backend pupn'importe où → utilisez le mode pup immédiatement. Ignorez les étapes 2–4. - Vérifiez si
get_datadog_flaky_testsfigure parmi vos outils disponibles. - Si présent → utilisez le mode MCP partout. Appelez les outils exactement comme nommés dans les sections workflow de ce skill.
- Si absent → vérifiez si
pupest exécutable : lancezpup --versionvia Bash. Une réponse JSON contenant"version"confirme que pup est disponible. - 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.
- 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 refreshoupup 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é commeiddans 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 échouentflaky_category— catégorie de cause racinecodeowners— équipe responsablepipeline_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.idpour 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
infraet 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
unknownOU 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 > 10OU rayon d'impact > 5 pipelines → quarantainefailure_rate_pct ≤ 10ET catégorie connue ET correctif clair → correctiffailure_rate_pct ≤ 10ET catégorieunknown→ escalade 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 |