Ouverture

Comment (sur)optimiser Claude Code pourSHIPPER
LES YEUX
FERMÉS
1SPEC
L'intention
2AGENT
Le code
3GATES
Remparts
4JUGE
Relecture
5HUMAIN
Je tranche
PROD
Production

36 heures

La plus longue session en autonomie de Claude le week-end dernier.

Les yeux fermés,
ce n'est pas en aveugle.

NOUS SOMMES ICI
0PROLOGUE
Le départ
IARSENAL
L'arsenal
IIDOUTE
Le doute
IIIDÉMARCHE
La démarche
IVREMPARTS
Les remparts
VVITESSE
La vitesse
À GAGNER
PROD
En prod

Acte I · L'arsenal

acte I L'arsenal ce qu’il y a dans la besace
I·II·III·IV·V
Cédric Chariere Fiedler
Cédric Chariere Fiedler
Président & directeur technique · siliceum
siliceum

Pompier des plateformes critiques
spécialisé en archi distribués & fronts exigeants.

99,9 % d'uptime sur >2M requêtes/jour <30 ms pour afficher une page web
Nous avons travaillé ensemble
Fiabilité & performance
Mesurer. Corriger. Optimiser.
Méta-programmation
Du code qui génère du code.
Claude Code
Génère trop de code ...
qui a besoin d'être corrigé

Vous

  • Une bafouilleen langage humain

Claude Code L'agent · Claude Code

  • Lit les fichiers
  • Les modifie
  • Lance des scripts

Le dossier

  • Un changementque vous validez
rien ne part sans votre accord (en théorie)
je fiabilise la prod
le tokenizer découpe
je fia bil ise la prod

≈ ¾ d'un mot · le modèle ne voit que ces morceaux, et chacun se paie.

la fenêtre de contexte 200K1M tokens
CLAUDE.md les fichiers lus la conversation ton prompt

≈ 75 000 lignes de code.

SessionStart il charge ton contexte
CLAUDE.md + rules skills découverts
UserPromptSubmit ton intention
un skill s'active
la boucle read · edit · bash · test
hooks pre/post-outil rules par fichier un agent en renfort
Stop fin du tour
les quality-gates passent
Claude Code
Claude Code
un seul moteur
Interactif
je discute en direct, tour par tour
$ claude
  • dans le terminal ou l'IDE
  • pour explorer, coder à deux
Headless
une seule passe, sans interface
$ claude -p "corrige le lint"
  • dans la CI, un cron, un script
  • pas d'humain dans la boucle
SEXPLORER
Haiku
entrée / sortie · $·Mtok0,25 / 1,25
MQUOTIDIEN
Sonnet
entrée / sortie · $·Mtok3 / 15
l'archi
LLE LOURD
Opus
entrée / sortie · $·Mtok15 / 75
le mythe
XLL'IMPOSSIBLE
Fable 5
entrée / sortie · $·Mtok/

Haiku · le volume

Le plus rapide, le moins cher (0,25 / 1,25 $). Je le lâche sur tout ce qui se compte en masse.

Premier balayage du code, tri de centaines de tickets, résumé de logs.
Transcription en masse ? un modèle self-hosted à la maison : la facture fond.

Sonnet · le quotidien

Le cheval de trait (3 / 15 $). La plupart des cycles tournent dessus.

Écrire le code, dérouler les tests, relire une MR.
Le défaut de l'agent, sauf quand le nœud résiste.

Opus · le lourd

Le plus capable (15 / 75 $). Réservé aux problèmes complexes, à la planification

Les décisions d'architecture (ADR), l'étape juge contre la spec.
Le bug tordu qui résiste à tout le reste. Existe en 2 format de contexte

Fable 5 · l'impossible

Le tout dernier, le plus capable.

Assez puissant pour se faire interdire par les gouvernements
??? . Seulement 2 sessions ensemble
1VOLATILE
Le contexte
un tour, puis /clear /compact
2SEMI-DURABLE
La session
des jours, en JSONL : --resume
L'ÉTAT VIT ICI
3DURABLE
La mémoire déportée
fichiers tickets base

Le contexte · volatile

la fenêtre de travail du moment
jetable : /clear ou /compact
rien n'y survit au tour d'après

La session · semi-durable

JSONL sur le disque
rejouable avec --resume
durée de vie : en jours
local à une machine

La mémoire déportée · durable

Fichiers markdown · CLAUDE.md & mémoires : règles, décisions
Tickets GitLab · le backlog, l'état des features, les ADR
Base de données · métriques, état du daemon, historique des cycles
CLAUDE.md
# Règles permanentes du projet
- Toujours un test rouge avant un fix.
- Jamais de natif : le design system.
- Secrets : gitleaks bloque le commit.
le contrat du projet, pas un README
Session #1
Session #2
Session #N
Le même contrat, lu au démarrage de chaque session.
1LA CHARTE
Les règles permanentes
180 l. · les toujours & les jamais
LA CARTE
2L'INDEX
Où vit quoi
la table des matières
3LE DÉPORTÉ
Le savoir-faire, ailleurs
≈ 33 fichiers à la demande
4PAR DOSSIER
Un CLAUDE.md par dossier
chargé quand on y entre

La charte · les règles permanentes

~180 lignes d'impératifs, non négociables. C'est le contrat lu à chaque réveil.

CLAUDE.md
- Toujours un test rouge avant un fix.
- Jamais de natif : le design system.
- Secrets : gitleaks bloque le commit.

L'index · où vit quoi

Dans le CLAUDE.md : seulement les règles communes à tout. Tout le reste est splitté en fichiers dédiés  · l'index ne fait que pointer.

.rs → charge la skill rust-axum
backend/ → l'agent senior-rust-dev
.sql → la rule rls-queries (scopée par chemin)
incident → le gabarit postmortem

Le déporté · le savoir-faire

≈ 33 fichiers, chargés à la demande : jamais tout en tête, jamais halluciné.

Skills (.claude/skills) · les protocoles, étape par étape
Mémoires · les décisions, les conventions apprises
security/ · la classification des données sensibles

Par dossier · les CLAUDE.md imbriqués

Chaque sous-dossier peut avoir le sien. backend/CLAUDE.md se charge quand l'agent lit un fichier de backend/, pas avant.

