erplibre/.claude/rules/04-code-conventions.md
Mathieu Benoit 76c548a781 [UPD] commit rule: English subject first, French title under --- FR ---
git log --oneline shows only the subject, and it read in whichever language
the author was thinking in. The subject and the body under it are now in
English, then --- FR --- opens the French section, which starts with the
subject translated under the same tag. The hook refuses a --- EN --- marker
and a French section without that title, and checks the title like a
subject; it does not count against the body budget. Whether the subject is
really English is not checked. /commit and /git_prepare_merge follow.
Checked: 55 hook tests, 7 of them new; i18n tests pass.

--- FR ---

[UPD] règle de commit : sujet anglais d'abord, titre FR sous --- FR ---

git log --oneline ne montre que le sujet, et il se lisait dans la langue où
l'auteur pensait. Le sujet et le corps qui le suit sont désormais en anglais,
puis --- FR --- ouvre la section française, qui commence par le sujet traduit
sous le même tag. Le hook refuse un marqueur --- EN --- et une section
française sans ce titre, et juge ce titre comme un sujet ; il ne compte pas
dans le budget du corps. Que le sujet soit vraiment en anglais ne se vérifie
pas. /commit et /git_prepare_merge suivent.
Vérifié : 55 tests du hook, dont 7 nouveaux ; tests i18n au vert.

Assisted-by: Claude Opus 5.5
2026-09-25 01:31:27 -04:00

