debugging-difficult-bugs

Par crbnos · carbon

Débogage par instrumentation à l'exécution pour les bugs que la lecture statique ne permet pas de localiser — ajouter un logging JSONL inconditionnel temporaire sur le vrai chemin de code, reproduire, lire le log, puis corriger. À utiliser quand `/root-cause` aboutit à une confiance MEDIUM/LOW, quand un bug implique un état d'exécution, un ordonnancement, du cache, du streaming, de la concurrence, ou une reproduction manuelle/UI, ou avant un second correctif spéculatif. À ignorer quand une stack trace ou un test déterministe en échec prouve déjà la cause.

npx skills add https://github.com/crbnos/carbon --skill debugging-difficult-bugs

debugging-difficult-bugs — instrumenter, reproduire, lire, puis corriger

Idée centrale : quand tu ne vois pas la défaillance en lisant le code, fais parler le runtime. Ajoute du logging JSONL temporaire append-only le long du vrai chemin de code, reproduis le vrai problème une fois, lis le log chronologiquement, et seulement alors corrige. Ne fais jamais une deuxième correction spéculative sans nouvelle preuve du runtime.

Annonce au démarrage : « Utilisation de la skill debugging-difficult-bugs — instrumentation du chemin d'exécution pour observer la défaillance. »

Étape 1 : Énonce l'incertitude

Écris : ce que tu crois, ce que tu ne peux pas vérifier statiquement, et le chemin d'exécution exact qui doit être observé (route → service → query, edge function, job).

Étape 2 : Ajoute l'instrumentation temporaire inconditionnelle

Règles :

  • Inconditionnelle — jamais derrière une variable d'env, flag de débogage, ou log level. Si la reproduction nécessite de se souvenir de définir un flag, elle ne s'activera silencieusement pas.
  • JSONL append-only, un objet JSON par ligne, dans un fichier du répertoire de travail du processus.
  • Log les frontières et décisions, pas chaque ligne : entrée/sortie de fonction, décisions de branchement avec les données qui les ont causées, état avant/après mutation, marqueurs d'ordre async, erreurs attrapées, formes de valeurs retournées.
  • Log les formes, pas les payloads : ids, clés, compteurs, statuts. Ne log jamais de tokens, en-têtes d'auth, cookies, ou contenu utilisateur complet.
import { appendFileSync } from "node:fs";
import { join } from "node:path";

function debugBug(event: string, data: Record<string, unknown> = {}) {
  appendFileSync(
    join(process.cwd(), "debug-difficult-bug.jsonl"),
    `${JSON.stringify({ ts: new Date().toISOString(), event, ...data })}\n`
  );
}

debugBug("service.beforeUpdate", { id, companyId, status: row.status });

Note multi-processus Carbon. Les serveurs dev ERP/MES, les edge functions (conteneur Docker edge-runtime), et les handlers Inngest s'exécutent comme des processus séparés avec des répertoires de travail différents. Log process.cwd() + un rôle de processus une fois au démarrage, ou utilise des noms de fichiers distincts (debug-erp.jsonl, debug-edge.jsonl). Pour les edge functions, console.error les lignes JSON (visibles dans les logs du conteneur) peut suffire quand le filesystem du conteneur est difficile d'accès.

Étape 3 : Reproduis le vrai problème une fois

  • Privilégie te reproduire toi-même : démarre la stack (crbn up si pas déjà en cours), authentifie-toi avec /auth, et pilote le flux défaillant exact avec agent-browser (la skill /test documente les pièges de formulaires Carbon — requestSubmit, react-aria blur).
  • Si seul l'utilisateur peut reproduire (ses données, son environnement), dis-lui exactement : « J'ai ajouté du logging temporaire. Reproduis le problème une fois, puis pointe-moi sur <cwd>/debug-difficult-bug.jsonl. »

Étape 4 : Lis le log AVANT de corriger

Lis chronologiquement et réponds par écrit :

  1. Le chemin instrumenté a-t-il vraiment exécuté ?
  2. Quelle était la séquence d'événements attendue ?
  3. Quelle a été la séquence réelle ?
  4. Quel est le premier point où l'état/ordre/branchement diverge de l'attente ?

Cette première divergence est le candidat cause racine. Réinjecte-le dans le brief cause-racine (ou écris-le maintenant) — puis implémente via /fix, dont le test de régression défaillant doit affirmer la vraie divergence que tu as observée, pas ton hypothèse antérieure.

Étape 5 : Nettoie — obligatoire

  • Supprime chaque appel de log temporaire, helper, et import.
  • Supprime les fichiers .jsonl générés.
  • Vérifie explicitement le diff final pour les restes : git diff | grep -n "debugBug\|debug-difficult\|\.jsonl" → aucun hit attendu.

Le diff final contient seulement la correction et ses tests.

Terminé quand

  • [ ] Le premier point de divergence est identifié par preuve du log (cite les lignes)
  • [ ] La correction est déployée via /fix avec un test de régression rouge→vert affirm ant ce comportement
  • [ ] La reproduction du flux original passe maintenant
  • [ ] Zéro remnant d'instrumentation dans le diff

Skills similaires