0.3.4-alpha.1

This commit is contained in:
2026-09-21 17:14:34 +02:00
parent 0ad980a06b
commit 27978c3782
14 changed files with 831 additions and 90 deletions

View File

@@ -1,11 +1,11 @@
<!-- file: docs/plans/000-README.md -->
<!-- version: 4 -->
<!-- version: 5 -->
# Plans de versions games.sasedev
Ce répertoire contient les plans vivants des versions concrètes.
Un plan est créé ou révisé pendant `0-pre.1`. Il conserve le scope, les décisions utiles, les validations et surtout le découpage prévisionnel souple des tranches jusqu'à la release. Il peut évoluer lorsque les audits ou validations imposent de scinder, fusionner, reporter ou corriger une tranche.
Un plan est créé ou révisé pendant `alpha.1`. Il conserve le scope, les décisions utiles, les validations et surtout le découpage prévisionnel souple des tranches jusqu'à la release. Il peut évoluer lorsque les audits ou validations imposent de scinder, fusionner, reporter ou corriger une tranche.
Le `ROADMAP.md` reste la trajectoire macroscopique du projet ; les deltas décrivent ce qui a réellement été livré. Le plan se situe entre les deux et sert au suivi de la version en cours.
@@ -14,3 +14,4 @@ Le `ROADMAP.md` reste la trajectoire macroscopique du projet ; les deltas décri
- [`001-V0_3_0_WEB_SNAKE_POC_PLAN.md`](001-V0_3_0_WEB_SNAKE_POC_PLAN.md) — plan clôturé de `0.3.0`, baseline Snake et premier POC Web direct.
- [`002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md`](002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md) — plan clôturé de `0.3.1`, second host Snake Tauri Android.
- [`003-V0_3_3_ANDROID_NATIVE_MULTI_ABI_PLAN.md`](003-V0_3_3_ANDROID_NATIVE_MULTI_ABI_PLAN.md) — plan clôturé de `0.3.3`, pipeline Android SDL3 natif Gradle/Cargo multi-ABI.
- [`004-V0_3_4_REALTIME_TRANSPORT_WEBSOCKET_PLAN.md`](004-V0_3_4_REALTIME_TRANSPORT_WEBSOCKET_PLAN.md) — plan actif de `0.3.4`, API de transport realtime et baseline WebSocket Tokio/tokio-tungstenite.

View File

