Étape 0d.1 : domaine « partie » en TypeScript, scénario exécuté ; ADR 0009 accepté #11
@@ -46,3 +46,9 @@ construire ou tester ; rien n'est embarqué dans l'application.
|
||||
| Python 3 | PSF | `ustagammon/build-c` | Comparateur des références |
|
||||
| jq | MIT | `ustagammon/build-c` | Lecture du JSON dans les tests |
|
||||
| Emscripten | MIT / NCSA | `emscripten/emsdk:3.1.64` | Compilation du moteur en WebAssembly (étape 0b) |
|
||||
|
||||
### 2026-11-02 — Outils de l'application web (étape 0d)
|
||||
|
||||
Validés par Pierre avec l'ADR 0009, dans Docker, jamais embarqués :
|
||||
TypeScript (`tsc`, Apache-2.0), Biome (MIT ou Apache-2.0),
|
||||
`@cucumber/cucumber` (MIT), `dependency-cruiser` (MIT).
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# 0009. Socle : PWA en TypeScript, moteur en WebAssembly
|
||||
|
||||
- **Statut** : proposé
|
||||
- **Date** : 2026-11-02
|
||||
- **Décideurs** : Pierre (langage, outils), sur proposition de Claude Code ;
|
||||
le socle sera accepté après les mesures sur le Fairphone 4
|
||||
|
||||
## Contexte
|
||||
|
||||
L'étape 0 doit trancher entre une PWA (moteur en WebAssembly) et une
|
||||
application Android native (`docs/etape-0.md`). L'étape 0b a produit le moteur
|
||||
en WebAssembly (MR !9) : même suite de contrat qu'en natif (écart maximal
|
||||
9,5e-4 pour une tolérance de 0,002), 7,3 Mo compressés à télécharger (seuil
|
||||
40 Mo). Sur le PC de développement (i5-2450M, 2011), le meilleur coup à 2 plis
|
||||
prend au plus 0,3 s sous Chromium et 2,3 s sous Firefox (seuil sur le
|
||||
téléphone : 3 s). Les mesures sur le Fairphone 4 restent à faire.
|
||||
|
||||
L'ADR 0007 renvoyait au choix du socle le langage de l'interface et l'outil de
|
||||
vérification des dépendances.
|
||||
|
||||
## Décision
|
||||
|
||||
Sous réserve des mesures sur le Fairphone 4 :
|
||||
|
||||
- **Socle : PWA**, installable et utilisable hors ligne, moteur en WebAssembly
|
||||
dans un Web Worker. L'étape 0c (Android natif) n'est pas faite.
|
||||
- **Langage : TypeScript**, compilé par `tsc` en modules JavaScript standard,
|
||||
sans framework d'interface ni empaqueteur.
|
||||
- **Lint et formatage : Biome.**
|
||||
- **Scénarios exécutés** (ADR 0008) par `@cucumber/cucumber`, sous Node, sur le
|
||||
domaine branché au vrai moteur WebAssembly.
|
||||
- **Règles d'architecture vérifiées** (ADR 0007) par `dependency-cruiser` :
|
||||
le domaine n'importe ni l'interface, ni le stockage, ni le moteur ; aucun
|
||||
écran n'importe le moteur.
|
||||
- Tous ces outils tournent dans Docker et ne sont jamais embarqués dans
|
||||
l'application.
|
||||
|
||||
## Alternatives écartées
|
||||
|
||||
- **Android natif (Kotlin, NDK)** : un seul système, une chaîne de build lourde
|
||||
(Gradle, NDK) sur une machine de 2011, et aucun gain mesuré à ce stade sur
|
||||
les temps de calcul. Reste le plan B si les mesures du téléphone échouent.
|
||||
- **JavaScript annoté (JSDoc) vérifié par TypeScript** : pas d'étape de build,
|
||||
mais des types moins lisibles ; Pierre a choisi TypeScript.
|
||||
- **Un framework d'interface** (React, Vue…) : inutile pour un plateau et
|
||||
quelques écrans, et contraire à la règle de simplicité (ADR 0007).
|
||||
|
||||
## Conséquences
|
||||
|
||||
- La distribution sur F-Droid et le Play Store demandera plus tard une
|
||||
enveloppe Android minimale autour de la PWA (à décider à l'étape 1).
|
||||
- Si les mesures du Fairphone 4 dépassent les seuils, cet ADR passe au statut
|
||||
« obsolète » et l'étape 0c est lancée.
|
||||
@@ -15,3 +15,4 @@ l'ancien passe au statut « remplacé par NNNN ». Voir l'ADR 0001.
|
||||
| [0006](0006-merge-requests-systematiques.md) | Merge requests systématiques, fusionnées par Claude Code | accepté |
|
||||
| [0007](0007-architecture-et-conventions-de-code.md) | Architecture et conventions de code | accepté |
|
||||
| [0008](0008-glossaire-et-scenarios-source-unique.md) | Glossaire et scénarios : une source unique pour le code, l'aide et les tests | accepté |
|
||||
| [0009](0009-socle-pwa-typescript.md) | Socle : PWA en TypeScript, moteur en WebAssembly | proposé |
|
||||
|
||||
@@ -18,9 +18,10 @@ page de test, page de mesure et guide de test (0b).
|
||||
| Sous-étape | Contenu | État | Plan |
|
||||
| --- | --- | --- | --- |
|
||||
| Mesures | Pierre relève les mesures sur le Fairphone 4, en suivant `docs/guide-test-etape-0.md` | 🔄 | |
|
||||
| Décision | Socle PWA ou Android natif, consigné dans un ADR — validation de Pierre | ⏳ | |
|
||||
| Décision | Socle PWA ou Android natif : ADR 0009 proposé (PWA, TypeScript), à accepter après les mesures | 🔄 | |
|
||||
| 0c | Android natif (NDK, Gradle en ligne de commande, `make deploy` via adb) | ⏸ si 0b échoue | |
|
||||
| 0d | Plateau minimal jouable sur le socle retenu ; vérifié avec Pierre en suivant `docs/scenarios/jouer-une-partie.feature` | ⏳ | |
|
||||
| 0d.1 | Domaine « partie » en TypeScript (journal d'événements), scénario exécuté sur le vrai moteur, garde-fous d'architecture | 🔄 | `plans/2026-11-02-domaine-partie.md` |
|
||||
| 0d.2 | Plateau minimal jouable (PWA hors ligne) ; vérifié avec Pierre en suivant `docs/scenarios/jouer-une-partie.feature` | ⏳ | |
|
||||
|
||||
**Critère de fin** : 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.
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
# Domaine « partie » en TypeScript, scénarios exécutés, garde-fous
|
||||
|
||||
- **Date** : 2026-11-02
|
||||
- **Étape** : 0d.1
|
||||
- **Statut** : en cours
|
||||
- **Exécutant** : sous-agent general-purpose, dans un worktree isolé
|
||||
|
||||
## Objectif
|
||||
|
||||
Le domaine d'une partie contre l'ordinateur existe en TypeScript, sous forme de
|
||||
journal d'événements (ADR 0007), branché au moteur WebAssembly par une
|
||||
interface `Engine`. Le scénario `docs/scenarios/jouer-une-partie.feature`
|
||||
s'exécute sous Node, sur le vrai moteur, dans `make test`. Les règles
|
||||
d'architecture et le lien glossaire ↔ code sont vérifiés par les tests.
|
||||
L'interface graphique et la PWA sont l'étape suivante (0d.2), pas celle-ci.
|
||||
|
||||
## Consignes
|
||||
|
||||
1. **Outillage** (ADR 0009, ADR 0004) : une image `docker/web/` (Node
|
||||
`node:22.11.0-alpine3.20` déjà présent, versions npm figées et vérifiées) avec
|
||||
TypeScript, Biome, `@cucumber/cucumber` et `dependency-cruiser`. Cibles
|
||||
`make web` (compile `app/` vers `build/web/` avec `tsc`), et intégration à
|
||||
`make lint` (Biome et `tsc --noEmit`) et `make test`. Étiquette d'image dans
|
||||
le `Makefile`, `make setup` la construit. `CREDITS.md` à jour.
|
||||
2. **Arborescence** (à ajuster si plus simple) :
|
||||
- `app/src/domain/` : le domaine pur, sous-dossier `game/` ;
|
||||
- `app/src/engine/` : l'adaptateur qui implémente `Engine` avec le moteur
|
||||
WebAssembly (réutiliser `web/engine-wasm.mjs` et `build/wasm/`) ;
|
||||
- `app/src/ui/` : vide pour l'instant (étape 0d.2) ;
|
||||
- `app/tests/` : tests unitaires (runner intégré de Node, `node:test`) et
|
||||
définitions des étapes Cucumber.
|
||||
Les pages de prototype existantes (`web/index.html`, `web/bench.html`)
|
||||
doivent continuer de fonctionner.
|
||||
3. **Interface `Engine`** définie par le domaine (coups légaux avec position
|
||||
résultante, meilleur coup pour un niveau, décision de videau, décodage d'une
|
||||
position en plateau pour l'affichage). Compléter `engine.h` et `engine-cli`
|
||||
si une information manque (par exemple décoder un Position ID en nombre de
|
||||
pions par case, savoir si la partie est finie et combien elle rapporte), en
|
||||
restant simple, avec tests natifs.
|
||||
4. **Journal d'événements** (ADR 0007, point 3) : événements immuables avec
|
||||
identifiant, parent et version de format (`GameStarted`, `DiceRolled`,
|
||||
`MovePlayed`, `CubeOffered`, `CubeTaken`, `CubeDropped`, `GameEnded`). L'état
|
||||
se calcule en rejouant le journal. Une branche est un nouvel événement
|
||||
accroché à un ancien ; annuler revient à repartir du parent. Le hasard des
|
||||
dés est injecté (source de dés passée au domaine).
|
||||
5. **Règles de la partie de 0d** : partie libre contre l'ordinateur (Jacoby
|
||||
selon les réglages par défaut de gnubg) ; l'ordinateur joue le meilleur coup
|
||||
au niveau « standard » (choisir un niveau qui tienne les 2 s sur téléphone :
|
||||
2 plis d'après les mesures 0b, à confirmer) ; il décide du videau avec le
|
||||
moteur ; le joueur peut prendre ou passer, et peut lui-même doubler (le
|
||||
moteur décide alors si l'ordinateur prend ou passe). Le joueur saisit son
|
||||
coup demi-coup par demi-coup (case de départ, case d'arrivée) ; le domaine
|
||||
n'accepte que ce qui mène à un coup légal complet. Aucune règle du jeu n'est
|
||||
réimplémentée : tout vient du moteur.
|
||||
6. **Glossaire ↔ code** (ADR 0008) : chaque type du domaine qui correspond à
|
||||
un terme porte `Glossaire : docs/glossaire/<fiche>.md` en commentaire, et la
|
||||
fiche reçoit `code: <Type>`. Ajouter les fiches manquantes. Étendre
|
||||
`tests/test_glossary.sh` pour vérifier le lien dans les deux sens.
|
||||
7. **Scénarios exécutés** : définitions des étapes en français pour
|
||||
`docs/scenarios/jouer-une-partie.feature`, branchées sur le domaine et le
|
||||
vrai moteur WebAssembly (sous Node), avec des dés imposés pour être
|
||||
reproductibles. Si une étape du scénario est impossible à exécuter telle
|
||||
quelle, ajuster le scénario en gardant son sens pour le joueur, et le dire.
|
||||
8. **Garde-fous d'architecture** (dependency-cruiser) : le domaine n'importe
|
||||
ni `engine/`, ni `ui/`, ni rien de spécifique au navigateur ; `ui/`
|
||||
n'importe pas `engine/` ; pas de dépendance circulaire. Vérifier qu'une
|
||||
violation volontaire fait échouer `make test`.
|
||||
|
||||
Contraintes :
|
||||
- `CLAUDE.md`, ADR 0004, 0007, 0008, 0009 : simplicité avant tout, pas de
|
||||
patron de conception sans besoin, identifiants en anglais, commentaires et
|
||||
docs en français, tout outil dans Docker, `-j2` ;
|
||||
- ne pas modifier `engine/gnubg/` ni les références ;
|
||||
- `make lint` et `make test` doivent passer ; commits petits, en français, avec
|
||||
la ligne `Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>` ;
|
||||
- ne pas pousser ni créer de merge request ; ne rien simuler.
|
||||
|
||||
Rapport attendu : ce qui a été fait, l'API du domaine en quelques lignes, les
|
||||
fiches de glossaire ajoutées, le résultat des scénarios, les vérifications des
|
||||
garde-fous, les difficultés, les écarts au plan.
|
||||
|
||||
## Critères de réussite
|
||||
|
||||
- `make test` exécute le scénario « Jouer une partie contre l'ordinateur » sur
|
||||
le vrai moteur et passe.
|
||||
- Une partie complète (jusqu'à `GameEnded`) se joue dans un test, l'ordinateur
|
||||
contre une stratégie simple du joueur, avec des dés imposés.
|
||||
- Les garde-fous d'architecture et le lien glossaire ↔ code échouent sur une
|
||||
violation volontaire.
|
||||
- `make lint` et `make test` passent.
|
||||
|
||||
## Résultat
|
||||
|
||||
À remplir à la clôture.
|
||||
Reference in New Issue
Block a user