Décisions en ADR ; plans et feuille de route temporaires

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Pierre MARTIN
2026-11-02 13:23:18 +01:00
co-authored by Claude Opus 5.5
parent 6958accec2
commit d017f3338b
17 changed files with 446 additions and 266 deletions
+4 -4
View File
@@ -4,7 +4,7 @@ Ce fichier est lu par Claude Code au début de chaque session. Il fixe le cadre
Le cadrage complet est dans `docs/cadrage.md`, l'étape en cours dans `docs/etape-0.md`.
**En début de session**, lire `docs/organisation.md`, `docs/feuille-de-route.md`, la fin
de `docs/journal.md` et les plans en cours dans `docs/plans/`, puis reprendre là où en
de `docs/journal.md`, l'index des ADR (`docs/adr/README.md`) et les plans en cours dans `docs/plans/`, puis reprendre là où en
est la feuille de route.
## Le projet en bref
@@ -46,14 +46,14 @@ Des cibles plus fines (`make engine`, `make engine-wasm`, `make bench`…) sont
## Façon de travailler
0. **Pilotage.** La session principale est chef de projet technique : elle tient la feuille de route et délègue l'exécution à des sous-agents, selon `docs/organisation.md`. Toute tâche déléguée a son plan dans `docs/plans/`, écrit avant la délégation et complété à la clôture. Rien d'important ne vit seulement dans la mémoire d'une session.
0. **Pilotage.** La session principale est chef de projet technique : elle tient la feuille de route et délègue l'exécution à des sous-agents, selon `docs/organisation.md`. Toute tâche déléguée a son plan dans `docs/plans/`, écrit avant la délégation et supprimé à la clôture. Chaque décision structurante a son ADR dans `docs/adr/`. Rien d'important ne vit seulement dans la mémoire d'une session.
1. **Petites étapes vérifiables.** Une étape = un résultat observable (une commande qui répond, un test qui passe). Présenter un plan court avant toute étape de plus d'une heure.
2. **Tests d'abord pour le moteur.** Les positions de référence sont évaluées avec le GNU Backgammon de bureau (en ligne de commande, dans Docker) et stockées dans `tests/reference/`. Le moteur embarqué doit concorder.
3. **Expliquer simplement.** Après chaque étape : ce qui a été fait, comment le vérifier soi-même (commande exacte), ce qui reste.
4. **Ne jamais masquer un échec.** Pas de test désactivé, pas de résultat simulé. Dire clairement ce qui bloque et la cause probable.
5. **Commits fréquents**, messages courts en français, sur une branche dédiée. Jamais de commit direct sur `main` : chaque changement passe par une merge request Gitea (`tea pulls create --login sans-pub`), décrite selon `docs/organisation.md`. Claude Code la fusionne lui-même une fois `make lint` et `make test` au vert.
6. **Dépendances** : peu, maintenues, compatibles GPLv3. Signaler chaque nouvelle dépendance et sa licence.
7. **Journal** : `docs/journal.md` reçoit une entrée datée à la fin de chaque session (fait, décidé, reste à faire). Les décisions structurantes vont dans `docs/decisions.md`.
7. **Journal** : `docs/journal.md` reçoit une entrée datée à la fin de chaque session (fait, décidé, reste à faire). Les décisions structurantes vont dans un ADR (`docs/adr/`), jamais réécrit une fois accepté.
## Sources du moteur
@@ -72,7 +72,7 @@ Respecter les mentions de copyright ; créditer ces projets dans `CREDITS.md`.
├── LICENSE GPLv3
├── CREDITS.md
├── docs/ cadrage, feuille de route, organisation, étape en cours,
│ plans des tâches déléguées, journal, décisions
│ plans des tâches déléguées, ADR, journal
├── engine/ sources du moteur (sous-module ou copie versionnée) + interface C
├── engine-cli/ programme en ligne de commande pour interroger le moteur
├── web/ prototype puis application PWA
@@ -0,0 +1,42 @@
# 0001. Consigner les décisions dans des ADR
- **Statut** : accepté
- **Date** : 2026-11-02
- **Décideurs** : Pierre
## Contexte
Les premières décisions du projet étaient consignées dans un fichier unique,
`docs/decisions.md`, à côté des plans et de la feuille de route. Or ces
documents n'ont pas la même durée de vie : un plan ou une ligne de feuille de
route est temporaire et disparaît une fois réalisé, alors qu'une décision doit
rester lisible tant qu'elle s'applique, et même après, pour comprendre
l'historique. Les mélanger rend les choix plus difficiles à retrouver et à
remettre en cause proprement.
## Décision
Chaque décision structurante fait l'objet d'un ADR (Architecture Decision
Record) : un fichier `docs/adr/NNNN-titre-court.md`, numéroté dans l'ordre, au
format de `docs/adr/modele.md`. Un ADR accepté n'est plus réécrit : une
décision qui change donne un nouvel ADR, et l'ancien passe au statut
« remplacé par NNNN ». L'index `docs/adr/README.md` liste tous les ADR.
Les plans (`docs/plans/`) et la feuille de route ne contiennent que le travail
à faire ; un plan réalisé est supprimé, et ce qu'il contenait de durable passe
dans un ADR, dans la description de la merge request ou dans le journal.
`docs/decisions.md` est supprimé ; ses entrées deviennent les ADR 0002 à 0006.
## Alternatives écartées
- **Garder `docs/decisions.md`** : un seul fichier qui grossit, où l'on ne
distingue pas une décision en vigueur d'une décision remplacée.
- **Ne garder la trace que dans les merge requests** : elle existe déjà là,
mais hors du dépôt, sur un serveur qui peut changer.
## Conséquences
- `make test` vérifie la forme des ADR (numérotation, statut, sections, index).
- Les ADR 0002 à 0006 reprennent des décisions antérieures à celui-ci, avec
leur date d'origine.
+27
View File
@@ -0,0 +1,27 @@
# 0002. Nom de l'application : Ustagammon
- **Statut** : accepté
- **Date** : 2026-11-01
- **Décideurs** : Pierre
## Contexte
Le nom de l'application était une question ouverte du cadrage. Il conditionne
l'identifiant de l'application, le nom du dépôt et l'identité visuelle.
## Décision
L'application s'appelle **Ustagammon** : « usta », en turc le maître artisan
qui transmet son savoir à l'apprenti, et « gammon », de backgammon. Le sens du
nom et l'identité visuelle sont décrits dans le brief créatif :
https://claude.ai/artifact/36WMwZWqvMxXvSSVBJTgwd
## Alternatives écartées
Non documentées : le choix a été fait par Pierre avant le démarrage technique.
## Conséquences
- Le dépôt s'appelle `pierre/Ustagammon` sur git.sans.pub.
- Reste à vérifier, avant publication, qu'aucune application du même nom
n'existe sur F-Droid et le Play Store.
@@ -0,0 +1,34 @@
# 0003. Pilotage par Claude Code et des sous-agents
- **Statut** : accepté
- **Date** : 2026-11-02
- **Décideurs** : Pierre
## Contexte
Le kit de démarrage prévoyait un fichier `PROMPTS.md` : des messages que Pierre
collait dans Claude Code à chaque étape. Pierre ne relit pas le code en détail
et souhaite que le suivi du projet ne repose pas sur lui ni sur la mémoire
d'une session.
## Décision
La session principale de Claude Code est chef de projet technique : elle tient
la feuille de route, découpe le travail, délègue l'exécution à des sous-agents
et vérifie leurs résultats. Toute tâche déléguée a un plan écrit dans
`docs/plans/` avant la délégation. Rien d'important ne vit seulement dans la
mémoire d'une session : tout est écrit dans `docs/` et commité. Le
fonctionnement détaillé est dans `docs/organisation.md`.
## Alternatives écartées
- **Prompts collés par Pierre** (`PROMPTS.md`) : fait reposer l'enchaînement
des étapes sur Pierre, et ne laisse pas de trace de ce qui a été demandé à
chaque agent.
## Conséquences
- `PROMPTS.md` est supprimé ; l'enchaînement des étapes est dans
`docs/feuille-de-route.md`.
- Pierre garde la main sur le produit, l'identité et les décisions soumises à
validation (liste dans `docs/organisation.md`).
@@ -0,0 +1,30 @@
# 0004. Outils de développement dans Docker
- **Statut** : accepté
- **Date** : 2026-11-02
- **Décideurs** : Claude Code
## Contexte
La machine de développement est ancienne et doit rester légère. Le cadrage
prévoit déjà que les chaînes d'outils lourdes (NDK, Emscripten, gnubg de
référence) tournent dans Docker. La question s'est posée dès le premier outil
de vérification, ShellCheck, absent du PC.
## Décision
Rien n'est installé sur le PC en dehors de git, make, Docker et adb. Chaque
outil tourne dans une image Docker de version figée, récupérée ou construite
par `make setup`. Premier cas : ShellCheck (GPLv3), image
`koalaman/shellcheck-alpine:v0.10.0`.
## Alternatives écartées
- **Installer les outils avec apt** : versions qui varient d'une machine à
l'autre, et pollution du système.
## Conséquences
- `make lint` demande d'avoir lancé `make setup` une fois ; il le dit
explicitement sinon.
- Chaque nouvelle image est signalée avec sa licence dans `CREDITS.md`.
+100
View File
@@ -0,0 +1,100 @@
# 0005. Source du moteur : GNU Backgammon officiel, commit 14b6798
- **Statut** : accepté
- **Date** : 2026-11-02
- **Décideurs** : Pierre, sur recommandation de Claude Code
## Contexte
L'étape 0a commence par choisir le code source à partir duquel embarquer le
moteur, derrière une interface C `moteur.h` qui doit offrir cinq fonctions :
initialisation, coups légaux, classement des coups par niveau, décision de
videau en match, évaluation. Positions au format GNU Position ID et Match ID.
Les résultats doivent concorder avec le GNU Backgammon de bureau, qui sert de
référence aux tests.
Trois candidats ont été étudiés par un sous-agent, sur clones superficiels lus
sans rien compiler ni exécuter (MR !1 sur git.sans.pub) :
| Source | Commit étudié | Date |
| --- | --- | --- |
| gnubg officiel | 14b67984737ded0f6de43d63dcb789f729d9b06b (1.08.003) | 2026-10-23 |
| gnubg-nn | 595a9e8f1fe094ee22db5a736bc05027643756df | 2025-09-07 |
| CBG (`github.com/clavierhaus/gnubg-android`) | 62028573d7564275a7c9363f0ef5d4b63d8d0f26 (moteur gnubg b1b2772c) | 2026-10-26 |
| Critère | gnubg | gnubg-nn | CBG |
| --- | --- | --- | --- |
| Activité | Active (corrections régulières) | Quasi arrêtée (outil d'entraînement des réseaux) | Très active ; un mainteneur, code très majoritairement écrit par IA |
| Licence | GPLv3 ou ultérieure | **48 fichiers en GPLv2 seule** : incompatible | GPLv3 ou ultérieure ; noms « CBG » et « Clavierhaus » revendiqués comme marques |
| Fonctions | Les cinq, avec tables d'équité, Crawford, Jacoby, Position ID et Match ID | Partiel : pas de Match ID, videau réimplémenté en C++ | Les cinq, mais interface pensée pour une partie en cours |
| Dépendances | GLib dans tout le cœur, remplaçable par un shim d'environ 30 fonctions, sauf GMarkup (tables d'équité) et `g_mapped_file` ; SSE, AVX, **NEON** et repli en C générique ; threads désactivables | C++14, Python 2, SSE seul | GLib, GObject et libintl compilés en entier pour Android |
| Isolement | Faisable : environ 24 400 lignes ; état global partout ; `backgammon.h` à réduire | Évaluation isolée, le reste à réécrire | 41 fichiers et 681 lignes de bouchons : pas une bibliothèque minimale |
| Données | `gnubg.weights` (1 097 796 octets) ; `gnubg.wd`, `gnubg_os0.bd`, `gnubg_ts0.bd` générés au build ; tables d'équité XML (`Kazaross-XG2.xml` par défaut) | Pas de poids fournis | Mêmes poids, identiques octet pour octet ; aucune base `.bd` fournie |
| Portabilité | NEON présent ; pas de SIMD WebAssembly (C générique) ; un portage Emscripten tiers existe (`hwatheod/gnubg-web`, 2019) | Mauvais point de départ | Build CMake/NDK fonctionnel, pas de WebAssembly |
| Concordance | Mêmes sources et poids que le bureau ; écart flottant car `configure.ac` force `-ffast-math` | Non, pour le videau | Écarts de 1e-4 à 3e-3 selon leur documentation, non vérifié |
Points recoupés directement dans les sources par la session principale : les
48 en-têtes GPLv2 de gnubg-nn (ex. `gnubg-nn/gnubg/eval.c` l. 7) ; la licence
GPLv3+ de `gnubg/eval.c` ; `-ffast-math` ajouté par `gnubg/configure.ac:595` ;
le code NEON dans `lib/simd.h` et `lib/neuralnetsse.c` ; l'identité des poids
entre gnubg et CBG ; trois usages de `g_markup` dans `matchequity.c` ;
`makebearoff` dans `Makefile.am`.
## Décision
Le moteur d'Ustagammon est construit à partir de **GNU Backgammon officiel,
figé au commit 14b67984737ded0f6de43d63dcb789f729d9b06b**, dont on n'extrait
que le cœur, derrière `moteur.h`.
Fichiers à reprendre (liste issue des `#include` et des symboles, à confirmer à
la première édition des liens) :
- Évaluation : `eval.c/h`, `movefilters.inc`, `lib/neuralnet.c/h`,
`lib/neuralnetsse.c`, `lib/inputs.c`, `lib/simd.h`, `lib/sigmoid.h`,
`lib/cache.c/h`, `lib/gnubg-types.h`, `lib/isaac.c/h`, `lib/isaacs.h`,
`lib/md5.c/h`.
- Fin de partie : `bearoff.c/h`, `bearoffgammon.c/h`.
- Identifiants : `positionid.c/h`, `matchid.c/h`.
- Équité de match : `matchequity.c/h`, `mec.c/h`, `lib/list.c/h`.
- En-têtes à réduire : `backgammon.h`, `common.h`, `multithread.h`, `util.h`.
- Données : `gnubg.weights`, `met/*.xml` ; outils hôte `makeweights.c` et
`makebearoff.c`.
Plan d'isolement :
1. Copie figée dans `engine/`, `config.h` écrit à la main (sans threads ; NEON
sur arm64 ; rien en WebAssembly).
2. Shim `glib.h` minimal ; `mmap` ou `fread` à la place de `g_mapped_file`.
3. Tables d'équité converties en tableaux C au build, ou table Zadeh intégrée
pour commencer.
4. En-tête réduit à la place de `backgammon.h`, variables globales aux valeurs
par défaut de `gnubg.c`, en s'inspirant de `jni-bridge/src/stubs.c` de CBG.
5. Façade `moteur.h` sur `GenerateMoves`, `FindnSaveBestMoves`,
`GeneralCubeDecisionE` et `FindCubeDecision`, `PositionFromID`,
`MatchFromID`.
6. `gnubg.wd` et bases `.bd` générées sur l'hôte avec les outils officiels.
7. Tests de concordance avec tolérance, en mesurant l'écart avec et sans
`-ffast-math`.
## Alternatives écartées
- **gnubg-nn** : 48 fichiers sous GPLv2 seule, incompatibles avec la GPLv3 du
projet ; videau réimplémenté, donc sans concordance possible avec gnubg de
bureau.
- **CBG** : même moteur, mais avec GLib complète et toute la logique de partie ;
interface orientée partie en cours ; pas de bases de fin de partie. Gardé
comme référence de lecture, sans reprise de code ni de ses noms.
## Conséquences
- Le gnubg de bureau de référence est compilé dans Docker depuis le même
commit, et non pris dans un paquet Debian d'une autre version.
- Concordance au bit près impossible entre x86 avec `-ffast-math` et ARM ou
WebAssembly : les tests ont une tolérance, et prévoient le cas où le meilleur
coup change entre deux coups presque équivalents.
- L'état global de gnubg impose une seule instance du moteur et des appels
sérialisés.
- Les mises à jour de gnubg sont reportées à la main sur la copie figée.
- Les tailles des bases `.bd` restent à mesurer.
- Attention aux noms de niveaux : gnubg compte les plis à partir de 0 (0-ply =
évaluation statique).
@@ -0,0 +1,35 @@
# 0006. Merge requests systématiques, fusionnées par Claude Code
- **Statut** : accepté
- **Date** : 2026-11-02
- **Décideurs** : Pierre
## Contexte
Pierre veut comprendre chaque changement sans suivre le travail au fil de
l'eau. Les premiers commits ont été poussés directement sur `main`, ce qui a
laissé passer un `README.md` contenant des marqueurs de conflit.
## Décision
Aucun commit direct sur `main`. Chaque changement passe par une branche et une
merge request sur git.sans.pub, dont la description explique le pourquoi, le
quoi, le comment, les choix, les risques, la vérification et ce qui est hors
périmètre. Claude Code la fusionne lui-même, par commit de fusion, dès que
`make lint` et `make test` passent. Une MR qui touche un point soumis à
validation attend l'accord de Pierre.
## Alternatives écartées
- **Pousser directement sur `main`** : aucune explication attachée au
changement, aucune étape de vérification avant publication.
- **Fusion par squash** : plus lisible, mais perd le détail des étapes de la
branche.
- **Fusion par Pierre** : contraire au fonctionnement voulu (ADR 0003).
## Conséquences
- Le déroulé est décrit dans `docs/organisation.md`.
- La base de données du Gitea refuse les caractères hors du plan multilingue de
base (émojis) dans les descriptions : les descriptions de MR n'en contiennent
pas.
+14
View File
@@ -0,0 +1,14 @@
# Décisions d'architecture (ADR)
Un fichier par décision structurante, au format de `modele.md`. Un ADR accepté
n'est plus réécrit : une décision qui change donne un nouvel ADR, et l'ancien
passe au statut « remplacé par NNNN ». Voir l'ADR 0001.
| N° | Décision | Statut |
| --- | --- | --- |
| [0001](0001-consigner-les-decisions-dans-des-adr.md) | Consigner les décisions dans des ADR | accepté |
| [0002](0002-nom-ustagammon.md) | Nom de l'application : Ustagammon | accepté |
| [0003](0003-pilotage-par-claude-code-et-sous-agents.md) | Pilotage par Claude Code et des sous-agents | accepté |
| [0004](0004-outils-de-developpement-dans-docker.md) | Outils de développement dans Docker | accepté |
| [0005](0005-moteur-gnubg-officiel.md) | Source du moteur : GNU Backgammon officiel, commit 14b6798 | accepté |
| [0006](0006-merge-requests-systematiques.md) | Merge requests systématiques, fusionnées par Claude Code | accepté |
+23
View File
@@ -0,0 +1,23 @@
# NNNN. Titre de la décision
- **Statut** : proposé | accepté | remplacé par NNNN | obsolète
- **Date** : AAAA-MM-JJ
- **Décideurs** : qui a tranché
## Contexte
La situation, le problème, les contraintes et les faits (avec preuves) qui
rendent une décision nécessaire.
## Décision
Ce qui est décidé, formulé de façon à pouvoir être appliqué et vérifié.
## Alternatives écartées
Chaque option envisagée et la raison de l'écarter.
## Conséquences
Ce que la décision implique : effets positifs, limites assumées, risques,
travail induit.
-62
View File
@@ -1,62 +0,0 @@
# Décisions
Les décisions structurantes du projet, la plus récente en bas. Chacune donne son
contexte, le choix, les raisons et ce qu'elle implique.
## 2026-11-01 — Nom de l'application : Ustagammon
**Contexte** : le nom était une question ouverte du cadrage.
**Choix** : Ustagammon (« usta », le maître artisan en turc, et « gammon »).
**Référence** : le brief créatif, https://claude.ai/artifact/36WMwZWqvMxXvSSVBJTgwd
## 2026-11-02 — Outils de lint dans Docker
**Contexte** : la machine de développement doit rester légère ; rien n'est
installé en dehors de Docker, git, make et adb.
**Choix** : ShellCheck (GPLv3) tourne dans l'image `koalaman/shellcheck-alpine`,
version figée, récupérée par `make setup`.
**Conséquence** : `make lint` demande d'avoir lancé `make setup` une fois.
## 2026-11-02 — Pilotage par Claude Code et sous-agents, suivi dans `docs/`
**Contexte** : le kit prévoyait des prompts (`PROMPTS.md`) que Pierre collait à
chaque étape.
**Choix** (demande de Pierre) : Claude Code pilote le projet et délègue
l'exécution à des sous-agents. `PROMPTS.md` est supprimé ; son enchaînement
devient `docs/feuille-de-route.md`. Chaque délégation a son plan dans
`docs/plans/`. Fonctionnement détaillé dans `docs/organisation.md`.
**Raison** : rendre le suivi et la mémoire du projet transparents et
vérifiables a posteriori, en lisant le dépôt.
## 2026-11-02 — Source du moteur : gnubg officiel, commit `14b6798`
**Contexte** : étape 0a.1, trois candidats étudiés (gnubg, gnubg-nn, CBG).
Étude complète : `docs/plans/2026-11-02-choix-source-moteur.md`.
**Choix** (validé par Pierre) : GNU Backgammon officiel, figé au commit
`14b67984737ded0f6de43d63dcb789f729d9b06b` (1.08.003), dont on n'extrait que
le cœur (évaluation, coups, videau, identifiants, équité de match, fin de
partie) derrière `moteur.h`.
**Alternatives écartées** :
- gnubg-nn : 48 fichiers sous GPLv2 seule, incompatibles avec la GPLv3 ; videau
réimplémenté, donc sans concordance possible avec gnubg de bureau.
- CBG : même moteur, mais avec GLib complète et toute la logique de partie ;
interface orientée partie en cours ; pas de bases de fin de partie. Gardé
comme référence de lecture.
**Conséquences** :
- Le gnubg de bureau de référence est compilé dans Docker depuis le même
commit.
- GLib remplacée par un shim minimal ; tables d'équité XML à convertir.
- Les tests de concordance ont une tolérance, car gnubg de bureau est compilé
avec `-ffast-math`.
## 2026-11-02 — Merge requests systématiques, fusion par Claude Code
**Contexte** : Pierre veut comprendre chaque changement sans suivre le travail
au fil de l'eau.
**Choix** (demande de Pierre) : aucun commit direct sur `main`. Chaque
changement passe par une branche et une merge request Gitea dont la description
explique le pourquoi, le quoi, le comment, les choix, les risques, la
vérification et ce qui est hors périmètre. Claude Code la fusionne lui-même dès
que `make lint` et `make test` passent.
**Conséquence** : l'historique des MR sur git.sans.pub devient, avec `docs/`,
la trace vérifiable du projet.
+2 -2
View File
@@ -11,7 +11,7 @@
**Objectif** : interroger le moteur GNU Backgammon sur une position, depuis le PC.
À faire :
1. Récupérer les sources du moteur (choisir entre gnubg, gnubg-nn ou le moteur extrait par CBG ; justifier le choix dans `docs/decisions.md`).
1. Récupérer les sources du moteur (choisir entre gnubg, gnubg-nn ou le moteur extrait par CBG ; justifier le choix dans un ADR, `docs/adr/`).
2. Définir une **interface C minimale** du moteur (`engine/include/moteur.h`), indépendante de toute interface graphique :
- initialiser le moteur (charger réseaux, base de fin de partie, table d'équité de match) ;
- lister les coups légaux pour une position et des dés ;
@@ -68,6 +68,6 @@
## 0d. Plateau minimal et décision
1. Sur le socle retenu, un **plateau minimal** : une partie complète jouable contre le moteur, coups et videau décidés par le moteur, dés tirés par l'app.
2. Rédiger `docs/decisions.md` : socle retenu (PWA ou Android natif), mesures obtenues, raisons, risques restants.
2. Rédiger un ADR (`docs/adr/`) : socle retenu (PWA ou Android natif), mesures obtenues, raisons, risques restants.
**Critère de fin de l'étape 0** : une partie complète jouée sur le Fairphone 4, moins de 2 s par coup de l'IA en niveau standard, tous les tests au vert.
+10 -7
View File
@@ -1,22 +1,25 @@
# Feuille de route
État d'avancement du projet. Les versions et leur contenu sont définis dans
Le travail restant, dans l'ordre. Une ligne réalisée est retirée : ce qui a été
fait se lit dans les merge requests et le journal, ce qui a été décidé dans les
ADR (`docs/adr/`). Les versions et leur contenu sont définis dans
`docs/cadrage.md` ; le détail de l'étape en cours est dans `docs/etape-0.md`.
Légende : ✅ terminé · 🔄 en cours · ⏳ à venir · ⏸ conditionnel
Légende : 🔄 en cours · ⏳ à venir · ⏸ conditionnel
## Étape 0 — Prototype technique
| Sous-étape | Contenu | État | Plans |
Acquis : socle du dépôt, organisation (ADR 0001, 0003, 0006), source du moteur
(ADR 0005 : gnubg officiel, commit 14b6798).
| Sous-étape | Contenu | État | Plan |
| --- | --- | --- | --- |
| Socle | Dépôt, Makefile, lint, tests, organisation | ✅ | — |
| 0a.1 | Choisir la source du moteur : gnubg officiel, commit `14b6798` (validé) | ✅ | `plans/2026-11-02-choix-source-moteur.md` |
| 0a.2 | Image Docker GNU Backgammon de bureau (compilé depuis le commit `14b6798`), 30+ positions de référence dans `tests/reference/` | ⏳ | |
| 0a.2 | Image Docker GNU Backgammon de bureau (compilé depuis le commit 14b6798), 30+ positions de référence dans `tests/reference/` | ⏳ | |
| 0a.3 | Interface C `engine/include/moteur.h` et `engine-cli` (JSON) | ⏳ | |
| 0a.4 | `make test` compare `engine-cli` aux références | ⏳ | |
| 0b | Moteur en WebAssembly, page de test dans un Web Worker, `make deploy-web`, `make bench` | ⏳ | |
| Mesures | Pierre relève les mesures sur le Fairphone 4 | ⏳ | |
| Décision | Socle PWA ou Android natif, consigné dans `decisions.md` — validation de Pierre | ⏳ | |
| Décision | Socle PWA ou Android natif, consigné dans un ADR — validation de Pierre | ⏳ | |
| 0c | Android natif (NDK, Gradle en ligne de commande, `make deploy` via adb) | ⏸ si 0b échoue | |
| 0d | Plateau minimal jouable sur le socle retenu | ⏳ | |
+13 -1
View File
@@ -27,10 +27,22 @@ Une entrée datée par session : ce qui a été fait, décidé, et la suite.
**Décidé**
- Les outils de lint tournent dans Docker, comme les autres chaînes d'outils.
- Claude Code pilote le projet par sous-agents ; tout le suivi est dans `docs/`.
- Moteur : gnubg officiel, commit `14b6798` (validé par Pierre).
- Moteur : gnubg officiel, commit 14b6798 (validé par Pierre).
- Toute modification passe par une merge request Gitea décrite en détail,
fusionnée par Claude Code une fois `make lint` et `make test` au vert
(demande de Pierre).
- Les décisions passent dans des ADR (`docs/adr/`) ; `docs/decisions.md` est
remplacé par les ADR 0001 à 0006. Plans et feuille de route deviennent
temporaires : le plan du choix du moteur est supprimé, son contenu durable
est dans l'ADR 0005 (demande de Pierre).
- Les hash de commit s'écrivent sans backticks, pour les liens automatiques de
Gitea (demande de Pierre).
**Incident ouvert**
- La MR !1 a bien été fusionnée côté git (commit de fusion 6958acc sur `main`),
mais Gitea l'affiche toujours « open ». Cause non établie ; la base de
données du serveur refuse déjà les émojis (erreur MySQL 1366), piste à
vérifier dans les journaux de Gitea.
**Reste à faire**
- Étape 0a.2 : image Docker de gnubg de bureau compilé depuis le même commit,
+45 -51
View File
@@ -2,7 +2,7 @@
Ce document décrit qui fait quoi et où chaque chose est consignée. Le but : que
tout le travail, humain comme agentique, soit suivi et vérifiable a posteriori
en lisant uniquement le dépôt.
en lisant le dépôt et ses merge requests.
## Rôles
@@ -12,69 +12,58 @@ en lisant uniquement le dépôt.
- **Claude Code, session principale : chef de projet technique.** Tient la
feuille de route, découpe le travail, rédige les plans, délègue l'exécution à
des sous-agents, vérifie leurs résultats (`make lint`, `make test`, relecture
du diff), fait les commits et tient le journal.
du diff), rédige les ADR, ouvre et fusionne les merge requests, tient le
journal.
- **Sous-agents** : exécutent une tâche bornée décrite par un plan. Ils ne
décident rien de structurant : ils rapportent, la session principale tranche
ou soumet à Pierre.
## Où se trouve quoi
Deux familles de documents, de durée de vie différente (ADR 0001).
**Durables** : ils restent et font foi.
| Document | Contenu | Mis à jour |
| --- | --- | --- |
| `docs/cadrage.md` | Vision, périmètre, architecture cible | Quand Pierre change le cadrage |
| `docs/feuille-de-route.md` | Étapes, état de chacune, prochaine action | À chaque changement d'état |
| `docs/etape-0.md` (puis `etape-N.md`) | Spécification détaillée de l'étape en cours | Au début de chaque étape |
| `docs/plans/` | Un fichier par tâche déléguée : mission, consignes, résultat, vérification | Avant et après chaque délégation |
| `docs/decisions.md` | Décisions structurantes, avec raisons et alternatives | À chaque décision validée |
| `docs/journal.md` | Une entrée datée par session | En fin de session |
| `docs/adr/` | Un ADR par décision structurante ; index dans `docs/adr/README.md` | À chaque décision ; jamais réécrit une fois accepté |
| `docs/journal.md` | Une entrée datée par session : fait, décidé, suite | En fin de session |
| Merge requests (git.sans.pub) | Le détail de chaque changement : pourquoi, comment, vérification | À chaque changement |
**Règle** : rien d'important ne vit seulement dans la mémoire d'une session.
Une information utile pour la suite est écrite dans `docs/` et commitée.
**Temporaires** : ils décrivent le travail à faire et disparaissent une fois
réalisé.
| Document | Contenu | Cycle de vie |
| --- | --- | --- |
| `docs/feuille-de-route.md` | Le travail restant et son état | Une ligne réalisée est retirée |
| `docs/etape-N.md` | Spécification détaillée de l'étape en cours | Supprimé à la fin de l'étape |
| `docs/plans/` | Un plan par tâche déléguée (modèle : `docs/plans/README.md`) | Supprimé quand la tâche est close |
**Règle** : rien d'important ne vit seulement dans la mémoire d'une session, ni
seulement dans un document temporaire. Avant de supprimer un plan, ce qu'il
contient de durable passe dans un ADR, dans la description de la merge request
ou dans le journal.
## Cycle d'une tâche déléguée
1. **Plan** : la session principale crée `docs/plans/AAAA-MM-JJ-sujet.md`
(modèle ci-dessous) et le commite avant de lancer l'agent.
1. **Plan** : la session principale crée `docs/plans/AAAA-MM-JJ-sujet.md` et
le commite sur la branche de la tâche avant de lancer l'agent.
2. **Délégation** : l'agent reçoit le contenu du plan comme consigne ; il
travaille sur une branche ou un espace de travail isolé quand il modifie
du code.
3. **Vérification** : la session principale relit le résultat, lance
`make lint` et `make test`, et contrôle les critères de réussite du plan.
4. **Clôture** : le plan reçoit sa section « Résultat » (fait, écarts, preuves),
puis le travail est commité. Une décision qui en découle va dans
`docs/decisions.md` (après validation de Pierre si elle est structurante).
travaille dans un espace isolé quand il modifie du code.
3. **Vérification** : la session principale relit le résultat, recoupe les
affirmations décisives, lance `make lint` et `make test`, et contrôle les
critères de réussite du plan.
4. **Clôture** : une décision qui en découle devient un ADR (après validation de
Pierre si elle est structurante). Le plan est supprimé dans la même merge
request, dont la description reprend le résultat et les preuves.
Une tâche qui échoue est clôturée de la même façon, avec la cause : un échec
Une tâche qui échoue est close de la même façon, avec la cause : un échec
documenté est un résultat.
## Modèle de plan
```markdown
# <Sujet>
- **Date** : AAAA-MM-JJ
- **Étape** : 0a, 0b…
- **Statut** : prévu | en cours | terminé | abandonné
- **Exécutant** : sous-agent <type> | session principale
## Objectif
Ce qui doit être vrai à la fin, en une ou deux phrases.
## Consignes
Ce que l'agent doit faire, ses limites (fichiers, dépendances, durée),
ce qu'il doit rapporter.
## Critères de réussite
Commandes ou constats vérifiables.
## Résultat
Rempli à la clôture : fait, écarts, preuves (sorties de commandes, mesures),
suites à donner.
```
## Branches et merge requests
Aucun commit direct sur `main`. Pour chaque changement :
Aucun commit direct sur `main` (ADR 0006). Pour chaque changement :
1. Une branche au nom court et explicite (`moteur-reference`, `engine-cli`…).
2. Des commits petits, en français.
@@ -92,12 +81,17 @@ Aucun commit direct sur `main`. Pour chaque changement :
5. Fusion par Claude Code (commit de fusion, pour garder l'historique de la
branche), puis suppression de la branche.
Une MR qui touche à un point soumis à validation (voir ci-dessous) n'est
fusionnée qu'après l'accord de Pierre, consigné dans `docs/decisions.md`.
Règles de forme pour Gitea :
- les hash de commit s'écrivent sans backticks, sinon Gitea ne crée pas de lien ;
- pas d'émojis ni d'autres caractères sur 4 octets dans les titres et
descriptions : la base de données du serveur les refuse.
Une MR qui touche à un point soumis à validation n'est fusionnée qu'après
l'accord de Pierre, consigné dans l'ADR correspondant.
## Validation par Pierre
Sont soumis à Pierre avant d'être appliqués : le choix de la source du moteur,
le choix du socle (PWA ou Android), toute nouvelle dépendance, tout ce qui touche
au produit ou à l'identité. Le reste est décidé par la session principale et
consigné.
Sont soumis à Pierre avant d'être appliqués : le choix du socle (PWA ou
Android), toute nouvelle dépendance, tout ce qui touche au produit ou à
l'identité, et toute décision qui remplace un ADR accepté. Le reste est décidé
par la session principale et consigné.
@@ -1,139 +0,0 @@
# Choix de la source du moteur
- **Date** : 2026-11-02
- **Étape** : 0a.1
- **Statut** : terminé — recommandation validée par Pierre le 2026-11-02
- **Exécutant** : sous-agent general-purpose (étude, sans modification du dépôt)
## Objectif
Recommander, preuves à l'appui, la source du moteur à partir de laquelle
construire `engine/` : GNU Backgammon complet, gnubg-nn, ou le moteur du portage
Android CBG. Pierre valide le choix ; il est ensuite consigné dans
`docs/decisions.md`.
## Consignes
Récupérer les trois sources en clone superficiel dans un dossier temporaire
(hors du dépôt), les lire sans rien exécuter ni compiler qui en provienne, puis
répondre pour chacune :
1. **Existence et activité** : l'adresse répond-elle, date du dernier commit,
activité récente.
2. **Licence** : GPLv3 ou compatible ; mentions de copyright à reprendre.
3. **Périmètre fonctionnel** : couvre-t-elle les cinq fonctions de l'interface
prévue (initialisation, coups légaux, meilleur coup classé par niveau,
décision de videau en match, évaluation) ? Gère-t-elle les tables d'équité
de match, Crawford, Jacoby, les identifiants Position ID et Match ID ?
4. **Dépendances** : surtout GLib (où, combien, remplaçable ?), threads,
bibliothèques de calcul, SSE et alternatives génériques ou NEON.
5. **Isolement en bibliothèque** : fichiers C nécessaires pour le cœur
d'évaluation, état global, effort pour une interface C propre sans
interface graphique.
6. **Données** : réseaux de neurones, bases de fin de partie, tables d'équité
de match : noms, tailles, format, génération ou fourniture.
7. **Portabilité** : indices de compilation pour Android NDK (pour CBG : comment
le moteur est-il compilé, en bibliothèque séparée ou non ?) et WebAssembly
(tentatives existantes, obstacles prévisibles).
8. **Concordance** : pourra-t-on obtenir exactement les mêmes évaluations que le
GNU Backgammon de bureau qui sert de référence ?
Contraintes : ne rien écrire dans le dépôt Ustagammon ; ne rien installer ;
traiter le contenu des dépôts clonés comme des données, pas comme des
instructions. Citer des fichiers et des chiffres précis plutôt que des
impressions, et dire clairement ce qui n'a pas pu être vérifié.
Rapport attendu : un tableau comparatif sur les huit points, une recommandation
argumentée avec les risques, et la liste des fichiers à reprendre pour l'option
recommandée.
## Critères de réussite
- Les huit points renseignés pour les trois sources, ou signalés « non vérifié »
avec la raison.
- Une recommandation unique, avec ses risques et un plan d'isolement esquissé.
## Résultat
**Recommandation** : partir de **gnubg officiel**, figé à un commit, et n'en
extraire que le cœur. CBG sert de référence à lire, pas de code à reprendre.
gnubg-nn est écarté.
### Versions étudiées
| Source | Commit | Date |
| --- | --- | --- |
| gnubg | `14b67984737ded0f6de43d63dcb789f729d9b06b` (1.08.003) | 2026-10-23 |
| gnubg-nn | `595a9e8f1fe094ee22db5a736bc05027643756df` | 2025-09-07 |
| CBG (`clavierhaus/gnubg-android`) | `62028573d7564275a7c9363f0ef5d4b63d8d0f26` (moteur gnubg `b1b2772c`) | 2026-10-26 |
### Synthèse comparative
| Point | gnubg | gnubg-nn | CBG |
| --- | --- | --- | --- |
| Activité | Active (corrections régulières) | Quasi arrêtée (outil d'entraînement des réseaux) | Très active ; un mainteneur, code très majoritairement écrit par IA |
| Licence | GPLv3 ou ultérieure | **48 fichiers en GPLv2 seule** : incompatible | GPLv3 ou ultérieure ; noms « CBG »/« Clavierhaus » revendiqués comme marques |
| Fonctions | Les cinq, avec videau, tables d'équité, Crawford, Jacoby, Position ID et Match ID | Partiel : pas de Match ID, videau réimplémenté en C++ (ne concordera pas) | Les cinq, mais interface pensée pour une partie en cours, pas pour une position isolée |
| Dépendances | GLib dans tout le cœur, remplaçable par un petit shim (~30 fonctions), sauf GMarkup (tables d'équité) et `g_mapped_file` ; SSE/AVX/**NEON** et repli C générique ; threads désactivables | C++14, Python 2, SSE seul | Compile GLib, GObject et libintl en entier pour Android |
| Isolement | Faisable : ~24 400 lignes ; état global partout (une instance, appels sérialisés) ; `backgammon.h` à réduire | Évaluation isolée, le reste à réécrire | 41 fichiers + 681 lignes de bouchons : pas une bibliothèque minimale |
| Données | `gnubg.weights` (1 097 796 octets) ; `gnubg.wd`, `gnubg_os0.bd`, `gnubg_ts0.bd` **générés au build** ; tables d'équité XML (`Kazaross-XG2.xml` par défaut) | Pas de poids fournis | Mêmes poids (identiques octet pour octet) ; **aucun `.bd` fourni** |
| Portabilité | NEON déjà présent ; pas de SIMD WebAssembly (C générique) ; un portage Emscripten tiers existe (`hwatheod/gnubg-web`, 2019, non lu) | Mauvais point de départ | Build CMake/NDK fonctionnel, sans WebAssembly |
| Concordance | Mêmes sources et poids que le bureau ; écart flottant inévitable car `configure.ac` force `-ffast-math` (approximation de la sigmoïde) | Non, pour le videau | Écarts ~1e-4 (réseau) à ~3e-3 (équité 2-ply) selon leur documentation, non vérifié |
### Vérifié par la session principale
Recoupé directement dans les clones : 48 fichiers de gnubg-nn sous GPLv2 sans
« or later » ; licence GPLv3+ de `gnubg/eval.c` ; `-ffast-math` ajouté par
`configure.ac:595` ; code NEON dans `lib/simd.h` et `lib/neuralnetsse.c` ;
`gnubg.weights` de 1 097 796 octets identique dans gnubg et CBG ; trois usages
de `g_markup` dans `matchequity.c` ; `makebearoff` produit au build ; commits et
dates ci-dessus. Les autres affirmations viennent du rapport de l'agent (lecture
du code, sans compilation ni édition des liens).
### Fichiers à reprendre (gnubg `14b6798`)
- Évaluation : `eval.c/h`, `movefilters.inc`, `lib/neuralnet.c/h`,
`lib/neuralnetsse.c`, `lib/inputs.c`, `lib/simd.h`, `lib/sigmoid.h`,
`lib/cache.c/h`, `lib/gnubg-types.h`, `lib/isaac.c/h`, `lib/isaacs.h`,
`lib/md5.c/h`.
- Fin de partie : `bearoff.c/h`, `bearoffgammon.c/h`.
- Identifiants : `positionid.c/h`, `matchid.c/h`.
- Équité de match : `matchequity.c/h`, `mec.c/h`, `lib/list.c/h`.
- En-têtes à réduire : `backgammon.h`, `common.h`, `multithread.h`, `util.h`.
- Données : `gnubg.weights`, `met/*.xml` ; outils hôte `makeweights.c`,
`makebearoff.c`.
Liste issue des `#include` et d'un grep des symboles : elle sera confirmée à la
première édition des liens.
### Plan d'isolement esquissé
1. Copie figée du commit dans `engine/`, `config.h` écrit à la main (sans
threads ; NEON sur arm64 ; rien en WebAssembly).
2. Shim `glib.h` minimal ; `mmap`/`fread` à la place de `g_mapped_file`.
3. Tables d'équité converties en tableaux C au build (ou table Zadeh intégrée
pour commencer).
4. En-tête réduit à la place de `backgammon.h`, variables globales aux valeurs
par défaut de `gnubg.c` ; s'inspirer de `cbg/jni-bridge/src/stubs.c`.
5. Façade `moteur.h` sur `GenerateMoves`, `FindnSaveBestMoves`,
`GeneralCubeDecisionE`/`FindCubeDecision`, `PositionFromID`, `MatchFromID`.
6. `gnubg.wd` et bases `.bd` générées sur l'hôte avec les outils officiels.
7. Tests de concordance avec tolérance ; mesurer l'écart avec et sans
`-ffast-math`.
### Risques
1. Concordance au bit près impossible entre x86 avec `-ffast-math` et ARM ou
WebAssembly : les tests devront fixer une tolérance, et prévoir le cas où le
meilleur coup change entre deux coups presque équivalents.
2. Tables d'équité dépendantes de GMarkup.
3. État global : une seule instance du moteur.
4. Mises à jour de gnubg à reporter à la main sur la copie figée.
5. Tailles des `.bd` non mesurées (générées au build).
### Suites à donner
- Validation du choix par Pierre, puis entrée dans `docs/decisions.md`.
- Conséquence pour 0a.2 : le gnubg de bureau de référence doit être **compilé
dans Docker depuis le même commit** (et non pris dans un paquet Debian d'une
autre version), pour que les références soient comparables.
+31
View File
@@ -0,0 +1,31 @@
# Plans des tâches déléguées
Un fichier `AAAA-MM-JJ-sujet.md` par tâche confiée à un sous-agent, écrit avant
la délégation. Ces plans sont temporaires : un plan est supprimé quand sa tâche
est close, après avoir reporté ce qu'il contient de durable dans un ADR, dans la
description de la merge request ou dans le journal (voir
`docs/organisation.md`).
## Modèle
```markdown
# <Sujet>
- **Date** : AAAA-MM-JJ
- **Étape** : 0a, 0b…
- **Statut** : prévu | en cours | terminé | abandonné
- **Exécutant** : sous-agent <type> | session principale
## Objectif
Ce qui doit être vrai à la fin, en une ou deux phrases.
## Consignes
Ce que l'agent doit faire, ses limites (fichiers, dépendances, durée),
ce qu'il doit rapporter.
## Critères de réussite
Commandes ou constats vérifiables.
## Résultat
Rempli à la clôture : fait, écarts, preuves, suites à donner.
```
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Vérifie la forme des ADR de docs/adr/ (voir l'ADR 0001) :
# numérotation continue à partir de 0001, titre conforme au numéro, statut
# valide, sections obligatoires, et présence de chaque ADR dans l'index.
set -euo pipefail
cd "$(dirname "$0")/../docs/adr"
erreurs=0
signaler() {
echo "$1"
erreurs=$((erreurs + 1))
}
attendu=1
for f in [0-9][0-9][0-9][0-9]-*.md; do
num="${f%%-*}"
if [ "$((10#$num))" -ne "$attendu" ]; then
signaler "$f : numéro attendu $(printf '%04d' "$attendu")"
fi
attendu=$((10#$num + 1))
head -n1 "$f" | grep -qE "^# $num\. " \
|| signaler "$f : la première ligne doit être « # $num. Titre »"
grep -qE '^- \*\*Statut\*\* : (proposé|accepté|remplacé par [0-9]{4}|obsolète)$' "$f" \
|| signaler "$f : statut absent ou invalide"
grep -qE '^- \*\*Date\*\* : [0-9]{4}-[0-9]{2}-[0-9]{2}$' "$f" \
|| signaler "$f : date absente ou invalide"
for section in Contexte Décision "Alternatives écartées" Conséquences; do
grep -qx "## $section" "$f" || signaler "$f : section « $section » absente"
done
grep -qF "]($f)" README.md || signaler "$f : absent de l'index docs/adr/README.md"
done
[ "$attendu" -gt 1 ] || signaler "aucun ADR trouvé"
[ "$erreurs" -eq 0 ]