fix

Par crbnos · carbon

Pipeline de correction de bugs de bout en bout qui diagnostique, implémente et valide le correctif. Il orchestre `/root-cause`, `/debugging-difficult-bugs`, `/test` et `/check-and-commit`, et effectue lui-même la correction — la modification de code minimale découlant de la cause identifiée, accompagnée d'un test de régression rouge→vert obligatoire et de gates de validation ciblées. Au démarrage, il choisit un mode d'autonomie (approbation avant chaque phase vs entièrement autonome) et un ensemble de phases (root-cause + fix sont obligatoires ; l'instrumentation runtime est conditionnelle à la confiance ; le test est optionnel ; le commit ne s'exécute que sur demande explicite), détectés automatiquement depuis la requête et confirmés avec l'utilisateur en cas d'ambiguïté. Conserve un journal d'exécution structuré dans `.ai/runs/{date}-{slug}.md`. À utiliser pour corriger un bug, un échec de test ou un comportement inattendu (« corrige ce bug », « pourquoi X échoue »). Ne pas utiliser pour développer de nouvelles fonctionnalités (utiliser `/feature`). Pour un seul élément surveillé avec des critères d'acceptation explicites, préférer `/conductor`.

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

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

fix — pipeline end-to-end de correction de bug

Exécute le cycle de vie de correction de bug : diagnostiquer → (instrumenter) → implémenter la correction minimale avec test de régression rouge→vert → (vérifier) → (committer). Cette skill orchestre les phases environnantes et effectue elle-même la correction. Les phases de diagnostic et vérification délèguent à leurs propres skills ; l'implémentation de la correction (Phase 3) se fait inline ici — c'est le cœur de cette skill.

Annonce au démarrage : « Using the fix skill — {autonomy mode}, phases: {selected}. »

Les phases

# Phase Skill / responsable Artifact Obligatoire ? Arrêt dur
1 Cause racine /root-cause brief de cause racine toujours 🛑 trois erreurs architecturales → remonter
2 Instrumentation /debugging-difficult-bugs cause sauvegardée en log conditionnelle aucune
3 Correction cette skill (inline) changement prêt + test régression rouge→vert toujours 🛑 BLOQUÉ (2 échecs de correction) → remonter
4 Vérification web /test résultat pass/fail + playbook optionnelle le flux utilisateur doit passer
5 Commit /check-and-commit commit conventionnel uniquement sur demande les portes doivent être au vert

Cause racine et Correction sont non-négociables — la règle en fer est pas de correction sans cause prouvée, et la correction en est l'enjeu. Tout le reste est opt-in.

Étape 0 : Choisir mode autonomie + ensemble de phases — toujours en premier

Écris le registre d'exécution (ci-dessous) en faisant ces choix, puis annonce-les.

0a. Mode autonomie

Détecte à partir de la demande ; demande seulement si aucun des deux n'est clair.

Mode Signaux Comportement
Approbation par phase « ask me », « step by step », « check with me », « gate each phase » Pause avant chaque phase, énonce ce qu'elle fera en une ligne, attends le feu vert.
Entièrement autonome « autonomously », « just fix it », « don't ask », « end to end » Exécute sans intervention ; auto-décide les branches conditionnelles (instrumenter ? tester ?) et enregistre chaque choix. Les deux 🛑 arrêts dur remontent toujours — trois-strikes architecturales et BLOQUÉ ne sont pas auto-résolubles.

Défaut quand ambigu : demander — une question, les deux options ci-dessus.

0b. Ensemble de phases

Cause-racine et correction tournent toujours sur un démarrage frais ; une exécution reprise peut commencer au-delà quand un artifact antérieur satisfait déjà la phase (voir Entrer en milieu de pipeline). Le reste se décide comme suit — note que certaines branches se résolvent après cause-racine, pas en amont :

  • Instrumentation runtime (/debugging-difficult-bugs) — une branche runtime, décidée après phase 1 : exécute cause-racine d'abord, lis sa ligne Confidence. Inclus quand cause-racine retourne MEDIUM/LOW et le bug implique état runtime, ordonnancement, cache, concurrence, streaming, ou reproduction manuelle/UI. Saute quand cause-racine est HIGH ou une stack trace / test défaillant déterministe prouve déjà la cause.
  • Test (/test) — inclus quand la correction est tournée utilisateur ou la preuve est intrinsèquement visuelle (layout, espacement, animation). Saute pour une correction de pur logic déjà couverte par le test de régression Phase 3 rouge→vert — enregistre le saut (« browser test skipped — regression test covers it »).
  • Commit (/check-and-commit) — tourne seulement si l'utilisateur l'a explicitement demandé (ex. « fix and commit »). Sinon le pipeline s'arrête à la correction (+ test) avec un résumé READY et arrête ; propose de committer, ne le fais pas sans demande.

