[ADD] convention : dire le fonctionnement, pas le contexte ni les noms
Le dépôt n'avait aucune règle sur le commentaire de code : le seul modèle d'écriture était le corps de commit, et le gabarit y renvoyait le raisonnement qui n'y tenait pas. Le récit s'écoulait dans les sources, avec les noms qu'il portait. L'épreuve tient en une phrase : le code est le sujet, au présent de ce qu'il fait. Une phrase dont le sujet est un incident, une machine, une date ou une personne part vers tasks/, non versionné ; le mode de défaillance que le code empêche reste. Rien d'identifiant hors de private/, et seulement sur un dépôt privé. --- EN --- The repository had no rule at all about code comments: the only writing model available was the commit body, and the template sent the reasoning that did not fit there into a comment. The story flowed into the sources, carrying the names it named. The test fits in one sentence: the code is the subject, in the present of what it does. A sentence whose subject is an incident, a machine, a date or a person goes to tasks/, unversioned; the failure mode the code prevents stays. Nothing identifying outside private/, and only on a private repository. Assisted-by: Claude Opus 5
This commit is contained in:
parent
960918c939
commit
5fb49da0f2
4 changed files with 134 additions and 21 deletions
|
|
@ -8,6 +8,72 @@ configuration du dépôt — les lire plutôt que de supposer : `.flake8`,
|
||||||
Prettier (via npm) formate XML/JSON/YAML ; `.editorconfig` donne les
|
Prettier (via npm) formate XML/JSON/YAML ; `.editorconfig` donne les
|
||||||
indentations par type de fichier.
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
## Git
|
||||||
- Branches : `develop` (développement), `master` (production)
|
- Branches : `develop` (développement), `master` (production)
|
||||||
- Pas de submodules Git — utilise **Google Repo** pour les addons
|
- Pas de submodules Git — utilise **Google Repo** pour les addons
|
||||||
|
|
@ -39,8 +105,13 @@ virgules, en disent plus dans la même place — `[FIX] proxmox : pmxcfs à terr
|
||||||
pvesm muet, diagnostic à la source`. C'est un repli, pas un défaut : la phrase
|
pvesm muet, diagnostic à la source`. C'est un repli, pas un défaut : la phrase
|
||||||
reste préférable quand elle tient.
|
reste préférable quand elle tient.
|
||||||
|
|
||||||
Un garde-fou refuse le mécanique — tag absent, plus de 72 caractères, sujet
|
Un garde-fou refuse le mécanique. Sur le sujet : tag absent, plus de 72
|
||||||
qui s'ouvre sur une citation :
|
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, et tout terme de
|
||||||
|
`private/noms_interdits.txt` — la liste des clients et des machines, qui ne
|
||||||
|
peut pas vivre dans git puisque c'est ce qu'elle protège. Absente, ce dernier
|
||||||
|
contrôle est muet. Ce qui reste un jugement — « ce corps raconte-t-il
|
||||||
|
l'enquête » — n'est vérifié par personne.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git config core.hooksPath script/git/hooks # une fois par clone
|
git config core.hooksPath script/git/hooks # une fois par clone
|
||||||
|
|
@ -60,9 +131,16 @@ Trois exigences, sans exception — `AI_POLICY.md` en donne la raison :
|
||||||
- Corps **bilingue** : le corps, puis `--- FR ---` (ou `--- EN ---`, le
|
- Corps **bilingue** : le corps, puis `--- FR ---` (ou `--- EN ---`, le
|
||||||
marqueur nomme la langue de ce qui SUIT), puis la traduction.
|
marqueur nomme la langue de ce qui SUIT), puis la traduction.
|
||||||
|
|
||||||
Court et direct : **10 lignes par langue**, 15 est déjà long. Le corps dit
|
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
|
pourquoi c'était nécessaire, puis s'arrête. Rien de ce que le diff montre
|
||||||
déjà ; on garde le symptôme, le chiffre mesuré et la vérification.
|
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é
|
Le mode d'emploi complet — résolution dynamique du modèle, gabarit, identité
|
||||||
git, taille des correctifs — est dans
|
git, taille des correctifs — est dans
|
||||||
|
|
|
||||||
|
|
@ -45,5 +45,8 @@
|
||||||
2. **Verify Plan**: Check in before starting implementation.
|
2. **Verify Plan**: Check in before starting implementation.
|
||||||
3. **Track Progress**: Mark items complete as you go.
|
3. **Track Progress**: Mark items complete as you go.
|
||||||
4. **Explain Changes**: High-level summary at each step.
|
4. **Explain Changes**: High-level summary at each step.
|
||||||
5. **Document Results**: Add review section to `tasks/todo.md`
|
5. **Document Results**: Add review section to `tasks/todo.md`. L'enquête,
|
||||||
|
les mesures datées, les impasses et les traces d'exécution restent LÀ.
|
||||||
|
`tasks/` n'est pas versionné : il porte ce que ni le code ni le commit ne
|
||||||
|
doivent porter. Ne les fais pas remonter.
|
||||||
6. **Capture Lessons**: Update `tasks/lessons.md` after corrections
|
6. **Capture Lessons**: Update `tasks/lessons.md` after corrections
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,14 @@ Version Odoo par défaut : **18.0** (support officiel ERPLibre 1.6.0)
|
||||||
`ls -d .venv.odoo*` plutôt que de le composer de tête
|
`ls -d .venv.odoo*` plutôt que de le composer de tête
|
||||||
- Les scripts ERPLibre utilisent `.venv.erplibre/bin/python`
|
- Les scripts ERPLibre utilisent `.venv.erplibre/bin/python`
|
||||||
- Le Makefile principal inclut des fragments depuis `conf/make.*.Makefile`
|
- Le Makefile principal inclut des fragments depuis `conf/make.*.Makefile`
|
||||||
- Les fichiers privés vont dans `private/` (non versionné)
|
- Les fichiers privés vont dans `private/`. C'est le SEUL endroit qui a le
|
||||||
|
droit de porter une donnée de client — nom, base, machine, adresse,
|
||||||
|
chiffres. Il peut être commité, mais seulement sur un dépôt privé : sur
|
||||||
|
un fork public, ce qui s'y trouve devient public comme le reste
|
||||||
|
- Partout ailleurs — code, commentaires, messages de commit, documentation
|
||||||
|
— aucune donnée identifiante, jamais. Ce sont les fichiers qui suivent le
|
||||||
|
dépôt en amont. La règle complète, avec l'épreuve qui tranche, est dans
|
||||||
|
`.claude/rules/04-code-conventions.md`
|
||||||
- La DB PostgreSQL par défaut est sur le port 5432, mot de passe admin : `admin`
|
- La DB PostgreSQL par défaut est sur le port 5432, mot de passe admin : `admin`
|
||||||
- Port Odoo par défaut : 8069, longpolling : 8072
|
- Port Odoo par défaut : 8069, longpolling : 8072
|
||||||
- Pour les commits : suivre le format `[TYPE] description` (ex: `[FIX]`, `[UPD]`, `[ADD]`, `[REM]`)
|
- Pour les commits : suivre le format `[TYPE] description` (ex: `[FIX]`, `[UPD]`, `[ADD]`, `[REM]`)
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,9 @@ The first five cover every one of the last 400 commits. Reach for `[REM]`,
|
||||||
[TAG] scope: short description in imperative mood
|
[TAG] scope: short description in imperative mood
|
||||||
|
|
||||||
Explain WHY the change was made — the diff already shows what. Name the
|
Explain WHY the change was made — the diff already shows what. Name the
|
||||||
symptom that led to it, and what was measured rather than assumed.
|
failure mode, and what was measured rather than assumed, in words a
|
||||||
|
stranger to this site can read: the software, the version, the class of
|
||||||
|
situation — never a customer, a real database, a machine or an address.
|
||||||
Wrap at 80 characters.
|
Wrap at 80 characters.
|
||||||
|
|
||||||
--- FR ---
|
--- FR ---
|
||||||
|
|
@ -135,21 +137,27 @@ that matter says more in the space than half a sentence does:
|
||||||
That form is a fallback, not a default. Prefer the sentence when it fits.
|
That form is a fallback, not a default. Prefer the sentence when it fits.
|
||||||
|
|
||||||
**The guard rail.** `script/git/hooks/commit-msg` refuses a subject with no
|
**The guard rail.** `script/git/hooks/commit-msg` refuses a subject with no
|
||||||
tag, one over 72 characters, and one opening on a quotation. Install it with
|
tag, one over 72 characters, and one opening on a quotation. It reads the body
|
||||||
`git config core.hooksPath script/git/hooks`; `git commit --no-verify` passes
|
too: over ten lines for one language, an IP address, an e-mail, a
|
||||||
a legitimate exception. It checks only what is mechanical — whether the
|
`/home/<account>/` path, or any term listed in `private/noms_interdits.txt` —
|
||||||
subject says what the code is about stays a judgement, and the test above is
|
the customer and machine names, which cannot live in git because they are what
|
||||||
how you make it.
|
the list protects. With no such file, that last check stays silent. Install
|
||||||
|
the hook with `git config core.hooksPath script/git/hooks`; `git commit
|
||||||
|
--no-verify` passes a legitimate exception. It checks only what is mechanical
|
||||||
|
— whether the subject says what the code is about, and whether the body tells
|
||||||
|
the story instead of the mechanism, stay judgements, and the tests above are
|
||||||
|
how you make them.
|
||||||
|
|
||||||
### Keep it short
|
### Keep it short
|
||||||
|
|
||||||
The body answers one question: why was this necessary. Stop once it is
|
The body answers one question: why was this necessary. Stop once it is
|
||||||
answered — the reader owes you nothing beyond that.
|
answered — the reader owes you nothing beyond that.
|
||||||
|
|
||||||
**Ten lines per language. Fifteen is already long.** Past that, the reasoning
|
**Eight lines per language. Ten is the ceiling.** Past that, the reasoning
|
||||||
belongs in a document or a code comment, and the commit points at it. The
|
belongs in `tasks/`, which is not versioned, and the commit points at it —
|
||||||
budget is per language: bilingual doubles everything, so it buys terseness,
|
never in a code comment: a comment says how the code WORKS, not what happened
|
||||||
it does not excuse length.
|
the week it was written. The budget is per language: bilingual doubles
|
||||||
|
everything, so it buys terseness, it does not excuse length.
|
||||||
|
|
||||||
Cut, in this order:
|
Cut, in this order:
|
||||||
|
|
||||||
|
|
@ -160,10 +168,25 @@ Cut, in this order:
|
||||||
- Every clause that would not change what a reader does: no `this commit`,
|
- Every clause that would not change what a reader does: no `this commit`,
|
||||||
no `I decided to`, no summary of the summary, no restating the subject.
|
no `I decided to`, no summary of the summary, no restating the subject.
|
||||||
|
|
||||||
Keep, always: the symptom that led to the change, the figure you measured
|
Keep, always: the failure mode the change removes, the figure that bounds it,
|
||||||
rather than assumed, and one line naming what you verified and how. A single
|
and one line naming what you verified and how. A single `Checked: 4 jobs,
|
||||||
`Checked: 4 jobs, 1.63 s at parallelism 1 vs 0.58 s at 4` is worth three
|
1.63 s at parallelism 1 vs 0.58 s at 4` is worth three paragraphs of prose.
|
||||||
paragraphs of prose.
|
|
||||||
|
Two tests decide what survives, and they apply to every sentence of the body.
|
||||||
|
|
||||||
|
**Tense and subject.** Each sentence says what the code now does or refuses,
|
||||||
|
in the present. A sentence whose subject is an incident, a session, a machine,
|
||||||
|
a date or a person is cut — including your own reasoning: no `my conclusion
|
||||||
|
was wrong`, no `three faults found by running it`. That belongs in `tasks/`.
|
||||||
|
|
||||||
|
**Nothing identifying.** No customer or third-party organisation, no real
|
||||||
|
database name, no VM or host name, no IP address, no e-mail, no path carrying
|
||||||
|
a user name, no label or figure taken from a customer's data. Generalise to
|
||||||
|
the CLASS of situation instead of censoring: `on a production database`, `on a
|
||||||
|
development VM`, `on a host that demands interactive sudo` — the class is what
|
||||||
|
serves the reader; the name never was. A figure that is a durable limit or
|
||||||
|
threshold stays (65 536 inotify watches); a reading taken during one incident
|
||||||
|
goes.
|
||||||
|
|
||||||
### Bilingual body
|
### Bilingual body
|
||||||
|
|
||||||
|
|
@ -197,7 +220,9 @@ the work.
|
||||||
- `scope` is the Odoo technical module (`sale_order`, `account`, `stock`) or
|
- `scope` is the Odoo technical module (`sale_order`, `account`, `stock`) or
|
||||||
the area of the repository (`script todo`, `qemu ssh`, `migration`).
|
the area of the repository (`script todo`, `qemu ssh`, `migration`).
|
||||||
- The commit stands on its own: state what was verified, and how. If a claim
|
- The commit stands on its own: state what was verified, and how. If a claim
|
||||||
was not checked, say so rather than implying it was.
|
was not checked, say so rather than implying it was. Standing on its own
|
||||||
|
means it needs no OTHER COMMIT to be understood — not that it carries the
|
||||||
|
whole investigation. The line budget above still binds.
|
||||||
- If you cannot explain and defend every line, do not commit it.
|
- If you cannot explain and defend every line, do not commit it.
|
||||||
|
|
||||||
### Size and pace
|
### Size and pace
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue