ADR-0001 — Le verrou d'un item de travail est une branche git, pas une checklist partagee
La codebase passe d'un seul developpeur a une flotte d'agents Claude Code travaillant en parallele. Ces agents ont trois proprietes qui cassent les methodes de coordination habituelles : Ils ne se voient pas. Chaque…
Statut
Accepté · 2026-08-12
Piliers : data-platform, security-identity, billing, ai-platform, integrations, commerce-systems, intelligence, marketplace, design-system, growth-web, platform-ops, app-shell
Contexte
La codebase passe d'un seul developpeur a une flotte d'agents Claude Code travaillant en parallele. Ces agents ont trois proprietes qui cassent les methodes de coordination habituelles :
- Ils ne se voient pas. Chaque session est isolee. Un agent ne saura jamais qu'un autre edite le meme fichier a la meme seconde.
- Ils demarrent amnesiques. Aucune memoire d'une session a l'autre. Tout ce qui n'est pas ecrit dans le repo n'existe pas.
- Ils sont rapides et simultanes. Le nombre d'ecritures concurrentes est plus proche d'une equipe de dix que d'un solo.
L'etat de depart etait tasks/todo.md : 356 lignes, 13 workstreams, des cases a
cocher. Format parfait pour une personne seule. Avec trois agents, chaque
progression est une ecriture dans le meme fichier, donc un conflit git.
Le probleme n'est pas "comment les faire communiquer". C'est "comment rendre la collision impossible sans communication".
Décision
L'unite de travail est un fichier isole dans backlog/, et le verrou qui dit
"cet item est pris" est l'existence de la branche fleet/<pillar>/<id>-<slug>
sur origin.
En complement, la frontiere d'ecriture de chaque agent est une liste de chemins
dans .claude/fleet/ownership.json, verifiee mecaniquement par
pnpm fleet:scope en CI.
Alternatives écartées
| Option | Pourquoi non |
|---|---|
Checklist partagee (todo.md avec des cases) | Chaque claim est une ecriture dans un fichier commun. C'est le mode de panne qu'on veut supprimer, pas le formaliser. |
Champ status: claimed dans le fichier de l'item, sans branche | Deux agents peuvent lire ready puis ecrire claimed en meme temps. Le fichier est le verrou et le verrou est racy : rien n'est gagne. |
| Issues GitHub avec assignation | Fonctionne, mais deplace la source de verite hors du repo. Un agent qui clone n'a plus le contexte, et la boucle depend d'un appel reseau. Le repo doit se suffire. |
Un service de lock externe (Redis, table Lock) | Correct techniquement, mais ajoute une dependance runtime a un probleme de coordination de developpement. Et un lock qui survit au crash de l'agent doit etre expire par un autre systeme. |
| Confiance dans les consignes ("reste dans ton domaine") | Un agent respecte une consigne de bonne foi et la viole quand meme, parce que le fix "d'a cote" est evident. Une regle non verifiee n'est pas une regle. |
Conséquences
Ce que ca donne. Le claim est atomique (une ref git existe ou n'existe pas),
visible par tout le monde en une commande (git ls-remote), et ne demande
d'editer aucun fichier partage. Zero conflit possible sur le claim lui-meme.
Ce que ca coute.
- Une branche abandonnee bloque un item indefiniment. Mitige par la regle des
72h :
@conductorsupprime la branche et repasse l'item enready.pnpm fleet:statusremonte le signaldead-lock, mais la liberation reste manuelle. - Le champ
statusdans le fichier de l'item peut diverger de la realite des branches. La branche fait foi ; le champ est une commodite de lecture. - Une collision d'
id(deux agents prennent le meme numero au meme moment) est possible. Elle est benigne : deux fichiers differents, aucun conflit git, et le triage renumerote. - La granularite est celle de la PR. Deux agents ne peuvent pas travailler sur deux zones du meme pilier en meme temps sans se coordonner. C'est assume : un pilier trop large est un signal qu'il faut le decouper, pas relacher le verrou.
Ce qui indiquerait qu'il faut revisiter. Si fleet:status montre
regulierement des locks morts, ou si les agents attendent souvent qu'un pilier
se libere, la granularite des piliers est mauvaise. Le fix est de decouper la
carte d'ownership, pas d'abandonner le verrou.
Comment c'est appliqué
scripts/fleet-scope-check.mjs+.github/workflows/fleet-guard.yml: une PR qui traverse plusieurs piliers sans trailerCross-pillar:, touche un hot file sans trailerHot-file:, ou laisse un role en ecriture restreinte modifier du code de production, echoue en CI.scripts/fleet-status.mjs: remonte les locks inactifs, les items P0/P1 bloques, les piliers non audites.docs/team/protocol.mdsection 1 : la procedure de claim.AGENTS.mdsection "Git workflow" : la convention de branche.
Le verrou lui-meme n'est pas verifie par une machine : rien n'empeche un agent de travailler sans creer la branche. C'est la partie tenue par la convention, et donc la partie qui cassera en premier si le protocole n'est pas lu.