[UPD] claude: align the commit command with the AI policy

The template wrote « Generated by Claude Code », the form AI_POLICY.md
replaces with the Assisted-by trailer. Three defects rode along: the model
came from ~/.claude/settings.json, which has no model key here, so it
declared the sonnet default rather than the truth; --author alone failed on
the committer, this checkout having no git identity; and [UPD] was missing
from the tag table while being the most used tag, 134 of the last 400.

The model now comes from the session transcript, the only source that
follows a /model switch — checked, it prints Claude Opus 5. The timezone is
left to the system so contributors keep their own, and the menu substitutes
name and email separately, the placeholders no longer being adjacent.

--- FR ---

Le gabarit écrivait « Generated by Claude Code », la forme que AI_POLICY.md
remplace par le trailer Assisted-by. Trois défauts l'accompagnaient : le
modèle venait de ~/.claude/settings.json, sans clé model ici, si bien qu'il
déclarait le défaut sonnet plutôt que la vérité ; --author seul échouait sur
le committer, ce checkout n'ayant aucune identité git ; et [UPD] manquait au
tableau des tags alors qu'il est le plus utilisé, 134 des 400 derniers.

Le modèle vient désormais de la transcription de session, seule source qui
suive un changement par /model — vérifié, elle rend Claude Opus 5. Le fuseau
est laissé au système, pour que chaque contributeur garde le sien, et le
menu substitue nom et courriel séparément, les jetons n'étant plus accolés.

Assisted-by: Claude Opus 5
This commit is contained in:
Mathieu Benoit 2026-08-07 01:56:11 -04:00
parent e5582e2427
commit b4b95042ef
3 changed files with 161 additions and 39 deletions

View file