165 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Conventions de code
Le formatage et le lint sont entièrement décrits par les fichiers de
configuration du dépôt — les lire plutôt que de supposer : `.flake8`,
`.editorconfig`, et les sections `[tool.black]` / `[tool.isort]` de
`pyproject.toml`. `make format` applique l'ensemble.
Prettier (via npm) formate XML/JSON/YAML ; `.editorconfig` donne les
indentations par type de fichier.
## Commentaires
Un commentaire dit COMMENT le code fonctionne : ce que la fonction prend, ce
qu'elle rend, l'invariant qu'elle tient, ses effets de bord, la contrainte
technique qu'on ne devine pas en lisant la ligne d'à côté. Il doit se lire
dans dix ans sans rien savoir de la semaine où il a été écrit. La règle vaut
pour les docstrings autant que pour les lignes `#`.
**L'épreuve : le sujet et le temps.** Chaque phrase a le CODE pour sujet, au
présent de ce qu'il fait. Une phrase dont le sujet est un incident, une
machine, une date ou une personne est à couper, où qu'elle se trouve dans le
paragraphe. Le MODE DE DÉFAILLANCE que le code empêche est du fonctionnement
et reste — « une VM renommée se voit attribuer la passerelle ». L'INCIDENT où
on l'a observé est du récit et part — « vécu sur telle VM, annoncée à telle
adresse ».
**Les chiffres.** Une mesure qui établit un fait durable reste, dépouillée de
sa date, de son lieu et de son opérateur : une limite, un seuil, une valeur
que documente l'éditeur. Un relevé de ce qui répondait ce jour-là part.
**Rien d'identifiant, jamais** : nom d'un client ou d'une organisation tierce,
nom de base de données réelle, nom de VM ou d'hôte, adresse IP, courriel,
chemin portant un nom d'utilisateur, libellé ou chiffre tiré des données d'un
client. La seule exception est l'en-tête de copyright : le dépôt nomme son
propriétaire, pas ses clients. Généraliser plutôt que censurer — « sur une
base de production », « sur un hôte qui exige une authentification sudo
interactive » — dit la CLASSE de situation, qui est ce qui sert au lecteur.
**L'exemple qui illustre un interdit s'invente.** La règle a d'abord été
violée par ses propres tests : pour démontrer qu'une adresse et un chemin de
compte sont refusés, ils en portaient de vrais, pris dans le parc. Choisir un
cas réel « parce qu'il est parlant » est exactement le réflexe que la règle
combat, et un test le fige pour toujours. Une valeur inventée démontre aussi
bien ; vérifier qu'elle n'existe nulle part ailleurs dans le dépôt.
Le récit n'est pas perdu, il change de place : l'enquête, les mesures datées
et les impasses vivent dans `tasks/`, qui n'est pas versionné. Ni le fichier
ni le corps du commit ne les portent.
Cela vaut aussi pour l'existant, mais **au fur et à mesure** : on corrige les
commentaires du fichier qu'on touche, au moment où on le touche, et non en une
passe qui réécrirait le dépôt. Le hook `pre-commit` liste ce qui est à relire
dans les fichiers indexés, sans jamais bloquer le commit ; le même outil se
lance à la main :
```bash
python3 script/analyse/check_comment_hygiene.py script/todo/todo.py
python3 script/analyse/check_comment_hygiene.py --staged
```
🔴 `identifiant` est une trouvaille, à retirer. 🟡 `récit` est un signal à
relire : l'outil ne sait pas si la phrase énonce un fait durable ou raconte
une journée, et ne tranche pas à votre place. 🟡 `nom` en est un autre, et sa
limite est plus dure : un nom d'hôte NU ne se distingue mécaniquement ni d'un
mot ordinaire ni du nom d'un logiciel, donc l'outil ne voit que la forme
pleinement qualifiée. Un miroir de paquets nommé dans un commentaire y
répond, et se confirme d'un coup d'œil ; l'absence de signal ne prouve rien
sur les noms.
Trois exemples pris dans ce dépôt, leurs noms propres masqués — une règle qui
interdit de nommer ne se cite pas elle-même en clair.
`qemu_manage.py` — la dernière phrase, « Vécu sur « <VM> », annoncée en
<adresse> au lieu de <adresse> », part en entier. Les deux qui la précèdent
disent déjà tout, une fois l'imparfait du récit passé au présent : « une VM
renommée, dont le bail porte encore l'ancien nom d'hôte, SE VOIT attribuer la
passerelle ».
`todo.py` — « recopier « <base_client>_neutralize_upgrade_18 » oblige à
regarder ce qu'on détruit » devient « recopier un nom long oblige à regarder
ce qu'on détruit, là où « o » se tape par réflexe ». L'exemple ne servait qu'à
illustrer « long ».
`qemu_install.py` — le relevé daté des miroirs, qui répondait et qui non tel
jour, part : c'est l'état d'une journée. « Aucun miroir ne réplique tout,
d'où plusieurs entrées plutôt qu'une » reste : c'est la raison d'être de la
liste, et elle est vraie demain.
## Git
- Branches : `develop` (développement), `master` (production)
- Pas de submodules Git — utilise **Google Repo** pour les addons
- Manifests XML dans `manifest/` pour chaque version Odoo
- Format de commit : `[TYPE] scope: subject`, sujet **en anglais**, à
l'impératif, 72 caractères au plus. Tags réellement utilisés : `[UPD]`,
`[FIX]`, `[ADD]`, `[IMP]`, `[REF]`.
- **Nommer les fichiers à l'indexation, jamais `git add -A`** : `private/` et
`tasks/` ne sont pas suivis EXPRÈS, et un ratissage les commit. Il emporte
aussi ce qui est en cours ailleurs dans le checkout, sous un sujet qui ne le
couvre pas. `git add -p` quand un fichier porte deux sujets.
### Le sujet
Le sujet est lu cent fois pour une fois que le corps l'est — `git log
--oneline`, un blame, une note de version, un bisect. Il a une seule tâche :
dire **sur quoi porte le code**.
L'épreuve : le lire seul, sans diff ni corps. Sait-on quelle partie du système
est en jeu, et ce qui y est désormais différent ? Sinon il n'est pas fini.
Nommer la chose, puis ce qui change pour elle. Le symptôme, le message d'erreur
cité et la métaphore sont des PREUVES, et une preuve va dans le corps — un
sujet bâti sur elles se lit bien et n'apprend rien. La portée dit OÙ, les mots
après le deux-points doivent dire QUOI.
Le sujet résume le commit ENTIER, pas sa plus grosse pièce. S'il lui faut un
« et » entre deux choses sans rapport, c'étaient deux commits.
Si le travail n'entre décidément pas dans une phrase de 72 caractères, ne pas
en écrire une amputée : des **mots-clés qui résument**, séparés par des
virgules, en disent plus dans la même place — `[FIX] proxmox: pmxcfs down,
pvesm silent, diagnosis at the source`. C'est un repli, pas un défaut : la
phrase reste préférable quand elle tient.
Un garde-fou refuse le mécanique. Sur le sujet : tag absent, plus de 72
caractères, ouverture sur une citation. Sur le corps : plus de 10 lignes pour
une langue, une adresse IP, un courriel, un chemin de compte. Sur l'ordre des
langues : un marqueur `--- EN ---`, une section française qui ne s'ouvre pas
sur le sujet traduit sous le même tag. Que le sujet soit bien en anglais
reste à l'auteur. Ce qui reste un jugement — « ce corps raconte-t-il
l'enquête » — n'est vérifié par personne.
```bash
git config core.hooksPath script/git/hooks # une fois par clone
git commit --no-verify # exception légitime
```
Le mode d'emploi complet, avec des exemples avant/après pris dans l'historique
de ce dépôt, est dans `conf/template_claude_commands_commit.md`.
### Tout commit assisté par IA
Trois exigences, sans exception — `AI_POLICY.md` en donne la raison :
- Trailer `Assisted-by: <modèle>`, une ligne par modèle. C'est **binaire** :
il y a eu IA ou non, aucun seuil à apprécier.
- **Jamais** d'IA dans `Co-authored-by:` — ce champ est réservé aux humains.
- Message **bilingue, l'anglais d'abord** : le sujet et le corps en anglais,
puis `--- FR ---`, puis le sujet traduit en français sous le même tag, puis
le corps traduit. `--- EN ---` n'existe plus : l'ordre ne varie jamais.
Court et direct : **8 lignes par langue**, 10 est un plafond. Le corps dit
pourquoi c'était nécessaire, puis s'arrête. Rien de ce que le diff montre
déjà ; on garde le mode de défaillance, le chiffre qui borne et la
vérification. Le bilinguisme achète la concision, il ne l'excuse pas.
Le corps obéit aux mêmes deux règles que les commentaires : **rien
d'identifiant**, et **le fonctionnement plutôt que l'enquête**. Le corps dit
ce que le code fait ou refuse DÉSORMAIS ; il ne raconte ni la séance, ni les
hypothèses écartées, ni qui s'est trompé. Une mesure se généralise à sa classe
de situation — « sur une base de production », jamais son nom.
Le mode d'emploi complet — résolution dynamique du modèle, gabarit, identité
git, taille des correctifs — est dans
`conf/template_claude_commands_commit.md`, déployable en `/commit` par
`TODO › Execute › GPT code › Claude configs`.