Du général au précis : racine → sous-dossier. Tout se cumule, rien ne s'écrase (le plus proche est lu en dernier).
Et au-dessus du projet : ~/.claude (toi) puis la policy d'org.
audit-security/
# SKILL.md · le mode d'emploi
name: audit-security
when: auditer TLS, secrets, auth…

# puis le protocole, étape par étape,
# + scripts du dossier à appeler.
un dossier + un SKILL.md
Il charge la skill à la demande
Il déroule le protocole
Composable avec les autres
Embarque assets, templates, scripts
Pas de magie : du texte que l'agent lit et applique.
SE DÉCLENCHE SEUL
BACKEND
rust-axum
domaine → API, DDD + CQRS
SE DÉCLENCHE SEUL
FRONTEND
vue-nuxt
store → page, design system
QUALITÉ
audit-* · tests
sécu, archi, couverture…

Backend · feature-implementation-rust-axum

Le skill sait quand s'invoquer : il porte sa propre frontière.

feature-implementation-rust-axum.md
## Quand MOI et pas X
- MOI : ticket ready-to-dev + fichiers backend/
- vue-nuxt si : modifs exclusivement frontend/
Ses rules : rls-queries · l'ast-grep rust-api-server-raw-begin bloque un .begin() sans contexte RLS.

Frontend · feature-implementation-vue-nuxt

Types → store Pinia → composable → page → composant. Réutiliser @nuxt/ui avant de créer.

Ses rules : design system d'abord · data-testid sur tout interactif · jamais de prop non déclarée (sync fantôme #812).
Refactor d'API partagée → grep exhaustif des call sites, wrappers compris.

Qualité · les protocoles transverses

Pas liés à un langage : ils cadrent comment on vérifie.

audit-security · audit-architecture · writing-robust-tests
Composables : le skill backend appelle le skill tests, qui appelle la rule.
/plan le départ de tout
la carte avant l'assaut
/goal
chantier long : le Stop hook vérifie le but
/loop
critère connu : itérer jusqu'à l'atteindre
/monitor
process long : le surveiller pour moi
/ma-commande · custom
un geste revient trois fois : un fichier Markdown versionné dans le repo
Une fois · au démarrage
SessionStart
UserPromptSubmit
À chaque outille tour se répète
PreToolUse
L'outil tourne
PostToolUse
Une fois · à la fin
Stop
PreCompact
Dépile le backlog

les tickets ready-to-dev, par priorité

Délègue en parallèle

un worktree isolé par ticket

wt · #265 wt · #267 wt · #271
Pilote via le daemon

plan → execute → review, fusionné quand c'est vert

daemon.ts dispatch-tickets.ts worktree.ts
Installé8 + 3 MCP

des capacités en plus, branchées une fois

superpowers playwright LSP rust·ts·vue·css frontend-design MCP grafana·infra
Skills38

améliorent le fonctionnement de Claude · il les déclenche seul

brainstorming systematic-debugging test-driven code-review audit-* +33
Rules~15

le bornent fichier par fichier · toujours actives

commits minimal-code secure-logging rls-queries test-discipline +10
le vrai moteur
Le moteur80+ scripts testés

des raccourcis déterministes · du code, pas un prompt

daemon.ts mr-review worktree.ts retro-fixes agents-status.ts production-diagnostic
Acte I · l'arsenal

Les questions

Q1ÇA TOURNE
Est-ce que ça tourne ?
Q2CONFORME
Conforme à la demande ?
Q3LE BESOIN
Le vrai besoin ?
+COÛT
À quel coût ?

place au doute

Acte II · le doute

Acte II · Le doute

acte II Le doute pas forcément une solution miracle
I·II·III·IV·V
moi · le prompt
> fais-moi un module de facturation
git diff --stat · ce que l'agent a pondu
 invoice.ts | 312 ++++++++++
 tax.ts | 208 ++++++++
 pdf.ts | 176 ++++++--
 webhooks.ts | 143 +++++-
 ... + 43 autres fichiers
 47 fichiers, +1 240 −287

Ça marche, à côté de la demande. Devant ce pavé, la review ne voit rien.

la limite de vision de l'agent l'agent Le code · tout est vert L'app · pool conforme L'infra · drift de config entre DB et app 503 hors champ
une demande floue · le tunnel
moi  > « aligne mieux ce bloc »
agent ✓ marges revues, bloc recentré
moi  > « non, toujours décalé »
agent ✓ autre jeu de marges
moi  > « pas encore ça… »
 … et ainsi de suite, encore et encore
~300 sessions juste pour des marges et de l'alignement
LA SPEC
Respectée
tests verts · gates passées
AUCUN TEST NE LE VOIT
LE BESOIN
Raté
incohérent avec le métier

Tout est vert : tests passés, gates franchies. Le vrai besoin métier, lui, n'est pas cohérent.

Acte II · le doute
OUVERTE
Q1ÇA TOURNE ?
Le code-machine casse
OUVERTE
Q2CONFORME ?
L'agent dérive seul
OUVERTE
Q3LE BESOIN ?
Aucun test ne le voit

Le doute est posé voici la méthode

Acte III · la démarche

Acte III · La démarche

acte III La démarche du prompt unique à la chaîne
I·II·III·IV·V
le produitUn SaaS de monitoring de qualité continue
« Vibe codé », vitevraie prod, mais du chaos · encore plein de bugs à corriger
Puis stabiliségarde-fous, gates en couches
ce que la démarche a apporté à une vraie prod
une méthode des tools, un outillage une usine autonome
granit-golem · démo
daemon.tsun script · du code maison, déterministe
/planune commande · l'humain la tape au clavier
brainstormingun skill · l'agent l'ouvre seul, au bon moment
rls-queriesune rule · un fichier qui borne, toujours active
ci:lintune étape CI · un job de la pipeline
le jugeun juge LLM · un agent qui tranche
avantun prompt unique, et j'espère Six maillons, une chaîne
01CADRER
Cadrer
le besoin, en questionnant
02SPÉCIFIER
Spécifier
le contrat, en Gherkin
03DÉCOUPER
Découper
en lots livrables
04EXÉCUTER
Exécuter
en parallèle, en worktrees
CLÉ
05VÉRIFIER
Vérifier
gates + juge
06TRACER
Tracer
l'anti-récidive
au maillon 05, la chaîne répond aux trois questions
Q1 · Est-ce que ça tourne ? Q2 · Conforme à la demande ? Q3 · Le vrai besoin ?