@@ -0,0 +1,481 @@
<!-- file: docs/plans/004-V0_3_4_REALTIME_TRANSPORT_WEBSOCKET_PLAN.md -->
<!-- version: 1 -->
# Plan 0.3.4 — transport realtime et baseline WebSocket
## Statut
Plan actif créé pendant `0.3.4-alpha.1` à partir de l'archive taggée `v0.3.3`.
La tranche `alpha.1` migre d'abord la gouvernance de version vers `alpha.N / beta.N / rc.N`, audite la baseline et ferme les décisions d'ownership avant toute implémentation réseau lourde.
## Mission
`0.3.4` doit introduire une frontière de transport realtime async et une première implémentation WebSocket fondée sur Tokio + `tokio-tungstenite`, sans implémenter le protocole de session, la synchronisation gameplay ni la simulation authoritative.
La frontière reste :
```text
transport
wire codec
session protocol
synchronization
authoritative simulation
```
Le transport de `0.3.4` transporte des octets opaques. Il ne connaît ni joueur, ni room, ni tick, ni snapshot, ni delta métier.
## Baseline auditée
L'archive fournie comme téléchargement du tag `v0.3.3` est traitée comme autoritaire conformément à `CMD-GIT-003` et `CMD-GIT-004`.
L'audit local de l'archive confirme :
- archive ZIP intègre, sans chemin traversant ni symlink ;
- `400` fichiers, `14` membres Cargo et `55` fichiers Rust ;
- `workspace.package.version = 0.3.3` avant migration ;
- audits Rust/workspace, Markdown et distribution propres sur l'archive ;
- aucune arborescence générée `target/`, `node_modules/`, `gen/android` ou `build/` livrée ;
- gameplay et moteurs sans dépendance réseau realtime ;
- baseline Android `0.3.3` conservée et hors scope de cette version.
Le log utilisateur fourni à l'ouverture de session confirme également `cargo fmt`, `cargo check --workspace` et Clippy workspace strict sur son checkout `0.3.3`. Son audit Markdown annonce davantage de fichiers que l'archive taggée fournie ; la présente version reste néanmoins construite exclusivement depuis l'archive autoritaire reçue et n'invente aucun fichier absent de celle-ci.
## Migration de gouvernance
À partir de `0.3.4`, les seules formes de prerelease nouvelles sont :
```text
X.Y.Z-alpha.N
X.Y.Z-alpha.N.fix.M
X.Y.Z-beta.N
X.Y.Z-beta.N.fix.M
X.Y.Z-rc.N
X.Y.Z-rc.N.fix.M
```
`alpha.1` remplace l'ancien rôle de cadrage `0-pre.1`.
Les anciens labels `0-pre`, `1-alpha`, `2-beta` et `3-rc` restent valides uniquement comme preuves historiques déjà livrées. Les audits distinguent donc la convention courante de la compatibilité historique et n'autorisent plus l'ancien schéma pour un nouveau workspace ou un nouvel historique `0.3.4+`.
## Dépendances vérifiées au 2026-09-21
Versions amont observées pour la future implémentation :
```text
Tokio 1.53.1
futures-util 0.3.34
tokio-tungstenite 0.30.0
tungstenite 0.30.0, via réexport tokio-tungstenite
```
Contraintes utiles :
- Tokio `1.53.1` annonce un MSRV `1.71` ;
- `tokio-tungstenite 0.30.0` et `tungstenite 0.30.0` annoncent un MSRV `1.85` ;
- `tokio-tungstenite` dépend déjà de Tokio `1.x` et de Tungstenite `0.30.0` ;
- ses features par défaut couvrent `connect` et `handshake`, sans TLS ;
- `native-tls` et les variantes `rustls-*` sont optionnelles ;
- Tungstenite expose déjà des limites de message/frame et de write buffer configurables.
La compatibilité effective de la toolchain utilisateur avec ces MSRV sera attestée par les gates Cargo de la tranche qui introduira réellement les dépendances. Elles ne sont pas ajoutées pendant `alpha.1` : elles seront introduites uniquement avec les crates qui les consomment réellement.
## Ownership physique retenu
### `game-realtime-transport-lib`
Créer sous :
```text
crates/common/game-realtime-transport-lib
```
Responsabilités :
- contrat transport-neutral ;
- payload binaire opaque ;
- distinction send/receive/close ;
- fermeture distante explicite ;
- catégories d'erreur transport-neutral ;
- contrat de split permettant lecture et écriture concurrentes ;
- aucune dépendance à Tokio, Tungstenite, HTTP, TLS, SDL, Tauri, WASM, moteur ou gameplay.
Cette crate est une capability technique commune indépendante d'une génération de moteur. Elle n'est pas placée dans `engine-v1-*`.
### `game-realtime-websocket-lib`
Créer sous :
```text
crates/common/game-realtime-websocket-lib
```
Responsabilités :
- implémentation WebSocket du contrat transport ;
- `tokio-tungstenite` et Tokio réseau/temps ;
- connexion client WebSocket ;
- bind/accept serveur local ;
- mapping des frames WebSocket vers le contrat binaire ;
- close handshake, erreurs, timeouts, limites et tracing spécifiques au backend ;
- tests loopback localhost.
Le backend dépend de `game-realtime-transport-lib`. L'inverse est interdit.
### Dépendances interdites
Aucune crate sous :
```text
crates/games/
crates/engines/
```
doit dépendre de `tokio-tungstenite` ou du backend WebSocket pendant `0.3.4`.
Aucun contrat gameplay n'est déplacé vers les crates transport pour fabriquer artificiellement un consommateur.
## Contrat transport minimal
Le contrat public doit rester suffisamment petit pour être implémentable par WebSocket puis confronté au POC WebTransport de `0.3.5`.
### Payload
Le message transport est un buffer binaire possédé, conceptuellement `Vec<u8>`.
Décisions :
- aucune variante texte dans l'API transport-neutral ;
- aucun JSON, Serde, Protobuf ou codec gameplay dans `0.3.4` ;
- Ping/Pong WebSocket reste un détail du backend ;
- une frame Text reçue par le backend n'est pas promue en message métier et doit produire un comportement explicite, testé et tracé ;
- le futur wire codec consommera/produira ces octets au-dessus du transport.
### Connexion et split
Le contrat doit permettre conceptuellement :
```text
connection.split() -> sender + receiver
sender.send(bytes) -> async Result
sender.close() -> async Result
receiver.receive() -> async Result<Message | Closed>
```
L'implémentation Rust exacte est décidée dans `alpha.2`, avec priorité à une API statiquement dispatchée et sans allocation de futures imposée uniquement pour obtenir un trait object.
Le contrat doit supporter lecture et écriture concurrentes après split. Il n'expose pas de runtime Tokio et ne crée aucun executor.
### Fermeture
La fermeture distante n'est pas une erreur I/O générique. `receive()` doit pouvoir distinguer au minimum :
- message binaire reçu ;
- fermeture distante propre ;
- erreur de transport.
La fermeture locale est explicite via `close()`.
Une cancellation de task/future n'est pas assimilée à une fermeture WebSocket propre. Abandonner le propriétaire de la connexion doit néanmoins libérer les ressources sans tâche backend détachée.
### Erreurs
Le contrat transport-neutral doit représenter au minimum les catégories suivantes sans exposer les types d'erreur de Tungstenite :
```text
invalid endpoint/configuration
connect/bind/accept failure
timeout
message too large
backpressure/write buffer full
connection closed
I/O failure
protocol/backend failure
cancelled/operation aborted lorsque cette distinction est réellement observable
```
Les détails backend peuvent être conservés pour `Display`/source/tracing sans faire remonter `tungstenite::Error` dans l'API commune.
## Ownership Tokio/runtime
Le runtime est possédé par l'application, le service ou le test consommateur.
`game-realtime-websocket-lib` :
- utilise les primitives Tokio nécessaires ;
- ne crée pas de runtime global ;
- ne lance pas de thread runtime privé ;
- évite les tâches détachées pour la connexion de base ;
- ne propage aucune dépendance Tokio dans le gameplay.
Les tests peuvent utiliser `#[tokio::test]` comme harness de validation, sans transformer la macro en contrat public.
## Client et serveur
La séparation retenue est asymétrique et minimale :
- le contrat commun modélise une connexion déjà établie et ses deux moitiés ;
- le backend WebSocket possède les constructeurs concrets client/server ;
- aucun trait générique `Connector`, `Listener`, `Server`, `Provider` ou `Runtime` n'est créé dans `alpha.2` sans besoin démontré ;
- le client peut exposer une connexion à partir d'un endpoint WebSocket ;
- le serveur peut binder une adresse socket puis accepter une connexion ;
- le futur backend WebTransport pourra proposer ses propres étapes d'établissement tout en produisant une connexion compatible lorsque cela reste pertinent.
Cette décision évite de forcer aujourd'hui WebSocket et QUIC à partager artificiellement des opérations d'établissement différentes.
## TLS
La baseline `0.3.4` est d'abord un POC transport local reproductible en `ws://`.
Aucune feature TLS de `tokio-tungstenite` n'est activée par défaut dans la première implémentation. `wss://` pourra être ajouté si un consommateur direct ou la stratégie de terminaison TLS le justifie réellement.
Cette décision :
- réduit les dépendances initiales ;
- évite de choisir prématurément `native-tls` contre `rustls` ;
- n'interdit pas une terminaison TLS future en reverse proxy ;
- ne présente pas le WebSocket local de test comme configuration de production Internet.
## Timeouts et backpressure
### Principes
- aucune file interne non bornée ;
- `send()` attend la capacité du sink au lieu d'accumuler des messages arbitrairement ;
- les limites Tungstenite sont configurées explicitement et ne restent pas implicitement aux maxima amont ;
- l'absence de message reçu n'est pas un timeout de transport automatique : heartbeat/idle/session timeout appartient à la couche supérieure ;
- connect, send et fermeture propre disposent de bornes configurables afin qu'une opération locale ne reste pas bloquée indéfiniment.
### Valeurs de baseline proposées
Valeurs initiales, configurables et non assimilées à un protocole gameplay final :
```text
max message size 1 MiB
max frame size 1 MiB
write buffer target 64 KiB
max write buffer 2 MiB
connect timeout 10 s
send timeout 5 s
close timeout 2 s
receive idle timeout aucun au niveau transport
```
Le choix `2 MiB` pour le write buffer maximum laisse au moins la place au buffer cible plus un message maximal. Les tests négatifs doivent vérifier le comportement limite plutôt que supposer que ces constantes resteront éternellement inchangées.
## Tracing
Domaines proposés :
```text
games::realtime::transport
games::realtime::websocket
```
Le tracing doit couvrir au minimum connexion, accept, fermeture, timeout, rejet de message hors limite et erreurs backend.
Ne pas logguer par défaut le contenu brut des payloads de transport.
Les futurs domaines session/sync/simulation utilisent des targets distinctes.
## Tests retenus
### Contrat commun
Tests unitaires ciblés :
- types d'erreur et affichage ;
- invariants de configuration réellement portés par la crate commune ;
- aucune dépendance au backend concret.
### Backend WebSocket
Tests d'intégration localhost déterministes avec `127.0.0.1:0` :
1. bind serveur sur port éphémère ;
2. connexion client ;
3. client → serveur : payload binaire ;
4. serveur → client : réponse binaire ;
5. fermeture propre initiée d'un côté et observée de l'autre ;
6. dépassement de taille rejeté ;
7. comportement explicite sur frame Text ;
8. connexion interrompue/peer drop ;
9. timeout d'opération retenu ;
10. backpressure/write-buffer error provoquée par un test borné si elle est reproductible sans test flaky.
Les tests ne dépendent ni d'Internet, ni d'un serveur externe, ni d'un port fixe.
Un petit demo/CLI n'est pas prévu par défaut : il sera créé uniquement si les tests publics ne prouvent pas suffisamment le chemin client/server.
## Gates par jalon
### `alpha.1`
Changements : gouvernance, audit Python, version workspace, plan et delta.
Gate utilisateur :
```bash
cargo fmt --all
cargo fmt --all -- --check
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
```
Aucun test runtime réseau n'est requis avant l'existence du code réseau.
### `alpha.2`
Ajouter `game-realtime-transport-lib`, ses tests ciblés et sa documentation publique.
Gate minimale supplémentaire :
```bash
cargo test -p game-realtime-transport-lib --all-targets --all-features
```
### `alpha.3`
Ajouter `game-realtime-websocket-lib`, les dépendances backend et le loopback principal.
Gates ciblées :
```bash
cargo test -p game-realtime-transport-lib --all-targets --all-features
cargo test -p game-realtime-websocket-lib --all-targets --all-features
cargo tree -p game-realtime-websocket-lib --edges normal
```
### `alpha.4`
Fermer robustesse, limites, timeouts, close/cancellation et cas négatifs. Réexécuter les tests des deux crates. Un demo n'est ajouté que si une preuve manque réellement.
### Beta
La beta est le jalon large retenu pour :
```bash
cargo test --workspace --all-targets --all-features
```
Elle revalide également audits, format/check, Clippy, tests loopback et graphe de dépendances.
### RC
La RC gèle le comportement et rejoue les gates de publication utiles. Le test workspace complet n'est répété que si un fix depuis la beta a modifié du Rust, des dépendances ou une frontière transverse qui le justifie.
## Forecast révisé
### `0.3.4-alpha.1` — gouvernance, audit et contrat
- migrer les règles prospectives ;
- adapter l'audit de version sans casser l'historique ;
- synchroniser la version workspace ;
- vérifier dépendances et contraintes amont ;
- décider ownership, contrat, erreurs, lifecycle, limites et tests ;
- créer le présent plan.
Aucune dépendance réseau n'est ajoutée.
### `0.3.4-alpha.2` — API transport-neutral
- créer `game-realtime-transport-lib` ;
- implémenter message, receive/close, erreurs et split ;
- conserver l'API sans Tokio/Tungstenite ;
- tests unitaires ciblés ;
- README/USAGE uniquement si une valeur durable est démontrée par `DOC-CRATE-*`.
### `0.3.4-alpha.3` — backend WebSocket et loopback
- créer `game-realtime-websocket-lib` ;
- ajouter Tokio, `tokio-tungstenite` et `futures-util` avec features minimales ;
- client connect + serveur bind/accept ;
- mapping binaire, tracing, close ;
- round-trip localhost déterministe.
### `0.3.4-alpha.4` — robustesse et consolidation technique
- limites explicites ;
- timeouts ;
- fermeture distante/abrupt drop ;
- cas Text non supporté ;
- backpressure bornée ;
- cancellation/lifecycle sans tâche orpheline ;
- documentation API/backend et audit du graphe.
Cette tranche peut absorber la consolidation avant beta si elle reste dans le budget. Si elle devient trop lourde, une `alpha.5` de consolidation est créée ; elle ne doit pas être ajoutée uniquement pour suivre un numéro prévu.
### `0.3.4-beta.1` — validation large
- aucun nouveau scope ;
- test workspace complet planifié ;
- tests loopback/negatifs ;
- dépendances et frontières vérifiées ;
- confirmation qu'aucun gameplay/engine ne dépend du backend WebSocket.
Un défaut fermé produit `beta.1.fix.N`. Une capacité manquante réouvre une alpha.
### `0.3.4-rc.1` — candidate gelée
- scope gelé ;
- `CHANGELOG.md` ;
- `ROADMAP.md` si statut macro à réconcilier ;
- historique beta ;
- documentation finale ;
- prompt `0.3.5` préparant WebTransport/QUIC sur la même frontière ;
- aucune abstraction nouvelle sans défaut de release.
### `0.3.4` — stable
Promotion mécanique : version stable, historique RC, changelog stable, clôture du plan, delta final et ajustement mécanique du prompt suivant.
## Sizing
Le scope reste compatible avec une seule version/session : deux petites crates techniques, un seul backend concret et des tests locaux. Le POC WebTransport/QUIC, la session multijoueur et la simulation authoritative sont explicitement exclus.
Un split vers une autre version est requis si l'une des conditions suivantes apparaît :
- besoin d'un vrai wire codec partagé pour prouver le transport ;
- nécessité de concevoir le protocole session/joueur/room ;
- TLS direct nécessitant une politique de certificats/PKI produit ;
- abstraction commune WebSocket/QUIC exigeant déjà des concepts spécifiques à QUIC ;
- demo/app devenant un produit autonome plutôt qu'un harness de preuve.
## Hors scope confirmé
- Uroburas Mode 3 ;
- matchmaking ;
- auth complète ;
- snapshots/deltas métier ;
- prediction/reconciliation ;
- rollback ;
- persistence gameplay ;
- Redis/NATS/Kafka ;
- scaling/sharding/regions ;
- WebTransport/QUIC productif ;
- Actix Web dans le data plane realtime ;
- modification du pipeline Android `0.3.3` sans régression causée par `0.3.4`.
## Critères d'entrée en beta
`0.3.4` peut entrer en beta lorsque :
- l'API commune ne dépend ni de Tokio ni de WebSocket ;
- le backend WebSocket implémente le contrat public sans fuite de types Tungstenite ;
- client et serveur round-tripent des payloads binaires sur localhost ;
- close local/distant est observable ;
- limites et timeouts retenus sont testés ;
- aucun queueing non borné ni runtime privé n'est introduit ;
- les targets tracing transport/WebSocket sont distinctes des futurs domaines session/sync/simulation ;
- aucune crate gameplay ou engine ne dépend de `tokio-tungstenite` ;
- les audits et tests ciblés sont propres ;
- la documentation décrit ce qui est réellement implémenté et ce qui reste reporté.