Étape 0c : Ouvre le registre d'exécution — artifact de standardisation

Crée .ai/runs/{date}-{slug}.md avant la première phase sélectionnée (phase 1 sur un démarrage frais ; Fix ou Test sur une exécution reprise — voir Entrer en milieu de pipeline). Un log canonique unique de ce qui a été diagnostiqué, décidé et prouvé — pour que le même bug traité par des ingénieurs différents produise des résultats comparables.

# Bugfix run: {title}

- Date: {date} <!-- demande à l'utilisateur ou utilise currentDate injecté ; les skills n'ont pas d'horloge -->
- Mode: approval-per-phase | fully-autonomous
- Request: {le rapport de bug, verbatim}
- Phase plan: root-cause [run] · instrument [run|skip — résolu après root-cause] · fix [run] · test [run|skip — pourquoi] · commit [run|skip — demande explicite ?]

## Decisions <!-- choix de branche autonome + tout arrêt dur remonté -->

- {branche/porte}: {décision} — {justification} — {timestamp}

## Phase log

- root-cause: {confidence + résumé bref}
- {phase}: {résultat + chemin d'artifact}

## Outcome

- {READY / SHA commité / lien PR / BLOQUÉ + pourquoi}

Mets à jour à chaque transition de phase, quand la branche instrumentation se résout, et sur tout arrêt dur. Runtime vit dans .ai/runs/ (gitignored) — jamais dans l'arbre produit.

Exécution des phases

Exécute les phases sélectionnées dans l'ordre ; saute les désélectionnées. Annonce chaque transition en une ligne (« Phase 3: fix — cause confirmed HIGH, writing the test »).

  • Mode approbation : avant chaque phase, pause pour le feu vert de l'utilisateur.
  • Mode autonome : procède entre phases et auto-décide les branches instrument/test, enregistrant chacune. Mais arrête et remonte aux deux 🛑 arrêts dur — ils ont besoin de jugement humain, pas auto-résolution.

La décision instrumentation se prend en direct : après que /root-cause produit son brief, lis la ligne Confidence et branche par 0b avant de continuer.

Phase 3 en détail — implémenter la correction

C'est le cœur obligatoire. Entrée : le brief de cause racine prouvée. Sortie : la plus petite correction correcte plus test de régression, toutes portes au vert. Exécute le brief, prouve-le, et arrête.

3.1 Prérequis

  1. Lis le brief. Pas de cause prouvée → tu n'es pas en Phase 3 encore ; reviens à Phase 1 (/root-cause). Ne corrige jamais une hypothèse.
  2. Lis .ai/lessons.md pour la zone affectée.
  3. Lis le AGENTS.md du module/package affecté.
  4. Lis BACKWARD_COMPATIBILITY.md si le brief liste des impacts de compatibilité rétroactive.
  5. Si tu travailles un issue GitHub : gh issue edit <number> --add-assignee carbon-agent --add-label "agent:working".

3.2 Planifie le changement

Liste avant de toucher au code : fichiers à modifier (du brief), fichiers à créer (tests, migrations), appelants à mettre à jour (si signature change — grep chaque callsite). Si le brief dit 2 fichiers et ta liste en dit 8 → ARRÊTE et re-cadre avec l'humain.

3.3 Écris le test défaillant D'ABORD

Obligatoire pour toute correction. Écris un test de régression qui reproduit le bug, puis exécute-le et regarde-le échouer avant de changer du code production :

pnpm --filter <pkg> exec vitest run <path/to/test>
# Expected: FAIL, for the reason the brief describes (not a typo/import error)

Un test qui passe immédiatement ne prouve rien — il ne teste pas le bug. Emplacements test : apps/erp/app/modules/{module}/__tests__/ ou packages/{pkg}/src/__tests__/ (ou à côté de la source, pairs correspondants). Copie les patterns setup d'un fichier test voisin.

Si le bug n'est provable que dans le navigateur (layout, état visuel), la preuve défaillante est une exécution /test + screenshot AVANT à la place — dis-le explicitement, et assure-toi que Phase 4 (Browser verify) est dans l'ensemble phases.

3.4 Implémente

  • Une préoccupation. Corrige le bug. Pas de refactoring, pas de cleanup, pas de « tant que je suis là ».
  • Respecte les patterns environnants — grep le code similaire et copie son idiome.
  • Scoping companyId sur chaque requête de données locataire nouvelle ou modifiée. Ne le saute jamais.
  • Discipline de module : un {module}.service.ts, un {module}.models.ts.
  • Imports : ~/* code app, @carbon/* packages workspace.
  • Changements schema : suis .ai/rules/workflow-database-migration.md ; puis pnpm run generate:types AVANT vérification de type.
  • Rayon d'impact minimal : fewest files, fewest lines, toujours complet.

3.5 Valide (portes scoped, dans l'ordre)

# 1. Types (seulement si schema changé)
pnpm run generate:types

# 2. Format + lint les fichiers touchés
pnpm exec biome check --write <changed paths>

# 3. Typecheck chaque package touché — JAMAIS tout le repo (ça OOM)
pnpm exec turbo run typecheck --filter=<pkg>

# 4. Tests pour chaque package touché — ton nouveau test doit maintenant PASSER
pnpm --filter <pkg> test

Porte échouée ? Lis l'erreur. Causée par ton changement → corrige et re-exécute. Clairement pré-existante et sans rapport → note-le en sortie, ne la chasse pas. Deux échecs de correction sur la même porte → ARRÊTE, signale BLOQUÉ (🛑 arrêt dur — remonte à l'humain même en mode autonome).

3.6 Auto-revue

Vérification Question
Portée Ai-je changé seulement ce que le brief demandait ?
Rouge→vert Ai-je vu le test échouer avant la correction et réussir après ?
companyId Toute requête nouvelle/modifiée scoped ?
Appelants Tout appelant de signature modifiée mis à jour ?
CR Toute surface FROZEN touchée ? STABLE sans dépréciation ?
Patterns Le code se lit-il comme ses voisins ?
Restes Pas de log de debug, code commenté, ou fichiers errants dans le diff ?

3.7 Sortie de correction

## Fix Summary
**Status:** READY | BLOCKED <si BLOQUÉ: quoi et pourquoi>
**Root-cause brief:** <chemin/lien>
**Files changed:** <chemin — quoi>
**Regression test:** <chemin — échoué avant correction (sortie), passe après (sortie)>
**Gates:** generate:types PASS|SKIP · biome PASS · typecheck(<pkgs>) PASS · test(<pkgs>) PASS
**BC assessment:** NONE | <surfaces et comment elles se conforment>
**Summary:** <2–3 phrases>

Puis continue Phase 4/5 par l'ensemble phases, ou arrête à READY et propose de committer.

Entrer en milieu de pipeline

Commence à la première phase sélectionnée dont l'entrée manque :

Tu as déjà Commence à
Rien Cause racine
Un brief de cause-racine prouvé Correction (ou Instrumentation si cause MEDIUM/LOW + runtime)
Une correction implémentée, non vérifiée Test (ou Commit si utilisateur l'a demandé)

Règles dures

  • Sur un démarrage frais, cause-racine et la correction tournent tous deux — ne saute jamais le diagnostic, ne corrige jamais une hypothèse. Une exécution reprise peut commencer au-delà seulement quand un artifact antérieur (un brief prouvé, une correction implémentée) satisfait déjà cette phase (voir Entrer en milieu de pipeline).
  • Pas de commit, pas de push, pas de PR à partir de Phase 3 elle-même. Committer arrive seulement en Phase 5 via /check-and-commit, et seulement sur demande commit explicite ; sinon arrête à READY et propose.
  • Les deux 🛑 arrêts dur remontent à l'humain même en mode autonome — trois-strikes-architecturales (cause-racine) et BLOQUÉ (correction). Enregistre-les ; ne les couvre pas.
  • Ne présente jamais une hypothèse comme un finding — si cause-racine ne peut pas atteindre une cause confiante et aucun chemin runtime n'aide, arrête et dis-le.
  • Pas scope creep — bugs connexes recevront une ligne en sortie, pas une correction.
  • Sauter une phase est une décision enregistrée avec raison, pas une omission silencieuse.

Signaux d'alarme — penser l'un d'eux signifie que le processus déraille ; ARRÊTE :

  • « la correction est évidente, j'écrirai le test après » (un test écrit après passe immédiatement et ne prouve rien — 3.3 vient d'abord)
  • « tant que je suis là, je vais nettoyer ça aussi »
  • « le test est dur à écrire, je vais juste vérifier manuellement » (signale BLOQUÉ à la place)
  • « le brief est probablement juste » (si le code que tu lis ne confirme pas la cause, reviens à /root-cause)

Alternative : le conductor

Pour un seul bug étroitement cadré avec critères d'acceptation explicites que tu veux regarder itérer jusqu'à PR gated, préfère /conductor — une boucle doer→gate→judge supervisée à la place de ce pipeline.

Skills similaires