20 KiB
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.
Les tranches alpha.1 et alpha.2 ont été validées le 2026-09-21. La tranche active alpha.3 ajoute maintenant le backend WebSocket Tokio/tokio-tungstenite derrière le contrat transport-neutral validé ; les limites, timeouts et cas négatifs complets restent réservés à alpha.4.
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 :
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 ;
400fichiers,14membres Cargo et55fichiers Rust ;workspace.package.version = 0.3.3avant migration ;- audits Rust/workspace, Markdown et distribution propres sur l'archive ;
- aucune arborescence générée
target/,node_modules/,gen/androidoubuild/livrée ; - gameplay et moteurs sans dépendance réseau realtime ;
- baseline Android
0.3.3conservé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 :
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 retenues et introduites par alpha.3 :
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.1annonce un MSRV1.71; tokio-tungstenite 0.30.0ettungstenite 0.30.0annoncent un MSRV1.85;tokio-tungstenitedépend déjà de Tokio1.xet de Tungstenite0.30.0;- ses features par défaut couvrent
connectethandshake, sans TLS ; native-tlset les variantesrustls-*sont optionnelles ;- Tungstenite expose déjà des limites de message/frame et de write buffer configurables.
alpha.3 centralise désormais ces versions sous [workspace.dependencies] et active les features uniquement dans game-realtime-websocket-lib. futures-util est consommé avec default-features = false et seulement sink + std; tokio-tungstenite est consommé avec default-features = false et seulement connect + handshake; aucune feature TLS n'est activée. La compatibilité effective de la toolchain utilisateur avec ces MSRV sera attestée par la gate Cargo utilisateur de cette tranche.
Ownership physique retenu
game-realtime-transport-lib
Créer sous :
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 :
crates/common/game-realtime-websocket-lib
Responsabilités :
- implémentation WebSocket du contrat transport ;
tokio-tungsteniteet 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 :
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 :
connection.split() -> sender + receiver
sender.send(bytes) -> async Result
sender.close() -> async Result
receiver.receive() -> async Result<Message | Closed>
alpha.2 retient une API statiquement dispatchée fondée sur des associated types : RealtimeConnection produit un Sender et un Receiver, puis les opérations async exposent des futures associées GAT (SendFuture, CloseFuture, ReceiveFuture). Le contrat commun n'utilise ni async-trait, ni Box<dyn Future>, ni runtime concret.
Aucune borne Send n'est imposée aux futures par le contrat transport-neutral : un backend natif peut naturellement fournir des futures Send, tandis qu'un futur backend navigateur/WASM ne doit pas être rendu impossible par une contrainte de threading qui ne relève pas du transport abstrait.
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 :
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,ProviderouRuntimen'est créé dansalpha.2sans 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-tlscontrerustls; - 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 :
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 :
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.
Décisions matérialisées dans alpha.3
Le backend concret reste sous crates/common/game-realtime-websocket-lib et dépend uniquement du contrat commun plus des briques réseau/tracing nécessaires.
L'API publique expose :
connect(endpoint)
WebSocketListener::bind(address)
WebSocketListener::accept()
WebSocketConnection
WebSocketSender
WebSocketReceiver
Les types WebSocketStream, SplitSink, SplitStream, MaybeTlsStream et tungstenite::Error restent privés. Client et serveur produisent le même WebSocketConnection public grâce à une représentation interne à deux variantes ; le contrat commun reste donc la seule frontière partagée par les consommateurs.
connect() accepte volontairement uniquement ws:// dans cette baseline. Le TLS direct reste différé. Les frames binaires deviennent TransportMessage; Close devient TransportReceive::Closed; Ping/Pong sont traités comme contrôle backend ; Text et raw Frame sont explicitement rejetés comme erreurs de protocole. Les tests négatifs exhaustifs correspondants restent planifiés pour alpha.4.
Le backend ne crée aucun runtime, thread ni task détachée. Le harness d'intégration utilise un runtime Tokio de test courant, un bind 127.0.0.1:0 et une borne temporelle uniquement pour empêcher un test loopback défectueux de rester suspendu.
Aucun README.md/USAGE.md local n'est ajouté pendant alpha.3 : la crate reste petite, son API publique est documentée par rustdoc et le présent plan porte encore les décisions durables. Ce choix sera réévalué pendant la consolidation finale conformément à DOC-CRATE-*.
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 :
- bind serveur sur port éphémère ;
- connexion client ;
- client → serveur : payload binaire ;
- serveur → client : réponse binaire ;
- fermeture propre initiée d'un côté et observée de l'autre ;
- dépassement de taille rejeté ;
- comportement explicite sur frame Text ;
- connexion interrompue/peer drop ;
- timeout d'opération retenu ;
- 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 :
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 :
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 :
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 :
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 ;
- retenir des futures associées GAT afin de préserver le dispatch statique sans box ni contrainte
Sendimposée au contrat ; - 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-tungsteniteetfutures-utilavec 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.mdsi statut macro à réconcilier ;- historique beta ;
- documentation finale ;
- prompt
0.3.5pré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.3sans régression causée par0.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é.