@ -12,4 +12,25 @@ indentations par type de fichier.
- 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
- Manifests XML dans `manifest/` pour chaque version Odoo - Manifests XML dans `manifest/` pour chaque version Odoo
- Format de commit : `[TYPE] description` (ex: `[FIX]`, `[UPD]`, `[ADD]`, `[REM]`) - Format de commit : `[TYPE] portée : sujet`, sujet à l'impératif, 72
caractères au plus. Tags réellement utilisés : `[UPD]`, `[FIX]`, `[ADD]`,
`[IMP]`, `[REF]`.
### 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.
- 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
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.
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`.

View file

@ -1,6 +1,6 @@
--- ---
name: commit name: commit
description: "OCA/Odoo conventional commit in English with dynamic Claude Code attribution." description: "ERPLibre commit: OCA tag, bilingual body, Assisted-by trailer per AI_POLICY.md."
disable-model-invocation: true disable-model-invocation: true
allowed-tools: allowed-tools:
- Bash(git add:*) - Bash(git add:*)
@ -8,8 +8,6 @@ allowed-tools:
- Bash(git commit:*) - Bash(git commit:*)
- Bash(git diff:*) - Bash(git diff:*)
- Bash(git log:*) - Bash(git log:*)
- Bash(claude --version)
- Bash(cat:*)
- Bash(python3:*) - Bash(python3:*)
--- ---
@ -19,62 +17,171 @@ allowed-tools:
- Full diff: !`git diff HEAD` - Full diff: !`git diff HEAD`
- Current branch: !`git branch --show-current` - Current branch: !`git branch --show-current`
- Last 5 commits (for style reference): !`git log --oneline -5` - Last 5 commits (for style reference): !`git log --oneline -5`
- Claude Code version: !`claude --version 2>/dev/null | head -1`
## Task ## Task
Before committing, retrieve the active model with: Write a commit that satisfies `AI_POLICY.md` — the OCA generative AI policy
ERPLibre adopts — and the conventions below.
### Resolve the model — `{MODEL}`
Run this first. It reads the model from the CURRENT session transcript, which
is the only source that stays right when the model is switched mid-session
with `/model` or a CLI flag:
```bash ```bash
python3 -c " python3 -c "
import json, os import glob, json, os, sys
path = os.path.expanduser('~/.claude/settings.json') sid = os.environ.get('CLAUDE_CODE_SESSION_ID', '')
try: hits = glob.glob(os.path.expanduser('~/.claude/projects/*/%s.jsonl' % sid)) if sid else []
d = json.load(open(path)) mid = ''
print(d.get('model', 'claude-sonnet-4-6')) for path in hits[:1]:
except: with open(path) as fh:
print('claude-sonnet-4-6') for line in fh:
try:
m = json.loads(line).get('message', {}).get('model', '')
except Exception:
continue
if m and not m.startswith('<'):
mid = m
if not mid:
sys.exit('UNKNOWN')
mid = mid.removeprefix('claude-')
parts = [p for p in mid.split('-') if not (len(p) == 8 and p.isdigit())]
print('Claude %s %s' % (parts[0].capitalize(), '.'.join(parts[1:])))
" "
``` ```
Then create an OCA/Odoo-compliant commit. It prints the trailer value: `Claude Opus 5`, `Claude Sonnet 4.6`,
`Claude Haiku 4.5`. There is deliberately no fallback name — on `UNKNOWN`,
use the model you know you are running as, and never a value read from a
settings file: `~/.claude/settings.json` usually has no `model` key at all,
so it would quietly declare the default instead of the truth.
### OCA Tags ### Tags
| Tag | Usage | | Tag | Usage |
|-----|-------| |-----|-------|
| `[IMP]` | Improvement / new feature | | `[UPD]` | Update existing code, data or configuration |
| `[FIX]` | Bug fix | | `[FIX]` | Bug fix |
| `[REF]` | Refactoring | | `[ADD]` | New module, file or capability |
| `[ADD]` | New module | | `[IMP]` | Improvement to something that already works |
| `[REM]` | Remove code/module | | `[REF]` | Refactoring, no observable behaviour change |
| `[MOV]` | Move/rename | | `[REM]` | Remove code or module |
| `[MOV]` | Move or rename |
| `[I18N]` | Translations | | `[I18N]` | Translations |
The first five cover every one of the last 400 commits. Reach for `[REM]`,
`[MOV]` or `[I18N]` only when one of them genuinely fits better.
### Format ### Format
``` ```
[TAG] module_name: short description in imperative mood [TAG] scope: short description in imperative mood
Explain WHY the change was made (not what — the diff already shows that). Explain WHY the change was made — the diff already shows what. Name the
Keep lines under 80 characters. symptom that led to it, and what was measured rather than assumed.
Wrap at 80 characters.
Generated by Claude Code {VERSION} {MODEL} --- FR ---
Co-Authored-By: Your Name <your@email.com> The same body, translated.
Assisted-by: {MODEL}
``` ```
### 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.
Cut, in this order:
- Anything the diff already says. `adds function X` is visible; `X because
the DHCP lease can be stale` is not.
- Headings and bullet lists. If the change really needs sections, it needs
several commits.
- 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.
### Bilingual body
Every AI-assisted commit carries its body twice. Write it first in whichever
language you were thinking in, then the marker, then the translation.
The marker names the language of what FOLLOWS it: `--- FR ---` after an
English body, `--- EN ---` after a French one. One marker per commit, never
both.
Translate, do not re-summarise: a reader of either language must get the same
reasoning, the same measured figures and the same caveats.
### The Assisted-by trailer
`AI_POLICY.md` makes this binary — there was AI involvement or there was not,
with no threshold to judge. Anything from a single suggestion to fully
autonomous coding means the trailer, and it says nothing about the quality of
the work.
- One `Assisted-by:` line per model. A session that switched models declares
each of them, one line each.
- NEVER name an AI in `Co-authored-by:`: authorship of a work by a machine is
legally undefined. That field is for other HUMANS who worked on the change.
You are already the author, so never co-author yourself.
- No blank line between trailers.
### Rules ### Rules
- **English only**, imperative mood, subject line under 50 chars - Subject: imperative mood, **72 characters maximum**, aim for 50.
- Use the Odoo technical module name (e.g. `sale_order`, `account`, `stock`) - `scope` is the Odoo technical module (`sale_order`, `account`, `stock`) or
- If multiple modules are impacted, suggest splitting into separate commits 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.
- If you cannot explain and defend every line, do not commit it.
### Size and pace
A patch under 30 lines in a single file is the reference point. Past ~500
lines the policy asks for prior agreement with a maintainer — say so instead
of committing quietly. When several unrelated modules are touched, propose
splitting into separate commits before writing anything.
### Execute ### Execute
The timezone comes from the system, as it should: nothing is forced here, so
each contributor's commits carry their own zone. If yours land at `+0000`,
the machine itself is on UTC — common on a server or a VM — and the fix
belongs there, `sudo timedatectl set-timezone <Area/City>`, because it
affects every commit and not just this one.
The identity is passed explicitly with `-c`, which sets the author AND the
committer. `--author` alone sets only the author, and a checkout with no
configured `user.email` then fails on the committer.
Use a heredoc rather than `-m`: a body with quotes, backticks or accented
characters survives it unharmed.
```bash ```bash
git add -A && git commit --author="Your Name <your@email.com>" -m "[TAG] module: description git add -A
git -c user.name="Your Name" -c user.email="your@email.com" commit -F - <<'MSG'
[TAG] scope: description
Explain WHY here. Explain WHY here.
Generated by Claude Code {VERSION} {MODEL} --- FR ---
Co-Authored-By: Your Name <your@email.com>" The same body, translated.
Assisted-by: {MODEL}
MSG
``` ```

View file

@ -1086,14 +1086,8 @@ class TODO:
if personalize: if personalize:
name = input(t("Enter your full name: ")).strip() name = input(t("Enter your full name: ")).strip()
email = input(t("Enter your email: ")).strip() email = input(t("Enter your email: ")).strip()
content = content.replace( content = content.replace("your@email.com", email)
"Your Name <your@email.com>", content = content.replace("Your Name", name)
f"{name} <{email}>",
)
content = content.replace(
"Your Name ",
f"{name} ",
)
os.makedirs(dest_dir, exist_ok=True) os.makedirs(dest_dir, exist_ok=True)
with open(dest_file, "w") as f: with open(dest_file, "w") as f: