diff --git a/.claude/rules/04-code-conventions.md b/.claude/rules/04-code-conventions.md index b692e75..ad311de 100644 --- a/.claude/rules/04-code-conventions.md +++ b/.claude/rules/04-code-conventions.md @@ -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 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 « », annoncée en + au lieu de », 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 « _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 @@ -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 reste préférable quand elle tient. -Un garde-fou refuse le mécanique — tag absent, plus de 72 caractères, sujet -qui s'ouvre sur une citation : +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, 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 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 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 -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é git, taille des correctifs — est dans diff --git a/.claude/rules/09-workflow.md b/.claude/rules/09-workflow.md index aa5f335..16972f5 100644 --- a/.claude/rules/09-workflow.md +++ b/.claude/rules/09-workflow.md @@ -45,5 +45,8 @@ 2. **Verify Plan**: Check in before starting implementation. 3. **Track Progress**: Mark items complete as you go. 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 diff --git a/CLAUDE.md b/CLAUDE.md index 7281dc7..f9994c0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 - Les scripts ERPLibre utilisent `.venv.erplibre/bin/python` - 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` - Port Odoo par défaut : 8069, longpolling : 8072 - Pour les commits : suivre le format `[TYPE] description` (ex: `[FIX]`, `[UPD]`, `[ADD]`, `[REM]`) diff --git a/conf/template_claude_commands_commit.md b/conf/template_claude_commands_commit.md index 01fd745..f2dd341 100644 --- a/conf/template_claude_commands_commit.md +++ b/conf/template_claude_commands_commit.md @@ -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 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. --- 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. **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 -`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 stays a judgement, and the test above is -how you make it. +tag, one over 72 characters, and one opening on a quotation. It reads the body +too: over ten lines for one language, an IP address, an e-mail, a +`/home//` path, or any term listed in `private/noms_interdits.txt` — +the customer and machine names, which cannot live in git because they are what +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 The body answers one question: why was this necessary. Stop once it is answered — the reader owes you nothing beyond that. -**Ten lines per language. Fifteen is already long.** Past that, the reasoning -belongs in a document or a code comment, and the commit points at it. The -budget is per language: bilingual doubles everything, so it buys terseness, -it does not excuse length. +**Eight lines per language. Ten is the ceiling.** Past that, the reasoning +belongs in `tasks/`, which is not versioned, and the commit points at it — +never in a code comment: a comment says how the code WORKS, not what happened +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: @@ -160,10 +168,25 @@ Cut, in this order: - 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. -Keep, always: the symptom that led to the change, the figure you measured -rather than assumed, and one line naming what you verified and how. A single -`Checked: 4 jobs, 1.63 s at parallelism 1 vs 0.58 s at 4` is worth three -paragraphs of prose. +Keep, always: the failure mode the change removes, the figure that bounds it, +and one line naming what you verified and how. A single `Checked: 4 jobs, +1.63 s at parallelism 1 vs 0.58 s at 4` is worth three 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 @@ -197,7 +220,9 @@ the work. - `scope` is the Odoo technical module (`sale_order`, `account`, `stock`) or 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 - 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. ### Size and pace