Chaque maillon laisse une trace écrite, pas de l'oral qui s'évapore.

OK
Structuré
un format, pas de la prose
OK
Contrôlable
on le revoit, on le corrige
OK
Vérifiable
une gate peut le juger
OK
Versionnable
daté, suivi dans git
spec Gherkin
plan
code + tests
ADR · postmortem
Un artefact qu'on peut relire, rejouer, prouver.
Feature
explorer par interview
Bugfix
reproduire avant de corriger
le tronc commun
L'entrée
/brainstorming

brainstorming

L'interview
Il questionne
Je réponds
Il affine
La sortie
Intention explicite

le fonctionnel posé, prêt à spécifier

1REPRODUIRE
Isoler le cas
le cas qui casse, à part
systematic-debugging
LA PREUVE
2TEST ROUGE
Il prouve le bug
rouge, avant tout fix
test-driven
3FIX · VERT
Le test passe
le défaut est corrigé
verification-before-completion
4BLAST RADIUS
L'impact autour
ce que le fix touche ailleurs
adversarial-feature-challenge

Forcé, pas espéré

Plutôt que de croiser les doigts, on contrôle le résultat.

write-tests.md · 291 l. test-discipline · 1 bug = 1 test gabarit MR · la preuve
1PLAN MODE
On réfléchit
on n'écrit pas encore
/plan
LE PLAN ÉCRIT
2WRITING-PLANS
Un plan daté
découpé en tâches
writing-plans
3TASKS DAG
Un graphe de tâches
étapes + dépendances
cycle/plan.ts

Plan mode · on réfléchit

Explore, propose, questionne une par une, sans toucher au code, selon le type de tâche :

Plan · « Par où commencer : quelle cause racine traiter en premier ? »
Feature · « Quel comportement exact attend l'utilisateur, et où s'arrête le périmètre ? »
Fix · « Quel est le cas minimal qui reproduit le bug, avant tout correctif ? »

writing-plans · le plan écrit

Un fichier daté, versionné, découpé en tâches :

plans/2026-06-03-regle-metier.md
# Plan · 2026-06-03
## T1 · schéma de la règle
## T2 · validations (dépend de T1)
## T3 · tests (dépend de T1)
## T4 · job CI (dépend de T2, T3)

Tasks DAG · le graphe

Un graphe de dépendances : sans dépendance → parallèle, sinon en attente.

T1 T2 T3 T4 en parallèle
Supervision des checks · mise en sourdine #142 ready-to-dev
Epic #25 @crud @snooze @acknowledge @bulk écrit par project-maestro

Contexte · un check en alerte spamme l'équipe pendant une maintenance connue.

Critères d'acceptation
  • la sourdine expire seule, sans intervention
  • traçable et réversible en masse
monitoring/checks.feature
Scénario: Mettre un check en sourdine
 Étant donné un check en alerte
 Quand je le mets en sourdine 2 h
 Alors il n'émet plus jusqu'à expiration
specifications/**/*.feature NFR : WCAG 1.4.1 Tests : UT + E2E + axe-core Screenshot
un vrai, en ligne · #695 · accessibilité WCAG (closed)
Un verbatim, en clair
issue #588 · granit-golem
# PERF · Lighthouse CI bloquant + budget bundle
Étant donné un changement qui dégrade
 le FCP au-delà de 1.5s ou le TBT au-delà de 100ms
Quand le job frontend:lighthouse tourne
Alors le job échoue, score et métriques à l'appui
lighthouserc.js FCP < 1500 · TBT < 100 · bundle < 4500 KB

FCP · premier affichage · l'écran commence à se remplir TBT · temps figé · la page ne répond pas aux clics

Le même contrat, sur quatre autres domaines
A11Y · #695

« toute info portée par la couleur DOIT l'être aussi autrement »

axe wcag2a · 0 use-of-color
SÉCU · #641

« le scan hebdomadaire confirme une fuite : le pipeline échoue »

gitleaks-full bloquant
I18N · #550

« zéro chaîne anglaise en dur dans le rapport »

i18n-check · fail si manquant
DS · #307

« chaque <select : remplacé par UiDropdown, ou justifié »

design-system-audit
DÉCOUPER Des livrables traçables
schéma de la règle validations job CI

une MR thématique, pas cinq atomiques · ×4 moins de pipelines · sauf la migration, toujours séparée.

cycle/plan.ts
VALIDATION HUMAINE AVANT la première ligne

tant que l'humain n'a pas signé le plan, aucune ligne de code n'est écrite.

code verrouillé
Les agents déclarés agents

six rôles dans .claude/agents/, chacun son prompt et ses rules.

project-maestro senior-rust-dev senior-sre-architect qa-tester pipeline-monitor sre-product-owner

L'orchestration : /autopilot, délégation explicite, un daemon. Pas un agent qui appelle tout le monde.

Le vrai moteur : les skills par domaine

un skill sait quand s'invoquer · c'est ça qu'on met dans son header :

feature-implementation-rust-axum.md
MOI · ticket ready-to-dev + fichiers dans backend/
brainstorming · si l'archi Rust n'est pas définie
vue-nuxt · si ça touche frontend/ uniquement
LE DISPATCH 1 ticket, 1 worktree

un répertoire de travail dédié, par tâche

dev/worktree.ts
EN PARALLÈLE les agents s'activent
A B C
L'ISOLATION une branche par agent

chacun la sienne, aucun ne touche celle d'à côté

à titre d'exemple, 98 worktrees en 10 jours, sans un seul conflit

ClaudeJ'ouvre main.rs.
rust-analyzerJe l'indexe... types et emprunts analysés.
Tu vois des erreurs ?
Deux : ligne 42 le type ne correspond pas, ligne 57 une valeur déjà empruntée.
Claude lit ces diagnostics et corrige sans relancer le build.
via le LSP · l'agent voit les diagnostics, dans l'éditeur
Lint maison
règle diagnostic
Contraintes Design System Pas de natif
ast-grep
motif AST alerte
Force Feature Flag Pas de modif de migration
Marketplace locale
~/.claude/local-lsp/

