root-cause

Par crbnos · carbon

Analyse en lecture seule de la cause racine pour tout bug, échec de test ou comportement inattendu — avant de proposer ou d'écrire un correctif. Produit un rapport contenant la cause racine, les fichiers à modifier, l'approche et les risques. Aucune modification, aucun commit, aucune commande changeant l'état du système. À utiliser avant `/fix` ou `/conductor` lorsque la cause n'est pas encore établie avec certitude. Si la lecture statique ne permet pas d'atteindre une cause fiable, le relais est passé à `/debugging-difficult-bugs` pour une instrumentation à l'exécution.

npx skills add https://github.com/crbnos/carbon --skill root-cause

<!-- Workflow pattern inspired by Open Mercato (MIT License) https://github.com/open-mercato/open-mercato Copyright (c) 2025-2026 Open Mercato contributors -->

root-cause — analyse des bugs en lecture seule

Vous effectuez une analyse en lecture seule : aucune édition de fichier, aucune branche, aucune commande qui mute l'état. La sortie est un résumé sur lequel un humain ou /fix agit.

La règle d'or : pas de correction sans cause identifiée. Une correction proposée avant que la cause soit comprise est une devinette, et les devinettes créent de nouveaux bugs. Les rustines symptomatiques sont un échec, même si elles font disparaître l'erreur.

Annoncez au début : « Utilisation de la skill root-cause — analyse en lecture seule de ce bug. »

Step 0 : Charger le contexte

  1. Le rapport de bug — description complète, étapes de repro, fils/issues liés.
  2. .ai/lessons.md — pièges connus dans la zone affectée.
  3. Root AGENTS.md Task Router → les guides .ai/rules/ correspondants.
  4. Le AGENTS.md du module/package affecté.

Step 1 : Établir les faits

  1. Lire l'erreur complètement — stack trace complète, message, statut HTTP, noms et numéros de ligne. Le texte d'erreur contient souvent la réponse.
  2. Reproduire ou tracer. Énoncez les étapes de repro exactes. Si vous ne pouvez pas reproduire mentalement, collectez plus de données — ne devinez pas.
  3. Vérifier les changements récents : git log --oneline -20 -- <affected paths> et le diff de la branche. La plupart des bugs vivent dans ce qui a changé en dernier.
  4. Tracer le flux de données du point d'entrée à l'origine : route → loader/action → fonction service → requête → réponse. Notez chaque transformation. Suivez la mauvaise valeur vers l'arrière jusqu'au lieu où elle devient d'abord incorrecte — corriger à la source, non pas là où le symptôme apparaît (voir references/root-cause-tracing.md).
  5. Vérifier le schéma : lisez les migrations pertinentes les plus récentes (triées par timestamp) et les types générés. Les noms et contraintes de colonnes doivent correspondre à ce que le code suppose.

Step 2 : Modes de défaillance Carbon-spécifiques

Vérifiez chacun de ceux-ci avant d'inventer des théories exotiques :

Vérification À rechercher
Périmètre companyId Une requête manquant le filtrage companyId → fuite inter-locataires ou résultats vides
Types générés périmés Le code référence des colonnes d'une nouvelle migration mais pnpm run generate:types n'a pas été exécuté — typecheck ment
Lacunes de politique RLS Nouvelle table/colonne sans politiques ; vérifier les migrations de la table
Chaînes de permission requirePermissions() / permissions.can() les périmètres sont des littéraux de chaîne — invisibles à typecheck ; grepez tout le repo après tout changement de scope
Dérive de signature service Les args de l'appelant ne correspondent pas à la signature actuelle de la fonction service
Ordre des migrations Une migration antidatée plus ancienne que les déploiements appliqués s'applique hors ordre sur les remotes (voir .ai/lessons.md)
Soumission de formulaire ValidatedForm soumet uniquement sur un submit natif avec un submitter ; les champs number/date react-aria commettent des inputs cachés au blur (voir /test pour les détails)
Staleness d'import Import depuis un chemin déplacé sans pont de réexport

Step 3 : Une hypothèse à la fois

  1. Formez une seule hypothèse spécifique : « X dans le fichier Y cause le bug parce que Z. »
  2. Vérifiez-la contre le code que vous pouvez lire. Si le code la contredit, abandonnez-la — ne forcez pas.
  3. Distinguez la cause du symptôme : un TypeError UI peut provenir de trois couches plus bas. Continuez à tracer jusqu'à atteindre l'origine.
  4. Règle des trois tentatives : si 3 hypothèses ont échoué, le problème est probablement architectural (état partagé, couplage, un mauvais pattern) — ARRÊTEZ, notez ce que vous avez exclu, et surfacez la question architecturale à l'humain plutôt que de produire l'hypothèse #4.

Step 4 : Confiance

Niveau Signification
HIGH Cause identifiée avec preuves de code ; chemin de correction évident
MEDIUM Hypothèse forte soutenue par le code ; confirmation runtime aiderait
LOW Plusieurs causes plausibles ou le bug apparaît dépendant du runtime/environnement

Si MEDIUM ou LOW et le bug implique l'état runtime, l'ordre, le cache, la concurrence, ou la reproduction manuelle → recommandez /debugging-difficult-bugs (instrumentation JSONL temporaire) comme étape suivante plutôt que de deviner. Ne présentez jamais une devinette comme une découverte.

Step 5 : Sortir le résumé

Produisez exactement cette structure (~400 mots max) :

## Root-Cause Brief

**Bug:** <une ligne>
**Summary:** <2–3 phrases : symptôme et impact observable>
**Root cause:** <pourquoi ça arrive, citant file:line>
**Confidence:** HIGH | MEDIUM | LOW
<si non HIGH : ce qui est incertain et ce qui le résoudrait — p. ex. « instrumenter via /debugging-difficult-bugs »>

**Files to change:**
- `path/to/file.ts` — <quoi et pourquoi>

**Approach:**
1. <étape>

**Risks:**
- <p. ex. « changement de signature affecte 3 appelants »>

**BC impact:** <NONE | surfaces FROZEN/STABLE touchées, per BACKWARD_COMPATIBILITY.md>

Guardrails

  • Lecture seule. Aucune édition, aucune écriture git, aucune migration, aucune commande DB.
  • Aucune correction spéculative. « Essayez ceci et voyez » n'est pas une découverte.
  • Restez scoped. Analysez uniquement le bug signalé ; notez les découvertes non connexes en une ligne à la fin, ne les poursuivez pas.
  • Citez les preuves. Chaque affirmation référence un fichier, une ligne, une migration ou une politique.

Drapeaux rouges — penser à l'un de ceux-ci signifie que vous devinez, non pas analyser ; ARRÊTEZ :

  • « c'est probablement X, laissez-moi suggérer la correction » (pas de cause vérifiée → pas de correction)
  • « Je vais proposer deux corrections possibles et les laisser choisir » (c'est deux devinettes)
  • « une hypothèse de plus » après trois échecs (c'est une question architecturale maintenant — surfacez-la)
  • « le message d'erreur est trompeur, ignorez-le » (relisez-le ; c'est rarement le cas)

References (lire quand la situation correspond)

  • references/root-cause-tracing.md — tracer une mauvaise valeur en arrière dans la pile d'appels jusqu'à son origine
  • references/defense-in-depth.md — mise en couches de validation après que la cause soit trouvée
  • references/condition-based-waiting.md (+ condition-based-waiting-example.ts) — remplacer les timeouts arbitraires par l'interrogation basée sur condition dans les tests async flaky
  • references/find-polluter.sh — bisection pour savoir quel test antérieur pollue un test en échec

Skills similaires