vue-lsp Volar, html-lsp, css-lsp.

hors LSP · via un hook
Validations maison
hooks/granit-validate.ts PostToolUse → agent

un hook PostToolUse, pas le LSP.

L'implémentation
ce qui a été produit
La spec · le Gherkin
ce qui était demandé
les juges tranchent
1
Vérifie le code modifié

un agent juge indépendant ne voit que le Gherkin · sort VALIDATED / FAILED

cycle/postdeploy-validation.ts
2
Review de code

un agent relit le fond, comme un reviewer humain

ci/mr-reviewer.ts
1LOCAL
/ultrareview
préliminaire · un autre agent dégrossit le fond
2CI
La revue technique
mr-reviewer.ts lint bloquant hooks typecheck
LE DERNIER MOT
3HUMAIN
Le dernier reviewer
c'est l'humain, jamais la machine
Sauf le SQL multi-tenant : revue HUMAINE obligatoire
Une org a lu les données d'une autre. Jamais d'auto-merge ici. Je ne signe pas les yeux fermés.
no auto-merge
1ADR
Une décision tracée
datée, justifiée
recording-decisions
2MR
Le rapport de livraison
le diff, le contexte
gabarit MR
LE DÉCLENCHEUR
3POSTMORTEM
L'analyse d'incident
cause racine, actions
recurring-bug-root-cause
4DETTE
La dette assumée
listée, priorisée
detection-sweep

ADR · une décision tracée

Le choix, daté · les alternatives rejetées, chacune argumentée.

docs-internal/adrs/ADR-AUDIT-LOG-RECORDER.md
# ADR · Audit log org via record_org_audit explicite
Statut : Accepté (#294, MR !127). Baseline pragmatique.

## Décision
Un helper unique record_org_audit(…), appelé
explicitement dans les 12 handlers mutants. Chaque appel
porte : actor_id, org_id, AuditActionType typé,
target (type, id), summary JSON. Visible en diff → un
relecteur repère l'appel manquant.

## Ce qu'on a explicitement rejeté
Middleware Tower (POST/PUT/DELETE) · perd le métier :
 voit l'URL, pas « Create check » vs « Force re-run ».
Triggers DB · perdent l'acteur (DB user = service
 account partout) et le verbe d'action.
Bus d'événements + listener · idiomatique DDD mais
 ~3× le code ; aucun autre contexte ne publie d'events.
Macro / code-gen sur les handlers · ajoute une
 dépendance de build, obscurcit le call site.
→ optimisé pour la revue, pas les keystrokes.

## Conséquence assumée (négatif)
Invasif : 12 handlers modifiés, aucune contrainte
compile-time. Tout nouveau handler mutant doit penser
à appeler le recorder → risque de drift.

## Quand on revisite
Refactor (middleware Tower lisant un AuditHint) quand
2 signaux sur 4 s'allument : 5e contexte audité, un
audit manqué en prod, events émis ailleurs, ou
> 5 valeurs AuditActionType::Other(...).

MR · le rapport de livraison

Le résumé, le périmètre préservé, le test plan coché.

MR !694 · granit-golem
# refactor(dashboard): unifier le widget checks
# via CheckItem partagé (Closes #1034)

## Summary
Remplace le markup inline maison du widget Checks
(sparkline dots + badges manuels) par le composant
partagé CheckItem avec toCheckItemData().
Rendu aligné sur Health Checks : bar-chart 24h
(CheckUptimeBar), uptime %, latency, status dot.
Suppression de getCheckStatusLabel devenue orpheline.

## Groupement préservé
LANDING PAGE / MAILS / CHECKS ORPHELINS conservé tel
quel · seul le rendu des items individuels change.

## Test plan
[x] Typecheck Nuxt : OK [x] ESLint : OK
[x] 2648 tests unitaires : OK (270 fichiers, 0 échec)
[x] validate.sh : OK
[ ] Visual check : agent-bypass (mr-reviewer auto-merge)

Postmortem · le déclencheur

Sévérité, timeline, cause racine, correctif, suivi. De là naissent l'ADR et le gate anti-rechute.

docs/postmortems/2026-06-04-jwt-keys-prod-crashloop.md
# Postmortem · Crash-loop API prod · clés JWT EC
Sévérité P1 · 503 intermittents ~24h · 1424 restarts

## Timeline
06-01 21:38 release v0.124.0 (validation stricte)
06-03 ~07:37 1er boot prod → exit 1, crash-loop
06-04 08:30 signalement user (503 sur les checks)
06-04 09:40 clés EC provisionnées → 2 containers healthy
06-04 09:55 effet de bord : conflit router traefik
06-04 10:00 service partagé + healthcheck → API restaurée

## Cause racine
1. La v0.124.0 exige des clés EC en prod, jamais
 provisionnées dans les stacks Portainer → exit 1.
2. GRANIT_ENVIRONMENT=standby échappe à la
 validation : le standby boote avec la clé dev du
 repo → masque la panne ET forge de tokens possible.
3. verify-deployed-sha interroge /health servi
 par le standby → déploiement déclaré « vérifié ».

## Fix
Paire EC P-256 générée hors repo · env Portainer 44/45
· failover traefik réel (service partagé + healthcheck
actif /health/live) · sessions invalidées (re-login).

## Actions de suivi
#781 ✅ alerte restart-loop · #827 verify sur prod
#828 validation stricte en standby · #830 checklist
release : tout paramètre obligatoire = provisionné.

Dette · assumée

Nommée plutôt qu'enfouie : labellisée tech-debt P2-medium blocked, pas un secret.

issue #1043 · granit-golem
# [Frontend/Mobile] Balayage responsive exhaustif
# des 87 écrans (harnais Playwright · viewport 375px)

## Déjà corrigé à la racine (2 transverses)
SVG GSparkline largeur fixe 600/800px qui
 débordait → responsive (bba3eb64)
Header GCard non-wrappant, action clippée
 sur mobile → flex-wrap (f464594a)
9 écrans validés : login, register, onboarding,
dashboard, projects/new, checks (liste + détail)…

## Reste à faire · ~78 écrans
prioritaires : settings/*, alerts (channels, rules),
audits, components, incidents, service-map, slos, admin/*.

## Problème résiduel connu
1 card à slot header custom reste clippée
(cosmétique, pas de scroll doc). À traiter.
fixes accumulés sur 14 jours →
1 à 2 fixes rien de spécial on laisse vivre
≥ 3 fixes postmortem déclenché retro-fixes · seuil 3/14j
≥ 5 fixes root-cause obligatoire on remonte à la source
Et si les postmortems se répètent ?

3+ postmortems sur le même sujet → un méta-postmortem qui juge l'approche, pas le bug.

Acte III · la démarche
PROUVÉE
Q1ÇA TOURNE
Gates & CI
PROUVÉE
Q2CONFORME
Preuve dans la MR
À TRANCHER
Q3LE BESOIN
Le maillon humain

La démarche est posée on la borne

Acte IV · les remparts

Acte IV · Les remparts

acte IV Les remparts rien ne passe sans franchir
I·II·III·IV·V
DEVplein pouvoir · worktrees jetables
STAGINGsous gardes · smoke-tests
PRODlecture seule
Écrire & itérer
✓ libre
✓ via PR
Exécuter des commandes
sous gate
Déployer
✓ auto
humain valide
✗ jamais
Toucher aux données
✓ jetable
Lire signaux & alertes
✓ son seul droit
.claude/settings.json · permissions & env
L'agent
zéro credential
appel d'outil
le coffre
MCP
détient les creds · filtre la data · multi-user
creds
côté serveur
API logs
Grafana/Loki · exige des creds pour répondre
requête
auth
La prod
l'app · la base · l'infra
Données filtrées seules. Les secrets restent dedans.
granit-production-diagnostic.md optionnel, mais améliore l'usage : skill · bien utiliser le MCP CLI en pré-prompt · déterminisme

Borner sa course

  • Max 5 MRcap budget · mr-budget-guard.ts
  • Max 6 worktreeshook refuse le 7e · PreToolUse · settings.json

Limiter son geste

  • Outils au strict besoinallowlist par agent · settings.json
  • Zéro secret qui sortscanné avant de partir · granit-validate.ts

Fail-open : s'il plante, il laisse passer.

Un garde-fou buggé ne bloque jamais le travail.

L'oubli qui a fait fuiter une requête sans isolation multi-tenant
Une règle qui le détecte elle lit le code et repère l'oubli
Visible dans l'éditeur, bloquante en CI l'agent ne peut plus refaire l'erreur

L'incident se transforme en garde-fou qui empêche la récidive. rust-job-tx-without-bypass-rls.yml

01MÉTHODE
ISTQB
non-régression + test rouge avant le fix
02PATTERN
Page Object
obligatoire pour tout E2E Playwright
03LINT
no-focused-test
ast-grep interdit .only : pas de triche
04DATA
Golden datasets
jeux de référence, non-régression
05E2E
mcp-playwright
un vrai navigateur, piloté par l'agent
L'anti-pattern

Un navigateur entier pour vérifier une addition. Un test unitaire suffisait.

write-tests.md test-discipline TU > E2E (dans beaucoup de cas)
qa:flaky-detect
flakiness 40 % > 5 % ≥ 3 alternances
ticket auto flaky-test
mutation:nightly
Le code
On le mute
Le test DOIT casser
s'il reste vert, le test ne protège rien

Un test vert qui ne tient pas, c'est pire que pas de test : il rassure à tort.

Aucun secret ne sort
  • chaque commit est scanné avant de partir
  • les motifs interdits sont refusés net
pre-commit gitleaks pre-push freshness
Le code est propre
  • types, lint, format : 6 vérifications
  • rien d'approximatif ne traverse
typecheckESLintcargo fmt
Un humain regarde le rendu
  • l'agent ne voit pas les pixels
  • check visuel y / n avant le commit
  • tout bypass est tracé
Visual-Check: agent-bypass
LOCAL · le départ
1PRE-COMMIT
Local
format lint tests
CI
2SÉCU
Check & sécu
qualité secrets vulnérabilités dépendances
3BUILD
Build & deploy
image déploiement test de fumée
STAGING
4AUDIT
Runtime audit
audit auto sur staging
PROD
5OBSERVE
Observer
métriques logs alertes
4jobs Code sûr
compile sans erreur lint du code requêtes SQL vérifiées les hooks démarrent
6jobs Sécurité
secrets qui fuient ×2 motifs interdits dans le code failles des dépendances scan de l'image Docker licences vérifiées
3jobs Migrations
aucun changement destructeur · drop, rename rétro-compat obligatoire jamais toucher une ancienne migration
7jobs Le front
performance web accessibilité (bloquant) poids du bundle régression visuelle traductions complètes design system imposé couverture de tests
2jobs Tests fiables
chasse aux flaky (nightly) tests de mutation (nightly)

La CI prolonge les gates locaux. Tout est bloquant (sauf nightly).

.gitlab-ci.yml · check→build→deploy→validate→release
app tech infra produit bout en bout
01APP
Logs + erreurs
ce que le service dit de lui-même, en continu
02TECH
Métriques
ce que la machine ressent
03INFRA
Events
déploiements, redémarrages, runtime
04PRODUIT
PostHog
analytics produit : ce que les gens font vraiment
Garde-fou transverse · RGPD

La PII ne va jamais dans les logs. C'est codifié : granit-validate.ts bloque email=% dans le tracing.

Le système
app · db · infra · prod
L'IA elle-même
sessions · agents · cycles · tokens
métriques · logs · traces · RUM
Monitoring
Grafana · PostHog · alertes · devmetrics
le temps de détectersignaux & alertes
Agent AI-SRE
lit les signaux · diagnostique · agit
le temps de réparer en retour sur le système : rollback · fix · postmortem · avant que ça se voie.

Le Spectre des 503, revu par cet œil granit-production-diagnostic.md · MCP grafana·infra

Détection : de 50 minutes à la main à <15 minutes en auto.

marble-minotaur · audit de Accueil
Accueil Connexion Tableau Détail Profil M

7 auditeurs · seuil 70

SEO
a11y
perf
security headers
forms
i18n
images

sous 70 · l'auditeur bloque → ticket

1SPEC
L'intention
cadrée et validée avant la première ligne.
2CODE
L'agent écrit
le juge inscrit sa preuve dans la MR.
LE VERROU
3GATES
Local + CI
bloquantes : rien ne passe sans franchir.
4PROD
Observée
signaux en continu, crawler en audit.

Rien ne passe sans franchir chaque maillon.

Acte IV · les remparts
PROUVÉE
Q1ÇA TOURNE
Gates, CI, monitoring
PROUVÉE
Q2CONFORME
Preuve dans la MR
À TRANCHER
Q3LE BESOIN
Le maillon humain

Les remparts tiennent on accélère

Acte V · la vitesse

Acte V · La vitesse

acte V La vitesse accélérer sans lâcher
I·II·III·IV·V
Je discute au clavier un humain, un terminal
moi · clavier
> corrige la pagination de l'écran checks
claude -p le même moteur, sans clavier
cron · sans clavier
$ claude -p "corrige le ticket #412" \
 --output-format stream-json
Un méta-prompt déclenché par un événement
événement
hook PostToolUse -> métrique
cron 5 min -> daemon.ts dépile

Avant, j'appuyais sur Entrée. Maintenant, l'événement appuie à ma place.

Le workflow DANS Claude
fragile
il choisit l'ordre, rien ne l'arrête
non
Claude DANS le workflow
déterministe
l'agent ne fait qu'un pas, le daemon tient la chaîne
L'inversion

C'est le workflow qui appelle l'agent. Pas l'inverse.

En entrée
Backlog · poll 5 min
Dépile un ticket
Humain
je fixe le périmètre
Le cycle autonome · run.ts
preflight vert d'abord
plan périmètre
execute un pas
review juge LLM
Juge LLM · rouge → reprend, jamais de merge auto
Garde-fous
max 2 agents
3 échecs = pause
Humain
.daemon-pause
le merge, mon geste

daemon.ts tient la boucle · run.ts enchaîne les 4 étapes.

le système granit Capter tous les signaux Accumuler plusieurs bases Analyser /daily-improve Améliorer workflow, tests, ADR…

Tous les signaux qu'il capte

Échecs CI : un build qui repasse au rouge
Bugs tracés : un défaut remonté et fiché
Régressions : ce qui marchait et re-casse
Postmortems : un incident raconté noir sur blanc
Métriques infra : CPU, mémoire, latence en prod
Vécu utilisateur : ce que vivent les vrais users (RUM)
Traces des agents : chaque action, horodatée

Les gestes qu'on répète sans arrêt (7 j)

appel API GitLab×178
fouille dossiers×16
lancement tests×13
tests backend×8

Un geste répété 178 fois, c'est du temps perdu et du contexte rechargé à chaque tour. Sur une semaine, ça crève les yeux.

Chaque soir, il relit ses traces

Commande répétée 178× → en faire un raccourci
Fichier relu 40× → le mémoriser une bonne fois
Correction refaite 28× → la régler à la racine

C'est /daily-improve : il change les frictions en une liste d'actions.

scripts/dev/daily-improve.ts retro-fixes.ts quality-debt-sweep.ts

Ce qu'il a corrigé tout seul, ces jours-ci

Un CLI maison : une seule commande remplace les 178 curl tapés à la mainworkflow
Un hook tronque les sorties : les commandes bavardes sont coupées avant de gonfler le contextetokens
Répare seul les liens cassés entre un ticket et sa fusion (MR)fix
Affine ses propres règles : un bon outil n'est plus pris pour une frictionqualité
Détection
12 min
du pipeline rouge au diagnostic
Régressions
1 / 2 214
un seul rollback sur 2 214 commits
Fix auto
4 / 14 j
corrigés et livrés sans moi
Autonomie
36,4 h
la nuit · les « 36 heures » de l'ouverture
Ça arrêterégressions & reverts · bugs cachés · taux de succès
Ça orienteADR · MR & postmortem · la dette nommée
observer détecter analyser ticket la boucle se referme · cycle-metrics.db, requêtée devant vous
Toil
Travail répétitif, manuel ou scripté, sans valeur durable · automatisable.
relancer la gitlab-cli recharger le .env re-poll le backlog recoller logs + métriques
Retry
Relancer la même étape qui a échoué, en espérant qu'elle passe.
flaky test relancé build rejoué requête en timeout réessayée

Toil + retry = la friction · invisible un par un, énorme au cumul.

Toil
Retry
Durée
Coût
friction = toil (travail répétitif sans valeur, même scripté) + retries · ce que le daemon supprime
La friction descend
events Bash à la main / run autonome · devmetrics.db
12 mai
138,6
18 mai
88,9
27 mai
6,3
1 juin
7,0
L'autonomie monte
runs autonomes du daemon / semaine · cycle-metrics.db
12 mai
38
18 mai
52
27 mai
614
1 juin
1 283
gitlab-cli répétée 2 347× (406 sessions) .env rechargé 450× à la main le daemon s'est freiné seul 100 969×
Comprendre
1
Cartographier
zones chaudes
avant de toucher
Filet
2
Sécuriser
tests de caractérisation
vert d'abord
Découper
3
Isoler
une couture
pas big-bang
Verrouiller
4
Gates
lint · tests · review
rouge bloque
Enfin
5
Accélérer
zone sécurisée
autonomie tenue

Pas de filet, pas de vitesse · on accélère la zone sécurisée, jamais le code.

Acte V · la vitesse
Vitesse maîtrisée
observer, puis accélérer
En autonomie
le daemon tient le cycle
L'usine s'entretient
elle capte et se corrige

Ça tourne tout seul maintenant, le verdict

Acte VI · le bilan
Le marché : surveiller la machine
  • des agents qui surveillent les agents
  • Datadog, Resolve AI, la vague Gartner
  • un outil de plus, branché en aval
vs
Mon indus : borner en amont
  • l'usine qui borne : gates, juge, git
  • l'incident codifié en garde-fou, pas en doc
  • un humain qui tranche le périmètre

La machine surveille la machine : reste qui tranche quand ça casse ? Un humain.

1SPEC
L'intention
cadrée par le dev
2CODE
Le code
l'agent exécute
3GATES
Les remparts
local + CI, bloquants
4JUGE
La relecture
la machine relit
le maillon qui reste
5HUMAIN
L'humain
il tranche avant prod
6PROD
La prod
observée en continu
Le fantasme · l'agent remplace le dev La réalité · le dev orchestre la chaîne
1SPEC
L'intention
2AGENT
Le code
3GATES
Les remparts
4JUGE
La relecture
5HUMAIN
Je tranche
GAGNÉE
PROD
En production
Merci pour votre attention… À vos bafouilles !
Cédric · Fondateur siliceum
Dégraisser à la source, dans un hook PreToolUse
# .claude/settings.json
"PreToolUse": [{
 "matcher": "Bash",
 "command": "trim-output --max 4k"
}]

Un cat de 30 Ko n'injecte que 4 Ko dans le contexte. Le reste, l'agent le relit s'il en a vraiment besoin.

Replier le contexte sans perdre les décisions
# en pleine session, le contexte enfle
> /compact garde les décisions, jette le bruit

 contexte 180 K -> ~90 K (~50 %)

Je replie quand la fenêtre se remplit. Les choix d'archi restent, les tâtonnements partent.

Mettre en cache ce qui se répète à chaque tour
system: [{
 type: "text", text: CLAUDE_MD,
 cache_control: { type: "ephemeral" }
}]
// -90 % sur tout le préambule, tour après tour

Le gros préambule (CLAUDE.md, l'arbo) est lu une fois, puis rejoué quasi gratuitement.

Isoler l'exploration dans un sous-agent
Task(subagent: "trouve où vit la règle X")
 # 50 K de grep / lectures …
 -> restent DANS la bulle du sous-agent
 -> le principal ne reçoit que la réponse

Les 50 K de fouille ne polluent jamais mon contexte. Je récupère la conclusion, pas le dump.

On croit que les hooks ne font que dire non. En vrai, ce sont aussi eux qui me font économiser.

.claude/commands/write-tests.md · 291 l.
## Quand MOI et pas X

- MOI quand : code existant sans tests suffisants · objectif = couvrir du code déjà écrit
- test-sweep : audit global de couverture sur tout le projet
- feature-implementation-vue-nuxt / feature-implementation-rust-axum : feature pas encore implémentée (les tests font partie de l'implémentation)

> Règle rapide : code existe, tests manquent = MOI.

---

# Write Tests - Expert ISTQB Testing Skill

Expert ISTQB Foundation v4.0. `$ARGUMENTS` = le sujet, fichier ou feature à tester.

## 1. GOLDEN DATASET

Avant tout test E2E, vérifier que le dataset est chargé :
```bash
psql "$DATABASE_URL" -c "SELECT count(*) FROM checks WHERE id LIKE 'cccccccc%'"
```
Si count = 0, charger :
```bash
psql "$DATABASE_URL" -f test-data/golden-dataset.sql
```

### IDs de référence (figés · JAMAIS de données magiques)

| Entité | ID | État | Description |
|--------|-----|------|-------------|
| Org | `f32c735c-...` | - | Granit Labs |
| User | `bb5562b9-...` | - | test@granit.local / Password123 |
| Project Prod | `a1b2c3d4-1234-5678-9abc-def012345678` | production | Production API |
| Project Staging | `b2c3d4e5-2345-6789-abcd-ef0123456789` | staging | Staging Environment |
| Check Google | `d4e5f6a7-4567-89ab-cdef-012345678901` | passing | Google Homepage |
| Check GitHub | `e5f6a7b8-5678-9abc-def0-123456789012` | passing | GitHub API |
| Check Payment | `cccccccc-0001-0001-0001-000000000001` | failing | Payment API (12 failures consécutifs) |
| Check Staging DB | `cccccccc-0001-0001-0001-000000000002` | failing | Staging DB (5 failures) |
| Check CDN | `cccccccc-0001-0001-0001-000000000003` | warning | CDN Edge (lent) |
| Check Legacy | `cccccccc-0001-0001-0001-000000000004` | snoozé | Legacy API (snoozé 2h) |
| Alerts `eeeeeeee-...-0000000000` | `01` firing (Payment), `02` firing (Staging DB), `03` acknowledged (CDN), `04` resolved (Google 3j), `05` resolved (GitHub 7j), `06` resolved (Payment 30j) | | |
| Channels `ffffffff-0002-...-1/2/3` | actifs : Email, Slack, Webhook | | |
| Rules `ffffffff-0001-...-1/2/3` | actifs sur Payment, Staging DB, CDN | | |

---

## 3. NIVEAUX DE TEST (ISTQB v4.0)

| Niveau | Scope | Qui | Défauts typiques | Approche |
|--------|-------|-----|-----------------|----------|
| Unit | Fonction/classe isolée | Dev | Logique, boundaries | White-box, stubs |
| Intégration | Interfaces entre composants | Dev/QA | Mismatch API, mapping data | API contracts |
| Système (E2E) | Système complet | QA | Flux cassés, cross-fonctionnel | Black-box, golden dataset |
| Acceptation | Validation business | PO/User | Workflow gaps, compliance | UAT, Gherkin |

---

## 4. TECHNIQUES DE CONCEPTION (ISTQB)

Black-box : Equivalence Partitioning (classes d'inputs : <0 invalide / 0-100 valide / >100 invalide) · Boundary Value Analysis (frontières : seuil 100ms → 99, 100, 101) · Decision Table (conditions combinées) · State Transition (Alert: firing → acknowledged → resolved) · Use Case Testing (flux utilisateur).

White-box : Statement Coverage ≥80% · Branch Coverage ≥80% (recommandé ISTQB) · Path Coverage (code critique uniquement).

Experience-based : Error Guessing (null, vide, négatif, SQL injection, XSS) · Exploratory (sessions 60-120min avec charter) · Checklist-based (régression par feature).

---

## 5. PRINCIPES FIRST

| Principe | Règle |
|----------|-------|
| Fast | Unit < 1ms, suite < 10s · pas de DB, pas de réseau |
| Isolated | Pas d'état partagé mutable · setup/teardown indépendant par test |
| Repeatable | Même résultat partout · pas de dépendance horloge/réseau/random |
| Self-validating | Pass ou Fail · assertions claires, pas "check les logs" |
| Timely | Écrire avec le code (TDD ou test-alongside), pas après |

---

## 6. RÈGLES ABSOLUES (projet Granit Golem)

1. `data-testid` : TOUJOURS pour les locators E2E. JAMAIS `text=`, CSS class, XPath
2. Page Object Pattern : séparer locators / actions / assertions
3. ZERO `waitForTimeout` : attendre un état concret (`waitFor({ state: 'visible' })`, URL, response)
4. Scoped locators : `parent.getByTestId('child')` jamais `page.getByTestId('child')` global
5. Golden Dataset : utiliser les IDs de référence, JAMAIS de données magiques
6. Pas de `test.skip()` conditionnel : le golden dataset garantit les données
7. AAA Pattern : Arrange → Act → Assert, un seul `act` par test
8. Un concept par test : si "and" dans le nom, split

---

## 7. ANTI-PATTERNS

- waitForTimeout`await element.waitFor({ state: 'visible' })`
- Flaky → waits explicites, isolation, mock external
- Test coupling (B fail si A absent) → setup indépendant par test
- Over-mocking (tests verts, prod casse) → mock aux frontières, pas les internes
- Tester l'implémentation (refacto casse sans changer le comportement) → tester le comportement public
- The Liar (test sans assertion) → chaque test DOIT pouvoir échouer
- Giant Test / Copy-paste → un concept par test, page objects/helpers/fixtures

---

## 8. EXEMPLES MINIMAUX

E2E · locators scopés + wait sur état (Page Object) :
```typescript
const locators = {
 heading: page.getByTestId('feature-heading'),
 item: page.getByTestId('feature-item'),
 // SCOPED : dropdown DANS un item
 itemAction: page.getByTestId('feature-item').getByTestId('dropdown-trigger'),
}
async goto() {
 await page.goto('/dashboard/feature')
 await locators.heading.waitFor({ state: 'visible', timeout: 10000 })
}
```

E2E · spec AAA, un seul act :
```typescript
test('should display items from golden dataset', async ({ page }) => {
 const featurePage = createFeaturePage(page) // Arrange
 await featurePage.goto()
 // Act : aucun (vérif d'affichage)
 expect(await featurePage.getItemCount()).toBeGreaterThan(0) // Assert
})
```
Login partagé via `test.beforeEach` (`createLoginPage` + `testConfig.seedUser`).

Intégration API :
```typescript
test('GET /feature returns items', async ({ request }) => {
 const ctx = await request.newContext({ baseURL: 'http://localhost:3000/api/v1' })
 const response = await ctx.get('/feature') // Act
 expect(response.status()).toBe(200) // Assert
 expect((await response.json()).data.length).toBeGreaterThan(0)
})
```

Unitaire Rust (cas valide + cas d'erreur séparés) :
```rust
#[test]
fn should_reject_inverted_thresholds() {
 let result = validate_thresholds(1000, 500); // Arrange + Act
 assert!(result.is_err()); // Assert
 assert_eq!(result.unwrap_err().to_string(), "Warning threshold must be less than critical");
}
```

---

## 9. EXÉCUTION DU SKILL

1. Analyser le fichier/feature cible dans `$ARGUMENTS`
2. Classifier le type (E2E / intégration / unitaire)
3. Concevoir avec les techniques ISTQB (EP, BVA, State Transition...)
4. Préparer : ajouter les `data-testid` dans les composants Vue si besoin
5. Implémenter : page object dans `e2e/pages/` + test spec
6. Vérifier : lancer le test, corriger jusqu'à vert

---

## 10. CONDITION DE SORTIE

Terminé SEULEMENT quand :
- [ ] Tous les tests écrits passent (`npx playwright test e2e/XX-nom.spec.ts` / `vitest run` / `cargo test`)
- [ ] `data-testid` ajoutés, page object créé/à jour dans `e2e/pages/`
- [ ] Locators scopés au bon contexte, golden dataset référencé (pas de données magiques)
- [ ] Pattern AAA respecté, un concept par test
- [ ] ZERO `waitForTimeout`, ZERO sélecteur `text=` ou CSS class fragile

NE PAS déclarer terminé si un test est skipped, flaky ou commenté "à corriger plus tard".
La règle d'or

Frontières et valeurs limites : on teste les bords, jamais le hasard.

Golden dataset

Des IDs de référence figés, jamais de données magiques.

Anti-flaky bloqué

text= et waitForTimeout refusés net au pre-commit.

cargo test vitest playwright mutation axe a11y
/write-tests · la méthode est DANS le skill, versionnée
SEMAINE 1 Le cadre minimal

un CLAUDE.md qui décrit le projet, et le réflexe /clear · /compact entre les tâches.

MOIS 1 Les remparts

vous packagez vos skills, vous posez des hooks qui bornent, vous rendez les gates bloquantes en CI.

TRIMESTRE L'usine

un agent juge relit à votre place, des worktrees tournent en parallèle, et le daemon orchestre tout ça.

Chaque étage est utile seul. On ne déploie pas le daemon avant d'avoir un CLAUDE.md qui tient.

Outillage de l'agent

  • worktreeune branche git isolée sur le même dépôt, pour travailler en parallèle sans conflit.
  • MCPun protocole standard pour brancher l'agent sur des outils externes (bases, APIs, services).
  • ast-grepun chercheur qui lit la structure du code, pas le texte : il repère un motif interdit où qu'il soit.
  • Gherkinune spec écrite en langage quasi naturel, exécutable comme test : le contrat de la fonctionnalité.

Sûreté & mesure

  • RLSrow-level security : le cloisonnement des données par organisation, au niveau de la base.
  • MTTD / MTTAtemps moyen pour détecter un incident, puis pour y répondre : on les mesure, par incident.
  • fail-openen cas de panne du garde-fou, on laisse passer plutôt que tout bloquer : un choix à assumer.
Ce que je délègue
  • la frappe : taper le code ligne à ligne
  • la boilerplate : le code répétitif sans décision
  • la relecture de masse : le premier passage sur le diff
vs
Ce que je garde
  • l'architecture : où vont les choses, pourquoi
  • les specs : ce que le système doit vraiment faire
  • le verdict final et la lecture des diffs critiques

Le métier ne disparaît pas : il se déplace vers l'ingénierie du cadre.

Ce que ce n'est pas
un chatbot sur Grafana de l'AIOps qui corrèle « monitoring + LLM »
Ce que c'est
Observetélémétrie
ReasonRCA
Actfix borné
Learnrunbook
SLO · prévention · runbooks scope : prod + agent + harness